Course contentsShow
← Rust
Lesson 94 of 1,9102. The Ownership ModelFree lesson

Preventing Double-Free Errors

Explain how the compiler enforces memory safety to avoid invalid pointer access.

In this lesson, you’ll learn how Rust’s ownership rules automatically prevent "double-free" errors, a common memory bug where a program tries to deallocate the same piece of heap memory twice.

What is a Double-Free?

In languages without automatic memory management, you are responsible for freeing the memory you allocate. If you accidentally call free() on the same memory address twice, the program becomes unstable, often leading to crashes or security vulnerabilities.

How Rust Stops It

Rust prevents this by ensuring that for every piece of data on the heap, there is exactly one owner. When that owner goes out of scope, Rust calls the destructor to clean up the memory. Because ownership is unique, it is impossible for two different variables to both believe they are responsible for freeing that memory.

Consider this example of what would be a double-free risk in other languages:

fn main() {
    let s1 = String::from("hello"); // s1 owns the memory
    let s2 = s1;                    // Ownership moves to s2
    
    // Rust has "moved" the data. 
    // s1 is no longer valid, so it won't be freed again.
    // When s2 goes out of scope at the end of main,
    // it will be freed exactly once.
}

If Rust allowed both s1 and s2 to "own" the data, both variables would attempt to run their destructors when they left the scope, resulting in two attempts to free the same heap memory. By using move semantics, the compiler invalidates the original variable (s1).

The compiler enforces this at compile time. If you tried to use s1 after it was moved to s2, the code would simply refuse to compile. This strict enforcement means that memory is always cleaned up exactly when the owner goes out of scope, never before, and never twice. You don't have to manually track who owns what; the compiler’s ownership model handles the cleanup logic for you, guaranteeing that the memory is freed safely every single time.

Key Takeaway: Rust prevents double-free errors by enforcing unique ownership; because only one variable can ever own a piece of data, the compiler ensures its destructor is called exactly once.