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