|
1 | | -% Unsafe Code |
2 | | - |
3 | | -# Introduction |
4 | | - |
5 | | -Rust aims to provide safe abstractions over the low-level details of |
6 | | -the CPU and operating system, but sometimes one needs to drop down and |
7 | | -write code at that level. This guide aims to provide an overview of |
8 | | -the dangers and power one gets with Rust's unsafe subset. |
9 | | - |
10 | | -Rust provides an escape hatch in the form of the `unsafe { ... }` |
11 | | -block which allows the programmer to dodge some of the compiler's |
12 | | -checks and do a wide range of operations, such as: |
13 | | - |
14 | | -- dereferencing [raw pointers](#raw-pointers) |
15 | | -- calling a function via FFI ([covered by the FFI guide](ffi.html)) |
16 | | -- casting between types bitwise (`transmute`, aka "reinterpret cast") |
17 | | -- [inline assembly](#inline-assembly) |
18 | | - |
19 | | -Note that an `unsafe` block does not relax the rules about lifetimes |
20 | | -of `&` and the freezing of borrowed data. |
21 | | - |
22 | | -Any use of `unsafe` is the programmer saying "I know more than you" to |
23 | | -the compiler, and, as such, the programmer should be very sure that |
24 | | -they actually do know more about why that piece of code is valid. In |
25 | | -general, one should try to minimize the amount of unsafe code in a |
26 | | -code base; preferably by using the bare minimum `unsafe` blocks to |
27 | | -build safe interfaces. |
28 | | - |
29 | | -> **Note**: the low-level details of the Rust language are still in |
30 | | -> flux, and there is no guarantee of stability or backwards |
31 | | -> compatibility. In particular, there may be changes that do not cause |
32 | | -> compilation errors, but do cause semantic changes (such as invoking |
33 | | -> undefined behaviour). As such, extreme care is required. |
34 | | -
|
35 | | -# Pointers |
36 | | - |
37 | | -## References |
38 | | - |
39 | | -One of Rust's biggest features is memory safety. This is achieved in |
40 | | -part via [the ownership system](ownership.html), which is how the |
41 | | -compiler can guarantee that every `&` reference is always valid, and, |
42 | | -for example, never pointing to freed memory. |
43 | | - |
44 | | -These restrictions on `&` have huge advantages. However, they also |
45 | | -constrain how we can use them. For example, `&` doesn't behave |
46 | | -identically to C's pointers, and so cannot be used for pointers in |
47 | | -foreign function interfaces (FFI). Additionally, both immutable (`&`) |
48 | | -and mutable (`&mut`) references have some aliasing and freezing |
49 | | -guarantees, required for memory safety. |
50 | | - |
51 | | -In particular, if you have an `&T` reference, then the `T` must not be |
52 | | -modified through that reference or any other reference. There are some |
53 | | -standard library types, e.g. `Cell` and `RefCell`, that provide inner |
54 | | -mutability by replacing compile time guarantees with dynamic checks at |
55 | | -runtime. |
56 | | - |
57 | | -An `&mut` reference has a different constraint: when an object has an |
58 | | -`&mut T` pointing into it, then that `&mut` reference must be the only |
59 | | -such usable path to that object in the whole program. That is, an |
60 | | -`&mut` cannot alias with any other references. |
61 | | - |
62 | | -Using `unsafe` code to incorrectly circumvent and violate these |
63 | | -restrictions is undefined behaviour. For example, the following |
64 | | -creates two aliasing `&mut` pointers, and is invalid. |
65 | | - |
66 | | -``` |
67 | | -use std::mem; |
68 | | -let mut x: u8 = 1; |
69 | | -
|
70 | | -let ref_1: &mut u8 = &mut x; |
71 | | -let ref_2: &mut u8 = unsafe { mem::transmute(&mut *ref_1) }; |
72 | | -
|
73 | | -// oops, ref_1 and ref_2 point to the same piece of data (x) and are |
74 | | -// both usable |
75 | | -*ref_1 = 10; |
76 | | -*ref_2 = 20; |
77 | | -``` |
78 | | - |
79 | | -## Raw pointers |
| 1 | +% Raw Pointers |
80 | 2 |
|
81 | 3 | Rust offers two additional pointer types (*raw pointers*), written as |
82 | 4 | `*const T` and `*mut T`. They're an approximation of C's `const T*` and `T*` |
@@ -160,24 +82,3 @@ The `&*x` dereferencing style is preferred to using a `transmute`. |
160 | 82 | The latter is far more powerful than necessary, and the more |
161 | 83 | restricted operation is harder to use incorrectly; for example, it |
162 | 84 | requires that `x` is a pointer (unlike `transmute`). |
163 | | - |
164 | | - |
165 | | - |
166 | | -## Making the unsafe safe(r) |
167 | | - |
168 | | -There are various ways to expose a safe interface around some unsafe |
169 | | -code: |
170 | | - |
171 | | -- store pointers privately (i.e. not in public fields of public |
172 | | - structs), so that you can see and control all reads and writes to |
173 | | - the pointer in one place. |
174 | | -- use `assert!()` a lot: since you can't rely on the protection of the |
175 | | - compiler & type-system to ensure that your `unsafe` code is correct |
176 | | - at compile-time, use `assert!()` to verify that it is doing the |
177 | | - right thing at run-time. |
178 | | -- implement the `Drop` for resource clean-up via a destructor, and use |
179 | | - RAII (Resource Acquisition Is Initialization). This reduces the need |
180 | | - for any manual memory management by users, and automatically ensures |
181 | | - that clean-up is always run, even when the thread panics. |
182 | | -- ensure that any data stored behind a raw pointer is destroyed at the |
183 | | - appropriate time. |
0 commit comments