python.race_condition
Correctness
High
Detects potential race conditions from concurrent access to shared state without proper synchronization.
Why It Matters
Section titled “Why It Matters”Race conditions cause:
- Intermittent bugs — Problems that appear and disappear randomly
- Data corruption — Concurrent writes can corrupt shared state
- Hard to reproduce — Issues only manifest under specific timing
- Production-only failures — Tests often pass due to lower load
Example
Section titled “Example”# ❌ Before (race condition risk)counter = 0
async def increment(): global counter temp = counter await asyncio.sleep(0) # Yield control counter = temp + 1 # Another task may have modified counter# ✅ After (with synchronization)import asyncio
counter = 0lock = asyncio.Lock()
async def increment(): global counter async with lock: counter += 1What Unfault Detects
Section titled “What Unfault Detects”- Global variables modified in async functions without locks
- Shared state accessed across coroutines without synchronization
- Check-then-act patterns in concurrent code
- Non-atomic read-modify-write operations
Auto-Fix
Section titled “Auto-Fix”Unfault generates patches that add appropriate synchronization:
import asynciofrom threading import Lock
# For async codeasync_lock = asyncio.Lock()
async def safe_update(): async with async_lock: # Protected code here pass
# For threaded codethread_lock = Lock()
def safe_update_threaded(): with thread_lock: # Protected code here passThread-Safe Alternatives
Section titled “Thread-Safe Alternatives”# Use thread-safe data structuresfrom collections import dequefrom queue import Queue
# Or use atomic operationsimport threadingcounter = threading.Counter() # Python 3.12+
# Or use contextvars for request-scoped stateimport contextvarsrequest_state = contextvars.ContextVar('request_state')