-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Fix UnfairLock deadlock #15556
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
Fix UnfairLock deadlock #15556
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 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 counter productive. 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. |
|
/gemini review |
There was a problem hiding this comment.
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 critical deadlock issue by replacing the non-recursive os_unfair_lock with NSRecursiveLock in the UnfairLock utility. The change is straightforward and effectively resolves the re-entrancy problem that was causing deadlocks. The investigation into all usages of UnfairLock to ensure this change is safe is commendable. The code is clean and the change is well-contained. I have one minor stylistic suggestion.
|
I don't think this PR will solve the problem. I revisited this issue last week before holidays and I think the proper solution needs to be more involved. Based on the stack trace in the issue.
I had a few ideas to experiment with like trying to see if the notification could be posted off the main thread. The proper solution seemed like moving from theses locks to an actor based approach which seems possible now that Sessions is iOS 13+. |
|
Closing based on Nick's comment. This will require more thought. |
Fix #15394
The os_unfair_lock is causing a deadlock due to its lack of recursion support. Fixed by replacing it with NSRecursiveLock in UnfairLock.swift. This involves updating the import, properties, and lock/unlock methods to use the new recursive lock, while keeping the public API unchanged.
The core of the problem, as indicated by the stack trace, is a deadlock occurring within FirebaseCoreInternal.UnfairLock. This UnfairLock is a low-level locking primitive used by various Firebase modules, including Firebase Sessions.
The stack trace clearly shows:
FirebaseSessions/Sources/Settings/RemoteSettings.swift).
The issue arises because os_unfair_lock (which UnfairLock was wrapping) is not recursive. If the main thread attempts to acquire this lock while it already holds it (due to nested calls or multiple observers being triggered by the same event, like app foregrounding), it will deadlock.
✦ That's a very important question. A recursive lock behaves differently from a non-recursive one, and it's crucial to ensure this change doesn't introduce unintended side effects.
I'll investigate all usages of UnfairLock in the codebase to determine if any of them rely on the non-recursive behavior. My plan is as follows:
I'll start by finding all occurrences of "UnfairLock". │
│ Found 42 matches │
✦ The search results show UnfairLock is used across several Firebase modules (Functions, AI, Sessions, Auth, Core) primarily for safeguarding mutable properties.
Here's my analysis of the usage patterns:
The original crash was caused by a deadlock when different parts of the Sessions module, both responding to foregrounding notifications, tried to acquire the same non-recursive lock.
Given these observations, changing to a recursive lock is a safe and correct fix. It solves the deadlock problem without creating new issues because the existing code doesn't rely on the non-recursive behavior. The recursive lock will simply continue to work for simple cases and prevent deadlocks in the more complex re-entrant scenarios that were causing your crash.