Shiro Kawai
shiro****@lava*****
2005年 5月 21日 (土) 08:52:40 JST
GaucheとObjCがそれぞれ独自に例外チェインを作ってて、 それがinterleaveしてるのがまずいと思います。 例外チェインは例外発生時に必ず順に辿られなければなりません。 Gauche側の例外機構を仮に g_try, g_catch, g_throw, ObjC側のそれを o_try, o_catch, o_throw とした場合、 例えば次のコードでは: foo () { g_try { bar() } g_catch (e) { } } bar () { o_try { baz() } o_catch (e) { } } baz () { g_throw(e); } g_throwは直接foo()のg_catchへ飛びますから、bar()で設定された ObjCの例外フレームが飛ばされてしまい、うまく動きません。 ObjCとGaucheの役割が入れ替わっても同じことです。 従って全ての関数において、(1)その時点で一番内側にある例外フレームが どちらの機構のものであるかが決まっていること (2)その関数から例外を 投げる時は必ず一番内側の機構の例外に変換して投げること、という 原則を守る必要があります。 Gauche側では、Scm_Apply内でひとつGauche側の例外チェインが 作られます (ソース上では user_eval_inner in vm.c)。 疑似コードで書くとこんな感じです。 Scm_Apply(proc, args) { g_try { ret = run_vm_with_proc_and_args(proc, args); } g_catch { 色々処理 もしかするとg_throw()するかも } return ret; } なので、proc実行中に有効な例外機構はGaucheの方になっています。 そこでObjCの例外が投げられると、Scm_Apply内で設定された例外 フレームがクリーンアップされないまま、Scm_Applyの外側に飛んで しまいます。そこでScm_VMThrowExceptionを呼ぶと、既にマシン スタック上から削除されたはずの例外フレームを呼びにゆくので クラッシュします。 解決策としては、GaucheからObjCの世界へ入る箇所全てに、 ObjCの例外をGaucheの例外に変換して投げるコードを入れる、 ということしか思い付きません。一方、ObjCからGaucheを呼ぶ 箇所全てで、Gaucheから来た例外をObjCの例外に変換して投げる ようにします。 --shiro