在包装函数和局部变量clobbering中使用setjmp

时间:2017-08-06 02:14:12

标签: c undefined-behavior standard-library setjmp

联机帮助页(在我的系统上)中的setjmp(3)文档说明了

  

所有可访问的对象都具有调用longjmp()例程时的值,除了自动存储调用持续时间的对象值没有volatile类型且已被        在setjmp()调用和longjmp()调用之间改变是不确定的。

这是否仅包含与调用setjmp的函数在同一范围内的对象,还包括函数范围内调用堆栈上方的任何对象?

例如,以下代码是否正确?

#include <stdio.h>
#include <setjmp.h>

jmp_buf env;

void function_that_longjmps(void)
{
    longjmp(env, 1);
}

int setjmp_wrapper(jmp_buf env)
{
    if (setjmp(env) == 0)
        return 0;
    else
        return 1;
}

int main()
{
    int i = 0;

    if (setjmp_wrapper(env) == 0) {
        i = 1;
        function_that_longjmps();
    }

    printf("i = %d\n", i);
    return 0;
}

isetjmp调用之间修改了局部变量longjmp,但它在setjmp_wrapper的范围内不存在。在这种情况下,变量是否有可能被破坏?

1 个答案:

答案 0 :(得分:4)

您的示例展示了未定义的行为,无论局部变量发生了什么,因为您不能longjmp进入已经返回的函数执行。

至于一个没有展示UB的例子,也许是

#include <stdio.h>
#include <setjmp.h>

jmp_buf env;

void calls_longjmp(int *p) {
    *p = 1;
    longjmp(env);
}
void calls_setjmp(int *p) {
    if (setjmp(env)) {
        return;
    }
    calls_longjmp(p);
}
int main(void) {
    int x = 0;
    calls_setjmp(&x);
    printf("%d\n", x);
}

然后x保证在1之后具有值0,而不是longjmp或不确定。引用C11 N1570 draft

  

所有可访问的对象都有值,并且抽象机器 249)的所有其他组件都具有调用longjmp函数时的状态,除了自动存储持续时间的对象的值< strong>包含调用相应setjmp宏的函数的本地函数,它没有volatile限定类型,并且在setjmp调用和longjmp调用之间已经更改,这是不确定的。