[前][次][番号順一覧][スレッド一覧]

ruby-changes:53426

From: shyouhei <ko1@a...>
Date: Fri, 9 Nov 2018 18:14:28 +0900 (JST)
Subject: [ruby-changes:53426] shyouhei:r65642 (trunk): numeric.c: avoid division by zero

shyouhei	2018-11-09 18:14:23 +0900 (Fri, 09 Nov 2018)

  New Revision: 65642

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=65642

  Log:
    numeric.c: avoid division by zero
    
    In C, division by zero is undefined, even if the expression is double
    (cf: ISO/IEC 9899:1990 section 6.3.5).  OTOH we have tests about such
    operations and results, means we expect no exceptional situation shall
    occur.  We need to carefully reroute the situation, and generate what
    is needed.
    
    See also: https://travis-ci.org/ruby/ruby/jobs/452680646#L2943
    
    PS: Recently (last two decades), C have Annex. F document. It
    normatively specifies that the division operator is IEEE 754's
    division operator (cf: ISO/IEC 9899:1999 section F.3).  If we could
    move to such newer version this could be no problem.  But that is not
    possible today.

  Modified files:
    trunk/numeric.c
Index: numeric.c
===================================================================
--- numeric.c	(revision 65641)
+++ numeric.c	(revision 65642)
@@ -1083,6 +1083,12 @@ flo_mul(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1083
     }
 }
 
+static bool
+flo_iszero(VALUE f)
+{
+    return RFLOAT_VALUE(f) == 0.0;
+}
+
 /*
  * call-seq:
  *   float / other  ->  float
@@ -1093,23 +1099,52 @@ flo_mul(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1099
 static VALUE
 flo_div(VALUE x, VALUE y)
 {
-    long f_y;
-    double d;
+    double den;
+    double num = RFLOAT_VALUE(x);
+    double sign = 1.0;
 
     if (RB_TYPE_P(y, T_FIXNUM)) {
-	f_y = FIX2LONG(y);
-	return DBL2NUM(RFLOAT_VALUE(x) / (double)f_y);
+        if (FIXNUM_ZERO_P(y)) {
+            goto zerodiv;
+        }
+        else {
+            den = FIX2LONG(y);
+            goto nonzero;
+        }
     }
     else if (RB_TYPE_P(y, T_BIGNUM)) {
-	d = rb_big2dbl(y);
-	return DBL2NUM(RFLOAT_VALUE(x) / d);
+        if (rb_bigzero_p(y)) {
+            goto zerodiv;
+        }
+        else {
+            den = rb_big2dbl(y);
+            goto nonzero;
+        }
     }
     else if (RB_TYPE_P(y, T_FLOAT)) {
-	return DBL2NUM(RFLOAT_VALUE(x) / RFLOAT_VALUE(y));
+        if (flo_iszero(y)) {
+            sign = signbit(RFLOAT_VALUE(y)) ? -1.0 : 1.0;
+            goto zerodiv;
+        }
+        else {
+            den = RFLOAT_VALUE(y);
+            goto nonzero;
+        }
     }
     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);
+    }
 }
 
 /*
@@ -1676,10 +1711,7 @@ rb_float_abs(VALUE flt) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1711
 static VALUE
 flo_zero_p(VALUE num)
 {
-    if (RFLOAT_VALUE(num) == 0.0) {
-	return Qtrue;
-    }
-    return Qfalse;
+    return flo_iszero(num) ? Qtrue : Qfalse;
 }
 
 /*

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]