Course contentsShow
← Rust
Lesson 247 of 1,9103. Borrowing and ReferencesFree lesson

Unsafe Blocks and Raw Pointers

Learn when to bypass borrow checker rules using raw pointers as a last resort.

In this lesson, you will learn how to bypass the borrow checker's strict rules using unsafe blocks and raw pointers as a last-resort tool.

The Borrow Checker’s "Hard Mode"

So far, you’ve learned that the Rust compiler is a strict gatekeeper. It enforces rules like "no multiple mutable references to the same data" to prevent data races and memory corruption. Usually, this is exactly what you want. However, sometimes you are writing low-level code—like building a custom data structure or interacting with hardware—where you need to perform an operation that the compiler cannot verify as safe.

Entering unsafe

When the compiler cannot prove your code is safe, you must explicitly opt into unsafe territory. An unsafe block acts as a promise to the compiler: "I know what I’m doing, and I’ve checked that this memory access won’t crash the program."

One of the most common things to do inside an unsafe block is to create a raw pointer.

Raw Pointers (*const T and *mut T)

Unlike regular references (&T or &mut T), raw pointers:

  1. Are allowed to be null.
  2. Are not required to point to valid memory.
  3. Don't follow the borrow checker's rules (you can have multiple mutable raw pointers to the same data).

Because raw pointers can easily lead to undefined behavior, dereferencing them is the part that requires an unsafe block:

let mut num = 10;

// Creating raw pointers is safe, but using them is not.
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;

unsafe {
    // We are now outside the borrow checker's jurisdiction.
    // We can read and write to the same memory location.
    println!("Value: {}", *r1);
    *r2 = 20; 
}

When to use this?

Think of unsafe like a high-voltage fuse box. You only open it when you absolutely must perform an operation the "safe" standard library tools can't handle. Because the compiler stops checking your work, you are solely responsible for ensuring no memory safety violations occur. If you misuse raw pointers, your program might behave unpredictably or crash.

Key Takeaway: unsafe blocks and raw pointers allow you to bypass the borrow checker to perform manual memory management, but they remove the compiler's safety guarantees, placing the full burden of memory safety on you.