Since a while we're receiving crash reports from JavaScriptCore.
This seems to be related to us implementing WKScriptMessageHandlerWithReply
(we're using the async variant).
Unfortunately the crash report is not helpful. Does anybody know why this is crashing?
One can see our custom code being called in step 9-11.
Unfortunately we cannot reproduce, seems to happen only rarely.
Crashed: com .apple.root.user-initiated-qos.cooperative
0 JavaScriptCore 0x110a2f8 JSC::sanitizeStackForVM(JSC::VM&) + 52
1 JavaScriptCore 0x3c2048 JSC::JSString::create(JSC::VM&, ***::Ref<***::StringImpl, ***::RawPtrTraits<***::StringImpl> >&&) + 412
2 JavaScriptCore 0x3c2048 JSC::JSString::create(JSC::VM&, ***::Ref<***::StringImpl, ***::RawPtrTraits<***::StringImpl> >&&) + 412
3 JavaScriptCore 0x49fcf4 JSValueMakeString + 128
4 JavaScriptCore 0x43b65c objectToValueWithoutCopy(JSContext*, objc_object*) + 976
5 JavaScriptCore 0x437b14 objectToValue(JSContext*, objc_object*) + 100
6 JavaScriptCore 0x2f6c +[JSValue valueWithObject:inContext:] + 40
7 WebKit 0x254af8 API::SerializedScriptValue::createFromNSObject(objc_object*) + 96
8 WebKit 0x2f2844 invocation function for block in ScriptMessageHandlerDelegate::didPostMessageWithAsyncReply(WebKit::WebPageProxy&, WebKit::FrameInfoData&&, API::ContentWorld&, WebCore::SerializedScriptValue&, ***::Function<void (API::SerializedScriptValue*, ***::String const&)>&&) + 184
9 Our App 0x666710 thunk for @escaping @callee_unowned @convention(block) (@unowned Swift.AnyObject?, @unowned NSString?) -> ()
10 Our App 0x666544 thunk for @escaping @callee_guaranteed (@in_guaranteed Any?, @guaranteed String?) -> ()
11 Our App 0x6661a8 @objc closure #1 in ScriptMessageHandler.userContentController(_:didReceive:)
12 libswift_Concurrency.dylib 0x3b7cc swift::runJobInEstablishedExecutorContext(swift::Job*) + 244
13 libswift_Concurrency.dylib 0x3c1e8 swift_job_runImpl(swift::Job*, swift::ExecutorRef) + 72
14 libdispatch.dylib 0x15164 _dispatch_root_queue_drain + 396
15 libdispatch.dylib 0x1596c _dispatch_worker_thread2 + 164
16 libsystem_pthread.dylib 0x1080 _pthread_wqthread + 228
17 libsystem_pthread.dylib 0xe5c start_wqthread + 8
OK. I’d label that as “async”, and hence our earlier confusion.
Anyway, what’s happening here is that WebKit calls the delegate with a completion handler (like MyReplyHandler1
) and Swift concurrency wraps your async function (MyReplyHandler2
) in some glue that calls the completion handler when the async function returns. That ends up calling the completion handler from one of Swift concurrency’s worker threads. I suspect that WebKit is expecting the completion handler to be called on the main thread, and hence the crash.
Now, there’s a plethora of potential bugs to file here but before I send you off to Feedback Assistant I want to see if my theory is correct. I recommend that you switch from your current approach to the MyReplyHandler1
approach. That puts your in charge of calling the completion handler, allowing you to ensure that it’s called on the main thread.
So, something like this:
class MyReplyHandler1: NSObject, WKScriptMessageHandlerWithReply {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage, replyHandler: @escaping (Any?, String?) -> Void) {
Task {
let reply: Any? = … your code here …
let errorMessage: String? = … your code here …
DispatchQueue.main.async {
replyHandler(reply, errorMessage)
}
}
}
}
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"