[Webkit-unassigned] [Bug 275368] New: WKWebsiteDataStore thread assertions

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Tue Jun 11 12:54:28 PDT 2024


https://bugs.webkit.org/show_bug.cgi?id=275368

            Bug ID: 275368
           Summary: WKWebsiteDataStore thread assertions
           Product: WebKit
           Version: Safari 17
          Hardware: All
                OS: iOS 17
            Status: NEW
          Severity: Normal
          Priority: P2
         Component: WebKit API
          Assignee: webkit-unassigned at lists.webkit.org
          Reporter: adam at lickel.com

WKWebsiteDataStore lacks @MainActor annotations. While this is OK for closure-based methods, the auto-generated Swift Concurrency methods will never be called on the Main Thread. This creates a WTF assertion.

I suspect the entire class _should_ be marked as @MainActor to resolve this; however, at a minimum, the Swift Concurrency methods should not be auto-generated.

Presumably, this is fixed on main, per `WK_SWIFT_UI_ACTOR` though the initial Xcode 18 beta is not marked as such.

---

Sample code:

private extension WKWebsiteDataStore {
    private static let canCallDataStoreAPIs = true

    @MainActor
    @available(iOS 17, *)
    static func removeAllPersistentDataStores() async {
//        guard canCallDataStoreAPIs else {
//            return
//        }

        let storageIDs = if canCallDataStoreAPIs {
            await WKWebsiteDataStore.allDataStoreIdentifiers
        } else {
            await WKWebsiteDataStore.safeAllDataStoreIdentifiers
        }

        await withDiscardingTaskGroup { @MainActor group in
            for storageID in storageIDs {
                group.addTask {
                    if canCallDataStoreAPIs {
                        try? await WKWebsiteDataStore.remove(forIdentifier: storageID)
                    } else {
                        try? await WKWebsiteDataStore.safeRemove(forIdentifier: storageID)
                    }
                }
            }
        }
    }

    @MainActor
    @available(iOS 17, *)
    private static var safeAllDataStoreIdentifiers: [UUID] {
        get async {
            await withCheckedContinuation { continuation in
                WKWebsiteDataStore.fetchAllDataStoreIdentifiers { results in
                    continuation.resume(returning: results)
                }
            }
        }
    }

    @MainActor
    @available(iOS 17, *)
    private static func safeRemove(forIdentifier storageID: UUID) async throws {
        try await withCheckedThrowingContinuation { (checkedContinuation: CheckedContinuation<Void, Error>) in
            WKWebsiteDataStore.remove(forIdentifier: storageID) { error in
                if let error {
                    checkedContinuation.resume(throwing: error)
                } else {
                    checkedContinuation.resume()
                }
            }
        }
    }

    @MainActor
    func clearAllWebsiteData() async {
        let records = await dataRecords(
            ofTypes: WKWebsiteDataStore.allWebsiteDataTypes()
        )
        await withTaskGroup(of: Void.self) { group in
            for record in records {
                group.addTask { @MainActor in
                    await self.removeData(ofTypes: record.dataTypes, for: [record])
                }
            }
        }
    }
}

---

allDataStoreIdentifiers stack trace:

Thread 13 Queue : com.apple.WebKit.WebsiteDataStoreIO (serial)
#0      0x00000001953e5204 in WTF::RunLoop::dispatch(WTF::Function<void ()>&&) ()
#1      0x000000018b49ad58 in WTF::Detail::CallableWrapper<WebKit::WebsiteDataStore::fetchAllDataStoreIdentifiers(WTF::CompletionHandler<void (WTF::Vector<WTF::UUID, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&)>&&)::$_8, void>::call() ()
#2      0x0000000195442b8c in void WTF::dispatchWorkItem<WTF::(anonymous namespace)::DispatchWorkItem>(void*) ()
#3      0x000000010228573c in _dispatch_client_callout ()
#4      0x000000010228da30 in _dispatch_lane_serial_drain ()
#5      0x000000010228e774 in _dispatch_lane_invoke ()
#6      0x000000010229b1a8 in _dispatch_root_queue_drain_deferred_wlh ()
#7      0x000000010229a604 in _dispatch_workloop_worker_thread ()
#8      0x0000000103297814 in _pthread_wqthread ()
Enqueued from com.apple.main-thread (Thread 1) Queue : com.apple.main-thread (serial)
#0      0x000000010228a694 in dispatch_async_f ()
#1      0x000000018b495dc4 in WebKit::WebsiteDataStore::fetchAllDataStoreIdentifiers(WTF::CompletionHandler<void (WTF::Vector<WTF::UUID, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&)>&&) ()
#2      0x000000018b3248f4 in +[WKWebsiteDataStore(WKPrivate) _fetchAllIdentifiers:] ()
#3      0x000000010b863994 in static WKWebsiteDataStore.removeAllPersistentDataStores() at XXX

