Почему происходит ошибка сегментации при вызове функции внутри 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 иногда используется для реализации сопрограмм. Однако такое использование выходит за пределы стандартной спецификации библиотеки. И в любом случае такое использование никогда не будет ожидать сохранения значений параметров.

Другие вопросы по тегам