Fix AppCheck concurrency infinite recursion bug in Auth - #16552
Conversation
Using Gemini Code AssistThe 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
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 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. |
…I and Functions, add copyright
|
/gemini review |
There was a problem hiding this comment.
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.
|
/gemini review |
There was a problem hiding this comment.
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.
Resolves #16549.
Description
This PR addresses an infinite recursion crash (yielding
EXC_BREAKPOINT/SIGTRAPinside_assertionFailure) that happens inFirebaseAuth,FirebaseAI, andFirebaseFunctionswhen bridgingAppCheckInteropinto 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
asynccounterpart for the Objective-C protocol methodgetToken(forcingRefresh:completion:), or when the return type of aTask/withCheckedContinuationgeneric contains the protocol existentialFIRAppCheckTokenResultInterop?, 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 localTaskor async state machine.The Fix
To completely avoid the compiler bug, we must prevent the existential protocol object from ever crossing an
async/awaitboundary.This PR updates the internal implementations across
FirebaseAuth,FirebaseAI, andFirebaseFunctionsto usewithCheckedContinuationwrapping the raw block-basedgetToken(forcingRefresh:completion:)selector. Inside the completion block, we extract the concrete native Swift types (tokenasStringanderrorasError?) and resume the continuation with a tuple(String, Error?)(or justString?).Since
StringandError?are native concreteSendabletypes, the async state machine is fully decoupled from the Objective-C protocol existential, bypassing the compiler's buggy thunk generation entirely.