From: Yusuke ENDOH <mame@...> Date: 2009-10-30T21:46:20+09:00 Subject: [ruby-dev:39592] infinite recursive call to C function 遠藤です。 [ruby-core:24794] と似たような問題を探してみましたが、かなりありそうです。 $ ./ruby -e ' class Symbol include Enumerable alias to_enum zip end :each.zip(:each) { } ' Segmentation fault $ ruby19 -e ' class Hash alias default [] end {}[1] ' Segmentation fault $ ruby19 -e ' class Object alias to_open open public :to_open end o = Object.new eval("open(#{ (["o"] * 10000).join(",") })") # open(o, o, o, o, ...) ' Segmentation fault $ ruby19 -e ' class Time def to_str end end Time.now <=> "" ' Segmentation fault matz ruby では、この手のバグはちまちまと潰していくということで いいのでしょうか。 最後のは相互再帰するので rb_funcall_no_recursive では救えそうに ありません。<=> での相互再帰は多分結構ありそうですが、どうしま しょう。 Index: enum.c =================================================================== --- enum.c (revision 25576) +++ enum.c (working copy) @@ -1745,7 +1745,11 @@ if (!allary) { CONST_ID(conv, "to_enum"); for (i=0; i<argc; i++) { - argv[i] = rb_funcall(argv[i], conv, 1, ID2SYM(id_each)); + VALUE sym = ID2SYM(id_each); + argv[i] = rb_funcall_no_recursive(argv[i], conv, 1, &sym, enum_zip); + if (argv[i] == Qundef) { + rb_raise(rb_eRuntimeError, "recursive call to Enumerable#zip"); + } } } if (!rb_block_given_p()) { Index: io.c =================================================================== --- io.c (revision 25576) +++ io.c (working copy) @@ -5589,7 +5589,10 @@ } } if (redirect) { - VALUE io = rb_funcall2(argv[0], to_open, argc-1, argv+1); + VALUE io = rb_funcall_no_recursive(argv[0], to_open, argc-1, argv+1, rb_f_open); + if (io == Qundef) { + rb_raise(rb_eRuntimeError, "recursive call to Kernel#open"); + } if (rb_block_given_p()) { return rb_ensure(rb_yield, io, io_close, io); Index: hash.c =================================================================== --- hash.c (revision 25576) +++ hash.c (working copy) @@ -494,7 +494,11 @@ VALUE val; if (!RHASH(hash)->ntbl || !st_lookup(RHASH(hash)->ntbl, key, &val)) { - return rb_funcall(hash, id_default, 1, key); + VALUE ret = rb_funcall_no_recursive(hash, id_default, 1, &key, rb_hash_aref); + if (ret == Qundef) { + rb_raise(rb_eRuntimeError, "recursive call to Hash#[]"); + } + return ret; } return val; } -- Yusuke ENDOH <mame@tsg.ne.jp>