2012-04-18 2 views
23

세그멘테이션 오류 또는 Ctrl-c를 잡는 데 사용하는 응용 프로그램이 있습니다. 아래 코드를 사용하여 세분화 오류를 catch 할 수 있지만 핸들러가 계속 호출됩니다. 어떻게 그들을 막을 수 있습니까? 귀하의 정보를 위해 신청서를 종료하고 싶지 않습니다. 난 그냥 모든 손상된 버퍼를 무료로 돌볼 수 있습니다.세그먼테이션 오류 처리

가능합니까?

void SignalInit(void) 
{ 

struct sigaction sigIntHandler; 

sigIntHandler.sa_handler = mysighandler; 
sigemptyset(&sigIntHandler.sa_mask); 
sigIntHandler.sa_flags = 0; 
sigaction(SIGINT, &sigIntHandler, NULL); 
sigaction(SIGSEGV, &sigIntHandler, NULL); 

} 

및 처리기가 이렇게됩니다. 여기서 분할 오류 신호

void mysighandler() 
{ 
MyfreeBuffers(); /*related to my applciation*/ 
} 

이 핸들러는 여러 번 명백 MyfreeBuffers()이라고 이미 해제 된 메모리를 해제 나에게 오류를 제공하고있다. 난 단지 한 번만 해방하고 싶지만 여전히 응용 프로그램을 종료하고 싶지 않습니다.

도와주세요.

답변

28

SIGSEGV과 같은 기본 동작은 프로세스를 종료하는 것이지만 처리기를 설치하면 처리기를 호출하여 기본 동작을 재정의합니다. 그러나 문제는 segfaulting 명령은 처리기가 완료된 후 다시 시도 될 수 있으며 첫 번째 seg 오류를 해결하기위한 조치를 취하지 않은 경우 다시 시도 된 명령은 다시 오류를 일으키며 계속 켜져 있습니다.

그래서 첫째 자리 SIGSEGV 초래하고 (당신이 핸들러에서 backtrace() 같은 것을 호출 할 수 있으며, 무엇이 잘못되었는지 자신을 위해 참조) 또한

를 해결하려고 명령은 POSIX 표준은 말한다, 그

이 에서 통상 명(), RTS] sigqueue 의해 생성되지 않은 신호 잡기 [XSI] SIGBUS, SIGFPE, SIGILL 대한 함수 또는 SIGSEGV 신호를 리턴 한 후

프로세스의 동작은 정의되지(), 또는 raise().

따라서 가장 좋은 방법은 segfault를 수정하는 것입니다. 세그먼트 폴트에 대한 핸들러는 그래서 최고의 제안 SIGSEGV를 잡을하지 마십시오 BE-을주는 기본 오류 조건

를 무시하는 것은 아닙니다. 그것은 코어 덤프하자. 핵심을 분석하십시오. 잘못된 메모리 참조를 수정하면 거기에갑니다!

0

상태 변수를 설정하고 설정되지 않은 경우 사용 가능한 메모리 만 사용할 수 있습니다. 시그널 핸들러는 매번 호출되며 AFAIK를 제어 할 수 없습니다.

9

다시 SIGSEGV 화재 경우, 명백한 결론은 MyfreeBuffers();에 대한 호출하지가 기본이 문제를 해결한다는 것이다 (그 기능은 정말에만 free() 일부 할당 된 메모리를 않는 경우, 당신이 그것을 생각하는 이유를 모르겠어요 할 것이다).

대략 액세스 할 수없는 메모리 주소에 액세스하려고 시도하면 SIGSEGV이 실행됩니다. 응용 프로그램을 종료하지 않으려면 해당 메모리 주소를 액세스 가능하게 만들거나 실행 경로를 longjmp()으로 변경해야합니다.

6

