Hi Everyone,
My app runs fine with Swift 5, but crashes with Swift 6. To reproduce, clone this commit, open it in XCode, run the app in Simulator, and click the "I Agree" button in the app to trigger the crash.
Screenshot below.
I've tried cleaning the build folder, restarting Simulator, restarting XCode, running the app standalone without XCode, deleting the app, and erasing the simulator. I've also edited the code at the point of the crash to get more detail with the debugger:
public func staticPageSpec(pageKey: String) -> PageSpec? {
if let f = self.staticPages[pageKey] {
// Debugger inspector says:
// f = () -> () 0x000000010340d3d0 Applin Example.debug.dylib`reabstraction thunk helper from @escaping
// @callee_guaranteed (@in_guaranteed ApplinIos.ApplinConfig, @in_guaranteed Swift.String) ->
// (@out ApplinIos.ToPageSpec) to @escaping @callee_guaranteed
// (@guaranteed ApplinIos.ApplinConfig, @guaranteed Swift.String) -> (@out ApplinIos.ToPageSpec)
// partial apply forwarder with unmangled suffix ".59" at <compiler-generated>
let value = f(self, pageKey) // Process stops with EXC_BREAKPOINT (code=1, subcode=0x1026c4214).
let spec = value.toPageSpec()
return spec
} else {
return nil
}
}
I'm using an M4 Pro, MacOS 15.5, XCode 16.2, Simulator 16.0, and a simulated iPhone 16 Pro running iOS 18.3.
Can any of you please share some ideas for finding the root cause?
That page says that the diagnostics "report" problems they find, but it doesn't say how they report those problems. Does it stop the program or just log the error?
The screenshot suggests the crash happens in dispatch_assert_queue_fail. Does it happen only with some of Xcode diagnostics enabled? Try disable them all to see if the crash still happens.
Then I ran it with the Profiler, with the Time Profiling template, and it crashed in the same way. Here's an excerpt from the crash report:
...
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x000000018017ef14
Termination Reason: SIGNAL 5 Trace/BPT trap: 5
Terminating Process: exc handler [24660]
Triggered by Thread: 6
...
Thread 6 Crashed:
0 libdispatch.dylib 0x18017ef14 _dispatch_assert_queue_fail + 116
1 libdispatch.dylib 0x18017eea0 dispatch_assert_queue + 188
2 libswift_Concurrency.dylib 0x2495b7400 swift_task_isCurrentExecutorImpl(swift::SerialExecutorRef) + 284
3 Applin Example 0x10218a038 specialized thunk for @escaping @callee_guaranteed (@guaranteed ApplinConfig, @guaranteed String) -> (@out ToPageSpec) + 132
4 Applin Example 0x1021af394 thunk for @escaping @callee_guaranteed (@in_guaranteed ApplinConfig, @in_guaranteed String) -> (@out ToPageSpec) + 28 [inlined]
5 Applin Example 0x1021af394 ApplinConfig.staticPageSpec(pageKey:) + 28 (ApplinConfig.swift:79) [inlined]
6 Applin Example 0x1021af394 PageStack.fetchPageSpec(_:pageKey:) + 168 (PageStack.swift:309)
7 Applin Example 0x1021afb81 PageStack.doPushAction(pageKey:) + 1 (PageStack.swift:342)
8 Applin Example 0x1021b5619 specialized PageStack.handleInteractiveError(_:) + 1
9 Applin Example 0x102201149 closure #1 in FormButtonWidget.tap() + 1 (form_button.swift:111)
10 Applin Example 0x10218f3fd partial apply for specialized thunk for @escaping @isolated(any) @callee_guaranteed @async () -> (@out A) + 1
11 Applin Example 0x10219004d specialized thunk for @escaping @isolated(any) @callee_guaranteed @async () -> (@out A) + 1
12 Applin Example 0x102190045 partial apply for specialized thunk for @escaping @isolated(any) @callee_guaranteed @async () -> (@out A) + 1
13 libswift_Concurrency.dylib 0x2495bc829 completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) + 1
...
Your comment got me looking closer at the stack trace. Sadly, XCode doesn't come with the source code for UIKit or the swift libs. I searched for the function swift_task_isCurrentExecutorImpl and found some info online that seems to explain the problem:
Up the stack I see some UI-related things like page stack or button tap. It's not alright for that stuff to happen on anything but the main actor, and the crash is likely to be due to MainActor.assumeIsolated or its equivalent like dispatchPrecondition.
yes, the issue seems to me to likely be that the method here (and presumably the other similar ones as well) is perhaps being wrapped in an implicit closure that includes dynamic main actor executor checks given where the dictionary of functions is created. a lot of the code in the repo is nonisolated and so will run in the background and trying to invoke that function is presumably trapping at runtime due to the executor check failing. it's plausible that this is a compiler bug though, since i do not observe the same behavior if the code is built with Xcode 16.3, for example. if updating the compiler is an option for you, that may be worth a shot. otherwise auditing those functions in the dictionary and explicitly marking them as @Sendable (if appropriate) might work around the issue.