Hardening the C++ Standard Library at scale

Undefined behavior and security relevance

  • Some argue any C++ undefined behavior (UB) is inherently security‑critical because the compiler may do arbitrarily bad things.
  • Others distinguish UB that leaks or corrupts security‑relevant data from UB that just crashes or misbehaves in low‑impact contexts.
  • Counterpoint: in practice nobody knows which code will become security‑critical later, and libraries/OSes can’t assume “non‑critical” use.

Safety‑critical vs security‑critical

  • Thread distinguishes safety‑critical (people might die) from security‑critical (data/infra compromise).
  • Formal‑verification practitioners emphasize goal is “fail safely,” not “no UB,” but others note that in practice safety standards and toolchains require eliminating UB to define executable semantics.
  • Debate on whether safety‑critical systems are truly isolated; several commenters note networked, even pingable, safety‑critical systems.

Fail‑stop hardening vs “debug mode”

  • Article’s position: turning latent memory bugs into crashes is surfacing existing failures early.
  • Critics: many such bugs might never manifest; converting them into crashes can hurt reliability/user experience.
  • Some advocate classic “debug modes” with extra checks instead of shipping hardened builds; others note as‑shipped hardening has low measured overhead and catches real issues in production.

std::optional and idiomatic UB

  • Example: std::optional<int> x(std::nullopt); int v = *x; is UB and not caught by the type system.
  • Disagreement whether *opt is “idiomatic”; empirical comments say dereference without .value() is common in real code and even required on some older platforms.
  • Some claim static analysis and reviews would always forbid unchecked deref; others respond that human review and static analyzers are fallible and often permissive.

C++ hardening, contracts, and C++26

  • Hardening in libc++/libstdc++ is largely macro/config‑based and can coexist with old code, similar in spirit to _GLIBCXX_ASSERTIONS and “lite assertions.”
  • C++26 contracts and hardening profiles are contentious: mixed “evaluation semantics” across translation units can weaken guarantees; there’s concern about giving only an illusion of safety.
  • Follow‑up papers adjust the design (e.g., forbidding “observe” semantics for hardened preconditions, adding non‑ignorable contracts), but details remain complex.

C++ vs Rust and other safer languages

  • Some see these checks as narrowing the gap with Rust, Go, Zig: more memory bugs get caught with small overhead.
  • Others argue you can’t retrofit Rust‑style compile‑time guarantees into existing C++ without breaking vast code; runtime checks and sanitizers still miss many classes of bugs or are too expensive if always on.
  • Safe‑C++ proposals and lifetime analysis are mentioned as promising but immature or politically stalled.

Iterator invalidation and hardening limits

  • Example with std::vector::front() reference invalidated by push_back() illustrates bugs hardening can’t catch: dangling references after reallocation.
  • Sanitizers (ASan/UBSan) can catch such errors when the invalid reference is actually used, but not purely by library‑level precondition checks.
  • Commenters note iterator invalidation is a major real‑world source of memory bugs even in “modern” C++ using smart pointers.