Почему происходит ошибка сегментации при вызове функции внутри setjmp()?
Я не понимаю, почему в функции middleFunc()
, ошибка сегментации возникает, когда entry_point(arg)
вызывается внутри if ( setjmp(middle) )
заявление.
#include <stdio.h>
#include <setjmp.h>
jmp_buf start,middle,end;
void finalFunc(void *v)
{
printf("hello\n");
return ;
}
void middleFunc(void (*entry_point)(void *), void *arg)
{
//just debug : this does not cause segmentation fault
entry_point(arg);
if ( setjmp(middle) ){
//this casues the segmentation fault
entry_point(arg);
//once the entry point (finalFunc) is executed go to jmp_buffer end
longjmp(end,1);
}
else {
longjmp(start,1);
}
}
int main(){
if (setjmp(end)){
//exit since finalFunc has been executed
return 0;
}
if (setjmp(start)){
//the middleFunc has previously set the jmp_buffer middle
longjmp(middle,1);
}
else{
int x = 1;
middleFunc(finalFunc,(void*)&x);
}
}
1 ответ
В вашем коде поведение не определено. Вы не можете прыгать в длину middle
после middleFunc
законченное выполнение (либо обычным завершением, либо другим longjmp
).
7.13.2.1 Функция longjmp
2
longjmp
функция восстанавливает среду, сохраненную последним вызовомsetjmp
макрос в том же вызове программы с соответствующимjmp_buf
аргумент. Если такого вызова не было, [...] или если функция, содержащая вызовsetjmp
макрос завершил выполнение248) в промежутке [...] поведение не определено.248) Например, выполнив
return
заявление или потому что другойlongjmp
вызов вызвал перевод наsetjmp
вызов функции в начале набора вложенных вызовов.
В вашем коде middleFunc
устанавливает middle
и после этого немедленно выходит в main
при выполнении longjmp(start,1)
, После этого прыжка middle
больше не действителен Вам больше не разрешено прыгать на middle
откуда угодно. setjmp/longjmp
Механизм поддерживает только скачки вверх по стеку вызовов. Вы не можете делать боковые прыжки или прыжки вниз. Поддерживаются только прыжки вверх.
С практической точки зрения, вы пытаетесь перейти в "мертвый" вызов функции и каким-то образом ожидаете, что значения параметров функции все еще действительны (например, сохранены из предыдущего вызова или что-то в этом роде). Но это не так. setjmp/longjmp
не сохранять / восстанавливать значения параметров. Ценность entry_point
в этом "мертвом" вызове, вероятно, какая-то фигня. Когда вы пытаетесь позвонить через entry_point
Код coredumps.
PS Это правда, что прыжки в сторону с setjmp/longjmp
иногда используется для реализации сопрограмм. Однако такое использование выходит за пределы стандартной спецификации библиотеки. И в любом случае такое использование никогда не будет ожидать сохранения значений параметров.