liveBook · Manning

Unsafe block

As explained in Refactoring to Rust

An unsafe block is a Rust block that permits operations requiring an unsafe context, with the programmer responsible for upholding their safety conditions.

An `unsafe` block permits a small set of operations that ordinary Rust code forbids. It does not switch off Rust’s safety rules: the programmer must uphold rules the compiler cannot check. This matters when Rust works with memory supplied by C, whose validity the Rust compiler cannot establish. section 3.1 section 3.0

Operations that require an unsafe context include:

  • Dereferencing a raw pointer or calling a function marked `unsafe`. section 3.1
  • Implementing an unsafe trait, mutating a static value, or accessing a union field. section 3.1

Raw pointers are a common reason to use a block. Getting a pointer with `Vec::as_ptr()` is safe; dereferencing it requires `unsafe`. Unlike a Rust reference, a raw pointer carries no lifetime or ownership information the compiler can use to verify that its address is valid. section 3.1.1

Listing 3.1 Reading the elements of a vector using pointer arithmetic
fn main() {
  let data: Vec<u8> = vec![5, 10, 15, 20];  #1

  read_u8_slice(data.as_ptr(), data.len()); #2
}

fn read_u8_slice(slice_p: *const u8, length: usize) {  #3
  for index in 0..length {
    unsafe {   #4
      println!("slice[{}] = {}", index,
        *slice_p.offset(index as isize));  #5
    }
  }
}

The vector example keeps pointer creation outside `unsafe` and places the pointer-arithmetic dereference inside it. section 3.1.1

Writing through a C output pointer

A Rust function called from C receives `solution: *mut c_int`. It first checks `solution.is_null()` and returns an error if it is null. The assignment `*solution = 1024` then goes inside `unsafe { ... }`, because it dereferences the pointer. The null check addresses one danger; it does not make every possible pointer valid. section 3.2.2

The same boundary arises when reading a C string: after checking the pointer for null, `CStr::from_ptr(line)` is called inside an `unsafe` block. The resulting C string can then be converted to a Rust string slice without copying the underlying string. section 3.2.2

How Refactoring to Rust covers it

How deep it goes
Defines the permitted operations and works through pointer dereferences, null checks, and C-string conversion; does not elaborate the other operations.
Examples
Uses vector pointer arithmetic, a C calculator’s output pointer, and conversion of its input C string.
What it assumes
Introduces raw pointers through a C memory example and a Rust vector, while recalling Rust’s rule that references must be valid.
What you can do after
Apply it via Rust’s `unsafe` blocks to dereference raw pointers and handle C-provided values while taking responsibility for validity.
How it connects
Connects raw pointers and reference validity to C FFI, dynamic libraries, and C strings.

Also explained in

Compare how 3 books explain unsafe block →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Refactoring to Rust. The section links point to the parts of the book it draws on.