# Infinite recursive rb_block_call

e\$B1sF#\$G\$9!#e(B

[ruby-core:24794] e\$B\$H;w\$?\$h\$&\$JLdBj\$O!"e(Brb_block_call
e\$B\$G\$b5/\$-\$k\$h\$&\$G\$9!#e(B

\$ ./ruby -e ’
class C
include Enumerable
alias :each :min
end
C.new.min

Segmentation fault

min e\$B0J30\$G\$be(B Enumerable e\$B\$N%a%=%C%I\$GBgDqMn\$A\$k\$_\$?\$\$\$G\$9!#e(B

rb_funcall_no_recursive e\$B\$r??;w\$Fe(B rb_block_call_no_recursive
e\$B\$r:n\$C\$Fe(B
e\$B8+\$^\$7\$?!#e(B[ruby-dev:39592]
e\$B\$NAj8_:F5"\$NLdBj\$OF1\$8\$h\$&\$K\$"\$k\$H;W\$\$\$^\$9!#e(B

e\$B\$3\$NJ}?K\$@\$H\$[\$\$9\$Y\$F\$Ne(B rb_block_call
e\$B\$N8F\$S=P\$7\$r=q\$-49\$(\$FLa\$jCM\$,e(B
Qundef
e\$B\$G\$J\$\$\$+\$I\$&\$+%A%’%C%/\$9\$kI,MW\$,\$"\$j\$=\$&\$G\$9!#2DFI@-\$d@-G=\$re(B
e\$B5>@7\$K\$7\$F\$G\$b!"\$3\$N\$h\$&\$J0[>o\$J%W%m%0%i%`\$r5_:Q\$9\$Y\$-\$G\$7\$g\$&\$+e(B
(Qundef e\$B\$rJV\$5\$:D>@\Nc30\$rEj\$2\$l\$P\$b\$&>/\$7\$9\$C\$-\$j\$9\$k!)e(B)

# Index: enum.c

— enum.c (revision 25576)
+++ enum.c (working copy)
@@ -1101,7 +1101,10 @@
rb_block_call(obj, id_each, 0, 0, min_ii, (VALUE)result);
}
else {

• rb_block_call(obj, id_each, 0, 0, min_i, (VALUE)result);
• VALUE ret = rb_block_call_no_recursive(obj, id_each, 0, 0, min_i,
(VALUE)result, enum_min);
• if (ret == Qundef) {
• `````` rb_raise(rb_eRuntimeError, "recursive call to Enumerable#min");
``````
• }
}
if (result[0] == Qundef) return Qnil;
return result[0];
Index: vm_eval.c
===================================================================
— vm_eval.c (revision 25576)
+++ vm_eval.c (working copy)
@@ -815,7 +815,48 @@
return rb_iterate(iterate_method, (VALUE)&arg, bl_proc, data2);
}

+struct iter_method_arg_no_recursive {

• struct iter_method_arg arg;
• VALUE (*func)();
+};

+static VALUE
+iterate_method_no_recursive(VALUE obj)
+{

• const struct iter_method_arg_no_recursive * arg =
• `````` (struct iter_method_arg_no_recursive *) obj;
``````
• rb_method_entry_t *me = rb_search_method_emtry(arg->arg.obj,
arg->arg.mid);
• int call_status;
• if (!me) return Qundef;
• if (me->def && me->def->type == VM_METHOD_TYPE_CFUNC &&
• me->def->body.cfunc.func == arg->func)
• return Qundef;
• call_status = rb_method_call_status(th, me, CALL_FCALL, Qundef);
• if (call_status != NOEX_OK) {
• return Qundef;
• }
• stack_check();
• iterate_method((VALUE) &arg->arg);
+}

VALUE
+rb_block_call_no_recursive(VALUE obj, ID mid, int argc, VALUE * argv,

• ``````    VALUE (*bl_proc) (ANYARGS), VALUE data2,
``````
• ``````    VALUE (*func)())
``````

+{

• struct iter_method_arg_no_recursive arg;
• arg.arg.obj = obj;
• arg.arg.mid = mid;
• arg.arg.argc = argc;
• arg.arg.argv = argv;
• arg.func = func;
• return rb_iterate(iterate_method_no_recursive, (VALUE)&arg,
bl_proc, data2);
+}

+VALUE
rb_each(VALUE obj)
{
return rb_call(obj, idEach, 0, 0, CALL_FCALL);

e\$B\$^\$D\$b\$He(B e\$B\$f\$-\$R\$m\$G\$9e(B

In message “Re: [ruby-dev:39593] infinite recursive rb_block_call”
on Fri, 30 Oct 2009 22:17:04 +0900, Yusuke ENDOH [email protected]
writes:

|e\$B\$3\$NJ}?K\$@\$H\$[\$\$9\$Y\$F\$Ne(B rb_block_call e\$B\$N8F\$S=P\$7\$r=q\$-49\$(\$FLa\$jCM\$,e(B
|Qundef e\$B\$G\$J\$\$\$+\$I\$&\$+%A%'%C%/\$9\$kI,MW\$,\$“\$j\$=\$&\$G\$9!#2DFI@-\$d@-G=\$re(B
|e\$B5>@7\$K\$7\$F\$G\$b!”\$3\$N\$h\$&\$J0[>o\$J%W%m%0%i%`\$r5_:Q\$9\$Y\$-\$G\$7\$g\$&\$+e(B
|(Qundef e\$B\$rJV\$5\$:D>@\Nc30\$rEj\$2\$l\$P\$b\$&>/\$7\$9\$C\$-\$j\$9\$k!)e(B)

e\$B\$=\$N2ACM\$O\$J\$\$\$H;W\$\$\$^\$9!#e(B