Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

Guaranteeing Memory Safety in Rust

4.249 Aufrufe

Veröffentlicht am

An overview of how Rust guarantees memory safety.

Veröffentlicht in: Software

Guaranteeing Memory Safety in Rust

  1. 1. Rust Nicholas Matsakis Mozilla Research
  2. 2. What makes Rust different? C++ Haskell Java ML More Control More Safety Rust: Control and safety
  3. 3. Why Mozilla? Browsers need control. Browsers need safety. Servo: Next-generation browser built in Rust.
  4. 4. What is control? void example() { vector<string> vector; … auto& elem = vector[0]; … } Stack and inline layout. Lightweight references Deterministic destruction [0] string el…em vector data length capacity […] [n] … ‘H’ ‘e’ … Stack Heap C++
  5. 5. Zero-cost abstraction Ability to define abstractions that optimize away to nothing. vector data length cap. [0] […] data cap. ‘H’ ‘e’ […] Not just memory layout: - Static dispatch - Template expansion - … Java
  6. 6. What is safety? void example() { vector<string> vector; … auto& elem = vector[0]; vector.push_back(some_string); cout << elem; } vector data length capacity [0] … [0] [1] elem Aliasing: more than one pointer to same memory. Dangling pointer: pointer to freed memory. C++ Mutating the vector freed old contents.
  7. 7. What about GC? No control. Requires a runtime. Insufficient to prevent related problems: iterator invalidation, data races.
  8. 8. void foo(Foo &&f, …) { vec.push_back(f); } C++ Gut it: void foo(const Foo &f, …) { use(f.bar); } Read it: void foo(Foo &f, …) { f.bar = …; } Write it: void foo(unique_ptr<Foo> f, …) { … } Keep it:
  9. 9. Definitely progress. ! But definitely not safe: ! - Iterator invalidation. - Double moves. - Pointers into stack or freed memory. - Data races. - … all that stuff I talked about before … ! Ultimately, C++ mechanisms are unenforced.
  10. 10. The Rust Solution Codify and enforce safe patterns using the type system: ! 1. Always have a clear owner. 2. While iterating over a vector, don’t change it. 3. … ! No runtime required.
  11. 11. Credit where it is due Rust borrows liberally from other great languages: C++, Haskell, ML/Ocaml, Cyclone, Erlang, Java, C#, … Rust has an active, amazing community. ❤
  12. 12. The Rust type system
  13. 13. Observation Danger arises from… Aliasing Mutation Hides dependencies. Causes memory to be freed. { auto& e = v[0]; … v.push_back(…); }
  14. 14. Three basic patterns fn foo(v: T) { … } Ownership fn foo(v: &T) { … } Shared borrow fn foo(v: &mut T) { … } Mutable borrow
  15. 15. Ownership! ! n. The act, state, or right of possessing something.
  16. 16. Aliasing Mutation Ownership (T)
  17. 17. vec data length capacity 1 2 fn give() { let mut vec = Vec::new(); vec.push(1); vec.push(2); take(vec); … } fn take(vec: Vec<int>) { // … } ! Take ownership ! of a Vec<int> !
  18. 18. Compiler enforces moves fn give() { let mut vec = Vec::new(); vec.push(1); vec.push(2); take(vec); vec.… push(2); } fn take(vec: Vec<int>) { // … } ! ! Error: ve! c has been moved Prevents: - use after free - double moves - …
  19. 19. Borrow! ! v. To receive something with the promise of returning it.
  20. 20. Aliasing Mutation Shared borrow (&T)
  21. 21. Aliasing Mutation Mutable borrow (&mut T)
  22. 22. fn lender() { let mut vec = Vec::new(); vec.push(1); vec.push(2); use(&vec); … } fn use(vec: &Vec<int>) { // … } ! ! ! 1 data length capacity vec 2 vec “Shared reference to Vec<int>” Loan out vec
  23. 23. fn dot_product(vec1: &Vec<int>, vec2: &Vec<int>) elem1 elem2 sum -> int { let mut sum = 0; for (elem1, elem2) in vec1.iter().zip(vec2.iter()) { sum += (*elem1) * (*elem2); } return sum; } walk down matching indices elem1, elem2 are references into the vector 1 2 3 4 5 6 * vec1 vec2
  24. 24. Why “shared” reference? fn dot_product(vec1: &Vec<int>, vec2: &Vec<int>) -> int {…} ! fn magnitude(vec: &Vec<int>) -> int { sqrt(dot_product(vec, vec)) } two shared references to the same vector — OK!
  25. 25. Aliasing Mutation Shared references are immutable: fn use(vec: &Vec<int>) { vec.push(3); vec[1] += 2; } * Error: cannot mutate shared reference * Actually: mutation only in controlled circumstances
  26. 26. Mutable references fn push_all(from: &Vec<int>, to: &mut Vec<int>) { for elem in from.iter() { to.push(*elem); } } mutable reference to Vec<int> push() is legal
  27. 27. Mutable references fn push_all(from: &Vec<int>, to: &mut Vec<int>) { for elem in from.iter() { 1 2 3 to.push(*elem); } } from to elem 1 2 3 …
  28. 28. What if from and to are equal? fn push_all(from: &Vec<int>, to: &mut Vec<int>) { for elem in from.iter() { 1 2 3 from to elem 1 2 3 … 1 to.push(*elem); } } dangling pointer
  29. 29. fn push_all(from: &Vec<int>, to: &mut Vec<int>) {…} ! fn caller() { let mut vec = …; push_all(&vec, &mut vec); } shared reference Error: cannot have both shared and mutable reference at same time A &mut T is the only way to access the memory it points at
  30. 30. { let mut vec = Vec::new(); … for i in range(0, vec.len()) { let elem: &int = &vec[i]; … vec.push(…); } … vec.push(…); } Borrows restrict access to the original path for their duration. Error: vec[i] is borrowed, cannot mutate OK. loan expired. & &mut no writes, no moves no access at all
  31. 31. Abstraction! ! n. freedom from representational qualities in art.
  32. 32. Rust is an extensible language • Zero-cost abstraction • Rich libraries: - Containers - Memory management - Parallelism - … • Ownership and borrowing let libraries enforce safety.
  33. 33. fn example() { let x: Rc<T> = Rc::new(…); { let y = x.clone(); let z = &*y; … } // runs destructor for y } // runs destructor for x x 1 [0] y 2 1 … z Stack Heap
  34. 34. Borrowing and Rc fn deref<‘a,T>(r: &’a Rc<T>) -> &’a T { … } Given a borrowed reference to an `Rc<T>`… …return a reference to the `T` inside with same extent New reference can be thought of as a kind of sublease. Returned reference cannot outlast the original.
  35. 35. fn example() -> &T { let x: Rc<T> = Rc::new(…); return &*x; } // runs destructor for x Error: extent of borrow exceeds lifetime of `x`
  36. 36. Concurrency! ! n. several computations executing simultaneously, and potentially interacting with each other
  37. 37. Data race ✎ ✎ ✎ ✎ Two unsynchronized threads accessing same data! where at least one writes.
  38. 38. Aliasing Mutation No ordering Data race Sound familiar?
  39. 39. Messaging! (ownership)
  40. 40. data length capacity fn parent() { let (tx, rx) = channel(); spawn(proc() {…}); let m = rx.recv(); } proc() { let m = Vec::new(); … tx.send(m); } rx tx tx m
  41. 41. Shared read-only access! (ownership, borrowing)
  42. 42. Arc<Vec<int>> (ARC = Atomic Reference Count) Owned, so no aliases. Vec<int> &Vec<int> ref_count data length capacity [0] [1] Shared reference, so Vec<int> is immutable.
  43. 43. ✎ ✎ Locked mutable access! (ownership, borrowing)
  44. 44. fn sync_inc(mutex: &Mutex<int>) { let mut data = mutex.lock(); *data += 1; } Destructor releases lock Yields a mutable reference to data Destructor runs here
  45. 45. And beyond… Parallelism is an area of active development. ! Either already have or have plans for: - Atomic primitives - Non-blocking queues - Concurrent hashtables - Lightweight thread pools - Futures - CILK-style fork-join concurrency - etc. Always data-race free
  46. 46. Parallel! ! adj. occurring or existing at the same time
  47. 47. Concurrent vs parallel Blocks Concurrent threads Parallel jobs
  48. 48. fn qsort(vec: &mut [int]) { let pivot = vec[random(vec.len())]; let mid = vec.partition(vec, pivot); let (less, greater) = vec.mut_split_at(mid); qsort(less); qsort(greater); } let vec: &mut [int] = …; [0] [1] [2] [3] […] [n] less greater
  49. 49. fn parallel_qsort(vec: &mut [int]) { let pivot = vec[random(vec.len())]; let mid = vec.partition(vec, pivot); let (less, greater) = vec.mut_split(mid); parallel::do(&[ || parallel_qsort(less), || parallel_qsort(greater) ]); } let vec: &mut [int] = …; [0] [1] [2] [3] […] [n] less greater
  50. 50. Unsafe! ! adj. not safe; hazardous
  51. 51. Safe abstractions fn something_safe(…) { ! unsafe { ! … ! } ! } Validates input, etc. Trust me. • Uninitialized memory • Interfacing with C code • Building parallel abstractions like ARC • …
  52. 52. Status of Rust “Rapidly stabilizing.”! ! ! Goal for 1.0: - Stable syntax, core type system - Minimal set of core libraries
  53. 53. Conclusions • Rust gives control without compromising safety: • Zero-cost abstractions • Zero-cost safety • Guarantees beyond dangling pointers: • Iterator invalidation in a broader sense • Data race freedom

×