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

ruby-changes:43818

From: nobu <ko1@a...>
Date: Sat, 13 Aug 2016 23:08:06 +0900 (JST)
Subject: [ruby-changes:43818] nobu:r55891 (trunk): numeric.c: infinite recursion

nobu	2016-08-13 23:08:03 +0900 (Sat, 13 Aug 2016)

  New Revision: 55891

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

  Log:
    numeric.c: infinite recursion
    
    * numeric.c (num_funcall0, num_funcall1): get rid of infinite
      recursion in fallback methods of Numeric.

  Modified files:
    trunk/ChangeLog
    trunk/numeric.c
    trunk/test/ruby/test_float.rb
Index: numeric.c
===================================================================
--- numeric.c	(revision 55890)
+++ numeric.c	(revision 55891)
@@ -240,6 +240,62 @@ rb_num_negative_p(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L240
     return negative_int_p(num);
 }
 
+static VALUE
+num_funcall_op_0(VALUE x, VALUE arg, int recursive)
+{
+    ID func = (ID)arg;
+    if (recursive) {
+	const char *name = rb_id2name(func);
+	if (ISALNUM(name[0])) {
+	    rb_name_error(func, "%"PRIsVALUE".%"PRIsVALUE,
+			  x, ID2SYM(func));
+	}
+	else if (name[0] && name[1] == '@' && !name[2]) {
+	    rb_name_error(func, "%c%"PRIsVALUE,
+			  name[0], x);
+	}
+	else {
+	    rb_name_error(func, "%"PRIsVALUE"%"PRIsVALUE,
+			  ID2SYM(func), x);
+	}
+    }
+    return rb_funcall(x, func, 0, 0);
+}
+
+static VALUE
+num_funcall0(VALUE x, ID func)
+{
+    return rb_exec_recursive(num_funcall_op_0, x, (VALUE)func);
+}
+
+static VALUE
+num_funcall_op_1(VALUE x, VALUE arg, int recursive)
+{
+    ID func = (ID)((VALUE *)arg)[0];
+    VALUE y = ((VALUE *)arg)[1];
+    if (recursive) {
+	const char *name = rb_id2name(func);
+	if (ISALNUM(name[0])) {
+	    rb_name_error(func, "%"PRIsVALUE".%"PRIsVALUE"(%"PRIsVALUE")",
+			  x, ID2SYM(func), y);
+	}
+	else {
+	    rb_name_error(func, "%"PRIsVALUE"%"PRIsVALUE"%"PRIsVALUE,
+			  x, ID2SYM(func), y);
+	}
+    }
+    return rb_funcall(x, func, 1, y);
+}
+
+static VALUE
+num_funcall1(VALUE x, ID func, VALUE y)
+{
+    VALUE args[2];
+    args[0] = (VALUE)func;
+    args[1] = y;
+    return rb_exec_recursive_paired(num_funcall_op_1, x, y, (VALUE)args);
+}
+
 /*
  *  call-seq:
  *     num.coerce(numeric)  ->  array
@@ -443,7 +499,7 @@ num_uminus(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L499
     zero = INT2FIX(0);
     do_coerce(&zero, &num, TRUE);
 
-    return rb_funcall(zero, '-', 1, num);
+    return num_funcall1(zero, '-', num);
 }
 
 /*
@@ -476,7 +532,7 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/numeric.c#L532
 num_div(VALUE x, VALUE y)
 {
     if (rb_equal(INT2FIX(0), y)) rb_num_zerodiv();
-    return rb_funcall(rb_funcall(x, '/', 1, y), rb_intern("floor"), 0);
+    return rb_funcall(num_funcall1(x, '/', y), rb_intern("floor"), 0);
 }
 
 
@@ -494,9 +550,9 @@ num_div(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L550
 static VALUE
 num_modulo(VALUE x, VALUE y)
 {
+    VALUE q = num_funcall1(x, id_div, y);
     return rb_funcall(x, '-', 1,
-		      rb_funcall(y, '*', 1,
-				 rb_funcall(x, id_div, 1, y)));
+		      rb_funcall(y, '*', 1, q));
 }
 
 /*
@@ -511,7 +567,7 @@ num_modulo(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L567
 static VALUE
 num_remainder(VALUE x, VALUE y)
 {
-    VALUE z = rb_funcall(x, '%', 1, y);
+    VALUE z = num_funcall1(x, '%', y);
 
     if ((!rb_equal(z, INT2FIX(0))) &&
 	((negative_int_p(x) &&
@@ -618,7 +674,7 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/numeric.c#L674
 num_abs(VALUE num)
 {
     if (negative_int_p(num)) {
-	return rb_funcall(num, idUMinus, 0);
+	return num_funcall0(num, idUMinus);
     }
     return num;
 }
@@ -665,7 +721,7 @@ num_zero_p(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L721
 static VALUE
 num_nonzero_p(VALUE num)
 {
-    if (RTEST(rb_funcallv(num, rb_intern("zero?"), 0, 0))) {
+    if (RTEST(num_funcall0(num, rb_intern("zero?")))) {
 	return Qnil;
     }
     return num;
@@ -713,7 +769,7 @@ num_infinite_p(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L769
 static VALUE
 num_to_int(VALUE num)
 {
-    return rb_funcallv(num, id_to_i, 0, 0);
+    return num_funcall0(num, id_to_i);
 }
 
 /*
@@ -1002,7 +1058,7 @@ flo_div(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1058
 static VALUE
 flo_quo(VALUE x, VALUE y)
 {
-    return rb_funcall(x, '/', 1, y);
+    return num_funcall1(x, '/', y);
 }
 
 static void
@@ -1157,7 +1213,7 @@ flo_pow(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1213
 	dx = RFLOAT_VALUE(x);
 	dy = RFLOAT_VALUE(y);
 	if (dx < 0 && dy != round(dy))
-	    return rb_funcall(rb_complex_raw1(x), idPow, 1, y);
+	    return num_funcall1(rb_complex_raw1(x), idPow, y);
     }
     else {
 	return rb_num_coerce_bin(x, y, idPow);
@@ -1210,7 +1266,7 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/numeric.c#L1266
 num_equal(VALUE x, VALUE y)
 {
     if (x == y) return Qtrue;
-    return rb_funcall(y, id_eq, 1, x);
+    return num_funcall1(y, id_eq, x);
 }
 
 /*
@@ -2988,7 +3044,7 @@ rb_int_succ(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3044
     if (RB_TYPE_P(num, T_BIGNUM)) {
 	return rb_big_plus(num, INT2FIX(1));
     }
-    return rb_funcall(num, '+', 1, INT2FIX(1));
+    return num_funcall1(num, '+', INT2FIX(1));
 }
 
 #define int_succ rb_int_succ
@@ -3013,7 +3069,7 @@ rb_int_pred(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3069
     if (RB_TYPE_P(num, T_BIGNUM)) {
 	return rb_big_minus(num, INT2FIX(1));
     }
-    return rb_funcall(num, '-', 1, INT2FIX(1));
+    return num_funcall1(num, '-', INT2FIX(1));
 }
 
 #define int_pred rb_int_pred
@@ -3160,7 +3216,7 @@ rb_int_uminus(VALUE num) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3216
     else if (RB_TYPE_P(num, T_BIGNUM)) {
 	return rb_big_uminus(num);
     }
-    return rb_funcall(num, idUMinus, 0, 0);
+    return num_funcall0(num, idUMinus);
 }
 
 /*
@@ -3724,7 +3780,7 @@ fix_pow(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3780
 		return INT2FIX(-1);
 	}
 	if (b < 0)
-	    return rb_funcall(rb_rational_raw1(x), idPow, 1, y);
+	    return num_funcall1(rb_rational_raw1(x), idPow, y);
 
 	if (b == 0) return INT2FIX(1);
 	if (b == 1) return x;
@@ -3741,7 +3797,7 @@ fix_pow(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3797
 	    else return INT2FIX(-1);
 	}
 	if (negative_int_p(y))
-	    return rb_funcall(rb_rational_raw1(x), idPow, 1, y);
+	    return num_funcall1(rb_rational_raw1(x), idPow, y);
 	if (a == 0) return INT2FIX(0);
 	x = rb_int2big(FIX2LONG(x));
 	return rb_big_pow(x, y);
@@ -3755,7 +3811,7 @@ fix_pow(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L3811
 	{
 	    double dy = RFLOAT_VALUE(y);
 	    if (a < 0 && dy != round(dy))
-		return rb_funcall(rb_complex_raw1(x), idPow, 1, y);
+		return num_funcall1(rb_complex_raw1(x), idPow, y);
 	    return DBL2NUM(pow((double)a, dy));
 	}
     }
@@ -4081,7 +4137,7 @@ VALUE https://github.com/ruby/ruby/blob/trunk/numeric.c#L4137
 rb_num_coerce_bit(VALUE x, VALUE y, ID func)
 {
     bit_coerce(&x, &y);
-    return rb_funcall(x, func, 1, y);
+    return num_funcall1(x, func, y);
 }
 
 /*
@@ -4105,7 +4161,7 @@ fix_and(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L4161
     }
 
     bit_coerce(&x, &y);
-    return rb_funcall(x, '&', 1, y);
+    return num_funcall1(x, '&', y);
 }
 
 static VALUE
@@ -4141,7 +4197,7 @@ fix_or(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L4197
     }
 
     bit_coerce(&x, &y);
-    return rb_funcall(x, '|', 1, y);
+    return num_funcall1(x, '|', y);
 }
 
 static VALUE
@@ -4177,7 +4233,7 @@ fix_xor(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L4233
     }
 
     bit_coerce(&x, &y);
-    return rb_funcall(x, '^', 1, y);
+    return num_funcall1(x, '^', y);
 }
 
 static VALUE
Index: test/ruby/test_float.rb
===================================================================
--- test/ruby/test_float.rb	(revision 55890)
+++ test/ruby/test_float.rb	(revision 55891)
@@ -793,4 +793,21 @@ class TestFloat < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_float.rb#L793
     h = {0.0 => bug10979}
     assert_equal(bug10979, h[-0.0])
   end
+
+  def test_aliased_quo_recursion
+    assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}")
+    begin;
+      class Float
+        $VERBOSE = nil
+        alias / quo
+      end
+      assert_raise(NameError) do
+        begin
+          1.0/2.0
+        rescue SystemStackError => e
+          raise SystemStackError, e.message
+        end
+      end
+    end;
+  end
 end
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 55890)
+++ ChangeLog	(revision 55891)
@@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Sat Aug 13 23:08:01 2016  Nobuyoshi Nakada  <nobu@r...>
+
+	* numeric.c (num_funcall0, num_funcall1): get rid of infinite
+	  recursion in fallback methods of Numeric.
+
 Sat Aug 13 11:10:08 2016  Nobuyoshi Nakada  <nobu@r...>
 
 	* parse.y (command_asgn, arg): fix syntax errors with chained

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

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