SIG_SEGV 이후에 계속해서는 안됩니다. 이는 기본적으로 응용 프로그램의 환경이 어떤 식 으로든 손상되었음을 의미합니다. 당신이 null 포인터를 역 참조했거나, 어떤 버그로 인해 프로그램이 스택이나 힙 또는 포인터 변수를 손상시킬 수 있습니다. 단지 모를뿐입니다. 할 일은 프로그램을 종료하는 것입니다.

컨트롤 -C를 처리하는 것이 가장 합법적입니다. 많은 응용 프로그램에서이 작업을 수행하지만 신호 처리기에서 수행하는 작업을 정확하게 수행해야합니다. 재진입 기능이 아닌 다른 기능은 호출 할 수 없습니다. 즉, MyFreeBuffers()이 stdlib free() 함수를 호출하는 경우 사용자가 실수했을 수 있습니다. 프로그램이 malloc() 또는 free()의 중간에있는 동안 사용자가 control-C를 눌렀을 때 힙 할당을 추적하는 데 사용하는 데이터 구조를 조작하는 중간 단계에서 신호에 malloc() 또는 free()을 호출하면 거의 확실하게 힙이 손상됩니다 매니저.

신호 처리기에서 수행 할 수있는 유일한 안전에 관해서는 신호를 잡았 음을 나타내는 플래그가 설정되어 있습니다. 그런 다음 앱은 일정한 동작을 수행해야 하는지를 결정하기 위해 주기적으로 플래그를 폴링 할 수 있습니다.

0

SIG_SEGV에서 복구하는 경우를 볼 수 있습니다. 루프에서 핸들링 이벤트와 이러한 이벤트 중 하나가 세그먼트 화 위반을 일으키는 경우이 이벤트를 건너 뛰고 나머지 이벤트를 계속 처리하기 만하면됩니다. 내 눈에 SIG_SEGV Java에서 NullPointerException 비슷합니다. 예, 상태가 일관성이 없으며 이들 중 하나 후에 알 수없는 경우도 있지만 상황을 처리하고 계속 수행하려는 경우도 있습니다. 예를 들어 Algo 거래에서 주문 실행을 일시 중지하고 전체 시스템을 손상 시키거나 다른 모든 주문을 파기하지 않고 상인이 수동으로 인계하도록 허용 할 수 있습니다.

8

"Do not catch the SIGSEGV" 문에 전혀 동의하지 않습니다.

예 : 예기치 않은 조건을 처리하는 데 꽤 좋은 방법입니다. 그리고 코드 구조 전체에 오류 상태 관리를 배포하는 것보다 NULL 포인터 (malloc 실패로 제공됨)와 setjmp/longjmp에 연결된 신호 메커니즘을 처리하는 것이 훨씬 깔끔합니다. 당신이 SEGV에 ''은 sigaction ''를 사용하는 경우

참고 그러나, 당신은 SA_NODEFERsa_flags에 말을 잊지해야 - 아니면 그냥 한 번 핸들러를 트리거 할 사실 SEGV 처리하는 다른 방법을 찾을 수 있습니다.

#include <setjmp.h> 
#include <signal.h> 
#include <stdio.h> 
#include <string.h> 

static void do_segv() 
{ 
    int *segv; 

    segv = 0; /* malloc(a_huge_amount); */ 

    *segv = 1; 
} 

sigjmp_buf point; 

static void handler(int sig, siginfo_t *dont_care, void *dont_care_either) 
{ 
    longjmp(point, 1); 
} 

int main() 
{ 
    struct sigaction sa; 

    memset(&sa, 0, sizeof(sigaction)); 
    sigemptyset(&sa.sa_mask); 

    sa.sa_flags  = SA_NODEFER; 
    sa.sa_sigaction = handler; 

    sigaction(SIGSEGV, &sa, NULL); /* ignore whether it works or not */ 

    if (setjmp(point) == 0) 
    do_segv(); 

    else 
    fprintf(stderr, "rather unexpected error\n"); 

    return 0; 
} 
+0

좋은 해결책입니다. 특히 "코어 덤프 (core dump)를 충돌시키고 분석하자" – dturvene