Carbon memory safety: a first deep dive (v3)
Carbon memory safety
A first deep dive
https://chandlerc.blog/slides/2026-memory-safety-deep-3/
Hello, I’m Josh Levenberg from the Carbon programming language team.
This is an early preview of Carbon’s memory safety model, that we have been hard at work on and is now ready for community feedback.
Presentation is going to focus mainly on the question “what is Carbon’s memory safety design”, with a little bit of comparison to Rust.
You can see a copy of these slides at that URL, with speaker notes available.
click
This is just the first chapter, not the full Carbon memory safety story:
There is more to the design than I will cover
I won’t be covering how we arrived at this design, other models we considered, and why we prefer this approach.
There won’t be much about implementing this design, we are coming to you early so we can incorporate your feedback while things are still flexible
I also would like to make clear that this is the result of a collaboration with multiple members of the Carbon team and community, not just me.
Goal of Carbon’s memory safety design
Smooth and incremental transition from C++ to memory safety in Carbon
Result needs to be memory safe
Expressivity to represent common C++ code patterns
Makes the transition smooth
Incremental in two ways
Migrate to Carbon a little at a time
Incrementally add safety once migrated
Clear goals lead to good designs.
These goals are different than other languages, like Rust.
The differences in the design of Carbon’s memory safety arise from the differences in goals.
There are three components of this goal
click Compiler-checked memory safety, either at compile-time or runtime
Two modes: permissive and strict
Permissive mode, along with C++ interop, supports incremental migration
Allows code that doesn’t yet have safety annotations
Strict Carbon is fully memory safe
The destination; goal is to migrate all code to strict mode
Strict Carbon is fully memory safe
Temporal: Preventing “use after free” (UAF) at compile time
Spatial: Runtime bounds checking as in ๐ฆ Rust and being added to C++
Type, initialization, null pointer, and data race safety
In this talk I’m only going to talk about the compile-time safety enforcement, with a focus on preventing use after free.
I will briefly touch on initialization safety and data race safety.
Expressivity
Non-exclusive mutable pointers
Directly proving existing correct C++ code is memory safe
Support for C++ features like inheritance and specialization
More expressive than Rust, but with a complexity and verbosity cost
Allows smooth migration of C++
Code patterns translate without cliffs, rearchitecting, or lots of unsafe
I want to be clear that when I compare Carbon to Rust and say it has greater expressivity, I’m not saying Rust has made a mistake in its safety model, or that we expect Carbon to be a replacement for Rust. Rust has a proven safety model that has been shown to work well across many classes of programs. Carbon aims to be complementary, targeting the specific use case of C++ migration, where gaining expressivity at a cost of more complexity and verbosity is a more worthwhile trade-off.
Temporal safety
Preventing use after free at compile time
Anatomy of a use after free (C++)
#include<br>#include
int main() {<br>`std::vector x { 1, 20, 300 }`;<br>`int* p = &x[0]`;<br>`x.push_back(4000)`;<br>printf("%d\n", `*p`); //
Allocation
Capture a pointer into allocation
Free or reallocation
Use of dangling pointer
This is a minimal example of use after free.<br>Every use after free has four steps. Click
To have a “free,” you need an allocation. Here, the C++ standard vector type allocates on the heap to store its elements.
To have a “use,” you need to capture an address into the allocation.
The “free” is any deallocation or reallocation that invalidates the captured address.
And finally we have the “use” after the free, dereferencing the dangling pointer p.
Anatomy of a use after free (Carbon)
import Core library "io";
fn Run() {<br>// ``buf(T)`` is Carbon's equivalent of C++'s<br>// ``std::vector`` or Rust's ``Vec``<br>`var x: buf(i32) = (1, 20, 300)`;<br>`var p: i32* = &x[0]`;<br>`x.PushBack(4000)`;<br>// โ Compiler error: use of ``p`` after it was<br>// invalidated by ``x.PushBack(4000)``.<br>Core.Print(`*p`);
Allocation
Capture a pointer into allocation
Free or reallocation
Prevents use of dangling pointer
In Carbon, the code looks similar, except for it uses Carbon’s buf type, which is its equivalent for C++’s vector or Rust’s vec.
The steps are the same, but the compiler gives an error.
No safety annotations in the calling code
import Core library "io";
fn Run() {<br>// ``buf(T)`` is Carbon's equivalent of C++'s<br>// ``std::vector`` or Rust's ``Vec``<br>var x: `buf`(i32) = (1, 20, 300);<br>`var p:...