Учитывая этот код C
#include <stdio.h>
#include <setjmp.h>
void foo(int x) {
jmp_buf env;
if (setjmp(env) == 0) {
printf("%d\n", 23);
longjmp(env, 1);
} else {
printf("%d\n", x);
}
}
В результате должно быть напечатано 23, а затем x, и все должно быть четко определено.
Но допустим, что компилятор не знает, чтоsetjmp / longjmp являются специальными функциями, и он генерирует следующий код:
;function foo
;r0 : int x
foo:
sub sp, sp, #sizeof(jmp_buf) ; reserve space for env
push r0 ; save x for later
add r0, sp, #4 ; load address of env
call setjmp
pop r1 ; restore SP, move x to r1 <<== corrupt after jongjmp
cmp r0, #0 ; if (setjmp(env) == 0)
bne 1f
lea r0, "%d\n" ; printf("%d\n", 23)
mov r1, #23
call printf
mov r0, sp ; load address of env
mov r1, #1
call longjmp
b 2f
1:
lea r0, "%d\n" ; printf("%\dn", x), x already in r1
call printf
2:
add sp, sizeof(jmp_buf)
ret
Это выдает 23, как и ожидалось, но затем печатает адрес повторного запуска вызова longjmp, то есть адрес метки 1.
Переменная x временно сохраняется в стеке, чтобы сохранить ее при вызове функции setjmp (r0, будучи регистром аргументов, сохраняется вызывающей стороной).Я думаю, что это вполне допустимая вещь для компилятора.Но так как setjmp возвращает дважды, это повреждает переменную, в то время как стандарт C говорит, что не должен.