iOS crash 분석

C#/Xamarin Maui 2018. 12. 17. 23:47
728x90

출처

https://developer.apple.com/library/content/technotes/tn2151/_index.html




Header

모든 crash 리포트들은 header 를 가지고 있다.

Incident Identifier: B6FD1E8E-B39F-430B-ADDE-FC3A45ED368C

CrashReporter Key: f04e68ec62d3c66057628c9ba9839e30d55937dc

Hardware Model: iPad6,8

Process: TheElements [303]

Path: /private/var/containers/Bundle/Application/888C1FA2-3666-4AE2-9E8E-62E2F787DEC1/TheElements.app/TheElements

Identifier: com.example.apple-samplecode.TheElements

Version: 1.12

Code Type: ARM-64 (Native)

Role: Foreground

Parent Process: launchd [1]

Coalition: com.example.apple-samplecode.TheElements [402]

 

Date/Time: 2016-08-22 10:43:07.5806 -0700

Launch Time: 2016-08-22 10:43:01.0293 -0700

OS Version: iPhone OS 10.0 (14A5345a)

Report Version: 104 


Incident Identifier : 이 crash report 의 unique 한 식별자이다.

CrashReporter Key : 장치 별 식별자로, 동일한 장치의 두 보고서에는 동일한 값이 표현된다.

Beta Identifier : 장치와 공읍 업체의 조합에 대한 고유 식별자이다. Testlight 를 통해 배포된 앱에서만 노출된다.

Code Type : 장치의 아키텍쳐로 ARM-64, ARM, x86-64 또는 x86 중 하나이다.

Role : 앱 종료시 프로세스에 할당 된 task_role 을 뜻한다.





Exception Information

이 섹션에서는 충돌의 특성에 대한 정보를 제공하는
Mach Exception Type 및 관련 필드를 나열한다.
모든 crash report 에서 모든 입력란 (Exception Note, Exception Code ..)이 표시되지는 않는다.


처리되지 않은 Objective-C Exception 으로 인해 생성된 Crash Report

Exception Type: EXC_CRASH (SIGABRT)

Exception Codes: 0x0000000000000000, 0x0000000000000000

Exception Note: EXC_CORPSE_NOTIFY

Triggered by Thread: 0


Null 포인터에 값을 대입했기 때문에 생성된 Crash Report


Exception Type: EXC_BAD_ACCESS (SIGSEGV)

Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000

Termination Signal: Segmentation fault: 11

Termination Reason: Namespace SIGNAL, Code 0xb

Terminating Process: exc handler [0]

Triggered by Thread: 0



Exception Codes : 하나 이상의 64비트 16 진수로 인코딩 된 Exception 에 대한 프로세서 관련정보이다. 다른 필드에서 이를 이용하여 human-readable 한 정보를 추출한다.

Exception Subtype : human-readable 하게 바뀐 예외 코드의 이름

Exception Message : human-readable 하게 바뀐 예외 코드에서 추출한 추가 정보

Exception Note : Exceptoin Subtype 과 관련된 추가 정보로 이 필드에 SIMULATED 가 포함되어 있으면 Crash 는 아니지만 시스템 요청에 의해 종료된 것이다.

Termination Reason : 프로세스가 종료된 이유이다. 

Triggered by Thread : 예외가 발생한 Thread





Exception Type


