firebase-ios-sdk icon indicating copy to clipboard operation
firebase-ios-sdk copied to clipboard

Crash while fetching the auth token

Open saurabh-iOS2 opened this issue 6 months ago • 7 comments

Description

We are getting crashes when firebase internally triggers Auth.getToken(forcingRefresh:completion:) pointing to Crashed: com.google.firebase.auth.globalWorkQueue EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x00000002d041d090

Reproducing the issue

This is happening for our production users across app versions, we are using 11.9.0 version of firebase via cocoa pods

Firebase SDK Version

11.9.0

Xcode Version

16.1

Installation Method

CocoaPods

Firebase Product(s)

Crashlytics, Firestore, AB Testing, Analytics, App Distribution, Performance, Remote Config

Targeted Platforms

iOS

Relevant Log Output

Crashed: com.google.firebase.auth.globalWorkQueue
0  libobjc.A.dylib                0x1b50 objc_release_x0 + 16
1  libobjc.A.dylib                0x1b50 objc_release + 16
2  Porter                         0xd61c2c closure #1 in Auth.getToken(forcingRefresh:completion:) + 1594 (User.swift:1594)
3  Porter                         0x14880 thunk for @escaping @callee_guaranteed @Sendable () -> () + 4306913408 (<compiler-generated>:4306913408)
4  libdispatch.dylib              0x1aac _dispatch_call_block_and_release + 32
5  libdispatch.dylib              0x1b584 _dispatch_client_callout + 16
6  libdispatch.dylib              0xa2d0 _dispatch_lane_serial_drain + 740
7  libdispatch.dylib              0xadac _dispatch_lane_invoke + 388
8  libdispatch.dylib              0x151dc _dispatch_root_queue_drain_deferred_wlh + 292
9  libdispatch.dylib              0x14a60 _dispatch_workloop_worker_thread + 540
10 libsystem_pthread.dylib        0x4660 _pthread_wqthread + 292
11 libsystem_pthread.dylib        0x19f8 start_wqthread + 8

If using Swift Package Manager, the project's Package.resolved

Expand Package.resolved snippet

Replace this line with the contents of your Package.resolved.

If using CocoaPods, the project's Podfile.lock

