Crash in WKScriptMessageHandler — CFRelease / CoreFoundation on iOS with WKWebView

We are building a hybrid iOS app using Angular (web) rendered inside a WKWebView, hosted by a native Swift app. Communication between the Angular UI and native Swift code is done using WKScriptMessageHandler.

The app mostly works without issues, but in rare edge cases, we’re seeing crashes on the main thread, and the crash is reported in Firebase Crashlytics. The root cause appears related to CFRelease and WKScriptMessageHandler.

Here’s the relevant crash stack:

Crashed: com.apple.main-thread
0  CoreFoundation                 0xbfac CFRelease + 44
1  CoreFoundation                 0xa734 __CFURLDeallocate + 128
2  CoreFoundation                 0x730c _CFRelease + 292
3  libobjc.A.dylib                0x4e28 AutoreleasePoolPage::releaseUntil(objc_object**) + 204
4  libobjc.A.dylib                0x4cbc objc_autoreleasePoolPop + 260
5  WebKit                         0x99f194 WebKit::WebUserContentControllerProxy::didPostMessage(WTF::ObjectIdentifierGeneric<WebKit::WebPageProxyIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>, WebKit::FrameInfoData&&, WTF::ObjectIdentifierGeneric<WebKit::ScriptMessageHandlerIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>, std::__1::span<unsigned char const, 18446744073709551615ul>, WTF::CompletionHandler<void (std::__1::span<unsigned char const, 18446744073709551615ul>, WTF::String const&)>&&) + 680
6  WebKit                         0x1b358 WebKit::WebUserContentControllerProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 392
7  WebKit                         0xe86b0 IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&) + 272
8  WebKit                         0x23c0c WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 44
9  WebKit                         0xe3f054 IPC::Connection::dispatchMessage(WTF::UniqueRef<IPC::Decoder>) + 252
10 WebKit                         0x332d4 IPC::Connection::dispatchIncomingMessages() + 744
11 JavaScriptCore                 0x58a7c WTF::RunLoop::performWork() + 204
12 JavaScriptCore                 0x599a4 WTF::RunLoop::performWork(void*) + 36
13 CoreFoundation                 0x56328 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
14 CoreFoundation                 0x562bc __CFRunLoopDoSource0 + 176
15 CoreFoundation                 0x53dc0 __CFRunLoopDoSources0 + 244
16 CoreFoundation                 0x52fbc __CFRunLoopRun + 840
17 CoreFoundation                 0x52830 CFRunLoopRunSpecific + 588
18 GraphicsServices               0x11c4 GSEventRunModal + 164
19 UIKitCore                      0x3d2eb0 -[UIApplication _run] + 816
20 UIKitCore                      0x4815b4 UIApplicationMain + 340
21 APP1                           0xa2f80 main + 21 (AppDelegate.swift:21)
22 ???                            0x1c234eec8 (シンボルが不足しています)

Steps:

  1. WebView: WKWebView
  2. Message passing: WKScriptMessageHandler → passing data from Angular → Swift
  3. WKWebView is long-lived and reused
  4. Native is using WKUserContentController.add(_:name:) to register handlers
  5. Crashes are intermittent (hard to reproduce), but often follow:
    • Screen sleep/wake
    • Push notification open
    • Angular calling native immediately after resume

Questions:

  • Has anyone seen this specific crash pattern involving CFRelease and WKScriptMessageHandler?
  • Are there known WebKit or CoreFoundation bugs related to WKScriptMessageHandler and retained URLs or message content?

Thank you for your help!

Answered by DTS Engineer in 851310022

This backtrace is a classic symptom of an over-release bug. Someone has added an object to the autorelease pool and then someone — possible the same code, possibly not — has over released it. When the pool pops, it releases it again, which crashes.

I talk about this in depth in Objective-C Memory Management for Swift Programmers.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

This backtrace is a classic symptom of an over-release bug. Someone has added an object to the autorelease pool and then someone — possible the same code, possibly not — has over released it. When the pool pops, it releases it again, which crashes.

I talk about this in depth in Objective-C Memory Management for Swift Programmers.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Crash in WKScriptMessageHandler — CFRelease / CoreFoundation on iOS with WKWebView
 
 
Q