2c06b68c0d20a7997235cfddf5cdad932a17497a
[web.git] / personal / _drafts / unused-data.md
1 ---
2 title: "Why even unused data needs to be valid"
3 categories: rust
4 ---
5
6 `unsafe` code in Rust has a few ways that it can trigger [Undefined Behavior][ub], i.e., there are a few assumptions that the compiler makes about all code, and that for `unsafe` code the programmer is responsible for upholding.
7 Those assumptions are [listed in the Rust reference](https://doc.rust-lang.org/reference/behavior-considered-undefined.html).
8 The one that seems to be most surprising to many people is the clause which says that unsafe code may not produce "[...] an invalid value, even in private fields and locals".
9 The reference goes on to explain that "*producing* a value happens any time a value is assigned to or read from a place, passed to a function/primitive operation or returned from a function/primitive operation".
10 In other words, even just *constructing*, for example, an invalid `bool`, is Undefined Behavior---no matter whether that `bool` is ever actually "used" by the program.
11 The purpose of this post is to explain why.
12
13 [ub]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#undefined-behavior
14
15 <!-- MORE -->
16
17 First of all, let me clarify what is meant by "used" here, as that term is used to mean very different things.
18 The following code "uses" `b`:
19
20 {% highlight rust %}
21 fn example(b: bool) -> i32 {
22   if b { 42 } else { 23 }
23 }
24 {% endhighlight %}
25
26 I hope it is not very surprising that calling `example` on, e.g., `3` transmuted to `bool` is Undefined Behavior (UB).
27 When compiling `if`, the compiler assumes that `0` and `1` are the only possible values; there is no saying what could go wrong when that assumption is violated.
28
29 What is less obvious is why calling `example` on `3` is UB even when there is no such `if` being executed.
30 To understand why that is important, let us consider the following example:
31
32 {% highlight rust %}
33 fn example(b: bool, num: u32) -> i32 {
34   let mut acc = 0;
35   for _i in 0..num {
36     acc += if b { 42 } else { 23 };
37   }
38   acc
39 }
40 {% endhighlight %}
41
42 Now assume we were working in a slightly different version of Rust, where transmuting `3` to a `bool` is fine as long as you do not "use" the `bool`.
43 That would mean that calling `example(transmute(3u8), 0)` is actually allowed, because in that case the loop never gets executed, so we never "use" `b`.
44
45 However, this is a problem for a very important transformation called [loop-invariant code motion](https://en.wikipedia.org/wiki/Loop-invariant_code_motion).
46 That transformation can be used to turn our `example` function into the following:
47
48 {% highlight rust %}
49 fn example(b: bool, num: u32) -> i32 {
50   let mut acc = 0;
51   let incr = if b { 42 } else { 23 }
52   for _i in 0..num {
53     acc += incr;
54   }
55   acc
56 }
57 {% endhighlight %}
58
59 The increment `if b { 42 } else { 23 }` is "invariant" during the execution of the loop, and thus computing the increment can be moved out.
60 Why is this a good transformation?
61 Instead of determining the increment each time around the loop, we do that just once, thus saving a lot of conditional jumps that the CPU is unhappy about.