From: SASADA Koichi Date: 2009-05-22T05:39:46+09:00 Subject: [ruby-dev:38521] Re: [Bug:1.9] Enumerator.new { }.take(1).inject(&:+) causes stack overflow  ささだです. Yusuke ENDOH wrote:: > そこで、以下のように、yielder_new_i で proc メソッドを呼ぶことで > バグは直りました。  似たような話なんですが,そもそも rb_iterate を使う場面じゃなさそうな. Index: enumerator.c =================================================================== --- enumerator.c (リビジョン 23496) +++ enumerator.c (作業コピー) @@ -718,12 +718,6 @@ } static VALUE -yielder_new_i(VALUE dummy) -{ - return yielder_init(yielder_allocate(rb_cYielder), rb_block_proc()); -} - -static VALUE yielder_yield_i(VALUE obj, VALUE memo, int argc, VALUE *argv) { return rb_yield_values2(argc, argv); @@ -732,7 +726,7 @@ static VALUE yielder_new(void) { - return rb_iterate(yielder_new_i, (VALUE)0, yielder_yield_i, (VALUE)0); + return yielder_init(yielder_allocate(rb_cYielder), rb_proc_new(yielder_yield_i, 0)); } /* > 上に関係して、Ruby のソースコードには以下のアサーションが暗黙に > 存在すると思ったのですが、正しいでしょうか。 > > - passed_block が設定されたら、eval ループに戻る前に Ruby レベルの > メソッドを呼んで passed_block を回収させないといけない yes. > - rb_iterate や rb_block_call の第一引数に渡される関数は、その中で > Ruby レベルのメソッドを呼ばないといけない yes. > 後者は C API に関わる話なので、正しいようなら README.EXT に書き > 加えた方がいいと思います。というか書き加えようと思います。  これは,実は 1.8 以前との非互換の問題だったんですよね.  これを真面目に解決しようとすると,このようなレアケースのためにブロック をチェックする全てのコードに passed_block をチェックするように変更する必 要が出てきて,ちょっと現実的じゃないのです. *フレームをその時だけいじっちゃう,という回避手段があるような,  嫌なところに波及しそうな.  例えば,rb_iterate は obsolete にしてしまって(制限付きで存在), rb_block_call を使うようにして下さい,とドキュメントするのはどんなもんで しょうか. -- // SASADA Koichi at atdot dot net // 久しぶりに Ruby のソースコードをいじった