2013-04-24 1 views
0

오류 사례가 예외를 발생시키는 곳에서 일부 코드를 단위 테스트해야합니다. 간단히 말해 스택 프레임을 풀거나 오류를 통해 로컬 점프를하면 예외를 처리해야합니다. MSVC 사용은 옵션이 아닙니다.Windows SEH 및 GCC 레이블을 사용하여 로컬 오류 처리기로 이동

AddVectoredExceptionHandler에 대한 MSDN example은 eip를 수정 한 다음 EXCEPTION_CONTINUE_EXECUTION을 반환하여 로컬 점프를 수행 할 수 있음을 나타냅니다. 분명한 질문은 무엇을 뛰어 넘을 것인가입니다. GCC의 Label as Value 기능은 마치 그냥해야 할 것처럼 보입니다.

오류가있는 함수에서 한 번만 반환하면 아래 예제가 작동합니다. 그러나 두 번째 return 문이 추가되면 점프 오프셋이 의심스럽지 않고 점프가 실패합니다. 왜?

#include <assert.h> 
#include <stdbool.h> 
#include <stdio.h> 

#ifndef _WIN32_WINNT 
#define _WIN32_WINNT 0x0502 
#endif 

#define WIN32_LEAN_AND_MEAN 
#include <windows.h> 

static bool handler_called; 
static DWORD handler_eip; 

static LONG WINAPI local_handler(struct _EXCEPTION_POINTERS* ExceptionInfo) { 
    handler_called = true; 
    PCONTEXT Context = ExceptionInfo->ContextRecord; 
    Context->Eip = handler_eip; 
    return EXCEPTION_CONTINUE_EXECUTION; 
} 

static void badcall(void) { 
    handler_called = false; 
    handler_eip = &&fail; 

    int value = 100; 
    int zero = 0; 
    value = value/0; 
    printf("not handled.\n"); 
    assert(false); 
    //return; // Uncomment this to break the handler 

    fail: 
    printf("error handled.\n"); 
    return; 
} 

int main(int argc, char* argv[]) { 
    void* old_handler = SetUnhandledExceptionFilter(&local_handler); 
    badcall(); 
    SetUnhandledExceptionFilter(old_handler); 
    return(0); 
} 
+1

당신이 볼나요 여기

보다 최소한의 예입니다 이 코드의 분해? 거기 이상한 것을 알아 차렸습니까? –

답변

1

GCC의 죽은 코드 제거가 SEH와 관련이없는 것 같습니다. 함수의 맨 아래 블록에 도달 할 수 없으면 해당 명령문이 제거됩니다. 그런 다음 GCC는 주소를 찍은 위치에 임의로 레이블을 만듭니다.

우리는 프로그램 흐름을 직접 조작하기 때문에 C 규칙은 컴파일러가 이와 같이 엉뚱한 것을 수행 할 때 우리가 불평 할 수 없다는 것을 알려줍니다.

static void* handler_eip; 
static void badcall(void) { 
    handler_eip = &&fail; 

    int value = 100/0; 
    printf("not handled.\n"); 
    //goto fail; 
    return; 

    fail: 
    printf("error handled.\n"); 
    return; 
}

주 장소에 고토와 L2의 위치 :

_badcall: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $56, %esp 
    movl $L2, _handler_eip 
    movl $100, %eax 
    movl $0, -28(%ebp) 
    movl %eax, %edx 
    sarl $31, %edx 
    idivl -28(%ebp) 
    movl %eax, -12(%ebp) 
    movl $LC0, (%esp) 
    call _puts 
    nop 
L2: 
    movl $LC1, (%esp) 
    call _puts 
    nop 
    leave 
    ret

그리고 않고 :

_badcall: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $56, %esp 
L2: 
    movl $L2, _handler_eip 
    movl $100, %eax 
    movl $0, -28(%ebp) 
    movl %eax, %edx 
    sarl $31, %edx 
    idivl -28(%ebp) 
    movl %eax, -12(%ebp) 
    movl $LC0, (%esp) 
    call _puts 
    nop 
    leave 
    ret