SIGABRT 에 관한 글…

출처는 여기..

http://cocoawithlove.com/2010/05/handling-unhandled-exceptions-and.html

proper re-entrant coding is brutally difficult

크래시의 원인은 unhandled signal.

US이 오는 곳 : 커널 , 다른 프로세스 , 어플 자체.  가장 흔한 두가지는 아래.

  • EXC_BAD_ACCESS is a Mach exception sent by the kernel to your application when you try to access memory that is not mapped for your application. If not handled at the Mach level, it will be translated into a SIGBUS or SIGSEGV BSD signal.
  • -> 내 앱에 할당되지 않은 메모리에 접근하려할 때. 커널이 어플에게 보내는 Mach 예외. Mach 레벨에서 다뤄지지않으면  SIGBUS or SIGSEGV BSD 시그널로 번역된다.
  • SIGABRT is a BSD signal sent by an application to itself when an NSException or obj_exception_throw is not caught.
  • -> Sigabrt 은 NSException or obj_exception_throw 가 안 잡혔을 때 어플이 스스로에게 보내는 BSD 시그널.

Objective-C 의 경우 없는 객체나 릴리즈 된 객체 혹은 구현 안된 메서드 등이 주 원인.

[맥 어플의 경우] 맥이 모든 예외를 잡으므로 당장은 죽지 않지만, 위험성이 잔존함.

** Catching uncaught exception

잡는 법은 ‘코드 내의 버그’를 잡는 것.. 누가 모르나..

NSUncaughtExceptionHandler 사용.

Signal 함수.

잡히지 않는 시그널. Sigkill, Sigstop

** Requirements of the exception handler

An unhandled exception (UE) handler may never return 리턴 하지 않는 방법

UE 또는 시그널 핸들러를 야기하는 상황은 어플에서 복구될 수 없는 것으로 간주됨.

하지만, 종종 복구되지 못하는 부분은 단순히 스택 프레임이거나 현재 함수일 수 있다. 현재 스택 프레임이 계속되는 걸 막을 수 있다면 나머지 프로그램은 계속될 것이다.

이것을 시도하려면 당신의 UE 핸들러는 부른 함수에게 제어를 넘겨줘서는 안된다. 예외를 일으켰거나 시그널을 트리거한 코드는 다시 사용되서는 안된다.

부른 함수에 컨트롤을 넘겨주는 일 없시 프로그램을 계속하려면 메인 쓰레드에 리턴(메인 쓰레드에 없다면)해야 하고 그 쓰레드를 영원히 막아야한다. 메인쓰레드에서는 우리의 런루프를 시작하고 원래 런루프로 돌아가서는 안된다.

이것은 에러가 난 쓰레드에 의해 사용되는 스택 메모리가 영원히 ‘릭’ 되는 것을 의미한다. 이것은 이 접근 방식의 대가이다.

Atempt to recover  회복 시도

런루프가 대화상자를 보여주기 위해 사용될 것으므로 그 런루프를 무한히 돌게 놔둘 수 있고 어플의 메인 런루프의 가능한 대체품으로 작용할 수 있다.

이것이 되게 하려면 런루프는 메인 런루프의 모든 모드 들을 다뤄야 한다. 메인 런루프가 몇몇의 프라이빗 모드를 포함하므로 (GSEvent Handling & scroll tracking) 디폴트 NSDefaultRunLoopMode 는 불충분하다.

다행스럽게 UIApplication가 메인 루프의 모든 모드들을 생성했다면 루프로 부터 이 모든 모드를 읽어 올 수 있다. 이것이 메인 루프 생성 후 메인 쓰레드에서 돌고 있다고 가정한다면 다음 코드는 UIApplication 의 모든 모드에서 돌 것이다.

As part of the debug information, we want the stack addresses 디버그 정보의 일부로, 스택 주소를 원한다

함수 backtrace 를 이용하여 역추적 할 수 있고, 이것을 backtrace_symbols을 이용하여 심볼로 변환하는 것을 시도할 수 있다.

+ (NSArray *)backtrace
 {
 void* callstack[128];
 int frames = backtrace(callstack, 128);
 char **strs = backtrace_symbols(callstack, frames);

int i;
 NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
 for (
 i = UncaughtExceptionHandlerSkipAddressCount;
 i < UncaughtExceptionHandlerSkipAddressCount +
 UncaughtExceptionHandlerReportAddressCount;
 i++)
 {
 [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
 }
 free(strs);

return backtrace;
}

처음의 몇 주소는 건너뛰었음에 유의 : 그것들은 시그널 / 예외 처리 함수 의 주소일 것이므로 (별 관심 없음)
데이터를 최소로 두고 싶기 때문에 (UIAlert 상자안에 보이기 위해) 예외 처리 함수는 표시하지 않기로 했다.