Skip to content

Commit ba4e15d

Browse files
committed
Fix edgecase segfault of BigDecimal#remainder
There is a possibility where coerced remainder returns Qnil. NIL_P(BigDecimal_divremain(self, r, &d, &rv)) doesn't mean d and rv has a calculated value.
1 parent 57e0d40 commit ba4e15d

2 files changed

Lines changed: 13 additions & 7 deletions

File tree

ext/bigdecimal/bigdecimal.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,14 +2043,14 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
20432043
b = GetVpValue(r, 0);
20442044
}
20452045

2046-
if (!b) return DoSomeOne(self, r, rb_intern("remainder"));
2046+
if (!b) return Qfalse;
20472047
SAVE(b);
20482048

20492049
if (VpIsPosInf(b) || VpIsNegInf(b)) {
20502050
GUARD_OBJ(*dv, NewZeroWrapLimited(1, 1));
20512051
VpSetZero(*dv, 1);
20522052
*rv = a;
2053-
return Qnil;
2053+
return Qtrue;
20542054
}
20552055

20562056
mx = (a->MaxPrec + b->MaxPrec) *VpBaseFig();
@@ -2074,7 +2074,7 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
20742074

20752075
*dv = d;
20762076
*rv = ff;
2077-
return Qnil;
2077+
return Qtrue;
20782078
}
20792079

20802080
/* call-seq:
@@ -2087,11 +2087,11 @@ BigDecimal_divremain(VALUE self, VALUE r, Real **dv, Real **rv)
20872087
static VALUE
20882088
BigDecimal_remainder(VALUE self, VALUE r) /* remainder */
20892089
{
2090-
VALUE f;
20912090
Real *d, *rv = 0;
2092-
f = BigDecimal_divremain(self, r, &d, &rv);
2093-
if (!NIL_P(f)) return f;
2094-
return VpCheckGetValue(rv);
2091+
if (BigDecimal_divremain(self, r, &d, &rv)) {
2092+
return VpCheckGetValue(rv);
2093+
}
2094+
return DoSomeOne(self, r, rb_intern("remainder"));
20952095
}
20962096

20972097
/* call-seq:

test/bigdecimal/test_bigdecimal.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,12 @@ def test_remainder_with_rational
10891089
assert_kind_of(BigDecimal, BigDecimal("3").remainder(1.quo(3)))
10901090
end
10911091

1092+
def test_remainder_coerce
1093+
o = Object.new
1094+
def o.coerce(x); [x, BigDecimal("3")]; end
1095+
assert_equal(BigDecimal("1.1"), BigDecimal("7.1").remainder(o))
1096+
end
1097+
10921098
def test_divmod
10931099
x = BigDecimal((2**100).to_s)
10941100
assert_equal([(x / 3).floor, 1], x.divmod(3))

0 commit comments

Comments
 (0)