1# Working with Unsafe 2 3Rust generally only gives us the tools to talk about Unsafe Rust in a scoped and 4binary manner. Unfortunately, reality is significantly more complicated than 5that. For instance, consider the following toy function: 6 7```rust 8fn index(idx: usize, arr: &[u8]) -> Option<u8> { 9 if idx < arr.len() { 10 unsafe { 11 Some(*arr.get_unchecked(idx)) 12 } 13 } else { 14 None 15 } 16} 17``` 18 19This function is safe and correct. We check that the index is in bounds, and if 20it is, index into the array in an unchecked manner. We say that such a correct 21unsafely implemented function is *sound*, meaning that safe code cannot cause 22Undefined Behavior through it (which, remember, is the single fundamental 23property of Safe Rust). 24 25But even in such a trivial function, the scope of the unsafe block is 26questionable. Consider changing the `<` to a `<=`: 27 28```rust 29fn index(idx: usize, arr: &[u8]) -> Option<u8> { 30 if idx <= arr.len() { 31 unsafe { 32 Some(*arr.get_unchecked(idx)) 33 } 34 } else { 35 None 36 } 37} 38``` 39 40This program is now *unsound*, Safe Rust can cause Undefined Behavior, and yet 41*we only modified safe code*. This is the fundamental problem of safety: it's 42non-local. The soundness of our unsafe operations necessarily depends on the 43state established by otherwise "safe" operations. 44 45Safety is modular in the sense that opting into unsafety doesn't require you 46to consider arbitrary other kinds of badness. For instance, doing an unchecked 47index into a slice doesn't mean you suddenly need to worry about the slice being 48null or containing uninitialized memory. Nothing fundamentally changes. However 49safety *isn't* modular in the sense that programs are inherently stateful and 50your unsafe operations may depend on arbitrary other state. 51 52This non-locality gets much worse when we incorporate actual persistent state. 53Consider a simple implementation of `Vec`: 54 55```rust 56use std::ptr; 57 58// Note: This definition is naive. See the chapter on implementing Vec. 59pub struct Vec<T> { 60 ptr: *mut T, 61 len: usize, 62 cap: usize, 63} 64 65// Note this implementation does not correctly handle zero-sized types. 66// See the chapter on implementing Vec. 67impl<T> Vec<T> { 68 pub fn push(&mut self, elem: T) { 69 if self.len == self.cap { 70 // not important for this example 71 self.reallocate(); 72 } 73 unsafe { 74 ptr::write(self.ptr.add(self.len), elem); 75 self.len += 1; 76 } 77 } 78 # fn reallocate(&mut self) { } 79} 80 81# fn main() {} 82``` 83 84This code is simple enough to reasonably audit and informally verify. Now consider 85adding the following method: 86 87<!-- ignore: simplified code --> 88```rust,ignore 89fn make_room(&mut self) { 90 // grow the capacity 91 self.cap += 1; 92} 93``` 94 95This code is 100% Safe Rust but it is also completely unsound. Changing the 96capacity violates the invariants of Vec (that `cap` reflects the allocated space 97in the Vec). This is not something the rest of Vec can guard against. It *has* 98to trust the capacity field because there's no way to verify it. 99 100Because it relies on invariants of a struct field, this `unsafe` code 101does more than pollute a whole function: it pollutes a whole *module*. 102Generally, the only bullet-proof way to limit the scope of unsafe code is at the 103module boundary with privacy. 104 105However this works *perfectly*. The existence of `make_room` is *not* a 106problem for the soundness of Vec because we didn't mark it as public. Only the 107module that defines this function can call it. Also, `make_room` directly 108accesses the private fields of Vec, so it can only be written in the same module 109as Vec. 110 111It is therefore possible for us to write a completely safe abstraction that 112relies on complex invariants. This is *critical* to the relationship between 113Safe Rust and Unsafe Rust. 114 115We have already seen that Unsafe code must trust *some* Safe code, but shouldn't 116trust *generic* Safe code. Privacy is important to unsafe code for similar reasons: 117it prevents us from having to trust all the safe code in the universe from messing 118with our trusted state. 119 120Safety lives! 121