Skip to content

Fix AppCheck concurrency infinite recursion bug in Auth - #16552

Open
paulb777 wants to merge 5 commits into
mainfrom
fix-appcheck-crash-16549
Open

Fix AppCheck concurrency infinite recursion bug in Auth#16552
paulb777 wants to merge 5 commits into
mainfrom
fix-appcheck-crash-16549

Conversation

@paulb777

@paulb777 paulb777 commented Aug 24, 2026

Copy link
Copy Markdown
Member

Resolves #16549.

Description

This PR addresses an infinite recursion crash (yielding EXC_BREAKPOINT / SIGTRAP inside _assertionFailure) that happens in FirebaseAuth, FirebaseAI, and FirebaseFunctions when bridging AppCheckInterop into Swift concurrency.

The root cause of the crash is a known bug in Swift concurrency (particularly manifesting on older deployments or in some toolchains, like the Flutter iOS build environment) regarding generic reabstraction thunks.
When the compiler attempts to automatically synthesize the async counterpart for the Objective-C protocol method getToken(forcingRefresh:completion:), or when the return type of a Task / withCheckedContinuation generic contains the protocol existential FIRAppCheckTokenResultInterop?, it produces a faulty reabstraction thunk (partial apply forwarder for generic not re-abstracted specialization <__C.FIRAppCheckTokenResultInterop?>...). This thunk infinitely loops on itself when the continuation resumes.

Because the old code invoked the auto-bridged await appCheck.getToken(forcingRefresh:) directly, this buggy generic thunk was inevitably linked into the local Task or async state machine.

The Fix

To completely avoid the compiler bug, we must prevent the existential protocol object from ever crossing an async/await boundary.

This PR updates the internal implementations across FirebaseAuth, FirebaseAI, and FirebaseFunctions to use withCheckedContinuation wrapping the raw block-based getToken(forcingRefresh:completion:) selector. Inside the completion block, we extract the concrete native Swift types (token as String and error as Error?) and resume the continuation with a tuple (String, Error?) (or just String?).

Since String and Error? are native concrete Sendable types, the async state machine is fully decoupled from the Objective-C protocol existential, bypassing the compiler's buggy thunk generation entirely.

@gemini-code-assist

Copy link
Copy Markdown
Contributor
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

@paulb777

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses a persistent crash when interacting with App Check under certain Swift toolchains (such as the Flutter SDK) by avoiding a compiler bug in Swift concurrency thunk generation. The changes replace direct async calls to getToken with manual bridging using withCheckedContinuation and callback-based methods, returning a tuple (token: String, error: Error?) instead of FIRAppCheckTokenResultInterop. Feedback suggests simplifying the tuple construction in AppCheckInterop+FirebaseAuth.swift by directly passing the properties of result to continuation.resume(returning:) without intermediate local variables.

Comment thread FirebaseAuth/Sources/Swift/Auth/AppCheckInterop+FirebaseAuth.swift Outdated
@paulb777

Copy link
Copy Markdown
Member Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses a persistent crash when interacting with App Check under certain Swift toolchains (such as the Flutter SDK) caused by a compiler bug in Swift concurrency thunk generation. It achieves this by replacing direct calls to the async getToken method with a manual wrapper using withCheckedContinuation over the closure-based getToken method, returning a tuple (token: String, error: Error?) instead of FIRAppCheckTokenResultInterop. These updates are applied across FirebaseAI, FirebaseAuth, and FirebaseFunctions. There are no review comments to address.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PhoneAuthProvider/AppCheckInterop crash still reproduces on 12.18.0 despite #16453 (not iOS-26-specific)

2 participants