|
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