Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash: Simultaneous accesses, but modification requires exclusive access #257

Open
kevinrenskers opened this issue Mar 19, 2020 · 8 comments

Comments

@kevinrenskers
Copy link

ReactiveKit 3.16.3 (via Cocoapods).
Xcode 11.3.1
iOS 13.3

Simultaneous accesses to 0x6000024dd210, but modification requires exclusive access.
Previous access (a modification) started at ReactiveKit`AtomicObserver.dispose() + 135 (0x1097499c7).
Current access (a read) started at:
0    libswiftCore.dylib                 0x000000010b9a1590 swift_beginAccess + 568
1    ReactiveKit                        0x0000000109749110 AtomicObserver.on(_:) + 249
2    ReactiveKit                        0x0000000109749c60 protocol witness for ObserverProtocol.on(_:) in conformance AtomicObserver<A, B> + 16
3    ReactiveKit                        0x0000000109749f20 ObserverProtocol.receive(completion:) + 594
4    ReactiveKit                        0x0000000109777120 closure #1 in closure #1 in SignalProtocol<>.castError<A>() + 750
5    ReactiveKit                        0x0000000109749110 AtomicObserver.on(_:) + 1044
6    ReactiveKit                        0x0000000109749c60 protocol witness for ObserverProtocol.on(_:) in conformance AtomicObserver<A, B> + 16
7    ReactiveKit                        0x0000000109749f20 ObserverProtocol.receive(completion:) + 594
8    ReactiveKit                        0x000000010978de40 closure #1 in closure #1 in SignalProtocol<>.ignoreNils() + 1704
9    ReactiveKit                        0x0000000109749110 AtomicObserver.on(_:) + 1044
10   ReactiveKit                        0x0000000109749c60 protocol witness for ObserverProtocol.on(_:) in conformance AtomicObserver<A, B> + 16
11   ReactiveKit                        0x0000000109749f20 ObserverProtocol.receive(completion:) + 594
12   ReactiveKit                        0x0000000109785600 closure #1 in closure #1 in SignalProtocol.map<A>(_:) + 1470
13   ReactiveKit                        0x0000000109749110 AtomicObserver.on(_:) + 1044
14   ReactiveKit                        0x0000000109749c60 protocol witness for ObserverProtocol.on(_:) in conformance AtomicObserver<A, B> + 16
15   ReactiveKit                        0x0000000109749f20 ObserverProtocol.receive(completion:) + 594
16   ReactiveKit                        0x000000010978de40 closure #1 in closure #1 in SignalProtocol<>.ignoreNils() + 1704
17   ReactiveKit                        0x0000000109749110 AtomicObserver.on(_:) + 1044
18   ReactiveKit                        0x0000000109749c60 protocol witness for ObserverProtocol.on(_:) in conformance AtomicObserver<A, B> + 16
19   ReactiveKit                        0x0000000109749f20 ObserverProtocol.receive(completion:) + 594
20   ReactiveKit                        0x0000000109795940 closure #1 in closure #1 in SignalProtocol.scan<A>(_:_:) + 1906
21   ReactiveKit                        0x0000000109796fb0 partial apply for closure #1 in closure #1 in SignalProtocol.scan<A>(_:_:) + 66
22   ReactiveKit                        0x0000000109749110 AtomicObserver.on(_:) + 1044
23   ReactiveKit                        0x0000000109749c60 protocol witness for ObserverProtocol.on(_:) in conformance AtomicObserver<A, B> + 16
24   ReactiveKit                        0x0000000109749f20 ObserverProtocol.receive(completion:) + 594
25   ReactiveKit                        0x0000000109795940 closure #1 in closure #1 in SignalProtocol.scan<A>(_:_:) + 1906
26   ReactiveKit                        0x0000000109796fb0 partial apply for closure #1 in closure #1 in SignalProtocol.scan<A>(_:_:) + 66
27   ReactiveKit                        0x0000000109748bb0 thunk for @escaping @callee_guaranteed (@in_guaranteed Signal<A, B>.Event) -> () + 12
28   ReactiveKit                        0x00000001097af3a0 partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Signal<A, B>.Event) -> () + 54
29   ReactiveKit                        0x00000001097a4df0 thunk for @escaping @callee_guaranteed (@in_guaranteed Signal<A, B>.Event) -> (@out ()) + 12
30   ReactiveKit                        0x00000001097a48c0 Subject.on(_:) + 1234
31   ReactiveKit                        0x00000001097a61e0 PassthroughSubject.on(_:) + 113
32   ReactiveKit                        0x00000001097a5ab0 protocol witness for ObserverProtocol.on(_:) in conformance Subject<A, B> + 24
33   ReactiveKit                        0x00000001097a3830 SubjectProtocol.send(completion:) + 623
34   ReactiveKit                        0x000000010974c240 Property.deinit + 126
35   ReactiveKit                        0x000000010974c310 Property.__deallocating_deinit + 39
36   libswiftCore.dylib                 0x000000010b9a2f00 _swift_release_dealloc + 16
37   LastFm                             0x0000000107e20020 ReportsViewModel.deinit + 33
38   LastFm                             0x0000000107e20050 ReportsViewModel.__deallocating_deinit + 25
39   libswiftCore.dylib                 0x000000010b9a2f00 _swift_release_dealloc + 16
40   LastFm                             0x0000000107e30070 outlined assign with take of ReportPeriod + 469
41   libswiftCore.dylib                 0x000000010b9a2f00 _swift_release_dealloc + 16
42   LastFm                             0x0000000107e1dd40 thunk for @escaping @callee_guaranteed (@in_guaranteed ReportPeriod) -> (@owned Signal<ReportsViewModel.Status, Never>) + 69
43   libswiftCore.dylib                 0x000000010b9a2f00 _swift_release_dealloc + 16
44   ReactiveKit                        0x000000010978ce00 outlined destroy of Subscribers.Completion<A1.Error> + 138
45   libswiftCore.dylib                 0x000000010b9a2f00 _swift_release_dealloc + 16
46   ReactiveKit                        0x0000000109748f60 outlined consume of @escaping @callee_guaranteed (@in_guaranteed Signal<A, B>.Event) -> ()?<A, B> + 27
47   ReactiveKit                        0x0000000109749940 AtomicObserver.dispose() + 168
48   ReactiveKit                        0x0000000109749c80 protocol witness for Disposable.dispose() in conformance AtomicObserver<A, B> + 16
49   ReactiveKit                        0x0000000109749b00 closure #1 in AtomicObserver.dispose() + 74
50   libswiftCore.dylib                 0x000000010b8208b0 Sequence.forEach(_:) + 452
51   ReactiveKit                        0x0000000109749940 AtomicObserver.dispose() + 377
52   ReactiveKit                        0x0000000109749c80 protocol witness for Disposable.dispose() in conformance AtomicObserver<A, B> + 16
53   ReactiveKit                        0x0000000109731900 closure #1 in CompositeDisposable.dispose() + 74
54   libswiftCore.dylib                 0x000000010b8208b0 Sequence.forEach(_:) + 452
55   ReactiveKit                        0x00000001097316f0 CompositeDisposable.dispose() + 399
56   ReactiveKit                        0x0000000109731a50 protocol witness for Disposable.dispose() in conformance CompositeDisposable + 16
57   ReactiveKit                        0x0000000109749b00 closure #1 in AtomicObserver.dispose() + 74
58   libswiftCore.dylib                 0x000000010b8208b0 Sequence.forEach(_:) + 452
59   ReactiveKit                        0x0000000109749940 AtomicObserver.dispose() + 377
60   ReactiveKit                        0x0000000109749c80 protocol witness for Disposable.dispose() in conformance AtomicObserver<A, B> + 16
61   ReactiveKit                        0x0000000109728840 closure #1 in closure #1 in ConnectableSignalProtocol.refCount() + 715
62   ReactiveKit                        0x000000010972fee0 BlockDisposable.dispose() + 360
63   ReactiveKit                        0x0000000109730140 protocol witness for Disposable.dispose() in conformance BlockDisposable + 16
64   ReactiveKit                        0x0000000109749b00 closure #1 in AtomicObserver.dispose() + 74
65   libswiftCore.dylib                 0x000000010b8208b0 Sequence.forEach(_:) + 452
66   ReactiveKit                        0x0000000109749940 AtomicObserver.dispose() + 377
67   ReactiveKit                        0x0000000109749c80 protocol witness for Disposable.dispose() in conformance AtomicObserver<A, B> + 16
68   ReactiveKit                        0x0000000109731900 closure #1 in CompositeDisposable.dispose() + 74
69   libswiftCore.dylib                 0x000000010b8208b0 Sequence.forEach(_:) + 452
70   ReactiveKit                        0x00000001097316f0 CompositeDisposable.dispose() + 399
71   ReactiveKit                        0x0000000109731a50 protocol witness for Disposable.dispose() in conformance CompositeDisposable + 16
72   ReactiveKit                        0x0000000109749720 closure #1 in AtomicObserver.on(_:) + 74
73   libswiftCore.dylib                 0x000000010b8208b0 Sequence.forEach(_:) + 452
74   ReactiveKit                        0x0000000109749110 AtomicObserver.on(_:) + 867
75   ReactiveKit                        0x0000000109749c60 protocol witness for ObserverProtocol.on(_:) in conformance AtomicObserver<A, B> + 16
76   ReactiveKit                        0x0000000109749f20 ObserverProtocol.receive(completion:) + 594
77   ReactiveKit                        0x0000000109782780 closure #1 in closure #1 in SignalProtocol.prefix<A>(untilOutputFrom:) + 371
78   ReactiveKit                        0x0000000109749110 AtomicObserver.on(_:) + 1044
79   ReactiveKit                        0x0000000109749c60 protocol witness for ObserverProtocol.on(_:) in conformance AtomicObserver<A, B> + 16
80   ReactiveKit                        0x000000010974adf0 partial apply + 83
81   ReactiveKit                        0x0000000109748bb0 thunk for @escaping @callee_guaranteed (@in_guaranteed Signal<A, B>.Event) -> () + 12
82   ReactiveKit                        0x00000001097af3a0 partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed Signal<A, B>.Event) -> () + 54
83   ReactiveKit                        0x00000001097a4df0 thunk for @escaping @callee_guaranteed (@in_guaranteed Signal<A, B>.Event) -> (@out ()) + 12
84   ReactiveKit                        0x00000001097a48c0 Subject.on(_:) + 1234
85   ReactiveKit                        0x00000001097a7bd0 ReplayOneSubject.on(_:) + 1026
86   ReactiveKit                        0x00000001097a5ab0 protocol witness for ObserverProtocol.on(_:) in conformance Subject<A, B> + 24
87   ReactiveKit                        0x00000001097a3830 SubjectProtocol.send(completion:) + 623
88   ReactiveKit                        0x00000001097332d0 DisposeBag.deinit + 222
89   ReactiveKit                        0x00000001097334a0 DisposeBag.__deallocating_deinit + 25
90   libswiftCore.dylib                 0x000000010b9a2f00 _swift_release_dealloc + 16
91   libobjc.A.dylib                    0x00007fff5140d3d1 _object_remove_assocations + 239
92   libobjc.A.dylib                    0x00007fff5140a473 objc_destructInstance + 79
93   libobjc.A.dylib                    0x00007fff5141093a -[NSObject dealloc] + 21
94   UIKitCore                          0x00007fff480bf631 -[UIResponder dealloc] + 145
95   UIKit                              0x000000010c490925 -[UIResponderAccessibility dealloc] + 55
96   UIKitCore                          0x00007fff47a0f887 -[UIViewController dealloc] + 1392
97   libobjc.A.dylib                    0x00007fff514126c8 AutoreleasePoolPage::releaseUntil(objc_object**) + 147
98   libobjc.A.dylib                    0x00007fff514125b3 objc_autoreleasePoolPop + 199
99   UIKitCore                          0x00007fff47a0f887 -[UIViewController dealloc] + 1359
100  UIKitCore                          0x00007fff47940244 -[UITabBarController dealloc] + 689
101  libobjc.A.dylib                    0x00007fff514126c8 AutoreleasePoolPage::releaseUntil(objc_object**) + 147
102  libobjc.A.dylib                    0x00007fff514125b3 objc_autoreleasePoolPop + 199
103  CoreFoundation                     0x00007fff23c92380 _CFAutoreleasePoolPop + 22
104  UIKitCore                          0x00007fff4808c43a _prepareForCAFlush + 129
105  UIKitCore                          0x00007fff480bc354 _afterCACommitHandler + 140
106  CoreFoundation                     0x00007fff23bd3850 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
107  CoreFoundation                     0x00007fff23bce150 __CFRunLoopDoObservers + 430
108  CoreFoundation                     0x00007fff23bce390 __CFRunLoopRun + 1514
109  CoreFoundation                     0x00007fff23bcdeb0 CFRunLoopRunSpecific + 438
110  GraphicsServices                   0x00007fff384c0b6f GSEventRunModal + 65
111  UIKitCore                          0x00007fff480926f8 UIApplicationMain + 1621
112  LastFm                             0x0000000107e93e20 main + 75
113  libdyld.dylib                      0x00007fff5227ec24 start + 1
(lldb) 

Screen Shot 2020-03-19 at 16 19 04

@kevinrenskers
Copy link
Author

Updated to 3.17.0 (it's not on CocoaPods so switched it to SPM), still the same problem.

@TeunVR
Copy link

TeunVR commented Mar 30, 2020

Same problem here :(
I have a bit complex combineLatest of some properties.
The object containing the properties is deallocated when the disposeBag is emptied that contains the disposable for the combineLatest-subscription.

If i remove the subject.send(completion: .finished) from the Property.deinit the crash goes away.
Might be something in my own code, i'll try to make a demo-project.

@lmcd
Copy link

lmcd commented Mar 31, 2020

I'm seeing a similar issue in Atomic.swift, not sure if related:

image

As far as I tell, everything is happening on the main thread. I'm not setting up any observers elsewhere

@TeunVR
Copy link

TeunVR commented Mar 31, 2020

Ignore my previous reaction. Was my own fault.
I was indirectly capturing the property being observed inside the onNext.
Works ok for me now.

@srdanrasic
Copy link
Contributor

My assumption is that these are valid problems caused by the way ReactiveKit is used, caused by reasons like @TeunVR had. For example mutating a property that trigged the event from the observer or binding of that property is not a valid usage and is expected to throw a simultaneous accesses error.

@lmcd
Copy link

lmcd commented Mar 31, 2020

Yeah turns out merely referencing the property inside an observer is enough to crash once it's disposed. Fixed, thanks for clarifiying.

@kevinrenskers
Copy link
Author

Not sure where my problem could come from. My VC is something like this:

class ReportsContainerViewController: UIViewController {
  private let viewModel = ReportsViewModel()

  private func setupBindings() {
    viewModel.statusSignal.bind(to: self) { vc, status in
      // Do things
    }
  }
}

Now, the crash happens when the user logs out: that results in the root window's rootViewController getting set to a login VC. That in turn causes the ReportsContainerViewController to be released, and that releases the ViewModel.

@kevinrenskers
Copy link
Author

kevinrenskers commented Mar 31, 2020

Okay, I found the problem.

This is my ViewModel:

class ReportsViewModel {
  enum Status {
    case loading
    case loaded(data: ReportData)
    case error(error: ReportsViewModelError)
  }

  public var period = Property<ReportPeriod>(ReportPeriod(rawValue: 0))
  public var statusSignal: Signal<Status, Never> {
    return period.removeDuplicates().flatMapLatest(getData)
  }

  private let urlCache: URLCache
  private let sessionManager: SessionManager

  init() {
    urlCache = URLCache(memoryCapacity: 20 * 1024 * 1024, diskCapacity: 200 * 1024 * 1024, diskPath: nil)

    let configuration = URLSessionConfiguration.default
    configuration.requestCachePolicy = .returnCacheDataElseLoad
    configuration.urlCache = urlCache
    configuration.timeoutIntervalForRequest = 15
    sessionManager = Alamofire.SessionManager(configuration: configuration)
  }

  private func getData(period: ReportPeriod) -> Signal<Status, Never> {
    // ...
  }
}

If I change the statusSignal to no longer be a computed property but initialized in the init, no more crash.

class ReportsViewModel {
  enum Status {
    case loading
    case loaded(data: ReportData)
    case error(error: ReportsViewModelError)
  }

  public var period = Property<ReportPeriod>(ReportPeriod(rawValue: 0))
  public var statusSignal: Signal<Status, Never>!

  private let urlCache: URLCache
  private let sessionManager: SessionManager

  init() {
    urlCache = URLCache(memoryCapacity: 20 * 1024 * 1024, diskCapacity: 200 * 1024 * 1024, diskPath: nil)

    let configuration = URLSessionConfiguration.default
    configuration.requestCachePolicy = .returnCacheDataElseLoad
    configuration.urlCache = urlCache
    configuration.timeoutIntervalForRequest = 15
    sessionManager = Alamofire.SessionManager(configuration: configuration)

    statusSignal = period.removeDuplicates().flatMapLatest(getData)
  }

  private func getData(period: ReportPeriod) -> Signal<Status, Never> {
    // ...
  }
}

The reason why I did it like the first way first, was because I was getting 'self' used in method call 'getData' before all stored properties are initialized errors from the compiler, when statusSignal was not an implicitly unwrapped variable, which I wanted to avoid. Oh well :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants