Type checking memory safety in Rust

Transferring ownership

let p = Box::new(42i32);
//case 1
let q = p; 
// p is moved to q;
// q will be reclaimed (freed) after the scoped defined 
//case 2
foo(p); 
// function call receives the ownership of p

Borrowed type

  • Immutable + Full sharing
let s1 = String::from("hello"); //ownership
let s2 = calculate_length(&s1);
println!("The length of `{}` is {}.", s1, len);

fn calculate_length(s: &String) -> usize {
  s.len() // why safe?: &String type ensures that s is immutable
}


// function signature
// pub fn len(&self) -> usize
// pub fn make_ascii_uppercase(&mut self) 

Ensuring pointer validity

  • Using after free ```rust let p = Box::new(42i32); let x = &p; drop(p);

*x; // error!


- Dangling pointer
```rust
fn dangle() -> &String {
  let f = String::from("");
  &f
} // freed when the scope ends; f is dropped

Mutably borrowed type

  • Mutable + sharing
    fn change(mut some_string: String) -> String {
      some_string.push_str(" ");
      some_string
    }
    // mutable borrow sanitizes this code
    fn change(mut some_string: &mut String) {
      some_string.push_str(" "); //ok
    }
    // function call
    let mut s: String = String::from("hello");
    change(&mut s);
    

    Alias(borrow) XOR Mutation

  • mutating object with immutable borrow is prohibited.
  • mutation is ok if there is only no borrows

What Rust prevents

g = lock();   //  --
p = &g.data;  //    | lifetime of g
              //    | : critical section
drop(g);      //  --
do_something(*p) // rust compiler rejects this code
  • Some more programming features
    • slices and structs
    • smart pointers
    • first-class functions
    • parallel programming
  • lifetime-wise: lock > lockguard > data inside ```rust // api.rs:109

pub struct LockGuard<’s, L: RawLock, T> { lock: &’s Lock<L, T>,
// lifetime(lock) > lifetime(lockguard) token: ManuallyDrop<L::Token>, } ```