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 the RtlRunOnceExecuteOnce framework 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 int for error returns; the compiler can’t help distinguish incompatible success/failure conventions.
  • Suggestions:
    • Component‑specific result types (e.g., struct FooResult wrapping 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.
  • 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 WaitOnAddress in 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, -1 with errno), 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‑style Result) 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.