Bad Memory Access [EXC_BAD_ACCESS // SIGSEGV // SIGBUS] 

프로세스가 유효하지 않은 메모리에 접근하려고 시도했거나
read-only memory 에 쓰기를 하려고하는 등의 memory protection level 에 허용하지 않는 방식으로
메모리에 접근하려고 했음을 의미한다.

Exceptoin Subtype 필드는 오류를 설명하는 kern_return_t 와 
액세스된 메모리 주소를 포함한다.

잘못된 메모리 액세스를 디버깅하기 위한 팁은 아래와 같다.

- objc_msgSend 또는 objc_release가 crash 난 thread backtrace 의 맨 위에 있으면 
프로세스가 할당 해제 된 객체를 메시지로 보내려고 시도했을 수 있다. 
이 crash 를 더 잘 이해하기 위해서는 Zommbie Instrument 를 이용해서 profiling 해보는 것이 좋다.

-  gpus_ReturnNotPermittedKillClient가 crash 난 thread backtrace 의 맨 위에 있으면 
백그라운드에서 OpenGL ES 또는 Metal로 렌더링을 시도했기 때문에 프로세스가 종료된 것이다. 
(https://developer.apple.com/library/content/qa/qa1766/_index.html) 를 참조하여 해결한다.

- Address Sanitizer (https://developer.apple.com/videos/play/wwdc2015/413/) 가 활성화 된 상태에서 앱을 실행한다.
Address Sanitizer 는 컴파일 된 코드에서 메모리 액세스와 관련된 추가 수단을 추가한다. 
Crash 가 발생할 수 있는 코드가 존재하면 xcode 에서 경고를 나타내준다.


Abnormal Exit [EXC_CRASH // SIGABRT] 

프로세스가 비정상적으로 종료되었을 때 나타나는 type 이다.
가장 일반적인 원인으로는 Objective-C/C++ 예외나 abort() 호출이 있다.

또한 App Extension 이 initialize 에 너무 많은 시간이 소요되어
워치독에 의해 종료된 경우 위 type 이 나타날 수 있다.

launch 시 정지로 인해 extension 이 kill 된 경우 crash report 의
Exception Subtype 은 LAUNCH_HANG 으로 노출된다.
Extension 에는 main function 이 없기 때문에 
initializing 에 오랜 시간이 걸리면 안된다.

initialzing 에 오랜 시간이 소요되지 않도록 오랜 시간이 걸리는 job 은 나중으로 미루는 것이 좋다.




Killed [SIGKILL]

시스템의 요청에 따라 프로세스가 종료되었음을 의미한다.
종료 원인을 더 잘 이해하려면 Termination Reason 필드를 확인해야한다.

아래는 Watch App 의 경우 나타날 수 있는 코드들이다.

0xc51bad01 : 백그라운드 작업을 수행하는 동안 너무 많은 CPU 시간을 사용했기 때문에 App 이 종료되었음을 나타낸다.
이 문제를 해결하려면 백그라운드 작업을 수행하는 코드를 보다 효율적으로 만들어 CPU 를 최적화하거나
백그라운드 작업량을 줄여야한다.

0xc51bad02 : 할당된 시간 내에 백그라운드 작업을 완료하지 못해 App 이 종료되었음을 나타낸다.
이 문제를 해결하려면 백그라운드 작업량을 줄여야한다.

0xc51bad03 : 할당 된 시간 내에 백그라운드 작업을 완료하지 못했음을 나타내고, 시스템이 백그라운드 작업을 수행하는데
많은 CPU 시간을 받지 못했을 정도로 전반적으로 바빴을 때 나타낸다.
앱이 백그라운드 작업에서 수행하는 작업량을 줄임으로써 문제를 피할 수는 있지만
앱 코드의 잘못이라기 보단 전체 시스템 로그로 인해 앱이 작업을 완료하지 못했을 가능성이 크다.



Quit [SIGQUIT]

App 의 lifttime 을 관리할 권한이 있는 다른 프로세스의 요청으로 종료되었음을 의미한다.

프로세스가 crash 난 것을 의미하지는 않지만 탐지 가능한 방식으로 오작동했을 가능성이 높다.


iOS 에서는 키보드 앱이 너무 오래 걸리면 키보드 앱이 종료된다.

crash report 에 표시된 Backtraces 가 담당 코드를 가리킬 가능성은 거의 없다.


이 이슈를 더 잘 이해하기 위해선 시작 중 작업의 대부분을 background thread 로 옮기거나

Extension 이 로드된 이후까지 지연시켜야한다.




Trace Trap [EXC_BREAKPOINT // SIGTRAP]

Abnormal Exit 에서 abort () 를 사용하는 것처럼
__builtin_trap() 을 사용했을 때 발생하는 Exception type 이다.

사용자가 디버깅을 위해 호출할 수 있다.
debugger 가 연결되어 있지 않다면 프로세스가 종료되고 crash report 가 생성된다.

하위 수준 라이브러리 (ex. libdispatch) 에서 치명적인 오류가 발생하면
해당 프로세스를 트랩한다.
오류에 대한 추가 정보는 crash report 의 추가 진단 정보 섹션이나 장치 콘솔에 있다.

Swift 코드는 런타임시 예기치 않은 조건이 발생하면 이 예외 유형으로 종료된다.

- Optional 타입이 아닌데 nil 값일 경우
- 강제 형 변환 실패

추가 정보가 장치의 콘솔에 기록되었을 수도 있기 때문에 
Backtraces를보고 예기치 않은 상황이 발생했는지 확인해야한다.

런타임 오류를 적절히 처리하려면 crash 위치의 코드를 수정해야한다. 
(ex. Optional 을 unwrapping 하는 대신 선택적 바인딩을 사용한다.)


Illegal Instruction [EXC_BAD_INSTRUCTION // SIGILL]

프로세스가 불법적이거나 정의되지 않은 명령을 실행하려고 시도했음을 의미한다. 
프로세스가 잘못 구성된 함수 포인터를 통해 잘못된 주소로 점프하려고 시도했을 수 있습니다.

Intel 프로세서에서 ud2 연산 코드는 EXC_BAD_INSTRUCTION 예외를 발생시키지만 
일반적으로 디버깅 목적으로 프로세스를 트랩하는 데 사용된다.

런타임시 예기치 않은 상황이 발생하면 Intel 프로세서의 Swift 코드가 종료시킨다.
자세한 내용은 Trace Trap (트레이스 트랩)을 참조한다.


Resource Limit [EXC_RESOURCE]

프로세스가 resource 소비 한도를 초과했음을 의미한다.
이것은 프로세스가 너무 많은 리소스를 사용하고 있다는 OS로부터의 알림이다. 
정확한 자원은 Exception Subtype 필드에 나열된다. 
Excpetion Note 필드에 NON-FATAL condition 이 포함되어 있으면 
crash report 는 있지만 앱이 종료되지 않았음을 알 수 있다.

Exception subtype 이 MEMORY 이면 앱 프로세스가 시스템에서 부과한 메모리 한계를 넘었음을 나타낸다.
Exception subtype 이 WAKEUPS 이면 프로세스의 스레드가 초당 너무 많이 깨어나고 있음을 의미하며 이는 CPU 를 자주 깨우고 배터리 수명을 소모할 수 있다.
일반적으로 이 에러는 잦은 스레드간 통신 (performSelector:onThread: or dispatch_async) 사용으로 인해 발생한다.


Guarded Resource Violation [EXC_GUARD]

프로세스가 보호된 리소스를 보호하지 않았음을 의미한다.


Other Exception Types

일부 crash report 에는 16 진수 값 (예 : 00000020)으로 이름이 지정되지 않은 예외 유형이 포함될 수 있다. 

이러한 오류 보고서 중 하나가 표시되면 예외 코드 필드를 직접 확인하여 자세한 내용을 확인해야한다.


0xbaaaaaad : Crash 보고서가 아닌 전체 시스템의 스택 샷임을 나타낸다. 스택 샷을 찍으려면 홈 버튼과 모든 볼륨 버튼을 누른다.

종종 이러한 로그는 사용자가 실수로 생성한 것이므로 오류를 나타내지는 않는다.


0xbad22222 : VoIP 앱이 너무 자주 다시 시작 되었기 때문에 iOS에 의해 종료되었음을 나타낸다.


0x8badf00d : watch dog 시간 초과가 발생하여 앱이 iOS 에 의해 종료되었음을 나타낸다. 

앱이 시스템 이벤트를 시작, 종료 또는 응답하는데 너무 오래 걸렸을 경우에 발생한다.

가장 많이 하는 실수로는 Main Thread 에서 synchronous 하게 네트워크 통신을 하는 경우가 있다.

MainThread 에서의 오래 걸리는 작업은 background thread 로 이동하거나 다르게 처리해 main thread block 을 막야아한다.


0xc00010ff : 발열(?) 로 인해 OS 에서 앱을 종료했음을 나타낸다.  이 것은 device 또는 환경에 의한 것일 수 있다.

App 을 보다 효율적으로 실행하기 위해 (https://developer.apple.com/videos/play/wwdc2011/312/) 를 참고한다.


0xdead10cc : 앱이 suspend 된 상태에서 파일 lock 또는 sqlite lock 을 유지했기 때문에 OS 에 의해 종료되었음을 나타낸다.

앱이 suspend 된 상태에서 파일이나 sqlite db 에서 작업을 수행하고 싶다면 

background job 을 등록하여 (beginBackgroundTask:) 해당 작업을 완료하고 잠금을 해제해야한다.

728x90
Posted by kjun.kr
,