Skip to the content.

Safety Guarantees

A foundational goal of Rust is to ensure that your programs never have undefined behavior. That is the meaning of “safety”: Safety is the Absence of Undefined Behavior. Examples:

  1. to access invalid memory (e.g., when it’s been deallocated)
  2. to deallocate a memory that already has been “freed”

For such “safety”, Rust comes with the following concepts:

Cases of Compiling Errors

Learning how to fix an ownership error is a core Rust skill. When the borrow checker rejects your code, how should you respond?

click -> Cases for fixing these errors

Ownership

Ownership enables Rust to make memory safety guarantees without needing a garbage collector.

let a = Box::new([0; 1_000_000]);
let b = a;

When a is bound to Box::new([0; 1_000_000]), we say that a owns the box. The statement let b = a moves ownership of the box from a to b. Given these concepts, Rust’s policy for freeing boxes is more accurately described as:

Box deallocation principle : If a variable owns a box, when Rust deallocates the variable’s frame then Rust deallocates the box’s heap memory.

Moved heap data principle : if a variable x moves ownership of heap data to another variable y, then x cannot be used after the move.

Reference and Borrowing

References provide the ability to read and write data without consuming ownership of it. References are created with borrows (& and &mut) and used with dereferences (*), often implicitly. To avoid undefined behavior, Rust’s policy for pointers:

Pointer Safety Principle : data should never be aliased and mutated at the same time.

References can be easily misused. Rust’s borrow checker enforces a system of Permissions that ensures references are used safely:

As a part of the Pointer Safety Principle, the borrow checker enforces that data must outlive any references to it. Rust enforces this property in two ways.

case 1 : Rust knows how long a reference lives - references within a function body

fn main() {
    let s = String::from("Hello world");
    let s_ref = &s;
    drop(s);
    println!("{}", s_ref);
}

Rust knows how long s_ref lives. The Borrow Checker Finds Permission Violations

case 2 : Rust doesn’t know how long a reference lives - input/output references

Rust provides a mechanism called lifetime parameters for such case.

In fact, case 1 also has lifetimes which are inferred by Rust compiler. And in case 2, we need to annotate lifetimes manually to help with the compiler.