遠藤と申します。

1.9 で以下のようにすると落ちます。


$ ./ruby -ve '
loop do
    begin
        Thread.start(Thread.current) {|u| u.raise }
        raise
    rescue
    ensure
    end
end
'
ruby 1.9.0 (2007-08-09 patchlevel 0) [i686-linux]
-e: warning: instance variable #__ThrowState__ not initialized
-e:2: -- control frame ----------
c:0003 p:0008 s:0004 b:0005 l:0012ac d:0012ac TOP    -e:2
c:0002 p:---- s:0003 b:0003 l:000002 d:000002 FINISH :inherited
c:0001 p:---- s:0001 b:-001 l:000000 d:000000 ------
---------------------------
-- backtrace of native function call (Use addr2line) --
0x80dac65
0x80f4033
0x80f40fb
0x80d8ca5
0x80d9564
0x80d989b
0x8059229
0x805d79d
0x8056df2
0xb7dacea8
0x8056d21
-------------------------------------------------------
[BUG] Stack consistency error (sp: 4, bp: 5)
ruby 1.9.0 (2007-08-09) [i686-linux]

アボートしました (core dumped)


同じスレッドにほぼ同時に複数の例外が発生するとき落ちるようです。
timeout を使うコードを Ctrl+C で止めるとたまに発生するので気が付きました。


少し追ってみましたが、状況がややこしくてどこからどこまでが想定外の挙動なのか
わかりませんでした。以下のようなことが起きているようです。

- 1 発目の raise で rb_longjmp が呼ばれる
- rb_longjmp 中の rb_exc_new (eval.c:660 あたり) でコンテキストスイッチする
- 別スレッドから 2 発目の raise で rb_longjmp に再入する
- JUMP_TAG(TAG_FATAL); が実行される (eval.c:654 あたり)
- rb_ivar_get(err, idThrowState) が実行される (insnhelper.ci:1303 あたり)
- #__ThrowState__ は初期化されておらず、警告とともに Qnil が返る
- th->state = FIX2INT(Qnil) が実行される (insnhelper.ci:1303 あたり)
- Stack consistency error になる

-- 
Yusuke ENDOH <mame / tsg.ne.jp>