When your iOS app crashes, we need to analyze the crash log to help identify the root cause of it. The crash could be a “Low Memory Crash” or a “Normal Crash with Exceptions“. When it comes with “Exception”, a better understanding on “different types of exceptions” can truly help us target the issue quickly.
In this post, we will look into the different types of “exceptions” the iOS app can have, like EXC_CRASH, EXC_BAD_ACCESS, EXC_RESOURCE, 00000020, etc.
Table of Contents
- 1 “Exception” in Crash Log
- 2 UNIX Signals
- 3 Mach Exceptions
- 4 Exceptions
- 5 Future Reading
“Exception” in Crash Log
The term “Exception” in the context of “crash log” is more related to “Mach Exception” (with a prefix “EXC_“) and “UNIX signal” (like SIGSEGV, SIGBUS, etc.). In some cases, the “kernel” also does mapping to translate underlying “Mach Exception” to a “UNIX signal”. And this is the reason why you can see “EXC_CRASH (SIGABRT)” and “EXC_BAD_ACCESS (SIGSEGV)” shown in the crash log as “Exception Type”.
For some of the exceptions, it is also attaching an associated processor-specific Exception Code / Exception Subtype that contains further information about the problem. For example, exception type “EXC_BAD_ACCESS” could have a line like “KERN_INVALID_ADDRESS at 0x80000010” shown as “exception code”; “EXC_RESOURCE” could have line “WAKEUPS” shown as “exception subtype”.
Here is a list of UNIX signals that are usually shown in front of iOS developers.
|SIGSEGV||Access to an invalid memory address. The address exist, but your program does not have access to it.|
|SIGABRT||Program crash. It is initiated by C function |
|SIGBUS||Access to an invalid memory address. The address does not exist, or the alignment is invalid.|
|SIGILL||Attempts to execute an illegal, malformed, unknown, or privileged instruction.|
More UNIX signals can be found from here
|EXC_BAD_ACCESS||Bad Memory Access||Access to “bad” memory address. The “bad” can be either “the address does not exist” or “the app does not have privilege to access to”. So it usually ties to SIGBUS and SIGSEGV.|
|EXC_CRASH||Abnormal Exit||Usually tie to SIGABRT, meaning the app exits abnormally by detecting some uncaught exceptions through the code.|
|EXC_BREAKPOINT||Trace / breakpoint Trap||Usually tie to SIGTRAP. Can be triggered either by your own code or NSExceptions being thrown.|
|EXC_GUARD||Violated Guarded Resource Protection||Be triggered by violating a guarded resource protection, like “certain file descriptor”.|
|EXC_BAD_INSTRUCTION||Illegal Instruction||Usually related to certain illegal or undefined instruction or operand.|
|EXC_RESOURCE||Resource Limit||App crashes by hitting resource consumption limit.|
|00000020||Hexadecimal Exception Type||Not “OS Kernel” exception.|
For the entire list of Mach Exceptions, check the source code file (
sys/osfmk/mach/exception_types.h) from here.
EXC_BAD_ACCESS (Bad Memory Access)
“EXC_BAD_ACCESS” is one of the most popular exceptions when app crashes. Unfortunately, it is not easy to debug.
Normally it has two likely possibilities:
- Accessing something not initialized yet (SIGBUS).
- Accessing something already released by ARC so that the address becomes inaccessible (SIGSEGV). In this case, you should usually see
objc_releaseis near the top of the “Backstrace” in crash log.
Here are some examples:
Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: KERN_INVALID_ADDRESS at 0x6d783f44 ... Exception Type: EXC_BAD_ACCESS (SIGBUS) Exception Codes: KERN_PROTECTION_FAILURE at 0x00000011
“EXC_BAD_ACCESS” also has associated “exception code” to help provide additional info. For example,
KERN_PROTECTION_FAILURE indicates the memory is valid, but it does not permit the required forms of access, and
KERN_INVALID_ADDRESS means address is not currently valid.
Check the source code file (
sys/osfmk/mach/kern_return.h) from here to get a full list of possible values.
To help debug “EXC_BAD_ACCESS”, you can check “Enable Zombie Objects” in Xcode and try it again.
Image source: “Google Images”.
EXC_CRASH (Abnormal Exit)
Comparing to “EXC_BAD_ACCESS”, “EXC_CRASH” is usually a good one to encounter. Usually, it happens when an object receives an unimplemented message, as the line “unrecognized selector sent to instance 0x6a33840” shown in Xcode debugger.
Normally, this exception is indented to be worked with debugger as the debugger can break (interrupt) the process. If no debugger attached, a crash log will be generated instead.
Here is an example info shown in crash log.
Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 ... ## Usually you will see a similar line in the "backtrace" part 2 CoreFoundation 0x36c02e02 -[NSObject(NSObject) doesNotRecognizeSelector:] + 166
It may also have some special cases that are not related to “unrecognized selector”. If that happens, please be careful – things can happen everywhere.
Another common case of “EXC_CRASH” is about “App Extensions”. The App Extension can be terminated by OS if it “took too much time to initialize”. In this case, it shows “
LAUNCH_HANG” in Exception Subtype as well as a very decent Exception Message.
Exception Type: EXC_CRASH (SIGABRT) Exception Subtype: LAUNCH_HANG Exception Message: The extension took too much time to initialize
EXC_BREAKPOINT (Trace Trap)
Much like “EXC_CRASH”, it is more like to work with debugger and caught during your testing phase.
When using Swift, this exception will be thrown at runtime if:
- a non-optional type with a nil value
- a failed forced type conversion
An example info is like this:
Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000002, 0x0000000000000000
You can manually call
__builtin_trap()in your code to trigger this exception.
EXC_GUARD (Violated Guarded Resource Protection)
Unlike all other “EXC_” exceptions, this one is not a “native” Mach Exceptions. In fact, it is added into XNU – a derived OS kernel developed by Apple.
“XNU” stand for “X is Not Unix”.
The definition of “EXC_GUARD” can be found from here –
A good example of this exception is that the app closes the “file descriptor” of SQLite file while Core Data is accessing it.
Prior to iOS 7, this exception attaches a part of “Exception Codes” to help understand the situation. The “Exception Codes” contains “two” bitfields – code (e.g.
0x400000010000005e) and subcode (e.g.
- code part breaks down into “three” sections:
- [63:61] Guard Type – At the moment, it only has one type – guarded file descriptor (GUARD_TYPE_FD). Its value is
0x2. So if you can see 0x4 as the prefix of code, the crash is about “file descriptor”.
- [60:32] Flavor – Different conditions when violating “guarded file descriptor”:
- If “first” (
: "1 << 0") bit is set (kGUARD_EXC_CLOSE), it attempted to invoke
close()on a “guarded file descriptor”.
- If “second” (
: "1 << 1") bit is set(kGUARD_EXC_DUP), it attempted to invoked
F_DUPFD_CLOEXECon a “guarded file descriptor”. It also cover the attempt to open a “guarded file descriptor” by
- If “third” (
: "1 << 2") bit is set (kGUARD_EXC_NOCLOEXEC), it attempted to close the “close-on-exec” flag on a “guarded file descriptor”.
- If “fourth” (
: "1 << 3") bit is set (kGUARD_EXC_SOCKET_IPC), it attempted to send a “guarded file descriptor” via a socket.
- If “fifth” (
: "1 << 4") bit is set (GUARD_FILEPORT), it attempted to create a fileport from a “guarded file descriptor” via a socket.
- If “sixth” (
: "1 << 5") bit is set (kGUARD_EXC_MISMATCH), the “guard” of a “guarded file descriptor” was mismatch.
- If “seventh” (
: "1 << 6") bit is set (kGUARD_EXC_WRITE), it attempted to write on a “guarded file descriptor” via a socket. – [31:0] – File Descriptor – The guarded file descriptor that the app attempted to operate. – subcode part contains the “guard value”. > Detailed definition can be found from here –
Starting from iOS 7, “Exception Codes” is replaced by “Exception Subtype” and “Exception Message” which provides much more clear explanation.
# iOS 6 Exception Type: EXC_GUARD Exception Codes: 0x400000010000005e, 0x00007f8254a019c0 # The type is "GUARD_TYPE_FD" (0x4), with "kGUARD_EXC_CLOSE". The FD is "94". # ------- # iOS 7 and above Exception Type: EXC_GUARD Exception Subtype: GUARD_TYPE_FD Exception Message: CLOSE on file descriptor 81 (guarded with 0x0000000017e6eed0)
EXC_BAD_INSTRUCTION (Illegal Instruction)
“EXC_BAD_INSTRUCTION”, usually ties to “SIGILL“, is a very easy-understood exception – you are using the “wrong” instruction or operand. However, it is sometimes very hard to debug.
Here are some common ones.
This one is easy to identify because of the debug info Xcode provides – it is caused by an unsafe unwrapping.
## Usually show "EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)" in Xcode. “fatal error: unexpectedly found nil while unwrapping an Optional value”
Here is the format when showing in crash log:
Exception Type: EXC_BAD_INSTRUCTION (SIGILL) Exception Codes: 0x0000000000000001, 0x000000000000b6d2
“EXC_RESOURCE” means the process “hits a resource consumption limit”. Usually, it will be triggered when your app constantly runs beyond the limit over certain period.
This exception includes “Exception Subtype” to help understand the actual cases:
- CPU – The limit is
50%and the period is
- WAKEUPS – Indicate that a thread was waking up too many times per second. The limit is
150/secand the period is
- MEMORY – The limit is “not documented”.
Like “EXC_GUARD”, it used to use “bitfields” to convey info, and now it also use “Exception Subtype” and “Exception Message”.
Exception Type: EXC_RESOURCE Exception Subtype: CPU Exception Message: (Limit 50%) Observed 85% over 180 secs --- Exception Type: EXC_RESOURCE Exception Subtype: WAKEUPS Exception Message: (Limit 150/sec) Observed 206/sec over 300 secs --- Exception Type: EXC_RESOURCE Exception Subtype: MEMORY Exception Message: Crossed High Water Mark
Unlike “EXC_” exceptions, the “Exception Type” actually cannot tell you any info. Instead, you should check “Exception Codes” for more details.
0x8badf00d(read as ate bad food) – Indicate the app was terminated by OS by because a watchdog timeout occurred. It usually means the app too long to launch, terminate, or respond to system events. A very typical case of it is to “do synchronous networking on the main thread”.
0xbaaaaaad(read as “plooookhy”) – Indicate the log is a stackshot of the entire system, not a crash report.
0xc00010ff(read as cool off) – Indicate the app was forecely closed by OS in response to a thermal event.
0xbad22222– Indicate a VoIP application was terminated by OS since it resumed too frequently.
0xdead10cc(read as dead lock) – Indicate the app held on to a system resource while running in the background.
0xdeadfa11(read as deadfall) – Indicate the app was forcedly closed by user. Force quits occur when the user first holds down the Power button until “slide to power off” appears, then holds down the Home button.
These “hexadecimal” codes are actually hexspeak words – created by our developers as memorable magic numbers.
You can also check this port “Demystifying iOS Application Crash Logs” to understand the structure of an iOS crash log.
Happy iOS dev!!