Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Project Zero

Metadata
Short titleProject Zero
What and whyFix all known type system unsoundnesses so Rust’s safety guarantees are actually reliable
Point of contactlcnr
Task ownersBoxy, @Nadrieril, lcnr, Niko Matsakis

Summary

Fix every known type system soundness bug in Rust, so that unsafe is the only way to cause undefined behavior.

Motivation

The status quo

Rust’s reputation for reliability rests on its safety promise, that users who write “safe Rust” code (to a first approximation, Rust that does not contain the unsafe keyword) cannot violate memory safety or trigger undefined behavior. The US government strongly encourages the use of memory safe languages like Rust, going so far as to call the use of memory unsafe languages a “threat to national security”.

Despite its innocuous sounding name, bugs that trigger “undefined behavior” are among the worst kind of bugs, as they indicate a program that could do anything. Exploits based on undefined behavior typically give attackers complete control of the target machine, unlike other forms of vulnerabilities that frequently have more limited exposure. Many of the most infamous exploits in recent times, such as Heartbleed and Stuxnet, were caused by memory safety errors, and studies at Microsoft and elsewhere have found that fully 70% of vulnerabilities are triggered by memory safety errors.

Over the last few years, a number of known soundness bugs have been found in Rust’s type system. These bugs are obscure and have rarely if ever affected production systems, but if they are not fixed, one of them is likely to be the basis for a Rust exploit. This is frightening both because it could mean exposed systems (never good) but it would also do damage to Rust’s reputation as a secure language.

Design axioms

  • Zero means zero. Not “fewer bugs” or “the important ones.” The goal is to fix every known soundness issue, however obscure.

  • Migrate, don’t break. Breakage is acceptable to prevent unsound behavior but care should be taken to minimize the practical impact on users. Phasing in breaking changes gradually through future-compatibility warnings is preferred, particularly in cases where many crates affected.

What we are shooting for

Our goal is simple: If you stick to safe Rust, you don’t have to worry about memory unsafety. End of story.

How we get there

GoalTimespanWhat and why
Assumptions on Binders2026Attempt to implement a version of -Zhigher-ranked-assumptions which works for all binders, not just witness types of futures.
Dictionary Passing Style Experiment2026Experiment with converting where-clauses to use dictionary passing style, avoiding many implementation bugs by construction
Stabilize the next-generation trait solver2026Replace the existing trait solver with a sound, maintainable implementation that unblocks soundness fixes and async features
Fix self-contained bugs and issues2026 - FutureThere are a few minor unsoundnesses which don’t interact with the rest of the type system. Fixing these can happen in parallel to other work
Remove higher-ranked subtyping and replace it with coercions2026Subtyping can currently impact trait selection, breaking library abstractions such as Pin
Fix overlap between builtin and user-written impls for trait objectsFutureWork on a design for dyn-trait which avoids an existing unsoundness due to overlapping impls
Support emitting FCW for borrowck errors2026Support rerunning borrowck in case of errors, weakening the failure to future-compatability warnings to give users the time to fix their crates
Check where-bounds when instantiating bindersFutureChecking where bounds when instantiating binders fixes most of our unsoundnesses around implied bounds. Blocked on supporting assumptions on binders

Open soundness bugs remain open because naive fixes to them would also cause a number of safe Rust code patterns to break. Fixing these bugs in a way that ensures valid code continues to work requires extending Rust’s type system implementation with new capabilities.

Step 1: Stabilize the next-generation trait solver. For the last few years the Rust types team has been developing a next-generation trait solver that will lift a number of limitations in the current trait system. This new trait solver started being used for coherence checking in Rust 1.84. In 2026 we plan to stabilize it for use across all of Rust. This step is needed to unblock virtually all of the following steps.

Step 2: Fix self-contained issues and simplify implementation. A number of soundness bugs can be fixed independently, without waiting for larger infrastructure changes. These range from straightforward fixes (closure return value checking, orphan check projection handling) to more involved work (replacing higher-ranked subtyping with coercions, fixing Pin::new soundness). Each fix ships with future-compatibility warnings first.

Step 3: Land support for where-bounds on binders. A cluster of soundness bugs — implied bounds on nested references, normalization skipping well-formedness checks, and several related issues — are blocked on the new solver and on support for higher-ranked assumptions. This work also requires the ability to emit future-compatibility warnings from the borrow checker.

Step 4: Formalize trait system semantics. To prevent future soundness bugs, we need a formal specification of what the trait solver should do. This catches bugs before they ship and provides a reference for correctness as the type system evolves.

Frequently asked questions

Will these fixes break my code?

They might, but only if your code was relying on unsound behavior and you’ll get advance warning in that case. Soundness fixes causing non-trivial breakage land with future-compatibility warnings first, giving crate authors time to update before the old behavior is removed.

How many soundness bugs are there?

The tracking board lists the known issues. Some are self-contained and can be fixed independently; others are blocked on the next-generation trait solver or require design work on where-bounds and binder semantics.