Использование setjmp в функции-обертке и затирание локальной переменной

В документации по setjmp (3) на страницах руководства (в моей системе) указано, что

Все доступные объекты имеют значения на момент вызова подпрограммы longjmp (), за исключением того, что значения объектов продолжительности автоматического вызова хранилища, которые не имеют изменчивого типа и были изменены между вызовом 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;
}

Локальная переменная i изменяется между вызовами setjmp и longjmp, но не существует в области setjmp_wrapper. Есть ли вероятность, что в этом случае переменная будет заторможена?


person Tob Ernack    schedule 06.08.2017    source источник
comment
Попытка longjmp в setjmp_wrapper после того, как он уже был возвращен, сама по себе является неопределенным поведением.   -  person user2357112 supports Monica    schedule 06.08.2017


Ответы (1)


Ваш пример демонстрирует неопределенное поведение независимо от того, что происходит с локальными переменными, потому что вы не можете 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, за исключением значений объектов с длительностью автоматического хранения , которые являются локальными по отношению к функции, содержащей вызов соответствующего макроса setjmp, которые не имеют изменяемого типа и были изменены между вызовом setjmp и вызовом longjmp, являются неопределенными.

person user2357112 supports Monica    schedule 06.08.2017
comment
Спасибо, я не осознавал, что мой код имеет другое неопределенное поведение. - person Tob Ernack; 06.08.2017