2009-09-04 11 views
6

次のコードは、私が現時点で持っている問題をまとめたものです。私の現在の実行フローは以下の通りです。私はGCC 4.3で動作しています。SetJmp/LongJmp:なぜこれがセグメンテーションを投げているのですか?

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の最適化だと思っています。

ありがとうございました。

答えて

12

longjmp() back upコールスタックのみ可能です。 への呼び出しは、の後にもうb_bufで参照されるスタックフレームが存在しないため、問題が発生し始める場所です。 longjmpのドキュメントから

:setjmp関数を呼び出したルーチンは、()を返すルーチン後

のlongjmp()ルーチンが呼び出されない場合があります。

これには、機能のうちlongjmp()を「返す」ことが含まれます。

+0

スタックフレームをlongjmpにする方法はありますか?スタックからbをb_helperにコピーしてヒープにコピーし、そこから実行することは可能ですか? また、コールスタックをジャンプアップした後、b_bufによって参照されるスタックフレームが有効でなくなったのはなぜですか? – jameszhao00

+2

スタックの一部が解放されると、完全に無効になります(他の関数呼び出し、割り込み、またはメモリを上書きする可能性のあるもの)。 –

+4

'longjmp()'を "extended return"と考えることができます。成功した 'longjmp()'は一連の連続した戻り値のように機能し、対応する 'setjmp()'に達するまで呼び出しスタックを解放します。コールスタックフレームが解放されると、それらはもはや有効ではなくなります。これは、コールスタックがどこか別の場所にジャンプした後も有効であるコルーチン(例:Modula-2)や継続(たとえばScheme)の実装とは対照的です。CとC++は、複数の独立した呼び出しスタックを作成する場所でスレッドを使用しない限り、*単一の線形呼び出しスタックのみをサポートします*。 –

5

標準は、この約longjmp()(7.13.2.1 longjmp関数)言う:

longjmp関数を持つプログラムの同じ呼び出しで のsetjmpマクロの最も最近の呼び出しによって保存された環境を復元対応する jmp_buf引数。例えば、

:そのような呼び出しがなかった場合 setjmp関数マクロの呼び出しを含む関数は、脚注で

中間

に実行を終了した場合、またはこのビットを明確にそのreturn文を実行することによって、または別のlongjmp呼び出しによって、ネストされた呼び出しのセットの前の関数でsetjmp呼び出しに が転送されたためです。 setjmp/longjmpネストされたセットの間で前後

バックだから、あなたがすることができませんlongjmp() &。

+0

関数内に複数のネストされたスコープがあり、ネストされたスコープ内でsetjmp()が実行されている場合、setjmp()でスコープを離れても同じ関数内に留まっていれば、そこに正規のlongjmp()これは、ネストされたスコープ内の揮発性変数が、実行がそのスコープを離脱して再入力すると値を保持する必要があることを意味します(関数内にとどまります)。 – supercat

関連する問題