SetJmp/LongJmp: Why is this throwing a segfault?

The following code summarizes the problem I have at the moment. My current execution flow is as follows and a I'm running in 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();
}

The above execution flow creates a segfault right after the return in b_helper. It's almost as if only the b_helper stack frame is valid, and the stacks below it are erased.

Can anyone explain why this is happening? I'm guessing it's a GCC optimization that's erasing unused stack frames or something.

Thanks.


You can only longjmp() back up the call stack. The call to longjmp(b_buf, 1) is where things start to go wrong, because the stack frame referenced by b_buf no longer exists after the longjmp(a_buf).

From the documentation for longjmp:

The longjmp() routines may not be called after the routine which called the setjmp() routines returns.

This includes "returning" through a longjmp() out of the function.


The standard says this about longjmp() (7.13.2.1 The longjmp function):

The longjmp function restores the environment saved by the most recent invocation of the setjmp macro in the same invocation of the program with the corresponding jmp_buf argument. If there has been no such invocation, or if the function containing the invocation of the setjmp macro has terminated execution in the interim

with a footnote that clarifies this a bit:

For example, by executing a return statement or because another longjmp call has caused a transfer to a setjmp invocation in a function earlier in the set of nested calls.

So you can't longjmp() back & forth across nested setjmp/longjmp sets.