This is quite tricky. The immediate cause of the crash is this:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
You’ve crashed due to a memory access exception because you’ve referenced nil. The backtrace of the crash thread looks like this:
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libswiftCore.dylib … swift_getObjectType + 36
1 libswiftCore.dylib … findDynamicValueAndType+ 3101980
(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*,
swift::OpaqueValue*&, swift::TargetMetadata<swift::InProcess> const*&,
bool&, bool, bool) + 308
2 libswiftCore.dylib … findDynamicValueAndType+ 3101980
(swift::OpaqueValue*, swift::TargetMetadata<swift::InProcess> const*,
swift::OpaqueValue*&, swift::TargetMetadata<swift::InProcess> const*&,
bool&, bool, bool) + 308
3 libswiftCore.dylib … _dynamicCastToExistential+ 3112148
(swift::OpaqueValue*, swift::OpaqueValue*,
swift::TargetMetadata<swift::InProcess> const*,
swift::TargetExistentialTypeMetadata<swift::InProcess> const*,
swift::DynamicCastFlags) + 152
4 libswiftFoundation.dylib … specialized _arrayForceCast<A, B>+ 207620
(_:) + 524
5 libswiftFoundation.dylib …
static Array._unconditionallyBridgeFromObjectiveC+ 293220 (_:) + 276
6 ClickDocDE … thunk for @escaping @callee_guaranteed
(@guaranteed [Any]) -> () + 2127344 (<compiler-generated>:0)
7 libdispatch.dylib … _dispatch_call_block_and_release + 24
Note I’ve done a bunch of manual line wrapping to make this easier to read.
Frames 6 is the most interesting frame here. This thunk was generated by the compiler to check incoming parameters. For example, if you implement an IBAction in Swift like so:
@IBAction
private func okAction(_ button: UIButton) { … your code … }
then the compiler emits two functions:
-
A Swift function that represents your code.
-
An Objective-C compatible thunk that checks the incoming parameter (that it’s not nil and that it’s actually a UIButton) and then calls through to your Swift function. This ensures that undefined behaviour is caught early.
Normally these thunks have a meaningful name because they wrap a named function. In this case, however, there’s no name, most likely because the original Swift function is a closure.
What we can tell is that the function has a single parameter of type [Any]. This explains frame 5, which is the thunk’s call to Array._unconditionallyBridgeFromObjectiveC to check that the incoming NSArray is compatible with the Swift type [Any]. It’s this call that crashes. I originally thought that it might be because the NSArray was nil, but I tested that case [1] and it doesn’t crash; rather, the callee just gets an an empty array.
Beyond that it starts to get harder. Annoyingly, frames 7 and up are just standard Dispatch infrastructure, so that doesn’t offer any clues as to where things went wrong.
I can see two paths forward here:
I can’t really help you with the first path; I don’t have nearly enough expertise in the Swift runtime’s internals to offer any immediate insight. You might want to ask over on Swift Forums.
With regards the second path, it’s likely that this thunk was emitted right next to the original code, so you could:
-
Find the binary that corresponds to this crash report, matching it up using the UUID in the Binary Images section.
-
Load that up in the debugger.
-
Map the address in frame 6 (0x000000010461f5f0) to the address in your loaded binary. You have to undo the ASLR using the load address (0x104418000) from the Binary Images section.
-
Disassemble around that to see what’s nearby.
Like I said, this is quite tricky.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] Using code like this:
// Swift
Hack.test { input in
print(input)
}
// Objective-C
+ (void)testWithBlock:(void (^)(NSArray *))block {
block(nil);
}
Notably, if I set a breakpoint on the print then the backtrace includes this line:
frame #1: 0x000000010f6254c6 xxsi`thunk for @escaping @callee_guaranteed (@guaranteed [Any]) -> () at <compiler-generated>:0
which is good evidence for my thunk theory.