The case of the critical section that let multiple threads enter a block of code
Bug root cause: status vs boolean semantics
- Core issue: a lazy-init callback returned
STATUS_SUCCESS(numeric 0) to mean success, but theRtlRunOnceExecuteOnceframework expects non‑zero for success and 0 for failure. - As a result, the “run once” wrapper believed initialization failed and re‑ran it, reinitializing the critical section while in use and allowing multiple threads in.
- Commenters emphasize this is a mismatch of conventions, not a failure of the critical section primitive itself.
Error handling, loose typing, and stronger abstractions
- Several comments blame “loose typing” and overuse of
intfor error returns; the compiler can’t help distinguish incompatible success/failure conventions. - Suggestions:
- Component‑specific result types (e.g.,
struct FooResultwrapping an enum) to prevent casual mixing with plain integers. - Patterns like C++
std::error_code/ categories, effectively dynamic sum types with domain‑specific error spaces and equivalence rules.
- Component‑specific result types (e.g.,
- Some feel these patterns are overkill and that simpler enums plus better tooling would avoid most mistakes.
Windows synchronization primitives and SRWLock
- Confusion about why a critical section is used when a run‑once primitive already exists; clarification: they need “no more than one at a time,” not “only once ever,” and the callback itself must run exclusively.
- Discussion of SRWLock:
- Intended as a “simple reader‑writer lock” but often used as a plain mutex, making it feel overcomplicated.
- Noted bug: in certain unfair “lock stealing” paths, a request for a shared lock can end up with an exclusive lock, potentially causing deadlocks in specific patterns. This led some projects to avoid SRWLock.
- Some anecdotal claims that SRWLock can outperform
WaitOnAddressin mostly uncontended real workloads.
Windows vs Unix error conventions
- Windows is criticized for mixing conventions: some APIs use 0 for success (
NTSTATUS-style), others use non‑zero for success or return handles/NULL/INVALID_HANDLE_VALUE. - Unix is seen as more consistent (0 / non‑zero,
-1witherrno), but commenters note it too has pointer‑returning APIs and occasional inconsistencies. - Several suggest that such “0 vs non‑zero” ambiguities are an inherent legacy of C’s integer‑based booleans and pointer error signaling.
Coding style and Hungarian notation
- Many find Microsoft’s C/NT style hard to read: all‑caps types, pointer typedefs, dense formatting, and Hungarian notation.
- Others defend it as having its own “austere” regularity, especially with opaque handle types and consistent typedef usage.
- Distinction is drawn between:
- “Apps Hungarian” (kind‑based, e.g., row vs column vs character counts), argued to help make misuse visually obvious.
- “Systems Hungarian” (type‑based, e.g.,
pFoo,lBar), criticized as redundant in a typed language and widely regarded as noise.
- Some argue that modern IDEs and syntax highlighting make Hungarian largely obsolete.
Strong typing, Rust, and language choice
- One view: the specific bug could happen in any language if a developer confuses two status types; it’s a design/API-convention error.
- Counterpoint: languages with strong, distinct result/boolean types (including modern C with
_Bool, and especially Rust‑styleResult) make such confusion much harder, as the compiler would reject mixing incompatible success conventions. - A few comments generalize this into a broader preference for more expressive type systems over “social” naming conventions.
Broader sentiment about Microsoft code and APIs
- Several commenters express relief they don’t work on Windows code, describing it as verbose, inconsistent, and full of footguns.
- Others push back, noting the breadth and longevity of the Windows API surface and defending some design choices (e.g., C# aesthetics, NT coding guidelines).
- There is a recurring theme that massive historical accretion and multiple design lineages (NT kernel, Win32, subsystems) have left Windows with fragmented conventions that require deep institutional knowledge.