Race Condition
TL;DR
A race condition occurs when the outcome of a program depends on the relative timing of concurrent operations — two threads reading and writing shared state without coordination.
Explanation
Race conditions arise when multiple threads/processes access shared mutable state without synchronisation. Classic example: two threads both read a counter (value: 5), both increment locally, both write (both write 6 instead of 7). The TOCTOU (Time-Of-Check-To-Time-Of-Use) variant: check a condition then act on it, but state changes between check and act. In PHP: race conditions occur in file-based counters (read→increment→write without locks), cache stampede (multiple processes regenerating expired cache simultaneously), and database reads without transactions. Prevention: atomic operations, mutexes/locks, database transactions, optimistic locking.
Common Misconception
✗ Race conditions only happen in multi-threaded languages — PHP-FPM runs many processes concurrently, all sharing files, databases, and caches. Race conditions are very real in PHP.
Why It Matters
Race conditions cause intermittent data corruption that's extremely hard to reproduce and debug — they typically surface under load when multiple requests hit the same code path simultaneously.
Common Mistakes
- File-based counters without flock() — classic race condition.
- Cache aside pattern without stampede protection.
- Check-then-act on database records without SELECT FOR UPDATE.
- Assuming single-threaded PHP is race-condition-free.
Code Examples
✗ Vulnerable
// Race condition — read/increment/write without lock:
$count = (int)file_get_contents('counter.txt');
$count++;
file_put_contents('counter.txt', $count);
// Two simultaneous requests both read 5, both write 6
✓ Fixed
// File lock prevents race:
$fp = fopen('counter.txt', 'c+');
if (flock($fp, LOCK_EX)) {
$count = (int)stream_get_contents($fp);
$count++;
ftruncate($fp, 0); rewind($fp);
fwrite($fp, $count);
flock($fp, LOCK_UN);
}
fclose($fp);
// Better: use atomic DB increment:
$pdo->exec('UPDATE counters SET value = value + 1 WHERE id = 1');
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
23 Mar 2026
Views
32
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Perplexity 9
Amazonbot 7
Unknown AI 3
Ahrefs 2
Google 1
SEMrush 1
Also referenced
How they use it
crawler 22
pre-tracking 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟠 High
⚙ Fix effort: Medium
⚡ Quick Fix
Use flock() for file operations. Use DB atomic increments (UPDATE SET col = col + 1). Use SELECT FOR UPDATE for read-modify-write DB patterns. Use Redis INCR for counters.
📦 Applies To
web
cli
queue-worker
🔗 Prerequisites
🔍 Detection Hints
file_get_contents.*file_put_contents|read.*increment.*write
Auto-detectable:
✗ No
semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Low
False Positives: High
✗ Manual fix
Fix: High
Context: Function
Tests: Update
CWE-362
CWE-367