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 中返回后立即创建了一个段错误。就好像只有 b_helper 堆栈帧是有效的,它下面的堆栈被擦除了。

谁能解释为什么会这样?我猜这是删除未使用的堆栈帧或其他东西的 GCC 优化。

谢谢。

4

2 回答 2

16

您只能longjmp()备份调用堆栈调用longjmp(b_buf, 1)是事情开始出错的地方,因为b_buflongjmp(a_buf).

从文档中longjmp

在调用 setjmp() 例程的例程返回后,不得调用 longjmp() 例程。

这包括通过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 回答