为什么调用 setjmp() 中的函数会发生分段错误?
Why a segmentation fault occurs calling a function inside setjmp()?
我不明白为什么在函数 middleFunc()
中,在 if ( setjmp(middle) )
语句中调用 entry_point(arg)
时会引发分段错误。
#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);
}
}
在您的代码中,行为未定义。在 middleFunc
完成执行(通过正常完成或另一个 longjmp
)后,您不能长跳转到 middle
。
7.13.2.1 The longjmp function
2 The longjmp
function restores the environment saved by the most recent invocation of the setjmp
macro in the same invocation of the program with the corresponding jmp_buf
argument. If there has been no such invocation, [...] or if the function containing the invocation of the setjmp
macro has terminated execution248) in the interim [...] the behavior is undefined.
248) For example, by executing a return
statement or because another longjmp
call has caused a transfer to a setjmp
invocation in a function earlier in the set of nested calls.
在您的代码中 middleFunc
设置 middle
,然后通过执行 longjmp(start,1)
立即退出到 main
。之后跳转 middle
不再有效。您不再被允许从任何地方跳转到 middle
。 setjmp/longjmp
机制只支持向上跳转调用栈。你不能做侧跳或下跳。仅支持向上跳跃。
从实际的角度来看,您正试图跳转到 "dead" 函数调用并以某种方式期望函数参数值仍然有效(例如,从上次调用中保留下来或其他)。但他们不是。 setjmp/longjmp
不要preserve/restore 参数值。在 "dead" 调用中 entry_point
的值可能是 some garbage。当您尝试通过 entry_point
进行调用时,代码会转储。
P.S。的确,用 setjmp/longjmp
侧跳有时是用来实现协程的。但是,这种用法超出了标准库规范的范围。并且在任何情况下,这种用法永远不会期望保留参数值。
我不明白为什么在函数 middleFunc()
中,在 if ( setjmp(middle) )
语句中调用 entry_point(arg)
时会引发分段错误。
#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);
}
}
在您的代码中,行为未定义。在 middleFunc
完成执行(通过正常完成或另一个 longjmp
)后,您不能长跳转到 middle
。
7.13.2.1 The longjmp function
2 The
longjmp
function restores the environment saved by the most recent invocation of thesetjmp
macro in the same invocation of the program with the correspondingjmp_buf
argument. If there has been no such invocation, [...] or if the function containing the invocation of thesetjmp
macro has terminated execution248) in the interim [...] the behavior is undefined.248) For example, by executing a
return
statement or because anotherlongjmp
call has caused a transfer to asetjmp
invocation in a function earlier in the set of nested calls.
在您的代码中 middleFunc
设置 middle
,然后通过执行 longjmp(start,1)
立即退出到 main
。之后跳转 middle
不再有效。您不再被允许从任何地方跳转到 middle
。 setjmp/longjmp
机制只支持向上跳转调用栈。你不能做侧跳或下跳。仅支持向上跳跃。
从实际的角度来看,您正试图跳转到 "dead" 函数调用并以某种方式期望函数参数值仍然有效(例如,从上次调用中保留下来或其他)。但他们不是。 setjmp/longjmp
不要preserve/restore 参数值。在 "dead" 调用中 entry_point
的值可能是 some garbage。当您尝试通过 entry_point
进行调用时,代码会转储。
P.S。的确,用 setjmp/longjmp
侧跳有时是用来实现协程的。但是,这种用法超出了标准库规范的范围。并且在任何情况下,这种用法永远不会期望保留参数值。