Understanding iOS Exception Types

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_CRASHEXC_BAD_ACCESSEXC_RESOURCE00000020, etc.

Table of Contents [show]

“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 SIGSEGVSIGBUS, 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”.

UNIX Signals

Here is a list of UNIX signals that are usually shown in front of iOS developers.

UNIX Signals Annotations
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 abort(). It normally means that the system detects something wrong, like an assert() or NSAssert() fails.
SIGBUS Access to an invalid memory address. The address does not exist, or the alignment is invalid.
SIGTRAP Debugger related.
SIGILL Attempts to execute an illegal, malformed, unknown, or privileged instruction.

More UNIX signals can be found from here

Mach Exceptions

Mach Exception Decription Annotations
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.

Exceptions

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_release is 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_FAILUREindicates 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.

Xcode - Enable Zombie Objects

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 – osfmk/mach/exception_types.h.

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. 0x00007f8254a019c0).

  • 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” ([32]: "1 << 0") bit is set (kGUARD_EXC_CLOSE), it attempted to invoke close() on a “guarded file descriptor”.
  • If “second” ([33]: "1 << 1") bit is set(kGUARD_EXC_DUP), it attempted to invoked dup(2)dup2(2)fcntl(2) with F_DUPFD or F_DUPFD_CLOEXEC on a “guarded file descriptor”. It also cover the attempt to open a “guarded file descriptor” by /dev/fd/.
  • If “third” ([34]: "1 << 2") bit is set (kGUARD_EXC_NOCLOEXEC), it attempted to close the “close-on-exec” flag on a “guarded file descriptor”.
  • If “fourth” ([35]: "1 << 3") bit is set (kGUARD_EXC_SOCKET_IPC), it attempted to send a “guarded file descriptor” via a socket.
  • If “fifth” ([36]: "1 << 4") bit is set (GUARD_FILEPORT), it attempted to create a fileport from a “guarded file descriptor” via a socket.
  • If “sixth” ([37]: "1 << 5") bit is set (kGUARD_EXC_MISMATCH), the “guard” of a “guarded file descriptor” was mismatch.
  • If “seventh” ([38]: "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 – /bsd/sys/guarded.h.

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”

However, the ones like this and this are not easy – the first one is about GCD using and the other one is about a Apple bug!

Here is the format when showing in crash log:

Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x000000000000b6d2

EXC_RESOURCE

“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 180 sec.
  • WAKEUPS – Indicate that a thread was waking up too many times per second. The limit is 150/sec and the period is 300 sec.
  • 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

00000020

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.


转:http://www.5neo.be/understanding-ios-exception-types/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值