swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.32k stars 10.34k forks source link

Crash when compiling code using 6.0, can related to retroactive #76530

Open m1entus opened 2 days ago

m1entus commented 2 days ago

Description

I am getting crash on Swift 6.0 where all works fine on 5.9, can be related to retroactive implementation. Seems for UNUserNotificationService code stopped on dispatch_assert_queue which can be Foundation issue with Swift 6.0 but other stack dump might be related to retroactive (see additional information).

Reproduction

Inside @main AppDelegate i have applicationDidBecomeActive which call this method which causes a crash on swift 6.0 but not cause when i have swift 5.9:

private func registerForRemoteNotificationsIfAuthorized() {
        UNUserNotificationCenter.current().getNotificationSettings { settings in
            if settings.authorizationStatus == .authorized {
                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
        }
    }

Worth mention that i include SPM packages Models which contains this code:

extension UNUserNotificationCenter: @unchecked @retroactive Sendable, UserNotificationCenterServing {
    public func notificationAuthorizationStatus() async -> UNAuthorizationStatus {
        await notificationSettings().authorizationStatus
    }
}

When i changed method registerForRemoteNotificationsIfAuthorized to this implementation it works fine:

Task {
            let status = await notificationCenter.notificationAuthorizationStatus()
            if status == .authorized {
                UIApplication.shared.registerForRemoteNotifications()
            }
        }

Personally feel this can something related to @retroactive, because i tried to migrate other module and seeing crash on classes where @retroactive implemented too.

Stack dump

* thread #9, queue = 'com.apple.usernotifications.UNUserNotificationServiceConnection.call-out', stop reason = EXC_BREAKPOINT (code=1, subcode=0x1111183f8)
  * frame #0: 0x00000001111183f8 libdispatch.dylib`_dispatch_assert_queue_fail + 116
    frame #1: 0x0000000111118384 libdispatch.dylib`dispatch_assert_queue + 188
    frame #2: 0x00000001112103e0 libswift_Concurrency.dylib`swift_task_isCurrentExecutorImpl(swift::SerialExecutorRef) + 284
    frame #3: 0x00000001217ed4a0 geneva-dev.debug.dylib`closure #1 in AppDelegate.registerForRemoteNotificationsIfAuthorized(settings=0x000060000313e1c0) at <stdin>:0
    frame #4: 0x00000001217ed810 geneva-dev.debug.dylib`thunk for @escaping @callee_guaranteed (@guaranteed UNNotificationSettings) -> () at <compiler-generated>:0
    frame #5: 0x0000000111114ec0 libdispatch.dylib`_dispatch_call_block_and_release + 24
    frame #6: 0x00000001111167b8 libdispatch.dylib`_dispatch_client_callout + 16
    frame #7: 0x000000011111eaac libdispatch.dylib`_dispatch_lane_serial_drain + 912
    frame #8: 0x000000011111f7b0 libdispatch.dylib`_dispatch_lane_invoke + 420
    frame #9: 0x000000011112c1f0 libdispatch.dylib`_dispatch_root_queue_drain_deferred_wlh + 324
    frame #10: 0x000000011112b75c libdispatch.dylib`_dispatch_workloop_worker_thread + 732
    frame #11: 0x0000000112897814 libsystem_pthread.dylib`_pthread_wqthread + 284

Expected behavior

Should not crash

Environment

Swift 6.0 (6.0.0.9.10) - Xcode 16 Release

Additional information

Other place stack dump that i am getting some crash and custom actors are implemented is:

Inside initializer i have:

extension Notification: @unchecked @retroactive Sendable {}

extension Socket {
    @Socket.ClientActor
    public final class Client: SocketProviding { // swiftlint:disable:this type_body_length

        nonisolated public convenience init(notificationCenter: NotificationCenter) {
            self.init(center: notificationCenter)

            Task { @Socket.ClientActor in
                await setupObservers()
            }
        }

        private func setupObservers() async {
            notificationCenter
                .publisher(for: UIApplication.didBecomeActiveNotification)
                .sink { [weak self] notification in
                    Task { @Socket.ClientActor [weak self] in
                        self?.handleDidBecomeActive(notification: notification)
                    }
                }.store(in: &bag)
        }
    }
}
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x0000000110654f30 libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x00000001106e7124 libsystem_pthread.dylib`pthread_kill + 256
    frame #2: 0x000000010f5874ec libsystem_c.dylib`abort + 104
    frame #3: 0x000000010f05f44c libswift_Concurrency.dylib`swift::swift_Concurrency_fatalErrorv(unsigned int, char const*, char*) + 28
    frame #4: 0x000000010f05f468 libswift_Concurrency.dylib`swift::swift_Concurrency_fatalError(unsigned int, char const*, ...) + 28
    frame #5: 0x000000010f05f0e0 libswift_Concurrency.dylib`swift_task_checkIsolated + 152
    frame #6: 0x000000010f05c3e0 libswift_Concurrency.dylib`swift_task_isCurrentExecutorImpl(swift::SerialExecutorRef) + 284
    frame #7: 0x0000000120f34a40 geneva-dev.debug.dylib`closure #8 in Socket.Client.setupObservers(notification=Foundation.Notification @ 0x000000016ddbed10) at Socket+Client.swift:0
    frame #8: 0x0000000106be00ac Combine`Combine.Subscribers.Sink.receive(τ_0_0) -> Combine.Subscribers.Demand + 84
    frame #9: 0x0000000106be0760 Combine`protocol witness for Combine.Subscriber.receive(τ_0_0.Input) -> Combine.Subscribers.Demand in conformance Combine.Subscribers.Sink<τ_0_0, τ_0_1> : Combine.Subscriber in Combine + 20
    frame #10: 0x000000010b249f28 Foundation`closure #1 @Sendable (Foundation.Notification) -> () in Foundation.Notification.Subscription.init(__C.NSNotificationCenter, __C.NSNotificationName, Swift.Optional<Swift.AnyObject>, τ_0_0) -> Foundation.Notification.Subscription<τ_0_0> + 268
    frame #11: 0x000000010b249aa8 Foundation`reabstraction thunk helper from @escaping @callee_guaranteed @Sendable (@in_guaranteed Foundation.Notification) -> () to @escaping @callee_unowned @convention(block) @Sendable (@unowned __C.NSNotification) -> () + 48
    frame #12: 0x0000000106e7eaec CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 120
    frame #13: 0x0000000106e7ea24 CoreFoundation`___CFXRegistrationPost_block_invoke + 84
    frame #14: 0x0000000106e7df14 CoreFoundation`_CFXRegistrationPost + 404
    frame #15: 0x0000000106e7d8f0 CoreFoundation`_CFXNotificationPost + 688
    frame #16: 0x000000010b5f4350 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 88
    frame #17: 0x000000014c00d320 UIKitCore`-[UIApplication _stopDeactivatingForReason:] + 1364
    frame #18: 0x000000014b62d4f0 UIKitCore`-[_UISceneLifecycleMultiplexer _performBlock:withApplicationOfDeactivationReasons:fromReasons:] + 268
    frame #19: 0x000000014b62d794 UIKitCore`-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:] + 576
    frame #20: 0x000000014b62d1a0 UIKitCore`-[_UISceneLifecycleMultiplexer uiScene:transitionedFromState:withTransitionContext:] + 244
    frame #21: 0x000000014b638058 UIKitCore`__186-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]_block_invoke + 140
    frame #22: 0x000000014bab8770 UIKitCore`+[BSAnimationSettings(UIKit) tryAnimatingWithSettings:fromCurrentState:actions:completion:] + 656
    frame #23: 0x000000014bbdeaa4 UIKitCore`_UISceneSettingsDiffActionPerformChangesWithTransitionContextAndCompletion + 196
    frame #24: 0x000000014b637d64 UIKitCore`-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:] + 288
    frame #25: 0x000000014b47c084 UIKitCore`__64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke.199 + 608
    frame #26: 0x000000014b47ae2c UIKitCore`-[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:] + 200
    frame #27: 0x000000014b47bd08 UIKitCore`-[UIScene scene:didUpdateWithDiff:transitionContext:completion:] + 220
    frame #28: 0x000000014bae2f40 UIKitCore`-[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:] + 308
    frame #29: 0x0000000115c36380 FrontBoardServices`__76-[FBSScene updater:didUpdateSettings:withDiff:transitionContext:completion:]_block_invoke.159 + 216
    frame #30: 0x0000000115c350a4 FrontBoardServices`-[FBSScene _callOutQueue_coalesceClientSettingsUpdates:] + 60
    frame #31: 0x0000000115c3611c FrontBoardServices`-[FBSScene updater:didUpdateSettings:withDiff:transitionContext:completion:] + 744
    frame #32: 0x0000000115c62fe0 FrontBoardServices`__94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke_2 + 120
    frame #33: 0x0000000115c41618 FrontBoardServices`-[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 160
    frame #34: 0x0000000115c62f30 FrontBoardServices`__94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke + 308
    frame #35: 0x000000010ef627b8 libdispatch.dylib`_dispatch_client_callout + 16
    frame #36: 0x000000010ef663bc libdispatch.dylib`_dispatch_block_invoke_direct + 388
    frame #37: 0x0000000115c84b58 FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 44
    frame #38: 0x0000000115c84a34 FrontBoardServices`-[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] + 196
    frame #39: 0x0000000115c84b8c FrontBoardServices`-[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] + 24
    frame #40: 0x0000000106eb0324 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
    frame #41: 0x0000000106eb026c CoreFoundation`__CFRunLoopDoSource0 + 172
    frame #42: 0x0000000106eafa2c CoreFoundation`__CFRunLoopDoSources0 + 324
    frame #43: 0x0000000106eaa0b0 CoreFoundation`__CFRunLoopRun + 788
    frame #44: 0x0000000106ea9960 CoreFoundation`CFRunLoopRunSpecific + 536
    frame #45: 0x000000011efffb10 GraphicsServices`GSEventRunModal + 160
    frame #46: 0x000000014c011b40 UIKitCore`-[UIApplication _run] + 796
    frame #47: 0x000000014c015d38 UIKitCore`UIApplicationMain + 124
    frame #48: 0x000000014b409184 UIKitCore`UIKit.UIApplicationMain(Swift.Int32, Swift.Optional<Swift.UnsafeMutablePointer<Swift.UnsafeMutablePointer<Swift.Int8>>>, Swift.Optional<Swift.String>, Swift.Optional<Swift.String>) -> Swift.Int32 + 100
    frame #49: 0x000000011f64c450 geneva-dev.debug.dylib`static UIApplicationDelegate.main() at <compiler-generated>:0
    frame #50: 0x000000011f64c3c0 geneva-dev.debug.dylib`static AppDelegate.$main() at <compiler-generated>:0
  * frame #51: 0x000000011f64e63c geneva-dev.debug.dylib`main at AppDelegate.swift:37:16
    frame #52: 0x0000000102095410 dyld_sim`start_sim + 20
    frame #53: 0x000000010219e154 dyld`start + 2476
DannyBloky commented 1 day ago

Hi, I got the same problem. But I found out that it has to do with iOS 18 and not swift 6. When using a simulator below iOS 18 it all works fine it seems.

So I think we need to wait for a bug fix on iOS 18 that compiles with swift 6.

So if you want to go further with your migration from swift 5 to 6. I suggest you use a lower iOS version to test.

Also maybe good to know how to fix the data race

@MainActor private func registerForPushNotifications() { UNUserNotificationCenter.current().delegate = self let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] UNUserNotificationCenter.current().requestAuthorization( options: authOptions, completionHandler: { @Sendable _, _ in }) Messaging.messaging().delegate = self UIApplication.shared.registerForRemoteNotifications() }

So you need to add the @Sendable to the completionHandler