Expand Podfile.lock snippet


  - Firebase/Analytics (11.9.0):
    - Firebase/Core
  - Firebase/Auth (11.9.0):
    - Firebase/CoreOnly
    - FirebaseAuth (~> 11.9.0)
  - Firebase/Core (11.9.0):
    - Firebase/CoreOnly
    - FirebaseAnalytics (~> 11.9.0)
  - Firebase/CoreOnly (11.9.0):
    - FirebaseCore (~> 11.9.0)
  - Firebase/Crashlytics (11.9.0):
    - Firebase/CoreOnly
    - FirebaseCrashlytics (~> 11.9.0)
  - Firebase/Firestore (11.9.0):
    - Firebase/CoreOnly
    - FirebaseFirestore (~> 11.9.0)
  - FirebaseABTesting (11.9.0):
    - FirebaseCore (~> 11.9.0)
  - FirebaseAnalytics (11.9.0):
    - FirebaseAnalytics/AdIdSupport (= 11.9.0)
    - FirebaseCore (~> 11.9.0)
    - FirebaseInstallations (~> 11.0)
    - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
    - GoogleUtilities/MethodSwizzler (~> 8.0)
    - GoogleUtilities/Network (~> 8.0)
    - "GoogleUtilities/NSData+zlib (~> 8.0)"
    - nanopb (~> 3.30910.0)
  - FirebaseAnalytics/AdIdSupport (11.9.0):
    - FirebaseCore (~> 11.9.0)
    - FirebaseInstallations (~> 11.0)
    - GoogleAppMeasurement (= 11.9.0)
    - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
    - GoogleUtilities/MethodSwizzler (~> 8.0)
    - GoogleUtilities/Network (~> 8.0)
    - "GoogleUtilities/NSData+zlib (~> 8.0)"
    - nanopb (~> 3.30910.0)
  - FirebaseAppCheckInterop (11.9.0)
  - FirebaseAuth (11.9.0):
    - FirebaseAppCheckInterop (~> 11.0)
    - FirebaseAuthInterop (~> 11.0)
    - FirebaseCore (~> 11.9.0)
    - FirebaseCoreExtension (~> 11.9.0)
    - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
    - GoogleUtilities/Environment (~> 8.0)
    - GTMSessionFetcher/Core (< 5.0, >= 3.4)
    - RecaptchaInterop (~> 101.0)
  - FirebaseAuthInterop (11.9.0)
  - FirebaseCore (11.9.0):
    - FirebaseCoreInternal (~> 11.9.0)
    - GoogleUtilities/Environment (~> 8.0)
    - GoogleUtilities/Logger (~> 8.0)
  - FirebaseCoreExtension (11.9.0):
    - FirebaseCore (~> 11.9.0)
  - FirebaseCoreInternal (11.9.0):
    - "GoogleUtilities/NSData+zlib (~> 8.0)"
  - FirebaseCrashlytics (11.9.0):
    - FirebaseCore (~> 11.9.0)
    - FirebaseInstallations (~> 11.0)
    - FirebaseRemoteConfigInterop (~> 11.0)
    - FirebaseSessions (~> 11.0)
    - GoogleDataTransport (~> 10.0)
    - GoogleUtilities/Environment (~> 8.0)
    - nanopb (~> 3.30910.0)
    - PromisesObjC (~> 2.4)
  - FirebaseFirestore (11.9.0):
    - FirebaseCore (~> 11.9.0)
    - FirebaseCoreExtension (~> 11.9.0)
    - FirebaseFirestoreInternal (= 11.9.0)
    - FirebaseSharedSwift (~> 11.0)
  - FirebaseFirestoreInternal (11.9.0):
    - abseil/algorithm (~> 1.20240722.0)
    - abseil/base (~> 1.20240722.0)
    - abseil/container/flat_hash_map (~> 1.20240722.0)
    - abseil/memory (~> 1.20240722.0)
    - abseil/meta (~> 1.20240722.0)
    - abseil/strings/strings (~> 1.20240722.0)
    - abseil/time (~> 1.20240722.0)
    - abseil/types (~> 1.20240722.0)
    - FirebaseAppCheckInterop (~> 11.0)
    - FirebaseCore (~> 11.9.0)
    - "gRPC-C++ (~> 1.69.0)"
    - gRPC-Core (~> 1.69.0)
    - leveldb-library (~> 1.22)
    - nanopb (~> 3.30910.0)
  - FirebaseInstallations (11.9.0):
    - FirebaseCore (~> 11.9.0)
    - GoogleUtilities/Environment (~> 8.0)
    - GoogleUtilities/UserDefaults (~> 8.0)
    - PromisesObjC (~> 2.4)
  - FirebasePerformance (11.9.0):
    - FirebaseCore (~> 11.9.0)
    - FirebaseInstallations (~> 11.0)
    - FirebaseRemoteConfig (~> 11.0)
    - FirebaseSessions (~> 11.0)
    - GoogleDataTransport (~> 10.0)
    - GoogleUtilities/Environment (~> 8.0)
    - GoogleUtilities/MethodSwizzler (~> 8.0)
    - GoogleUtilities/UserDefaults (~> 8.0)
    - nanopb (~> 3.30910.0)
  - FirebaseRemoteConfig (11.9.0):
    - FirebaseABTesting (~> 11.0)
    - FirebaseCore (~> 11.9.0)
    - FirebaseInstallations (~> 11.0)
    - FirebaseRemoteConfigInterop (~> 11.0)
    - FirebaseSharedSwift (~> 11.0)
    - GoogleUtilities/Environment (~> 8.0)
    - "GoogleUtilities/NSData+zlib (~> 8.0)"
  - FirebaseRemoteConfigInterop (11.9.0)
  - FirebaseSessions (11.9.0):
    - FirebaseCore (~> 11.9.0)
    - FirebaseCoreExtension (~> 11.9.0)
    - FirebaseInstallations (~> 11.0)
    - GoogleDataTransport (~> 10.0)
    - GoogleUtilities/Environment (~> 8.0)
    - GoogleUtilities/UserDefaults (~> 8.0)
    - nanopb (~> 3.30910.0)
    - PromisesSwift (~> 2.1)
  - FirebaseSharedSwift (11.9.0)

saurabh-iOS2 avatar Jun 12 '25 07:06 saurabh-iOS2

Hi @saurabh-iOS2, this crash looks like it may be caused by your app's implementation of the completion handler parameter that's passed to the Auth.getToken(forcingRefresh:completion:) method. Specifically, an already released object is attempting to be released again.

0  libobjc.A.dylib                0x1b50 objc_release_x0 + 16
1  libobjc.A.dylib                0x1b50 objc_release + 16
2  Porter                         0xd61c2c closure #1 in Auth.getToken(forcingRefresh:completion:) + 1594 (User.swift:1594)

ncooke3 avatar Jun 12 '25 16:06 ncooke3

Hey @ncooke3 getToken api is internally invoked in FirebaseAuth which thereby provides the completion handler that is consumed downstream and is not being triggered by our app. The documentation explicitly mentions its usage is only for AuthInterop and not for public use. Can you please help resolve this.

