0%

The Rust Raw Pointer

In rust compiler ensures references are always valid. Unsafe Rust has a type called raw pointer that are similar to references. As with reference, raw pointers can be immutable or mutable and are written as *const T and * mut T

Different from references and smart pointers, raw pointers:

  • Are allowed to ignore the borrowing rules by having both immutable and mutable pointers or multiple mutable pointers to the same location
  • Aren’t guaranteed to point to valid memory
  • Are allowed to be null
  • Don’t implement any automatic cleanup

The code below show how to create an immutable and a mutable raw pointer from references.

1
2
3
let mut num = 10;
let r1 = &num as *const i32;
let r2 = &num as *mut i32;

Notice that we don’t include the unsafe keyword in this code. We can create raw pointers in safe code, but we just can’t dereference raw pointers outside an unsafe block.

Next we’ll create a raw pointer whose validity we can’t be so certain of. The code below show how to create a raw pointer to an arbitrary location in memory. Trying to use arbitrary memory is undefined: there might be data at that address or there might not, the compiler might optimize the code so there is no memory access, or the program might error with a segmentation fault. Usually, there is no good reason to write code like this, but it is possible.

1
2
let address = 0x012345usize;
let r = address as *const i32;

We can create raw pointers in safe code, but we can’t dereference raw pointers and read the data begin pointed to. The code below show we use the dereference operator * on a raw pointer that requires an unsafe block.

1
2
3
4
5
6
7
8
9
let mut num = 5;

let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;

unsafe {
println!("r1 is: {}", *r1);
println!("r2 is: {}", *r2);
}

With raw pointers, we can create a mutable pointer and an immutable pointer to the same location and change data through the mutable pointer, potentially creating a data race. Be careful!

With all of these dangers, why would you ever use raw pointers? One major use case is when interfacing with C code, for example calling an unsafe function or method. Another case is when building up safe abstractions that the borrow checker doesn’t understand.