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/