Skip to content

Commit 5f7422b

Browse files
committed
Fix negative Bignum conversion
Introduced in 4792a91 `rb_absint_size` return the number of bytes needed to fit the absolute integer, but negative integers need the sign, so one more bit, and potentially one more byte.
1 parent bdf2364 commit 5f7422b

File tree

2 files changed

+13
-0
lines changed

2 files changed

+13
-0
lines changed

ext/bigdecimal/bigdecimal.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2772,6 +2772,9 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
27722772

27732773
size_t size = rb_absint_size(val, NULL);
27742774
int sign = FIX2INT(rb_big_cmp(val, INT2FIX(0)));
2775+
if (sign < 0) {
2776+
size += 1;
2777+
}
27752778
if (size <= sizeof(long)) {
27762779
if (sign < 0) {
27772780
return rb_int64_convert_to_BigDecimal(NUM2LONG(val), digs, raise_exception);

test/bigdecimal/test_bigdecimal.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,6 +2089,16 @@ def test_initialize_copy_dup_clone_frozen_error
20892089
assert_raise(err) { bd.send(:initialize_dup, bd2) }
20902090
end
20912091

2092+
def test_llong_min
2093+
# https://github.com/ruby/bigdecimal/issues/199
2094+
# Between LLONG_MIN and -ULLONG_MAX
2095+
llong_min = -(2 ** 63 + 1)
2096+
assert_equal BigDecimal(llong_min.to_s), BigDecimal(llong_min)
2097+
2098+
minus_ullong_max = -(2 ** 64 - 1)
2099+
assert_equal BigDecimal(minus_ullong_max.to_s), BigDecimal(minus_ullong_max)
2100+
end
2101+
20922102
def assert_no_memory_leak(code, *rest, **opt)
20932103
code = "8.times {20_000.times {begin #{code}; rescue NoMemoryError; end}; GC.start}"
20942104
super(["-rbigdecimal"],

0 commit comments

Comments
 (0)