I am building some rudimentary crash logging system based on this blog post (Yes, I am aware of PLCRashReporter, and No, I can't use it and need to roll my own, however limited. Thank you).
My code registers both an exception handler (with NSSetUncaughtExceptionHandler()
) and a signal handler for most signals:
SIGQUIT
SIGILL
SIGTRAP
SIGABRT
SIGEMT
SIGFPE
SIGBUS
SIGSEGV
SIGSYS
SIGPIPE
SIGALRM
SIGXCPU
SIGXFSZ
It seems to work fine with basic Objective-C stuff such as "unrecognized selector sent to instance...", etc.
Next, I tried it with the following Swift code:
var empty:String! = nil
let index = empty.startIndex // < KA-BOOM!
...but the thrown exception EXC_BAD_INSTRUCTION
is not caught (my handler is not called), and instead I get the familiar:
fatal error: unexpectedly found nil while unwrapping an Optional value
...in the Xcode console.
What am I missing?
This answer says that this kind of runtime error can be handled with SIGTRAP
; however I am already handling that signal and it doesn't seem to work.
ADDENDUM: It seems there is no centralized exception handling system in place for Swift runtime errors (out of bounds, nil unwrap, etc.); see this post. However, Xcode is still able to crash with EXC_BAD_INSTRUCTION
, so my question stands: How is this possible, and why can't my signal handlers handle this?
ADDENDUM 2: Just to be safe, I tried registering my signal handler for all 20+ signals defined in signal.h (not just the ones listed above); still, no change.
ADDENDUM 3: Apple's official document Understanding and Analyzing Application Crash Reports contains this snippet:
Trace Trap [EXC_BREAKPOINT // SIGTRAP]
Similar to an Abnormal Exit, this exception is intended to give an attached debugger the chance to interrupt the process at a specific point in its execution. You can trigger this exception from your own code using the __builtin_trap() function. If no debugger is attached, the process is terminated and a crash report is generated.
Lower-level libraries (e.g, libdispatch) will trap the process upon encountering a fatal error. Additional information about the error can be found in the Additional Diagnostic Information section of the crash report, or in the device's console.
Swift code will terminate with this exception type if an unexpected condition is encountered at runtime such as:
- a non-optional type with a nil value
- a failed forced type conversion
Look at the Backtraces to determine where the unexpected condition was encountered. Additional information may have also been logged to the device's console. You should modify the code at the crashing location to gracefully handle the runtime failure. For example, use Optional Binding instead of force unwrapping an optional.
(emphasis mine)
Still: Why Can't I Handle This With My SIGTRAP
Signal Handler?