fix(state): acquireStateLock last-retry now re-acquires before proceeding (#3711)

This commit is contained in:
Tom Boucher
2026-05-18 17:55:06 -04:00
committed by GitHub
parent 3c2c56b9e8
commit 77b6bb62db
2 changed files with 17 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3705
---
Repair Windows-only TOCTOU regression in acquireStateLock — last-retry stale-lock recovery now re-acquires the lock atomically before proceeding, so concurrent state writes to different fields both persist (fixes main CI red on locking-bugs regression test).

View File

@@ -942,7 +942,18 @@ function acquireStateLock(statePath) {
} catch { /* lock was released between check — retry */ }
if (i === maxRetries - 1) {
try { fs.unlinkSync(lockPath); } catch {}
// Stale-lock recovery: delete the lock and do one final acquisition
// attempt. Returning lockPath without holding the lock (the previous
// behaviour) allowed two concurrent processes to both "acquire" a
// phantom lock, breaking mutual exclusion on Windows-24 where slower
// process spawn means concurrent writers overlap for longer (#3705).
try { fs.unlinkSync(lockPath); } catch { /* already gone — proceed */ }
try {
const fd = fs.openSync(lockPath, fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_WRONLY);
fs.writeSync(fd, String(process.pid));
fs.closeSync(fd);
_heldStateLocks.add(lockPath);
} catch { /* another process raced us — proceed without lock as last resort */ }
return lockPath;
}
const jitter = Math.floor(Math.random() * 50);