私のプロジェクトは C++ で書かれており、動的に生成されたコードを使用していくつかのものを結合しています (Fabrice Bellard のTCCと手動で生成されたアセンブリ サンクを少し使用しています)。動的に生成されたコードは、C++ で実装された「ランタイム ヘルパー」にジャンプして戻ってくることがあります。
どこにいても動的に生成されたコードを完全に中止して、C++ (呼び出し元) に戻ることができる機能があります。これを実現するために、単純に C++ 例外を使用しています。ランタイム ヘルパー (C 関数を装ったもの) は単純に C++ 例外をスローし、生成された関数を介して C++ に伝播します。私はSJLJを使用しており、これまでのところすべて正常に動作していますが、特定の実装に依存したくありません (SJLJ でのみ安全であると読みました)。
上記の中止スキームを除いて、私の C++ コードは主に重大な状況で例外を使用し、汎用の制御フローには使用されません。ただし、スタック上のオブジェクトを自動的に破棄するために RAII に依存しています。
私の質問は次のとおりです: setjmp が動的に生成された関数を呼び出す直前に設定され、longjmp が RAII に依存する C++ 関数を介して伝達されないことを条件として、代わりに longjmp/setjmp を使用することは理論的および実際的に安全ですか? C++ で実装されたランタイム ヘルパーはそれを利用し、常に setjmp (関数の直前に設定) に到達しますか?
または、C++ は非常に壊れやすいため、これでもうまく動作することが保証されておらず、何かが破損する可能性がありますか? それとも、実際の例外がスローされた場合にのみ C++ が壊れるのでしょうか? 例外がローカルでスローされ、すぐに (生成されたアセンブリによって呼び出されるランタイム ヘルパーで) キャッチされた場合、それは安全ですか? それとも、スタックにいくつかの外部フレームがあるという理由だけで、動作を拒否するのでしょうか?
例えば:
jmp_buf buf; // thread-local
char* msg; // thread-local
// ... some C++ code here, potentially some RAII thingy
GeneratedFunc func = (GeneratedFunc)compile_stuff();
if (!setjmp(buf)) {
// somewhere deep inside, it calls longjmp to jump back to the top function in case a problem happens
func();
} else {
printf("error: %s\n", msg);
// do something about the error here
}
// some other C++ code