梦兽编程
AI_SUITE

A 1000x Gap: How Google Used Rust to Push Memory-Safety Bugs Below 20% — and the Playbook You Can Copy

In 2025 Google disclosed that memory-safety vulnerabilities on Android fell below 20% for the first time, and Rust code carries roughly 1000x fewer memory-safety bugs per million lines than C/C++. This article breaks down why, shows a C/Rust use-after-free comparison, and gives an actionable checklist.

In November 2025, Google disclosed a set of numbers that silenced the entire security community:

  • Memory-safety vulnerabilities on Android dropped below 20% of all vulnerabilities for the first time — before the Rust migration, this class had long been the dominant majority.
  • Rust code carries about 0.2 memory-safety bugs per million lines versus roughly 1000 for C/C++ — a gap of about 1000x.
  • As a bonus: Rust changes had a rollback rate only one-quarter of C++’s, and code-review time was 25% shorter — the safer way to write code turned out to be the faster way too.

This isn’t marketing — it’s the conclusion of Android’s team cross-comparing 5 million lines of Rust against an equivalent volume of C++. This article breaks down why it holds, and what playbook you can copy.

Entire bug classes, eliminated at compile time

The headliners of memory-safety bugs — dangling pointers (use-after-free), double-free, buffer overflow, data races — are fundamentally “accessing memory you shouldn’t.” Rust’s ownership + borrow checking + lifetimes forbid these patterns at compile time:

  • Every piece of memory has either one mutable borrow or several immutable borrows at any instant, eliminating data races;
  • once a value is moved or freed, the old reference can’t be used, eliminating use-after-free;
  • slice/index access stays in bounds, leaving buffer overflow nowhere to hide.

C/C++ leave all of these checks to runtime and to your own discipline; Rust hands them to the compiler.

Hands-on comparison: use-after-free

The same “use after free” has completely different endings in C and Rust.

C version (undefined behavior, potentially exploitable):

char *buf = malloc(16);
free(buf);
// Undefined behavior: buf is freed but still used
strcpy(buf, "hello"); // may overwrite arbitrary memory, forming an exploit primitive

The compiler says nothing. The program might run fine, or it might turn into remote code execution after some unrelated update.

Rust version (rejected at compile time):

let mut buf = vec![0u8; 16];
drop(buf);
// buf.push(1); // ❌ compile error: borrow of moved value

Even without an explicit drop, the moment you pass buf’s reference out of a function or its lifetime conflicts, the borrow checker stops you at compile time. There is no “discovered at runtime” step.

Another classic C trap — returning a reference to a local buffer — fails to compile in Rust:

fn build() -> &'static [u8] {
    let data = [1u8, 2, 3];
    &data // ❌ compile error: returns reference to local variable
}

Real-world case: Rust can still break, but the defense is denser

Rust isn’t a silver bullet. Google found a linear buffer overflow in CrabbyAVIF — an AVIF image parser written in unsafe Rust — tracked as CVE-2025-48530, CVSS 8.1, theoretically enabling remote code execution.

But it was never exploited — because Android’s Scudo hardened allocator places guard pages around buffer regions, turning the overflow into an observable crash that was caught during testing. This “near-miss” teaches two things:

  1. unsafe blocks must still be held to safe-code standards — write // SAFETY: comments and run fuzz tests;
  2. language safety + allocator/sanitizer defense-in-depth beats relying on the language alone.

Google’s own words: unsafe Rust “is already really quite safe,” its bug density is still far below C/C++, and “unsafe” does not automatically switch off the language’s safety checks.

The playbook you can copy

  1. New code defaults to Rust: especially high-risk zones like parsers, network protocols, and system internals.
  2. Rewrite high-risk legacy components in Rust: image (PNG/AVIF), font, JSON, and compression parsers are CVE magnets. Chromium has already swapped its PNG, JSON, and web-font parsers for Rust implementations.
  3. unsafe must come with SAFETY comments + fuzzing: every unsafe block documents pointer origin, lifetime, and invariants; run cargo fuzz over it.
  4. Audit FFI boundaries separately: places that talk to C/C++ are where bugs cluster — enforce boundary checks and clean ownership transfer.
  5. Keep defense-in-depth: even with all-Rust, don’t drop Scudo / AddressSanitizer / fuzzing — they’re the last gate.

Security isn’t “switch languages and sleep easy,” but a 1000x density gap means this: moving high-risk code into Rust trades an entire bug class from “hope humans don’t err” to “the compiler won’t let them.” Google has already done the math for you.

Frequently Asked Questions

Does Rust have absolutely zero memory vulnerabilities?

No. Google found a linear buffer overflow written in unsafe Rust in CrabbyAVIF (CVE-2025-48530, CVSS 8.1). But Rust code's memory-safety bug density is about 0.2 per million lines versus roughly 1000 for C/C++ — about 1000x lower — and the vast majority of Rust bugs come from unsafe/FFI boundaries.

What about the legacy C/C++ code?

Two paths: write new code in Rust by default; rewrite high-risk existing components (image/font/JSON parsers) in Rust. Chromium has already replaced its PNG, JSON, and web-font parsers with memory-safe Rust implementations.

Does an unsafe block turn off Rust's safety checks?

No. unsafe only additionally permits 5 kinds of operations (dereferencing raw pointers, calling unsafe functions/FFI, mutating mutable statics, accessing union fields, implementing unsafe traits). Borrow checking and ownership rules still apply inside unsafe.

Where does the 1000x figure come from?

It's from Google's Android team internal statistics: Rust additions run about 0.2 memory-safety bugs per million lines versus roughly 1000 for historical C/C++ — a ratio of about 1000x. The data was disclosed by Jeff Vander Stoep in 2025.