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

bug: Crash on iOS when you access the storedCalls on threads other than the "bridge"-DispatchQueue #5889

Closed
ph1ps opened this issue Aug 30, 2022 · 2 comments

Comments

@ph1ps
Copy link

ph1ps commented Aug 30, 2022

Bug Report

Capacitor Version

💊   Capacitor Doctor  💊 

Latest Dependencies:

  @capacitor/cli: 4.1.0
  @capacitor/core: 4.1.0
  @capacitor/android: 4.1.0
  @capacitor/ios: 4.1.0

Installed Dependencies:

  @capacitor/android: not installed
  @capacitor/cli: 4.1.0
  @capacitor/core: 4.1.0
  @capacitor/ios: 4.1.0

[success] iOS looking great! 👌

Platform(s)

iOS

Current Behavior

Calling saveCall or releaseCall from another queue other than the "bridge"-DispatchQueue can cause crashes since Swift's dictionaries are not thread-safe.

Expected Behavior

The expected behaviour would be no crashes. I understand that it may be required that the calls are saved or released on the "bridge"-DispatchQueue. But there is no possibility to do this from other threads which should be possible in my opinion since you may want to release a call after some asynchronous portion of code is done. getDispatchQueue() is internal, so there is no way to schedule work on it other than reflection.

Code Reproduction

In the JS portion you literally just do this:

for (let i = 0; i < 10000; i++) { 
    Capacitor.Plugins.BridgeCrash.echo({value: 'test'});
}

And in the native part:

@objc func echo(_ call: CAPPluginCall) {
    call.keepAlive = true

    DispatchQueue.main.async { [self] in
        bridge?.saveCall(call)
        call.resolve([:])
        bridge?.releaseCall(call)
    }
}

Other Technical Details

npm --version output:
8.5.2
node --version output:
v16.13.1
pod --version output (iOS issues only):
1.11.3

Additional Context

The crash (most of the time) is here:

@objc public func releaseCall(withID: String) {
    storedCalls.removeValue(forKey: withID)
}

This makes sense since Swift's dictionaries are not thread-safe and the 10.000 calls was causing race conditions most of the times I tried. I am suggesting to either put a lock around the storedCalls dictionary access or grant access to the internal DispatchQueue so you can safely switch to the correct thread.

@LeonardoDavinci
Copy link

I'm having the same issue. Got a few crashes reported in analytics last week.

@jcesarmobile
Copy link
Member

should be fixed by #7480

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

No branches or pull requests

4 participants