summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-11-12 03:26:39 +0000
committershyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-11-12 03:26:39 +0000
commit00b8b11858785439785c0f6805ea4b6910070020 (patch)
tree2bdd01ea10b74ce28396a3caa0b69f1ede365ac4
parent21e1260fb94f7d339ee60eedbba1975113ade7f1 (diff)
vm_insnhelper.c: avoid division by zero
same as r65642. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65678 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--internal.h1
-rw-r--r--numeric.c65
-rw-r--r--vm_insnhelper.c4
3 files changed, 34 insertions, 36 deletions
diff --git a/internal.h b/internal.h
index 1a03056..d36723b 100644
--- a/internal.h
+++ b/internal.h
@@ -1755,6 +1755,7 @@ rb_num_negative_int_p(VALUE num)
VALUE rb_float_abs(VALUE flt);
VALUE rb_float_equal(VALUE x, VALUE y);
VALUE rb_float_eql(VALUE x, VALUE y);
+VALUE rb_flo_div_flo(VALUE x, VALUE y);
#if USE_FLONUM
#define RUBY_BIT_ROTL(v, n) (((v) << (n)) | ((v) >> ((sizeof(v) * 8) - n)))
diff --git a/numeric.c b/numeric.c
index 47dbf72..6d09836 100644
--- a/numeric.c
+++ b/numeric.c
@@ -1089,6 +1089,30 @@ flo_iszero(VALUE f)
return RFLOAT_VALUE(f) == 0.0;
}
+static double
+double_div_double(double x, double y)
+{
+ if (LIKELY(y != 0.0)) {
+ return x / y;
+ }
+ else if (x == 0.0) {
+ return nan("");
+ }
+ else {
+ double z = signbit(y) ? -1.0 : 1.0;
+ return x * z * HUGE_VAL;
+ }
+}
+
+VALUE
+rb_flo_div_flo(VALUE x, VALUE y)
+{
+ double num = RFLOAT_VALUE(x);
+ double den = RFLOAT_VALUE(y);
+ double ret = double_div_double(x, y);
+ return DBL2NUM(ret);
+}
+
/*
* call-seq:
* float / other -> float
@@ -1099,52 +1123,25 @@ flo_iszero(VALUE f)
static VALUE
flo_div(VALUE x, VALUE y)
{
- double den;
double num = RFLOAT_VALUE(x);
- double sign = 1.0;
+ double den;
+ double ret;
if (RB_TYPE_P(y, T_FIXNUM)) {
- if (FIXNUM_ZERO_P(y)) {
- goto zerodiv;
- }
- else {
- den = FIX2LONG(y);
- goto nonzero;
- }
+ den = FIX2LONG(y);
}
else if (RB_TYPE_P(y, T_BIGNUM)) {
- if (rb_bigzero_p(y)) {
- goto zerodiv;
- }
- else {
- den = rb_big2dbl(y);
- goto nonzero;
- }
+ den = rb_big2dbl(y);
}
else if (RB_TYPE_P(y, T_FLOAT)) {
- if (flo_iszero(y)) {
- sign = signbit(RFLOAT_VALUE(y)) ? -1.0 : 1.0;
- goto zerodiv;
- }
- else {
- den = RFLOAT_VALUE(y);
- goto nonzero;
- }
+ den = RFLOAT_VALUE(y);
}
else {
return rb_num_coerce_bin(x, y, '/');
}
-nonzero:
- return DBL2NUM(num / den);
-
-zerodiv:
- if (num == 0.0) {
- return DBL2NUM(nan(""));
- }
- else {
- return DBL2NUM(num * sign * HUGE_VAL);
- }
+ ret = double_div_double(num, den);
+ return DBL2NUM(ret);
}
/*
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 84ed116..05a5289 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3450,7 +3450,7 @@ vm_opt_div(VALUE recv, VALUE obj)
}
else if (FLONUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) {
- return DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj));
+ return rb_flo_div_flo(recv, obj);
}
else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
return Qundef;
@@ -3458,7 +3458,7 @@ vm_opt_div(VALUE recv, VALUE obj)
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) {
- return DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj));
+ return rb_flo_div_flo(recv, obj);
}
else {
return Qundef;