сбой setjmp/longjmp

кусок кода здесь

jmp_buf mark;
int Sub_Func()  
{  
    int be_modify, jmpret;    
    be_modify = 0;    
    jmpret = setjmp( mark );  
    if( jmpret == 0 )  
    {  
        // sth else here 
    }  
    else  
    {  
        // error handle 
        switch (jmpret)  
        {  
            case 1:  
                printf( "Error 1\n");  
                break;  
            case 2:  
                printf( "Error 2\n");  
                break;  
            case 3:  
                printf( "Error 3\n");  
                break;  
            default :  
                printf( "Unknown Error");  
                break;  
        }  
        printf("after switch\n");        
    }     
    return jmpret;  
}  

void main( void )  
{  
    Sub_Func();   
    // the longjmp after setjmp
    longjmp(mark, 1);  
}  

результат:
Ошибка 1
после переключения
Ошибка сегментации

Я знаю причину, по которой longjmp может вернуться к предыдущему стеку. но я не уверен в деталях, и какое значение было сохранено в «метке», кто-нибудь может это объяснить?


person nzomkxia    schedule 21.06.2012    source источник
comment
Обратите внимание: вы не можете присвоить возвращаемое значение из setjmp(); вы можете оценить его только как выражение. Google: setjmp назначить   -  person wildplasser    schedule 21.06.2012
comment
@wildplasser, конечно, можете, это обычная функция с возвращаемым значением, без специальной языковой конструкции.   -  person mensi    schedule 21.06.2012
comment
Это очень особенная функция: она может возвращать значение дважды, один раз с возвращаемым значением = 0 и один раз с возвращаемым значением != 0.   -  person wildplasser    schedule 21.06.2012
comment
@mensi: ты до сих пор не погуглил, не так ли?   -  person wildplasser    schedule 22.06.2012
comment
@wildplasser о чем ты? Это обычная функция с возвращаемым значением. Это абсолютно ничего не говорит о том, сколько раз возвращается функция. Функция, которая никогда не возвращается, тривиальна с while(1), а функция, которая возвращает X раз, возможна с использованием встроенного asm и либо вспомогательной функции, такой как longjmp, либо, альтернативно, что-то вроде прерывания таймера. В этом нет ничего особенного.   -  person mensi    schedule 22.06.2012
comment
mensi: ты до сих пор не погуглил, не так ли? velocityreviews.com/forums/ securecoding.cert.org/confluence/display/seccode/ archivum.info/comp.lang.c/2009-07/00732 / И setjmp(), конечно, не обычная функция.   -  person wildplasser    schedule 22.06.2012


Ответы (3)


setjmp() и longjmp() работают, записывая положение кадра стека. Если вы записываете кадр стека в Sub_Func(), но возвращаетесь из функции до вызова longjmp(), кадр стека становится недействительным. longjmp() предназначен для вызова в той же функции, что и setjmp() (подфункция в порядке).

person Yann Droneaud    schedule 21.06.2012
comment
И соответствующий раздел справочной страницы: Контекст стека будет аннулирован, если функция, вызвавшая setjmp(), вернется. - person mensi; 21.06.2012
comment
@ydroneaud в Sub_Func() вызывается setjmp, поэтому %ebp Sub_Func() сохраняется в jmp_buf. В main() вызывается longjmp. результат кажется, что он может вернуться к Sub_Func() и сделать что-то, но после этого потерпит неудачу. - person nzomkxia; 22.06.2012
comment
@nzomkxia, вы не можете вернуться к функции, которую вы только что покинули. Содержимое кадра стека, зарегистрированного setjmp(), не определено (и, безусловно, неверно). Смотрите другие ответы и комментарии. - person Yann Droneaud; 22.06.2012

Вы пытаетесь вернуться к более глубокой функции. Вы можете только вернуться к более мелкой функции.

Таким образом, если A звонит setjmp, затем звонит B, то B может longjmp вернуться в A.

Но если A звонит b, B звонит setjmp, B возвращается к A, A не может longjmp вернуться к B.

person Ben    schedule 21.06.2012

Вы вызвали неопределенное поведение, нарушив следующее (7.13.2.1):

Функция longjmp восстанавливает среду, сохраненную последним вызовом макроса setjmp в том же вызове программы с соответствующим аргументом jmp_buf. Если такого вызова не было, или если функция, содержащая вызов макроса setjmp, прекратила выполнение217) в промежутке, или если вызов макроса setjmp находился в пределах идентификатора с изменяемым типом и выполнение прекратилось что область в промежутке времени, поведение не определено.

217) Например, путем выполнения оператора return или из-за того, что другой вызов longjmp вызвал переход к вызову setjmp в функции, предшествующей набору вложенных вызовов.

Короче говоря, longjmp нельзя использовать для перехода к точке setjmp в функции, которая уже возвратилась.

person R.. GitHub STOP HELPING ICE    schedule 21.06.2012