Problem
nft_pclose() finds a PidList entry under ListMutex, releases the mutex, and continues using the shared pointer. A concurrent close can find the same entry, allowing duplicate close/wait/free operations and a use-after-free.
Fix
Atomically detach the entry while holding ListMutex, transferring exclusive ownership to the closing thread before cancellation is re-enabled. Cleanup then closes and frees only the caller-owned entry.
Acceptance criteria
- Exactly one concurrent closer owns a descriptor; another receives
EBADF.
- Cancellation after ownership transfer releases the descriptor and registry entry.
- Production-linked tests pass under AddressSanitizer and ThreadSanitizer.
- No changes to PHP Script Server handling.
Problem
nft_pclose()finds aPidListentry underListMutex, releases the mutex, and continues using the shared pointer. A concurrent close can find the same entry, allowing duplicate close/wait/free operations and a use-after-free.Fix
Atomically detach the entry while holding
ListMutex, transferring exclusive ownership to the closing thread before cancellation is re-enabled. Cleanup then closes and frees only the caller-owned entry.Acceptance criteria
EBADF.