3

私のプロジェクトは 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
4

1 に答える 1

1

setjmp が動的に生成された関数を呼び出す直前に設定され、longjmp が RAII に依存する C++ 関数を介して伝播されない場合、代わりに longjmp/setjmp を使用することは理論的および実際的に安全ですか (実行時ヘルパーが実装されていないことを確認する必要があります)。 C ++はそれを利用します)、常にsetjmp(関数の直前に設定)に着陸しますか?

標準の 18.10/4 は次のように述べています。

...longjmp(jmp_buf jbuf, int val)この国際規格では、より制限された動作があります。setjmp/呼び出しのlongjmpペアは、setjmpandlongjmpcatchandに置き換えた場合、未定義の動作throwをし、任意の自動オブジェクトに対して重要なデストラクタを呼び出します。

つまり、RAII だけではなく、重要なデストラクタ (つまり、「リソース」は構築に取得される可能性がありますが、破壊中に解放する必要があるか、リソースの解放以外の破壊の副作用がある可能性があります。ロギングなど)。

または、C++ は非常に壊れやすいため、これでもうまく動作することが保証されておらず、何かが破損する可能性がありますか?

単純なデストラクタに関する上記の警告に従って動作するはずです (これは非常に大きな制限です)。

それとも、実際の例外がスローされた場合にのみ C++ が壊れるのでしょうか? 例外がローカルでスローされ、すぐに (生成されたアセンブリによって呼び出されるランタイム ヘルパーで) キャッチされた場合、それは安全ですか?

setjmpそれは/のlongjmp振る舞いとは無関係です。通常の C++ コンパイラで生成されたコード内でスローしてキャッチする場合、動的に生成されたコードの実行 (再) 入力に関する残留/結果の問題はありません。C との間で呼び出されるラップされた C++ ライブラリにも同じアプローチが使用されます。例外は、C++ ライブラリの境界でキャッチされ、C が処理できるエラー コードに変換される場合があります。

于 2015-02-12T03:30:44.867 に答える