Lecture Note 4
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
let p = Box::new(42i32);
let x = &p;
drop(p);
*x; // error!
- Dangling pointer
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
// api.rs:109
pub struct LockGuard<'s, L: RawLock, T> {
lock: &'s Lock<L, T>,
// lifetime(lock) > lifetime(lockguard)
token: ManuallyDrop<L::Token>,
}