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

Neo*_*Neo 1 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);
    }

 }
Run Code Online (Sandbox Code Playgroud)

AnT*_*AnT 5

在您的代码中,行为是未定义的.middlemiddleFunc完成执行后(通过正常完成或由另一个执行longjmp),您不能长时间跳转到.

7.13.2.1 longjmp函数

2longjmp函数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有时用于实现协同例程.但是,这种使用超出了标准库规范的范围.并且在任何情况下,这样的使用永远不会期望保存参数值.