Practical Security in Production: Hardening the C++ Standard Library at Massive Scale (2025)
Louis Dionne and Konstantin Varlamov (Apple, libc++ maintainers) with Alex Rebert and Max Shavrick (Google, memory safety). ACM Queue 23(5), 7 November 2025.
Tier: T3, and the reason belongs on the page. The design half — four hardening modes, ABI-tag per-translation-unit selection, trap-on-failure — is the maintainers describing their own artifact, which the ladder grades T1. The load-bearing half, and the reason this source is in the wiki, is how well it worked: 0.3% overhead, a 30% drop in segfaults, 1,000+ bugs. Those are the makers measuring their own product in their own fleet, which is what T3 describes. Nobody outside Apple and Google has checked any of them. Read alongside cpp-safety-profiles (T1, the standards paper) — this is the deployment evidence that paper's approach is standing on.
What shipped, and why it is a library change rather than a language one
The argument starts from C++'s vocabulary types being unsafe by default — the paper takes
std::optional used beyond its contract as the example, and notes that "if you look at how this
compares with modern languages, you can see that C++ is the outlier."
The move is to make the library enforce its own preconditions in production rather than in a debug
build. The authors are blunt about why debug modes failed: they were understood as bug-finding tools,
so performance was never a design constraint, which made "infeasible in release mode" a
self-fulfilling prophecy. Four modes ship in libc++ from LLVM 18, each a superset of the last:
none → fast → extensive → debug. fast is almost entirely bounds checking — "It is a very
lucky coincidence that some of the most valuable checks also happen to be some of the cheapest."
Two decisions here are engineering rather than policy, and both are why partial adoption works. Hardening is
orthogonal to the ABI, because tying safety to an ABI break makes it unusable on a platform an
application does not control. And the mode is encoded in Itanium ABI tags, so one translation unit
can call vector::operator[] hardened while another calls it unhardened without violating the ODR —
which is what makes partial adoption possible at all.
The deployment numbers (self-reported)
Rolled out across hundreds of millions of lines of C++ at Google, in three phases: fix the tests (the first attempt broke more than 1,000), pilot in production, then default-on fleetwide.
- Average production performance overhead: 0.3%. Attributed to cheap checks, LLVM optimising them away, and PGO moving them off hot paths. Binary size overhead was cut from ~2% to under 0.5% by a non-verbose mode.
- More than 1,000 bugs found and fixed during the rollout, some over a decade old; a projected 1,000–2,000 prevented per year.
- Segfault rate across the production fleet dropped by roughly 30% — with an initial rise in crashes from hardening checks, which is the mechanism working as predicted rather than against it.
- Of hundreds of millions of lines, five services opted out entirely, and the fine-grained unsafe-access API was used in seven distinct places.
The stability argument underneath is a claim about what a crash means: "A crash from a detected memory-safety bug is not a new failure. It is the early, safe, and high-fidelity detection of a failure that was already present."
Where it lands in the standard
P3471 — Apple's proposal, based on this implementation — standardises a subset of fast mode as a
hardened implementation a program may select, and it was voted into C++26. The textual move is
smaller than it sounds: the checks were already in the standard as preconditions, and hardening turns
violating them from undefined behaviour into defined behaviour. It leans on C++26 Contracts for
how a violation is handled. Modes beyond fast are not proposed for standardisation, and no check
that would change the ABI is planned.
So the safety story that actually shipped in C++26 is this one, not profiles.
What the spoke should do with it
It is the first deployment evidence in this wiki for any safety claim. rust's guarantee, spark's proofs and elixir's isolation are all argued from design; this is a measured rollout with a cost figure, an opt-out count and a reliability delta. That is a different kind of claim, and growth edge 1 has been asking for exactly it.
It also cuts against the strongest version of the rewrite argument — 30% fewer segfaults for 0.3% and a recompile is a large fraction of a memory-safety benefit at a small fraction of a migration. It does not touch temporal safety (use-after-free), which is the class rust's borrow checker is actually about, and the paper does not claim it does.
Unreplicated, and by interested parties. The people reporting the overhead maintain the library and led the rollout. No independent measurement of hardened-libc++ overhead exists in this corpus — written up as growth edge 12.
Related
cpp · cpp-safety-profiles · wg21-croydon-2026 · rust · memory-management-model · type-system · c