__gnat_adjust_context_for_raiseの怪

これがわからない。

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50678

バグそのものは、Mountain Lionでの修正でそれまで__gnat_adjust_context_for_raiseに仕込んであったWorkaroundが不要になって、逆に悪さをするようになっていたというもの。Mountain Lionの時はWorkaroundを回避するようにしたら直った、らしい。

__gnat_adjust_context_for_raiseが何をする関数かといいますと、いくつかのプラットフォームで、シグナルハンドラから例外を投げるときに、sa_sigactionの第3パラメータとしてやってきたstruct ucontext *の補正を行うもの。

なんで補正が必要かというと、シグナルから復帰するためのucontextと、gccのunwinderが使うucontextが微妙に違うから。

うん、ここまではいいんですよ。

でもですよ、なんで、シグナルハンドラ中から投げるとはいえ、gccの例外がシグナルから復帰するためのstruct ucontext *に影響されるのかがわからないのです。

だって、このstruct ucontext *を補正した所で、そもそもこのstruct ucontext *の飛び先はシグナル発生箇所そのものなわけですよ。例外の飛び先は、もっとスタックを巻き戻した先にある例外ハンドラなわけですよ。_sigtramp云々書かれてますけど、_sigtramp中に戻るならともかく、例外はそんなところ飛び越えていくわけで。飛び先は現在のIPをDwrafのテーブルから検索して決めるわけで、レジスタの状態をどう戻すかも全部テーブルにあるわけですよ。
関係ないと思いませんか?
_Unwind_RaiseExceptionにこの情報が渡ってる気配のカケラも無いですし。
実際問題俺ランタイムなdrakeはこんな補正無くても動いてます。補正が必要とされてるLeopard〜Lionで。いや、こんな補正が本当に必要なら、世に無数にあるであろうシグナルを例外に変換しているアプリは(Darwinに限らず__gnat_adjust_context_for_raiseがなんかやってるプラットフォームで)軒並み怪しい動作をしているはず。

……ですけど現実にこれで挙動が変わるらしくて、冬の怪談です。