setjmp/longjmp (don't ask)を使用して行き詰まる状況に陥った場合、何か間違ったことをしている可能性があるときに、コンパイラから多くの適切な警告が表示されます。
しかし、Clang でAddress Sanitizer-Wall -Wextra -pedantic
を使用している間にビルドを行ったところ、次のようなケースに遭遇しました。
void outer() {
jmp_buf buf;
ERR error;
if (setjmp(buf) ? helper(&error) : FALSE) {
// process whatever helper decided to write into error
return;
}
// do the stuff you wanted to guard that may longjmp.
// error is never modified
}
longjmp で、スタック フレームを調べるとhelper
、エラー ポインタが null です。フレームを見ると、outer()
エラーが「最適化されています」と表示されます。
でコンパイルしているので不可解です。-O0
したがって、「最適化された」というのは奇妙です。しかし、ほとんどのものlongjmp-yと同様に、コンパイラがエラーアドレスを事前にどのレジスタに入れるかを決定する可能性を妨げているのは何なのだろうか...そしてそれを無効にする.
アドレスサニタイザーが私をパンクさせていますか、それとも実際に次のようなものを書く必要がありますか?
void outer() {
jmp_buf buf;
ERR error;
volatile ERR* error_ptr = &error;
if (setjmp(buf) ? helper(error_ptr) : FALSE) {
// process whatever helper decided to write into error
return;
}
// do the stuff you wanted to guard that may longjmp.
// error is never modified
}
これを調べているとjmp_buf
、どの例でも s がローカルではないことに気付きました。それはあなたができないことですか?:-/
注:コンストラクトに関する「言語弁護士」の問題については、@ AnT の回答と以下のコメントを参照してくださいsetjmp() ? ... : ...
。しかし、ここで私が実際に行っていたのは、関数が終了した後の壊れた longjmp 呼び出しであることが判明しました。ドキュメント(また、常識)によると、それはlongjmp()
間違いなく壊れています。私はそれが起こったことに気づかなかった:
setjmp を呼び出した関数が終了した場合、動作は未定義です (つまり、コール スタックの長いジャンプのみが許可されます)。