|
View:
New views
2 Messages
—
Rating Filter:
Alert me
|
|
|
[ruby-dev:39593] infinite recursive rb_block_call遠藤です。
[ruby-core:24794] と似たような問題は、rb_block_call でも起きるようです。 $ ./ruby -e ' class C include Enumerable alias :each :min end C.new.min ' Segmentation fault min 以外でも Enumerable のメソッドで大抵落ちるみたいです。 rb_funcall_no_recursive を真似て rb_block_call_no_recursive を作って 見ました。[ruby-dev:39592] の相互再帰の問題は同じようにあると思います。 この方針だとほぼすべての rb_block_call の呼び出しを書き換えて戻り値が Qundef でないかどうかチェックする必要がありそうです。可読性や性能を 犠牲にしてでも、このような異常なプログラムを救済すべきでしょうか (Qundef を返さず直接例外を投げればもう少しすっきりする?) 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); + rb_thread_t *th = GET_THREAD(); + 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); -- Yusuke ENDOH <mame@...> |
|
|
[ruby-dev:39597] Re: infinite recursive rb_block_callまつもと ゆきひろです
In message "Re: [ruby-dev:39593] infinite recursive rb_block_call" on Fri, 30 Oct 2009 22:17:04 +0900, Yusuke ENDOH <mame@...> writes: |この方針だとほぼすべての rb_block_call の呼び出しを書き換えて戻り値が |Qundef でないかどうかチェックする必要がありそうです。。可読性や性能を |犠牲にしてでも、このような異常なプログラムを救済すべきでしょうか |(Qundef を返さず直接例外を投げればもう少しすっきりする?) その価値はないと思います。 |
| Free embeddable forum powered by Nabble | Forum Help |