WasmLinux: VC++でWasm側からthrowした例外がcatchできない問題
... メモ取ろうとしたら一撃で解決してしまった。。
extern "C"
な関数は、デフォルトで noexcept と見做される。これはドキュメントにもあり、これを避けるには /EHsc-
する。そうしない場合、C関数の呼出し中にC++コードから throw
した場合(つまり C++ → C → C++ のような呼出しスタックを持つ場合)に、普通の abort
と同様のダイアログが出てくることになる。
この辺の事情はMSVCのドキュメントにもちゃんとある。
... この手の最適化って /O1
以上じゃないとやらないもんだと思ってたけど、無指定でも容赦なくやってくるようだ。
なぜコレが問題になるのか
WasmLinuxのランタイムでは、スレッドの中断を例外で実現しているため。。つまり、Linuxカーネル側からスレッドの中断がリクエストされた場合、 throw
で例外を投げて無理矢理止める実装になっている。このとき、Linuxカーネルはwasm2cされたCコードなので、ランタイム側から見ると extern "C"
な関数ということになる。
(↓ のコードは C で実装された関数から呼ばれる)
もちろん、単に throw
だけだとスレッドだけではなくプログラムごと終了してしまうので、スレッドのコードを実行する前に try
節で囲んでいる。
関数 wasmlinux_user_ctx_exec32
は extern "C"
されている。このため、デフォルトでは例外をthrowしない関数と見做され、try節の中には例外を発生させる要因が無いということになってしまう。このため、コンパイラに /EHsc-
オプションを指定して、try節を生存させる必要がある。
/EHsc-
は /EHs
(C++例外をサポートし、 extern "C"
な関数も例外をthrowすると見做す) /EHc-
(C 関数が例外をthrow しない と見做すオプション /EHc
の 効果を打ち消す) の意味。