Rust prevents double free and use of released memory with three ownership rules that the compiler checks: each value has one owner, there is only one owner at a time, and the value is dropped when the owner goes out of scope. Breaking a rule is a compile error, not a runtime crash.
The rules
From the Rust book:
- Each value in Rust has an owner.
- There can only be one owner at a time.
- When the owner goes out of scope, the value will be dropped.
Dropping means Rust calls the drop function at the closing brace, which returns heap memory to the allocator. You never write a free call.
How double free is blocked
The book's example assigns one string variable to another. A plain copy of the pointer, length and capacity would leave two variables pointing at the same heap memory, and both would try to free it when they leave scope. That is a double free.
Rust avoids it with a move. After the assignment the first variable is no longer valid, and only the second frees the memory.
fn main() {
let s1 = String::from("hello");
let s2 = s1;
println!("{s1}, world!"); // compile error: borrow of moved value
}
The compiler rejects the use of the moved value. In C the same pattern compiles and corrupts the heap at run time.
Copy versus clone
Simple types such as integers, booleans, characters and floats implement Copy, so the original stays valid. If you really want two independent heap copies, you call clone, which is explicit. Rust never makes automatic deep copies.
Borrowing in one paragraph
Moving is not the only way to use a value. You can lend it with a reference, and the compiler tracks how long the loan lasts. The Rust Reference describes the aliasing rules in terms of undefined behavior: a shared reference must not be mutated while it is live, and a mutable reference must not be accessed through other pointers while live. In safe code the compiler enforces these rules for you.
This is why use after free is so hard to write in safe Rust. A reference cannot outlive the value it points to, and a value cannot be freed while a reference to it is still in use. In C the programmer holds those facts in their head, and review has to catch the mistake.
Why this matters for migration
If your C code base has recurring double free and use after free bugs, the ownership model is the part of Rust that addresses them most directly. Spatial bugs are addressed by bounds checks on indexing, which safe Rust performs as well. Both are properties of safe Rust, not of the team using it.
What this does and does not give you
Safe Rust code gets these checks from the compiler for these rules. They cover a large share of temporal bugs. They do not remove:
- Logic errors, such as a wrong access control decision.
- Bugs in unsafe blocks, where the programmer upholds the rules, as the Rust Reference states.
- Bugs in C libraries called through FFI.
Reading the compiler errors
New Rust users often fight the borrow checker. A useful habit is to ask who owns the value at each line, and to pass references for temporary use. When the compiler complains, it is usually pointing at a real aliasing or lifetime mistake that would be a latent bug in C.
Quick check
Does Rust use a garbage collector to free memory?
No. Values are dropped deterministically when their owner goes out of scope, as described in the Rust book.
Sources
Last reviewed: 19 October 2026.