Unsafe Functions

Calling Unsafe Functions

A function or method can be marked unsafe if it has extra preconditions you must uphold to avoid undefined behaviour:

  1. extern "C" {
  2.     fn abs(input: i32) -> i32;
  3. }
  4. fn main() {
  5.     let emojis = "🗻∈🌏";
  6.     // SAFETY: The indices are in the correct order, within the bounds of the
  7.     // string slice, and lie on UTF-8 sequence boundaries.
  8.     unsafe {
  9.         println!("emoji: {}", emojis.get_unchecked(0..4));
  10.         println!("emoji: {}", emojis.get_unchecked(4..7));
  11.         println!("emoji: {}", emojis.get_unchecked(7..11));
  12.     }
  13.     println!("char count: {}", count_chars(unsafe { emojis.get_unchecked(0..7) }));
  14.     // SAFETY: `abs` doesn't deal with pointers and doesn't have any safety
  15.     // requirements.
  16.     unsafe {
  17.         println!("Absolute value of -3 according to C: {}", abs(-3));
  18.     }
  19.     // Not upholding the UTF-8 encoding requirement breaks memory safety!
  20.     // println!("emoji: {}", unsafe { emojis.get_unchecked(0..3) });
  21.     // println!("char count: {}", count_chars(unsafe {
  22.     // emojis.get_unchecked(0..3) }));
  23. }
  24. fn count_chars(s: &str) -> usize {
  25.     s.chars().count()
  26. }

Writing Unsafe Functions

You can mark your own functions as unsafe if they require particular conditions to avoid undefined behaviour.

  1. /// Swaps the values pointed to by the given pointers.
  2. ///
  3. /// # Safety
  4. ///
  5. /// The pointers must be valid and properly aligned.
  6. unsafe fn swap(a: *mut u8, b: *mut u8) {
  7.     let temp = *a;
  8.     *a = *b;
  9.     *b = temp;
  10. }
  11. fn main() {
  12.     let mut a = 42;
  13.     let mut b = 66;
  14.     // SAFETY: ...
  15.     unsafe {
  16.         swap(&mut a, &mut b);
  17.     }
  18.     println!("a = {}, b = {}", a, b);
  19. }

This slide should take about 5 minutes.

Calling Unsafe Functions

get_unchecked, like most _unchecked functions, is unsafe, because it can create UB if the range is incorrect. abs is unsafe for a different reason: it is an external function (FFI). Calling external functions is usually only a problem when those functions do things with pointers which might violate Rust’s memory model, but in general any C function might have undefined behaviour under any arbitrary circumstances.

The "C" in this example is the ABI; other ABIs are available too.

Writing Unsafe Functions

We wouldn’t actually use pointers for a swap function - it can be done safely with references.

Note that unsafe code is allowed within an unsafe function without an unsafe block. We can prohibit this with #[deny(unsafe_op_in_unsafe_fn)]. Try adding it and see what happens. This will likely change in a future Rust edition.