---
name: sota-c-cpp
description: >-
  State-of-the-art C and C++ engineering rules (2026 baseline) that Claude
  applies when writing or auditing C/C++. Covers modern idioms (RAII, value
  semantics, smart pointers, C++23), memory safety (lifetimes, bounds,
  sanitizers, hardening flags), undefined behavior, security (SEI CERT C/C++,
  MISRA, integer/buffer/format-string, injection), concurrency (C/C++ memory
  model, atomics, data races), build/tooling/CI (CMake, clang-tidy, cppcheck,
  ASan/UBSan/TSan, vcpkg/Conan, supply chain), and performance. Trigger keywords
  - C, C++, cpp, RAII, smart pointer, unique_ptr, shared_ptr, undefined
  behavior, UB, buffer overflow, use-after-free, double-free, sanitizer, ASan,
  UBSan, TSan, valgrind, CMake, clang-tidy, clang-format, cppcheck, MISRA, CERT
  C, memory safety, std::thread, atomics, std::move. Use for BOTH building
  C/C++ libraries/systems and reviewing or auditing them.
---

# SOTA C & C++ (2026)

Expert-level rules for producing and auditing production C and C++. C and C++
are *memory-unsafe by default*: the compiler will not stop you from reading
freed memory, overrunning a buffer, or invoking undefined behavior (UB) that
the optimizer then weaponizes. These rules exist to claw back the safety the
language doesn't give you — through RAII, the type system, sanitizers, hardened
build flags, and disciplined review. Baseline: C++23 (ISO/IEC 14882:2024) and
C17/C23; flag where a control needs a newer toolchain. Every rule states the
*why*; every rules file ends with an audit checklist of grep/clang-tidy/
sanitizer patterns.

## Purpose

Two consumers, one source of truth:

- **BUILD mode** — generating new C/C++: follow the rules as defaults, not
  suggestions. Prefer C++ with RAII over raw C idioms unless the target is C.
  Deviate only with a comment justifying it.
- **AUDIT mode** — reviewing existing C/C++: hunt violations using the audit
  checklists, classify by severity, report in the finding format below. Memory-
  safety and UB findings are presumed exploitable until proven otherwise.

## BUILD mode

1. Before writing, read the rules files relevant to the task (see index). A
   parser handling untrusted bytes needs `02`, `03`, `04`; a threaded service
   needs `05`.