/// Retrieves the Firebase authentication token, possibly refreshing it if it has expired. /// /// This method is not for public use. It is for Firebase clients of AuthInterop. @objc(getTokenForcingRefresh:withCallback:) public func getToken(forcingRefresh forceRefresh: Bool, completion callback: @escaping (String?, Error?) -> Void)

saurabh-iOS2 avatar Jun 12 '25 17:06 saurabh-iOS2

Apologies for the oversight. I will take a closer look.

ncooke3 avatar Jun 12 '25 17:06 ncooke3

This looks like a crash within the callback supplied by Firestore's use of Auth interop's getToken API. Perhaps related to the recursive call of GetToken?

https://github.com/firebase/firebase-ios-sdk/blob/5902b4087de393025cfda096091ad08743c3f3f2/Firestore/core/src/credentials/firebase_auth_credentials_provider_apple.mm#L75-L128

ncooke3 avatar Jun 12 '25 20:06 ncooke3

Seems like it, could you also suggest a solution to address this for Firebase user apps please

saurabh-iOS2 avatar Jun 13 '25 04:06 saurabh-iOS2

This particular code path has remain unchanged for years, i am curious what has changed that might have triggered this.

  1. Do you have debug logs from the SDK with an instance of this error? If not, is it possible to get logs?
  2. Were you able to reproduce this error?
  3. When do you start seeing this error, and does it stop at some point or is it still on-going?

Thanks.

wu-hui avatar Jun 13 '25 23:06 wu-hui

Hey @wu-hui 1 & 2. Our users are facing this in production app and currently this amounts to highest number of crashes overall, we did not encounter this in debug environment though 3. The mentioned crash started surfacing from 21st March'25 and is still on-going

saurabh-iOS2 avatar Jun 16 '25 10:06 saurabh-iOS2

Hey @wu-hui , any luck with this issue ?

saurabh-iOS2 avatar Jun 24 '25 07:06 saurabh-iOS2

@wu-hui any update on this ? It would helpful for us to formulate next set of action items, if we can know the update. Thanks!

saurabh-iOS2 avatar Jun 30 '25 07:06 saurabh-iOS2

@wu-hui and @ncooke3 Is there a workaround we can employ in the meantime, perhaps a version of the pod that'll propagate the exception and we can avoid crashing the app?

anvith-porter avatar Jul 04 '25 07:07 anvith-porter

@wu-hui @ncooke3

Sharing a hypothesis—could you please review and confirm its validity?

guard let strongSelf = self, let currentUser = strongSelf._currentUser else { DispatchQueue.main.async { callback(nil, nil) } return } // Call back with current user token. currentUser .internalGetToken(forceRefresh: forceRefresh, backend: strongSelf.backend) { token, error in DispatchQueue.main.async { callback(token, error) } } In the above code block of Auth extension currentUser and backend is retained from a weakly retained self object. Could it be possible that either currentUser or backend got released when the async Task in below code block is getting executed, resulting in bad memory access (particularly when invoking internalGetTokenAsync) ?

func internalGetToken(forceRefresh: Bool = false, backend: AuthBackend, callback: @escaping (String?, Error?) -> Void) { Task { do { let token = try await internalGetTokenAsync(forceRefresh: forceRefresh, backend: backend) callback(token, nil) } catch { callback(nil, error) } } }

saurabh-iOS2 avatar Jul 04 '25 15:07 saurabh-iOS2

March'25 and is still on-going

May I ask is there any version upgrade before March'25?

cherylEnkidu avatar Jul 04 '25 16:07 cherylEnkidu

Yes, Firebase SDK was updated from 11.5.0 to 11.9.0

saurabh-iOS2 avatar Jul 04 '25 16:07 saurabh-iOS2

@saurabh-iOS2, thanks for the hypothesis. I don't think so for two reasons:

  • the method runs on a strong user instance
  • the stack trace shows that the completion handler is called, which means the try await internalGetTokenAsync(forceRefresh: forceRefresh, backend: backend) finished

I opened #15079, which makes a different hypothesis, that the intermediary DispatchQueue.main.async { callback(token, error) } } in your above code snippet is preventing a clear memory ownership boundary between ObjC runtime and the Swift Task where it is ultimately executed. The PR tries to simplify this relationship so a double release is avoided.

ncooke3 avatar Jul 04 '25 17:07 ncooke3

Thanks @ncooke3 , when can we expect this release?

saurabh-iOS2 avatar Jul 04 '25 17:07 saurabh-iOS2

@saurabh-iOS2 , the next release is tentatively scheduled for the week of July 14th. Please note that this next release will be Firebase 12.0.0.

ncooke3 avatar Jul 04 '25 18:07 ncooke3