ReactiveCocoa / ReactiveSwift

Streams of values over time

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Adopt OSAllocatedUnfairLock on iOS 16

vcsoares opened this issue · comments

I am currently working on a project that has seen a huge spike of production issues since iOS 16 got released a couple of days ago, and virtually all of them point to a call to os_unfair_lock_lock made by ReactiveSwift as the cause of the crashes. One such example is included below for reference.

One of the changes introduced with iOS 16 is a new API for unfair locks, replacing os_unfair_lock and its related methods. Considering ReactiveSwift is used in a large number of live apps, the library should adopt OSAllocatedUnfairLock from iOS 16 onwards to fix crashes like these and avoid other potential issues.

Crashed: com.apple.main-thread
0  libsystem_platform.dylib       0x608c _os_unfair_lock_recursive_abort + 36
1  libsystem_platform.dylib       0x898 _os_unfair_lock_lock_slow + 280
2  ReactiveSwift                  0x3c0ac Signal.Core.send(_:) + 110 (Signal.swift:110)
3  ReactiveSwift                  0x2cfe8 Signal.Observer.send(value:) + 105 (Observer.swift:105)
4  ReactiveSwift                  0x3331c $defer #1 <A><A1>() in closure #1 in MutableProperty.modify<A>(_:) + 144
5  ReactiveSwift                  0x32d10 MutableProperty.modify<A>(_:) + 128 (<compiler-generated>:128)
6  ReactiveSwift                  0x32c68 MutableProperty.value.setter + 644 (Property.swift:644)
7  <REDACTED>          0x29d5b4 MapSearchViewModel.searchTextDidUpdate(with:) + 140 (MapSearchViewModel.swift:140)
8  <REDACTED>          0x2f292c MapSearchView.searchTextDidChange(_:) + 4304791852 (<compiler-generated>:4304791852)
9  <REDACTED>          0x2f2990 @objc MapSearchView.searchTextDidChange(_:) + 4304791952 (<compiler-generated>:4304791952)
10 UIKitCore                      0x24f6f8 -[UIApplication sendAction:to:from:forEvent:] + 132
11 UIKitCore                      0x24f3d8 -[UIControl sendAction:to:forEvent:] + 112
12 UIKitCore                      0x24ed6c -[UIControl _sendActionsForEvents:withEvent:] + 324
13 UIKitCore                      0x56a57c -[UITextField fieldEditorDidChange:] + 156
14 UIKitCore                      0xf102b8 -[UIFieldEditor textInputDidChange:] + 84
15 UIKitCore                      0x233968 -[UITextInputController _sendDelegateChangeNotificationsForText:selection:] + 152
16 UIKitCore                      0xf271f4 -[UITextInputController replaceRangeWithTextWithoutClosingTyping:replacementText:] + 344
17 UIKitCore                      0xf11db8 -[UIFieldEditor _handleObscuredTextInputIfNecessaryWithEditingBlock:] + 376
18 UIKitCore                      0xf12428 -[UIFieldEditor replaceRangeWithTextWithoutClosingTyping:replacementText:] + 144
19 UIKitCore                      0xf1c330 -[UITextField replaceRangeWithTextWithoutClosingTyping:replacementText:] + 76
20 UIKitCore                      0x95d040 -[UIKBInputDelegateManager replaceRange:oldText:withText:forReplaceAction:] + 188
21 UIKitCore                      0xba919c -[UIKeyboardImpl applyAutocorrection:] + 896
22 UIKitCore                      0xb9cfe4 -[UIKeyboardImpl acceptAutocorrection:executionContextPassingTIKeyboardCandidate:] + 1172
23 UIKitCore                      0xb9ba80 -[UIKeyboardImpl acceptAutocorrectionForWordTerminator:executionContextPassingTIKeyboardCandidate:] + 296
24 UIKitCore                      0xb9b8d8 __56-[UIKeyboardImpl acceptAutocorrectionForWordTerminator:]_block_invoke + 140
25 UIKitCore                      0x3d39b4 -[UIKeyboardTaskEntry execute:] + 208
26 UIKitCore                      0x3d3898 -[UIKeyboardTaskQueue continueExecutionOnMainThread] + 304
27 UIKitCore                      0xbc9914 -[UIKeyboardTaskQueue addAndReturnTask:] + 96
28 UIKitCore                      0x50cdb8 -[UIKeyboardTaskQueue performSingleTask:] + 96
29 UIKitCore                      0xb9b7d8 -[UIKeyboardImpl acceptAutocorrectionForWordTerminator:] + 208
30 UIKitCore                      0xb9f830 -[UIKeyboardImpl _acceptAutocorrection] + 452
31 UIKitCore                      0xb9f46c -[UIKeyboardImpl acceptAutocorrectionWithCompletionHandler:] + 296
32 UIKitCore                      0xb83c5c -[UIKeyboardImpl setDelegate:force:fromBecomeFirstResponder:] + 2020
33 UIKitCore                      0x8e165c -[UIKeyboardSceneDelegate _reloadInputViewsForKeyWindowSceneResponder:force:fromBecomeFirstResponder:] + 1752
34 UIKitCore                      0x8e0f44 -[UIKeyboardSceneDelegate _reloadInputViewsForResponder:force:fromBecomeFirstResponder:] + 128
35 UIKitCore                      0xd456ac -[UIResponder _finishResignFirstResponderFromBecomeFirstResponder:] + 328
36 UIKitCore                      0x565334 -[UITextField _finishResignFirstResponder] + 56
37 UIKitCore                      0x220060 -[UIResponder resignFirstResponder] + 284
38 UIKitCore                      0x3c5090 -[UITextField resignFirstResponder] + 100
39 <REDACTED>          0x2f285c closure #4 in MapSearchView.setupReactiveBindings() + 4304791644
40 ReactiveSwift                  0x2d328 closure #1 in Signal.Observer.init(value:failed:completed:interrupted:) + 60 (Observer.swift:60)
41 ReactiveSwift                  0x2d444 partial apply for closure #1 in Signal.Observer.init(value:failed:completed:interrupted:) + 48 (<compiler-generated>:48)
42 ReactiveSwift                  0x2d028 Signal.Observer.send(_:) + 97 (Observer.swift:97)
43 ReactiveSwift                  0x3c14c Signal.Core.send(_:) + 480 (<compiler-generated>:480)
44 ReactiveSwift                  0x2d528 closure #1 in Signal.Observer.init(mappingInterruptedToCompleted:) + 96 (Observer.swift:96)
45 ReactiveSwift                  0x2d028 Signal.Observer.send(_:) + 97 (Observer.swift:97)
46 ReactiveSwift                  0x3c14c Signal.Core.send(_:) + 480 (<compiler-generated>:480)
47 ReactiveSwift                  0x2cfe8 Signal.Observer.send(value:) + 105 (Observer.swift:105)
48 ReactiveSwift                  0x3331c $defer #1 <A><A1>() in closure #1 in MutableProperty.modify<A>(_:) + 144
49 ReactiveSwift                  0x32d10 MutableProperty.modify<A>(_:) + 128 (<compiler-generated>:128)
50 ReactiveSwift                  0x32c68 MutableProperty.value.setter + 644 (Property.swift:644)
51 <REDACTED>          0x29d48c MapSearchViewModel.didSelectRow(at:) + 123 (MapSearchViewModel.swift:123)
52 <REDACTED>          0x2f3410 @objc MapSearchView.tableView(_:didSelectRowAt:) + 4304794640 (<compiler-generated>:4304794640)
53 UIKitCore                      0xe65e9c -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:isCellMultiSelect:deselectPrevious:performCustomSelectionAction:] + 1196
54 UIKitCore                      0xe661b0 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 256
55 UIKitCore                      0x1a4958 -[_UIAfterCACommitBlock run] + 72
56 UIKitCore                      0x1a488c -[_UIAfterCACommitQueue flush] + 176
57 UIKitCore                      0x1a4798 _runAfterCACommitDeferredBlocks + 496
58 UIKitCore                      0x3f6c0 _cleanUpAfterCAFlushAndRunDeferredBlocks + 108
59 UIKitCore                      0x504fc4 _UIApplicationFlushCATransaction + 72
60 UIKitCore                      0x651678 _UIUpdateSequenceRun + 84
61 UIKitCore                      0xc90904 schedulerStepScheduledMainSection + 172
62 UIKitCore                      0xc8fad0 runloopSourceCallback + 92
63 CoreFoundation                 0xd622c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
64 CoreFoundation                 0xe2614 __CFRunLoopDoSource0 + 176
65 CoreFoundation                 0x6651c __CFRunLoopDoSources0 + 244
66 CoreFoundation                 0x7beb8 __CFRunLoopRun + 836
67 CoreFoundation                 0x811e4 CFRunLoopRunSpecific + 612
68 GraphicsServices               0x1368 GSEventRunModal + 164
69 UIKitCore                      0x3a2d88 -[UIApplication _run] + 888
70 UIKitCore                      0x3a29ec UIApplicationMain + 340
71 <REDACTED>          0x744c main + 17 (AppDelegate.swift:17)
72 ???                            0x1bbabd948 (Ausente)

Are you modifying a property recursively by any chance?

Not that I'm aware of, no. These crashes have never happened on iOS 15 and earlier.

Either I agree using OSAllocatedUnfairLock on iOS 16 and forward would be nice 👍🏻

I also see some crashes in iOS 16 due to same problem.

I ran into the same crash but it was due to modifying a property recursively.

From the documentation of OSAllocatedUnfairLock it says:

Important
If you have existing Swift code that uses os_unfair_lock, change it to use OSAllocatedUnfairLock to ensure correct locking behavior.

So to support iOS 16+ (and macOS, watchOS etc of the same era) use of os_unfair_lock should be changed to OSAllocatedUnfairLock.

Note that OSAllocatedUnfairLock is not recursive:

Warning
OSAllocatedUnfairLock isn’t a recursive lock. Attempting to lock an object more than once from the same thread without unlocking in between triggers a runtime exception.

But that shouldn't be an issue as os_unfair_lock doesn't allow recursion either.

Yeah I'm all for replacing the implementation starting with iOS 16 👍🏻

@vcsoares are you able to reproduce the crash? If so could you test with the branch of the PR I created to fix this issue to see if it resolves? #856

I can't reproduce the crash but i've tested the change and i can't find any side effect.