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
*optis “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_ASSERTIONSand “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 bypush_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.