【问题标题】:Why a segmentation fault occurs calling a function inside setjmp()?为什么调用 setjmp() 中的函数会出现分段错误?
【发布时间】:2019-01-03 20:19:54
【问题描述】:

我不明白为什么在函数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);
    }

 }

【问题讨论】:

    标签: c multithreading segmentation-fault fiber setjmp


    【解决方案1】:

    在您的代码中,行为未定义。在middleFunc 完成执行后(通过正常完成或另一个longjmp),您不允许长跳转到middle

    7.13.2.1 longjmp函数

    2 longjmp 函数在使用相应jmp_buf 参数的程序的同一调用中恢复最近一次调用setjmp 宏所保存的环境。如果没有这样的调用,[...] 或者如果包含 setjmp 宏调用的函数在中间 [...] 中终止了执行248),则行为未定义.

    248) 例如,通过执行 return 语句或因为另一个 longjmp 调用导致在嵌套调用集中较早的函数中转移到 setjmp 调用。

    在您的代码middleFunc 中设置middle,然后通过执行longjmp(start,1) 立即退出到main。之后跳转middle 不再有效。您不再被允许从任何地方跳转到middlesetjmp/longjmp 机制只支持向上跳转调用栈。你不能做侧跳或下跳。仅支持向上跳转。

    从实际的角度来看,您正试图跳入“死”函数调用,并且以某种方式期望函数参数值仍然有效(例如,从先前的调用中保留或其他)。但他们不是。 setjmp/longjmp 不保留/恢复参数值。在那个“死”调用中entry_point 的值可能是some garbage。当您尝试通过entry_point 拨打电话时,代码核心转储。

    附:确实,有时使用setjmp/longjmp 侧跳来实现协同程序。但是,这种用法超出了标准库规范的范围。而且在任何情况下,这种用法都不会期望保留参数值。

    【讨论】:

    • 谢谢,这是用新分配的堆栈实现协同程序的原因吗?
    • @Neo:在某种程度上,是的,但是 C 根本不承认协程。任何试图在 setjmp 之上实现它们的尝试,而不是通过诸如汇编或前 POSIX ucontext.h 接口之类的语言之外的一些构造,都是危险的未定义,并且依赖于 C 实现的特定实现细节。
    猜你喜欢
    • 1970-01-01
    • 2011-04-23
    相关资源
    最近更新 更多