2. Apply the **top-10 non-negotiables** (below) unconditionally.
3. New projects: CMake (≥3.20) with `-Wall -Wextra -Wpedantic -Werror`, the
   [OpenSSF hardening flags](https://best.openssf.org/Compiler-Hardening-Guides/Compiler-Options-Hardening-Guide-for-C-and-C++.html)
   (`rules/04`), a debug build wired to ASan+UBSan, clang-tidy + clang-format
   configs, and CI running all of it from day one (`rules/06`).
4. Prefer the standard library and RAII types over hand-rolled
   allocation/ownership. Every `new`/`malloc`/`fopen`/`mutex.lock()` should be
   owned by a destructor (`unique_ptr`, container, `lock_guard`), not a manual
   matching call you can forget on an early return or exception.
5. Treat warnings as errors. A clean `-Wall -Wextra` build is the floor, not
   the goal — also run a static analyzer and the sanitizers (`rules/06`).
6. When you must use a sharp tool (raw pointer arithmetic, `reinterpret_cast`,
   `unsafe` C interop, manual lifetime), leave a `// NOTE(sota):` comment
   explaining the invariant you're upholding so auditors don't flag it blind.

## AUDIT mode

Work through each relevant rules file's audit checklist against the target.
Run the listed grep/clang-tidy/sanitizer commands; confirm each hit manually
(greps are recall-oriented). Where feasible, build with `-fsanitize=address,
undefined` and run the test suite — a sanitizer abort is ground truth.

### Severity conventions

| Severity | Meaning | Examples |
|---|---|---|
| **CRITICAL** | Exploitable memory corruption or guaranteed UB on reachable input | Heap/stack buffer overflow on attacker data, use-after-free, double-free, OOB write, format-string with user-controlled fmt, `system()` with interpolated input, data race on a pointer |
| **HIGH** | Likely corruption, crash, or security weakness | Unchecked `malloc`/`new` size from input, integer overflow feeding an allocation or index, missing bounds check, `strcpy`/`sprintf`/`gets`, TOCTOU on a path, missing RAII so a leak/UB occurs on the exception path |
| **MEDIUM** | Correctness/maintainability hazard, latent bug | Raw owning pointers, manual `new`/`delete` pairs, C-style casts, narrowing conversions, `memcpy` where a typed copy fits, missing `override`/`= delete`, signed/unsigned comparison |
| **LOW** | Idiom/perf debt, works but wrong shape | Pass-by-value of large objects, needless copies instead of `std::move`, `using namespace std` in headers, macros where `constexpr`/`inline` fits |
| **INFO** | Style/doc/hygiene | clang-format drift, naming, missing `[[nodiscard]]`, include hygiene |

### Finding format

```
[SEVERITY] file.cpp:LINE — short title
  Rule: rules/NN-name.md § section
  Evidence: the offending line(s), verbatim
  Impact: one sentence — what corrupts/leaks/races, under what input
  Fix: concrete replacement code or action
  Effort: trivial | small | medium | large
```

Group findings by severity, CRITICAL first. End with: counts per severity, the
three highest-leverage fixes, and which checklists/sanitizers were run.

## Rules index

| File | Read this when... |
|---|---|
| `rules/01-idioms.md` | Writing/reviewing any C++: RAII and the rule of zero/five, ownership with `unique_ptr`/`shared_ptr`, value semantics and move, `const`/`constexpr`, references vs pointers, casts, `enum class`, error handling (exceptions vs `std::expected` vs error codes), C-vs-C++ idiom choices |
| `rules/02-memory-safety.md` | Anything touching pointers, buffers, lifetimes, or allocation: bounds, use-after-free/return, dangling references and views (`string_view`/`span`), iterator invalidation, ownership discipline, sanitizers (ASan/MSan), `_FORTIFY_SOURCE`/`_GLIBCXX_ASSERTIONS` |
| `rules/03-undefined-behavior.md` | Reasoning about UB and the optimizer: integer overflow, strict aliasing, uninitialized reads, null/misaligned access, signed shifts, data races as UB, `unsigned` arithmetic, UBSan, why "it worked in debug" proves nothing |
| `rules/04-security.md` | Any input crossing a trust boundary: CERT C/C++ + MISRA, banned functions (`gets`/`strcpy`/`sprintf`/`system`), integer-overflow-to-allocation, format strings, path traversal/TOCTOU, command injection, deserialization/parsers, CSPRNG, the OpenSSF hardening flag set |
| `rules/05-concurrency.md` | Anything with threads, atomics, or shared state: the C++ memory model, data races, `std::atomic` and memory orders, `mutex`/`lock_guard`/`scoped_lock`, deadlock ordering, condition variables, `std::jthread`/stop tokens, TSan |
| `rules/06-build-tooling-ci.md` | Setting up or auditing builds/CI: CMake hygiene, warning flags, clang-tidy/clang-format, static analysis (clang-analyzer, cppcheck, Coverity), sanitizer CI matrix, fuzzing (libFuzzer/OSS-Fuzz), dependencies and supply chain (vcpkg/Conan, pinning, SBOM). **Test *strategy* lives in `sota-testing`; this file owns C/C++ build/test mechanics.** |
| `rules/07-performance.md` | Latency/throughput/memory work: profiling (perf, VTune, Callgrind), allocation reduction and custom allocators, move/copy elision, cache locality and data-oriented layout, `<algorithm>` over hand loops, LTO/PGO, micro-benchmarking pitfalls |

## Top-10 non-negotiables

1. **Every resource is owned by a destructor (RAII).** No `new`/`delete` or
   `malloc`/`free` pairs you have to match by hand; no bare owning pointers.
   Use `unique_ptr`, containers, `lock_guard`/`scoped_lock`, RAII wrappers.
   A leak or UB on the exception/early-return path is the default failure mode
   of manual cleanup. (`rules/01`, `rules/02`)
2. **No buffer touches memory it doesn't own.** Bounds-check every index/
   length derived from input; use `std::span`/`std::string`/containers and
   `.at()` or explicit checks, never raw pointer + length you assume. Overflow
   on attacker input is CRITICAL. (`rules/02`)
3. **No use-after-free / dangling.** A pointer, reference, iterator,
   `string_view`, or `span` must not outlive its storage. Never return a
   reference/view to a local or to a temporary. (`rules/02`)
4. **Undefined behavior is a bug even if it "works".** Signed integer
   overflow, strict-aliasing violations, uninitialized reads, OOB, data races
   are UB the optimizer may exploit. Build with UBSan; treat any UBSan
   diagnostic as CRITICAL/HIGH. (`rules/03`)
5. **Integers feeding an allocation, index, or `memcpy` size are
   overflow-checked and the right signedness.** Validate ranges before use;
   prefer unsigned for sizes, check for wrap. Overflow-to-undersize-alloc is a
   classic RCE primitive. (`rules/03`, `rules/04`)
6. **Banned functions are banned.** No `gets`, `strcpy`/`strcat`/`sprintf`
   (use bounded forms or `std::string`/`std::format`), no `system()` with
   interpolated input (use `posix_spawn`/`exec*` with an argv array). (`rules/04`)
7. **Build hardened, by default.** `-Wall -Wextra -Werror` plus the OpenSSF
   set (`-D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -fstack-protector-strong
   -fstack-clash-protection -fcf-protection -Wl,-z,relro,-z,now`). Missing
   hardening on a network-facing binary is a HIGH finding. (`rules/04`,
   `rules/06`)
8. **Shared mutable state is synchronized; data races are CRITICAL.** Guard
   with a `mutex`/`scoped_lock` or use `std::atomic` with a justified memory
   order. A `-fsanitize=thread` failure is not flaky noise. (`rules/05`)
9. **Sanitizers and a static analyzer gate CI.** A debug/test job runs
   ASan+UBSan (and TSan for threaded code); clang-tidy + cppcheck run on every
   PR. Untrusted-input parsers get a fuzz target. (`rules/06`)
10. **Prefer the type system to convention.** `enum class` over macros,
    `constexpr`/`inline` over `#define`, `gsl::span`/`std::span` over pointer+
    length, `[[nodiscard]]` on must-check returns, `explicit` on single-arg
    constructors, `override`/`final`. Make misuse fail to compile. (`rules/01`)
