Unsafe

Dereferencing a Raw Pointer

Immutable raw pointer: *const T mutable raw pointer: *mut T

Reasons why raw pointers are unsafe

  • Ignore borrowing rules e.g. 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

Example


#![allow(unused)]
fn main() {
let mut num = 5;

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

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

Calling an Unsafe Function or Method


#![allow(unused)]
fn main() {
unsafe fn dangerous() {}

unsafe {
	dangerous();
}
}

Creating a safe abstraction on unsafe code

use core::slice;

fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
    let len = slice.len();
    let ptr = slice.as_mut_ptr();

    assert!(mid <= len);

    unsafe {
        (
            slice::from_raw_parts_mut(ptr, mid),
            slice::from_raw_parts_mut(ptr.add(mid), len - mid),
        )
    }
}

fn main() {
    let mut v = vec![1, 2, 3, 4, 5, 6];

    let r = &mut v[..];

    let (a, b) = split_at_mut(&mut v, 3);

    assert_eq!(a, &mut [1, 2, 3]);
    assert_eq!(b, &mut [4, 5, 6]);
}

Calling functions from other languages

Makes abs from C available

extern "C" {
    fn abs(input: i32) -> i32;
}

fn main() {
    unsafe {
        println!("Absolute value of -3 according to C: {}", abs(-3));
    }
}

Calling Rust function from another language

#[no_mangle]
pub extern "C" fn call_from_c() {
    println!("Just called a Rust function from C!");
}

Once compiled to library can be linked to from C

Static Variables (globals)

You can modify global state in unsafe Rust

static mut COUNTER: u32 = 0;

fn add_to_count(inc: u32) {
    unsafe {
        COUNTER += inc;
    }
}

fn main() {
    add_to_count(3);

    unsafe {
        println!("COUNTER: {}", COUNTER);
    }
}

Unsafe Traits

Must use unsafe keyword to implement an unsafe trait

unsafe trait Foo {
    // methods go here
}

unsafe impl Foo for i32 {
    // method implementations go here
}

fn main() {}

Unions

To access fields in a union is unsafe, as there is no guarantee what type it will be. Unions are generally only used for interacting with C code, they're like enums without the safety guarantees.

#[repr(C)]
union MyUnion {
    f1: u32,
    f2: f32,
}

fn main() {
    let mut u = MyUnion { f2: 1.5 };
    unsafe {
        let f = u.f2;
        println!("proper: {} wrong: {}", u.f2, u.f1);
        u.f1 = 10;
        println!("proper: {} wrong: {}", u.f1, u.f2);
    }
}