9

次のコードは、私が現在抱えている問題をまとめたものです。現在の実行フローは次のとおりで、GCC 4.3 で実行しています。

jmp_buf a_buf;
jmp_buf b_buf;

void b_helper()
{
    printf("entering b_helper");
    if(setjmp(b_buf) == 0)
    {
        printf("longjmping to a_buf");
        longjmp(a_buf, 1);
    }
    printf("returning from b_helper");
    return; //segfaults right here
}
void b()
{
    b_helper();
}
void a()
{
    printf("setjmping a_buf");
    if(setjmp(a_buf) == 0)
    {
        printf("calling b");
        b();
    }
    printf("longjmping to b_buf");
    longjmp(b_buf, 1);
}
int main()
{
    a();
}

上記の実行フローでは、b_helper に戻った直後に segfault が作成されます。あたかも b_helper スタック フレームのみが有効で、その下のスタックが消去されているかのようです。

なぜこれが起こっているのか誰でも説明できますか?未使用のスタック フレームなどを消去するのは GCC の最適化だと思います。

ありがとう。

4

2 に答える 2

16

コール スタックのみlongjmp()をバックアップできます。によって参照さlongjmp(b_buf, 1)れるスタック フレームb_buflongjmp(a_buf).

のドキュメントからlongjmp:

longjmp() ルーチンは、setjmp() ルーチンを呼び出したルーチンが戻った後に呼び出すことはできません。

これには、関数からの「戻り」が含まれlongjmp()ます。

于 2009-09-04T23:28:07.627 に答える
6

標準では、longjmp()(7.13.2.1 longjmp 関数)について次のように述べられています。

longjmp 関数は、対応する jmp_buf 引数を使用したプログラムの同じ呼び出しで、setjmp マクロの最新の呼び出しによって保存された環境を復元します。そのような呼び出しがなかった場合、または setjmp マクロの呼び出しを含む関数が途中で実行を終了した場合

これを少し明確にする脚注付き:

たとえば、return ステートメントを実行したり、別の longjmp 呼び出しによって、ネストされた呼び出しのセットの前の関数で setjmp 呼び出しに転送されたりしたためです。

したがって、ネストされた/セットlongjmp()間を行き来することはできません。setjmplongjmp

于 2009-09-04T23:30:47.807 に答える