C#-CWE-362¶
Race condition: unsynchronized access to shared resources can lead to incorrect behavior or security issues
Required inputs: CSharpAST
public class Counter
{
public int Value = 0;
public void Increment()
{
// Vulnerable: read-modify-write is not atomic
Value = Value + 1;
}
}
**Fix — use Interlocked (recommended):**
using System.Threading;
public class Counter
{
private int _value;
public void Increment()
{
Interlocked.Increment(ref _value); // atomic
}
}
---
**2) TOCTOU on filesystem (vulnerable)**
string path = @"C:\data\report.txt";
if (!File.Exists(path))
{
// Another thread/process could create the file here
File.Create(path).Dispose();
}
**Fix — use atomic API or try-create:**
try
{
using (var fs = new FileStream(path, FileMode.CreateNew, FileAccess.Write))
{
// created atomically or throws if exists
}
}
catch (IOException)
{
// handle existing file
}
---
**3) Enumerating and modifying a List concurrently (vulnerable)**
List items = new List();
void AddItem(int x) { items.Add(x); } // from multiple threads
void PrintAll()
{
foreach (var v in items) // may throw or see inconsistent state
Console.WriteLine(v);
}
**Fix — use concurrent collection or snapshot:**
using System.Collections.Concurrent;
ConcurrentBag items = new ConcurrentBag();
void AddItem(int x) { items.Add(x); }
void PrintAll()
{
foreach (var v in items) Console.WriteLine(v);
}
or
int[] snapshot;
lock (_sync) // same lock used by producers
{
snapshot = items.ToArray();
}
foreach (var v in snapshot) Console.WriteLine(v);
---
**4) Unsafe double-checked locking (vulnerable)**
public class Singleton
{
private static Singleton _instance;
public static Singleton Instance
{
get
{
if (_instance == null)
{
lock (typeof(Singleton))
{
if (_instance == null)
_instance = new Singleton(); // may be visible partially constructed
}
}
return _instance;
}
}
}
**Fix — use `Lazy
private static readonly Lazy _instance = new Lazy(() => new Singleton());
public static Singleton Instance => _instance.Value;
---
### Guidance for developers
- Prefer atomic primitives (`Interlocked`) and concurrent collections (`ConcurrentDictionary`, `ConcurrentQueue`, `ConcurrentBag`) for common concurrent patterns.
- Use `lock` for grouping multiple operations that must be atomic together.
- Use atomic file APIs (e.g., `FileMode.CreateNew`) instead of check-then-act on the filesystem.
- When designing APIs, prefer operations that perform checks and the action atomically (server-side), or document and protect the shared state.
This rule is intentionally conservative: it flags likely dangerous patterns for manual review rather than attempting to prove every race condition automatically.Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
race_check_then_act |
Check-then-act on shared state without synchronization detected: perform the check and action atomically. |
None |
False |
race_double_checked_locking |
Unsafe double-checked locking detected: use Lazy<T> or ensure proper volatile semantics and locking. |
None |
False |
race_enum_modify_collection |
Concurrent modification while enumerating a non-concurrent collection detected: use a concurrent collection, snapshot, or synchronization. |
None |
False |
race_non_atomic_increment |
Non-atomic update of shared numeric field detected: use Interlocked or lock. |
None |
False |
race_toctou_filesystem |
Time-of-check/time-of-use (TOCTOU) on filesystem detected: use atomic file APIs or perform operations under synchronization. |
None |
False |
Options
This rule shares the following common options: excludes, includes, justification_checker, post_processing, provider, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
This rule has no individual options.