From: Ralf Jung Date: Sat, 2 Jan 2016 14:03:17 +0000 (+0100) Subject: start working on the unsafe post X-Git-Url: https://git.ralfj.de/web.git/commitdiff_plain/b649db824638a88a255887b03f0103804c96ef08?hp=9054837aeed5dceb8c2540715407b462e6d307c2 start working on the unsafe post --- diff --git a/personal/_drafts/the-scope-of-unsafe.md b/personal/_drafts/the-scope-of-unsafe.md new file mode 100644 index 0000000..f6af9a0 --- /dev/null +++ b/personal/_drafts/the-scope-of-unsafe.md @@ -0,0 +1,46 @@ +--- +title: The scope of unsafe +categories: research rust +--- + +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: + +> *When checking unsafe code, it is not enough to just check the contents of every `unsafe` block.* + +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). + + + +## An Example + +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. + +Consider the type `Vec`, which is roughly defined as follows: +{% highlight rust %} +pub struct Vec { + ptr: *mut T, + cap: usize, + len: usize, +} +{% endhighlight %} +(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).) + +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. +`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). + +It is very easy to add a function to `Vec` that contains no `unsafe` code, and still breaks the safety of the data structure: +{% highlight rust %} +fn evil(&mut self) { + self.cap += 2; +} +{% endhighlight %} + +Why is this bad? +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. +Oops. + +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. + +## A Reason + +So, why is this the case?