---

remove(forIdentifier:) stack trace:

Thread 8 Queue : com.apple.root.user-initiated-qos.cooperative (concurrent)
#0      0x000000018af15ff8 in WTFCrashWithInfo(int, char const*, char const*, int) ()
#1      0x000000018b69584c in WebKit::allDataStores() ()
#2      0x000000018b696bc4 in WebKit::WebsiteDataStore::existingDataStoreForIdentifier(WTF::UUID const&) ()
#3      0x000000018b496028 in WebKit::WebsiteDataStore::removeDataStoreWithIdentifier(WTF::UUID const&, WTF::CompletionHandler<void (WTF::String const&)>&&) ()
#4      0x000000018b3249f8 in +[WKWebsiteDataStore(WKPrivate) _removeDataStoreWithIdentifier:completionHandler:] ()
#5      0x0000000110294330 in closure #1 in closure #1 in static WKWebsiteDataStore.removeAllPersistentDataStores() at XXX
#6      0x00000001102985f4 in partial apply for closure #1 in closure #1 in static WKWebsiteDataStore.removeAllPersistentDataStores() ()
#7      0x000000011029871c in thunk for @escaping @callee_guaranteed @Sendable @async () -> () ()
#8      0x000000011029885c in partial apply for thunk for @escaping @callee_guaranteed @Sendable @async () -> () ()

---

I have also seen this crash the closure-based method _on_ the main thread, early in the app's lifecycle.
Specifically, this gets called in func application(_:,didFinishLaunchingWithOptions:) in a `Task{}`

Thread 8 Queue : com.apple.WebKit.WebsiteDataStoreIO (serial)
#0      0x00000001953e5204 in WTF::RunLoop::dispatch(WTF::Function<void ()>&&) ()
#1      0x000000018b49ad58 in WTF::Detail::CallableWrapper<WebKit::WebsiteDataStore::fetchAllDataStoreIdentifiers(WTF::CompletionHandler<void (WTF::Vector<WTF::UUID, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&)>&&)::$_8, void>::call() ()
#2      0x0000000195442b8c in void WTF::dispatchWorkItem<WTF::(anonymous namespace)::DispatchWorkItem>(void*) ()
#3      0x000000010348d73c in _dispatch_client_callout ()
#4      0x0000000103495a30 in _dispatch_lane_serial_drain ()
#5      0x0000000103496774 in _dispatch_lane_invoke ()
#6      0x00000001034a31a8 in _dispatch_root_queue_drain_deferred_wlh ()
#7      0x00000001034a2604 in _dispatch_workloop_worker_thread ()
#8      0x00000001033e7814 in _pthread_wqthread ()
Enqueued from com.apple.main-thread (Thread 1) Queue : com.apple.main-thread (serial)
#0      0x0000000103492694 in dispatch_async_f ()
#1      0x000000018b495dc4 in WebKit::WebsiteDataStore::fetchAllDataStoreIdentifiers(WTF::CompletionHandler<void (WTF::Vector<WTF::UUID, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc>&&)>&&) ()
#2      0x000000018b3248f4 in +[WKWebsiteDataStore(WKPrivate) _fetchAllIdentifiers:] ()
#3      0x000000010baf0a48 in closure #1 in static WKWebsiteDataStore.safeAllDataStoreIdentifiers.getter at XXX
#4      0x000000020a881744 in closure #1 in withCheckedContinuation<τ_0_0>(function:_:) ()
#5      0x000000020a88177c in partial apply for closure #1 in withCheckedContinuation<τ_0_0>(function:_:) ()
#6      0x000000020a8815b4 in withUnsafeContinuation<τ_0_0>(_:) ()
#7      0x000000020a8b410c in swift::runJobInEstablishedExecutorContext(swift::Job*) ()
#8      0x000000020a8b4fd4 in swift_job_runImpl(swift::Job*, swift::ExecutorRef) ()
#9      0x000000010349d2a8 in _dispatch_main_queue_drain ()
#10     0x000000010349cf1c in _dispatch_main_queue_callback_4CF ()
#11     0x000000018040e960 in __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ ()
#12     0x0000000180409078 in __CFRunLoopRun ()
#13     0x00000001804084d4 in CFRunLoopRunSpecific ()
#14     0x000000018ef2aae4 in GSEventRunModal ()
#15     0x00000001853d0a28 in -[UIApplication _run] ()
#16     0x00000001853d46b0 in UIApplicationMain ()
#17     0x00000001004f614c in main at XXX/AppDelegate.swift:53

-- 
You are receiving this mail because:
You are the assignee for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-unassigned/attachments/20240611/e0be225a/attachment.htm>


More information about the webkit-unassigned mailing list