Использование setjmp в функции-обертке и локальная перестановка переменных
Документация setjmp(3) на страницах man (в моей системе) гласит, что
Все доступные объекты имеют значения на момент вызова подпрограммы 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;
}
Локальная переменная i
изменяется между setjmp
а также longjmp
звонки, но он не существует в рамках setjmp_wrapper
, Есть ли вероятность того, что переменная будет забита в этом случае?
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:
Все доступные объекты имеют значения, а все остальные компоненты абстрактной машины249) имеют состояние на момент вызова функции longjmp, за исключением того, что значения объектов автоматической длительности хранения являются локальными для функции, содержащей вызов соответствующий макрос setjmp, который не имеет тип volatile-квалифицированный и был изменен между вызовом setjmp и вызовом longjmp, является неопределенным.