Skip to content

Commit b9ce2c8

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 b9ce2c8

File tree

2 files changed

+15
-1
lines changed

2 files changed

+15
-1
lines changed

ext/bigdecimal/bigdecimal.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2770,8 +2770,12 @@ rb_big_convert_to_BigDecimal(VALUE val, RB_UNUSED_VAR(size_t digs), int raise_ex
27702770
{
27712771
assert(RB_TYPE_P(val, T_BIGNUM));
27722772

2773-
size_t size = rb_absint_size(val, NULL);
2773+
int leading_zeros;
2774+
size_t size = rb_absint_size(val, &leading_zeros);
27742775
int sign = FIX2INT(rb_big_cmp(val, INT2FIX(0)));
2776+
if (leading_zeros == 0) {
2777+
size += 1;
2778+
}
27752779
if (size <= sizeof(long)) {
27762780
if (sign < 0) {
27772781
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)