What a C++ team can actually point at when asked about memory safety
The memory-safety question has changed shape. It used to arrive in conference talks and blog arguments, where the answer could be a position. Now it arrives in vendor security questionnaires and supplier assessments, where the answer has to be a list of things you actually do.
In short
- Switch on the hardened standard library in production. Google measured the cost at roughly 0.3%.
- Run the sanitizers on every pull request, not only on a laptop.
- Turn the buffer warnings into errors. Chrome reached 97% compliance that way.
- Use types that make the bug unrepresentable.
- Do not claim profiles, contracts or “the compiler catches it”.
Why no standard feature answers it
C++26 did not settle it. The profiles work is still moving. Contracts are being argued about rather than deployed. Neither is in a compiler you can ship against this quarter. So the honest answer to “what is your memory-safety story” is not a standard feature. It is a set of things that already work.
What you can point at today
A hardened standard library, switched on in production. Both libc++ and libstdc++ ship modes that trap on out-of-range container access and similar precondition violations. Without the mode, those violations are undefined behaviour. People assume the cost is prohibitive. It is not: Google measured roughly 0.3% across its fleet. You can put that number in a questionnaire, and it covers a large share of the bug class being asked about.
Sanitizers in CI, not just on a developer’s laptop. AddressSanitizer, UndefinedBehaviorSanitizer and ThreadSanitizer find the bugs the type system does not. They are too slow for most production builds, yet affordable on a test suite. “We run ASan and UBSan on every pull request” is a concrete control; “we are careful” is not.
Warnings promoted to errors, including the ones about buffers. Clang’s -Wunsafe-buffer-usage warning drives Chrome’s spanification work. That work reached 97% compliance while fixing over a thousand security bugs. Whatever you think of the migration cost, it is a measurable programme with a number attached.
Types that make the bug unrepresentable. Use std::span instead of a pointer and a length. Use std::string_view where lifetimes allow. Use C++26’s std::indirect for the PImpl case. None of this is new, and all of it removes a category of bug rather than checking for it.
What not to claim
Do not claim profiles. They are not in a shipping compiler, and the framework paper is still being revised. Asserting otherwise in a security document surfaces badly later.
Do not claim contracts as a safety feature. They are in the C++26 draft and GCC implements them. A group including Stroustrup argues they should be removed before the final ballot, partly because they do not deliver safety guarantees. Whatever the outcome, “we use C++26 contracts” is not an answer to a memory-safety question today.
Do not claim the compiler catches it. The float-to-int conversion case shows why. The undefined behaviour sits in code that looks obviously fine, and no warning fires. Only a sanitizer flag catches it, and GCC leaves that flag out of -fsanitize=undefined.
The shape of an honest answer
An honest answer has five parts:
- an inventory of where memory-unsafe patterns live
- a hardened build for the parts that ship
- sanitizers gating the test suite
- warnings-as-errors on new code
- a migration plan for the highest-risk components
Everything in that list exists now. None of it depends on the standard settling its argument.
The reason to write it down is not compliance theatre. The alternative answer is that C++ is memory-unsafe and always will be. That is the answer being written down for you.
Sources: hardened stdlib overhead measurement · Chrome’s spanification report · NSA and CISA, “The Case for Memory Safe Roadmaps” · CISA guidance on memory-unsafe languages in critical infrastructure.