f6af9a0b032eef1244ed982c25ab8881852433cd
[web.git] / ralf / _drafts / the-scope-of-unsafe.md
1 ---
2 title: The scope of unsafe
3 categories: research rust
4 ---
5
6 I'd like to talk about an important aspect of dealing with unsafe code, that still regularly seems to catch people on the wrong foot:
7
8 > *When checking unsafe code, it is not enough to just check the contents of every `unsafe` block.*
9
10 It turns out that the underlying reason for this observation is also a nice illustration for the concept of *semantic* types that comes up in my [work on formalizing Rust]({{ site.baseurl }}{% post_url 2015-10-12-formalizing-rust %}) (or rather, its type system).
11
12 <!-- MORE -->
13
14 ## An Example
15
16 Before we dive into the deeper reasons for why this is the case, let me start by convincing your that the above statement is actually true.
17
18 Consider the type `Vec<T>`, which is roughly defined as follows:
19 {% highlight rust %}
20 pub struct Vec<T> {
21     ptr: *mut T,
22     cap: usize,
23     len: usize,
24 }
25 {% endhighlight %}
26 (I know this definition is not entirely right. If you want to know how the actual `Vec` works, check out the [corresponding section of the Rustonomicon](https://doc.rust-lang.org/nightly/nomicon/vec.html).)
27
28 Roughly speaking, `ptr` points to the heap-allocated block of memory holding the contents of the vector, `cap` holds the size of that memory block (counted in number of `T`), and `len` stores how many elements are actually stored in the vector right now.
29 `cap` and `len` can be different if the memory block contains some extra (uninitialized) space beyond the end of the vector, which speeds up pushing an element to the end of the vector (at the cost of some extra memory usage).
30
31 It is very easy to add a function to `Vec` that contains no `unsafe` code, and still breaks the safety of the data structure:
32 {% highlight rust %}
33 fn evil(&mut self) {
34     self.cap += 2;
35 }
36 {% endhighlight %}
37
38 Why is this bad?
39 The next time `push` is called, the vector will think that it has space for two more element than it actually does, which will eventually (after sufficiently many calls to `push`) result in using unallocated memory.
40 Oops.
41
42 So, this example clearly shows that to evaluate the safety of types like `Vec`, we have to look at *every single function* provided by that data structure, even if it does not contain any `unsafe` code.
43
44 ## A Reason
45
46 So, why is this the case?