isLowPowerModeEnabled causes a deadlock on iOS 15
Originator: | ncreated | ||
Number: | rdar://FB9741207 | Date Originated: | Nov 5, 2020 |
Status: | Open | Resolved: | |
Product: | iOS | Product Version: | 15 |
Classification: | Reproducible: | Very rare |
We work on a SDK and our users report unfrequent crashes (on iOS15, 15.1 and 15.2) in the code that can be simplified to: ``` observer = NotificationCenter.default .addObserver( forName: .NSProcessInfoPowerStateDidChange, object: nil, queue: .main ) { notification in guard let processInfo = notification.object as? ProcessInfo else { return } let lmpe = processInfo.isLowPowerModeEnabled // CRASH on _os_unfair_lock_recursive_abort in libsystem_platform.dylib print(lmpe) } ``` In some circumstances, getting `.isLowPowerModeEnabled` from `ProcessInfo` **within the `. NSProcessInfoPowerStateDidChange` notification callback** causes a dead lock in `libsystem_platform.dylib` and leads to `_os_unfair_lock_recursive_abort` crash. Unfortunately, I didn’t succeed in reproducing this issue locally and capturing Apple’s crash report, so I can only rely on backtraces reported by our users (below). Some of them include `WebCore` symbols, which could be a potential external factor causing this crash. I also found this recent change to Low Power Mode management in WebKit (dated Dec 2020), but I’m not sure if this is relevant: https://trac.webkit.org/changeset/270406/webkit. ``` Crashed: com.apple.main-thread 0 libsystem_platform.dylib 0x60c0 _os_unfair_lock_recursive_abort + 36 1 libsystem_platform.dylib 0xa10 _os_unfair_lock_lock_slow + 304 2 Foundation 0x29730 -[NSProcessInfo(NSProcessInfoHardwareState) isLowPowerModeEnabled] + 68 3 Datadog 0x2a680 closure #1 in LowPowerModeMonitor.init(initialProcessInfo:notificationCenter:) + 140 (MobileDevice.swift:140) 4 Datadog 0x2a720 thunk for @escaping @callee_guaranteed (@in_guaranteed Notification) -> () + 4339345184 (<compiler-generated>:4339345184) 5 Foundation 0x355b0 -[__NSObserver _doit:] + 348 6 CoreFoundation 0x2aee8 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 28 7 CoreFoundation 0xc6b9c ___CFXRegistrationPost_block_invoke + 52 8 CoreFoundation 0x99f54 _CFXRegistrationPost + 456 9 CoreFoundation 0x40d54 _CFXNotificationPost + 716 10 Foundation 0x1b028 -[NSNotificationCenter postNotificationName:object:userInfo:] + 96 11 Foundation 0x939d4 NSProcessInfoNotifyPowerState + 188 12 Foundation 0x29768 -[NSProcessInfo(NSProcessInfoHardwareState) isLowPowerModeEnabled] + 124 13 WebCore 0x9118 <redacted> + 96 14 WebCore 0xa8516c WebCore::LowPowerModeNotifier::LowPowerModeNotifier(WTF::Function<void (bool)>&&) + 52 15 WebCore 0x19aac4c WebCore::Page::Page(WebCore::PageConfiguration&&) + 1848 16 WebKitLegacy 0x3e34 -[WebView(WebPrivate) _commonInitializationWithFrameName:groupName:] + 3060 17 WebKitLegacy 0x3214 -[WebView(WebPrivate) _initWithFrame:frameName:groupName:] + 116 18 UIFoundation 0xdd028 -[NSHTMLReader _loadUsingWebKit] + 832 19 Foundation 0x3de0c __NSThreadPerformPerform + 232 20 CoreFoundation 0xbb030 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28 21 CoreFoundation 0xcbcf0 __CFRunLoopDoSource0 + 208 22 CoreFoundation 0x5ff8 __CFRunLoopDoSources0 + 268 23 CoreFoundation 0xb804 __CFRunLoopRun + 820 24 CoreFoundation 0x1f3c8 CFRunLoopRunSpecific + 600 25 GraphicsServices 0x138c GSEventRunModal + 164 26 UIKitCore 0x51b060 -[UIApplication _run] + 1100 27 UIKitCore 0x298b8c UIApplicationMain + 2124 ``` ``` Crashed: com.apple.main-thread 0 libsystem_platform.dylib 0x8e4c _os_unfair_lock_recursive_abort + 36 1 libsystem_platform.dylib 0x17e4 _os_unfair_lock_lock_slow + 324 2 Foundation 0x27b08 -[NSProcessInfo(NSProcessInfoHardwareState) isLowPowerModeEnabled] + 64 3 Datadog 0x2a680 closure #1 in LowPowerModeMonitor.init(initialProcessInfo:notificationCenter:) + 140 (MobileDevice.swift:140) 4 Datadog 0x2a720 thunk for @escaping @callee_guaranteed (@in_guaranteed Notification) -> () + 4374603552 (<compiler-generated>:4374603552) 5 Foundation 0x335f8 -[__NSObserver _doit:] + 316 6 CoreFoundation 0x28c5c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20 7 CoreFoundation 0xbd564 ___CFXRegistrationPost_block_invoke + 48 8 CoreFoundation 0x92b44 _CFXRegistrationPost + 416 9 CoreFoundation 0x3d764 _CFXNotificationPost + 696 10 Foundation 0x19c98 -[NSNotificationCenter postNotificationName:object:userInfo:] + 92 11 Foundation 0x8d998 NSProcessInfoNotifyPowerState + 184 12 Foundation 0x27b40 -[NSProcessInfo(NSProcessInfoHardwareState) isLowPowerModeEnabled] + 120 13 Datadog 0x2a680 closure #1 in LowPowerModeMonitor.init(initialProcessInfo:notificationCenter:) + 140 (MobileDevice.swift:140) 14 Datadog 0x2a720 thunk for @escaping @callee_guaranteed (@in_guaranteed Notification) -> () + 4374603552 (<compiler-generated>:4374603552) 15 Foundation 0x335f8 -[__NSObserver _doit:] + 316 16 CoreFoundation 0x28c5c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20 17 CoreFoundation 0xbd564 ___CFXRegistrationPost_block_invoke + 48 18 Foundation 0x4e21c __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16 19 Foundation 0x5f6f4 -[NSBlockOperation main] + 100 20 Foundation 0x39ddc __NSOPERATION_IS_INVOKING_MAIN__ + 20 21 Foundation 0x49f1c -[NSOperation start] + 780 22 Foundation 0x4d314 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 20 23 Foundation 0x5aa2c __NSOQSchedule_f + 180 24 libdispatch.dylib 0x632ec _dispatch_call_block_and_release + 24 25 libdispatch.dylib 0x642f0 _dispatch_client_callout + 16 26 libdispatch.dylib 0x109a0 _dispatch_main_queue_callback_4CF$VARIANT$mp + 936 27 CoreFoundation 0x4d7f8 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12 28 CoreFoundation 0xb0f8 __CFRunLoopRun + 2528 29 CoreFoundation 0x1dd8c CFRunLoopRunSpecific + 572 30 GraphicsServices 0x19a0 GSEventRunModal + 160 31 UIKitCore 0x4edfa8 -[UIApplication _run] + 1080 32 UIKitCore 0x28222c UIApplicationMain + 2060 ``` ``` Thread 0 [Crashed]: 0 libsystem_platform.dylib 0x1f15920c0 _os_unfair_lock_recursive_abort + 36 1 libsystem_platform.dylib 0x1f158ca10 _os_unfair_lock_lock_slow + 303 2 Foundation 0x183211730 -[NSProcessInfo(NSProcessInfoHardwareState) isLowPowerModeEnabled] + 67 3 Datadog 0x102bdfa28 closure #1 in LowPowerModeMonitor.init(MobileDevice.swift:140) 4 Datadog 0x102bdfac8 thunk for @escaping @callee_guaranteed (<compiler-generated>:0) 5 Foundation 0x18321d5b0 -[__NSObserver _doit:] + 347 6 CoreFoundation 0x1819e8ee8 _CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 27 7 CoreFoundation 0x181a84b9c __CFXRegistrationPost_block_invoke + 51 8 CoreFoundation 0x181a57f54 _CFXRegistrationPost + 455 9 CoreFoundation 0x1819fed54 _CFXNotificationPost + 715 10 Foundation 0x183203028 -[NSNotificationCenter postNotificationName:object:userInfo:] + 95 11 Foundation 0x18327b9d4 NSProcessInfoNotifyPowerState + 187 12 Foundation 0x183211768 -[NSProcessInfo(NSProcessInfoHardwareState) isLowPowerModeEnabled] + 123 13 WebCore 0x190a48118 -[WebLowPowerModeObserver initWithNotifier:] + 95 14 WebCore 0x1914c416c WebCore::LowPowerModeNotifier::LowPowerModeNotifier(WTF::Function<void (bool)>&&) + 51 15 WebCore 0x1923e9c4c WebCore::Page::Page(WebCore::PageConfiguration&&) + 1847 16 WebKitLegacy 0x1a550de34 -[WebView(WebPrivate) _commonInitializationWithFrameName:groupName:] + 3059 17 WebKitLegacy 0x1a550d214 -[WebView(WebPrivate) _initWithFrame:frameName:groupName:] + 115 18 UIFoundation 0x18c7b9028 -[NSHTMLReader _loadUsingWebKit] + 831 19 UIFoundation 0x18c7ba15c -[NSHTMLReader attributedString] + 31 20 UIFoundation 0x18c7734e8 _NSReadAttributedStringFromURLOrData + 8419 21 UIFoundation 0x18c771378 -[NSAttributedString(NSAttributedStringUIFoundationAdditions) initWithData:options:documentAttributes:error:] + 155 ``` All crashes occur on iOS 15 (so far we received reports for iOS 15, 15.1 and 15.2). Similar feedback has already been reported in FB9661108. --- **Please list the steps you took to reproduce the issue:** With my best efforts, I couldn’t reproduce it locally. I only rely on crash reports reported by our customers. **What did you expect to happen?** Obtaining `ProcessInfo.processInfo.isLowPowerModeEnabled` should be thread safe no matter of surrounding code. Reading it from `.NSProcessInfoPowerStateDidChange` notification callback should not lead to crash. **What actually happened?** Sometimes, reading `.isLowPowerModeEnabled` from `ProcessInfo` **within the `. NSProcessInfoPowerStateDidChange` notification callback** causes a dead lock in `libsystem_platform.dylib` and leads to `_os_unfair_lock_recursive_abort` crash.
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!
The status of this issue was updated with: `
Recent Similar Reports:Less than 10 Resolution:Potential fix identified - For a future OS update `