为什么在setjmp()内调用函数时发生分段错误?

时间:2018-07-26 18:39:06

标签: c multithreading segmentation-fault fiber 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 个答案:

答案 0 :(得分:5)

在您的代码中,行为是未定义的。在middle完成执行之后(无论是正常完成还是其他middleFunc),您不允许长时间跳转到longjmp

  

7.13.2.1 longjmp函数

     

2 longjmp函数可在与相应的setjmp相同的程序调用中恢复由jmp_buf宏的最新调用保存的环境。论点。如果没有这样的调用,或者如果包含setjmp宏的调用的函数在此期间终止执行 248),则该行为未定义。

     

248)例如,通过执行一条return语句,或者由于另一个longjmp调用已导致嵌套调用集中的函数中的setjmp调用转移。 / p>

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

从实际的角度来看,您试图跳入“死”函数调用,并以某种方式期望函数参数值仍然有效(例如,从先前的调用中保留下来的东西)。但事实并非如此。 setjmp/longjmp不保留/恢复参数值。在该“无效”调用中,entry_point的值可能为some garbage。当您尝试通过entry_point进行呼叫时,代码将转储。

P.S。的确,有时会使用setjmp/longjmp的边跳转来实现协同例程。但是,这种用法超出了标准库规范的范围。而且无论如何,这种用法永远都不会期望保留参数值。