-
Notifications
You must be signed in to change notification settings - Fork 301
Open
Labels
bugSomething is not working, or not working as intendedSomething is not working, or not working as intended
Description
Problem
FallbackUseLock.incrementUserCount() in NdbUseLock.swift acquires ndbUserCountLock, then blocks on ndbAccessSemaphore.wait(). If another thread holds the semaphore and needs the lock, deadlock occurs.
Location
nostrdb/NdbUseLock.swift lines 148-156
private func incrementUserCount(maxTimeout: DispatchTimeInterval = .seconds(2)) throws {
ndbUserCountLock.lock()
defer { ndbUserCountLock.unlock() }
// Signal that ndb cannot close while we have at least one user using ndb
if ndbUserCount == 0 {
try ndbAccessSemaphore.waitOrThrow(timeout: .now() + maxTimeout) // BLOCKS WHILE HOLDING LOCK
}
ndbUserCount += 1
}Root Cause
Classic lock ordering violation: Thread A holds lock, waits for semaphore. Thread B holds semaphore, needs lock. Deadlock.
Impact
- App freeze on iOS < 18 (FallbackUseLock is used)
- Timeout after 2 seconds but thread is blocked during that time
Suggested Fix
Release lock before waiting on semaphore, or refactor to avoid nested blocking primitives.
Related Issues
- Ndb ingester queue
pthread_mutex_lockcrash related to switching in/out of the app #2472 (Ndb ingester pthread_mutex_lock crash) - Ndbtxn transactions shouldn't be held open across async boundaries #3335 (NdbTxn async boundaries)
Test Plan
- Add concurrent access test with ThreadSanitizer
- Test database close during active reads
- Verify no deadlock under contention
Changelog-Fixed: Fix potential deadlock in FallbackUseLock
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething is not working, or not working as intendedSomething is not working, or not working as intended