]>
Commit | Line | Data |
---|---|---|
8bb4bdeb | 1 | # How Safe and Unsafe Interact |
c1a9b12d | 2 | |
3157f602 XL |
3 | What's the relationship between Safe Rust and Unsafe Rust? How do they |
4 | interact? | |
5 | ||
6 | The separation between Safe Rust and Unsafe Rust is controlled with the | |
7 | `unsafe` keyword, which acts as an interface from one to the other. This is | |
8 | why we can say Safe Rust is a safe language: all the unsafe parts are kept | |
3b2f2976 XL |
9 | exclusively behind the `unsafe` boundary. If you wish, you can even toss |
10 | `#![forbid(unsafe_code)]` into your code base to statically guarantee that | |
11 | you're only writing Safe Rust. | |
3157f602 XL |
12 | |
13 | The `unsafe` keyword has two uses: to declare the existence of contracts the | |
3b2f2976 XL |
14 | compiler can't check, and to declare that a programmer has checked that these |
15 | contracts have been upheld. | |
3157f602 XL |
16 | |
17 | You can use `unsafe` to indicate the existence of unchecked contracts on | |
3b2f2976 | 18 | _functions_ and _trait declarations_. On functions, `unsafe` means that |
3157f602 XL |
19 | users of the function must check that function's documentation to ensure |
20 | they are using it in a way that maintains the contracts the function | |
21 | requires. On trait declarations, `unsafe` means that implementors of the | |
22 | trait must check the trait documentation to ensure their implementation | |
23 | maintains the contracts the trait requires. | |
24 | ||
3b2f2976 XL |
25 | You can use `unsafe` on a block to declare that all unsafe actions performed |
26 | within are verified to uphold the contracts of those operations. For instance, | |
27 | the index passed to `slice::get_unchecked` is in-bounds. | |
28 | ||
29 | You can use `unsafe` on a trait implementation to declare that the implementation | |
30 | upholds the trait's contract. For instance, that a type implementing `Send` is | |
31 | really safe to move to another thread. | |
3157f602 | 32 | |
3157f602 XL |
33 | The standard library has a number of unsafe functions, including: |
34 | ||
35 | * `slice::get_unchecked`, which performs unchecked indexing, allowing | |
36 | memory safety to be freely violated. | |
37 | * `mem::transmute` reinterprets some value as having a given type, bypassing | |
38 | type safety in arbitrary ways (see [conversions] for details). | |
3b2f2976 XL |
39 | * Every raw pointer to a sized type has an `offset` method that |
40 | invokes Undefined Behavior if the passed offset is not ["in bounds"][ptr_offset]. | |
ff7c6d11 XL |
41 | * All FFI (Foreign Function Interface) functions are `unsafe` to call because the |
42 | other language can do arbitrary operations that the Rust compiler can't check. | |
c1a9b12d SL |
43 | |
44 | As of Rust 1.0 there are exactly two unsafe traits: | |
45 | ||
3157f602 XL |
46 | * `Send` is a marker trait (a trait with no API) that promises implementors are |
47 | safe to send (move) to another thread. | |
48 | * `Sync` is a marker trait that promises threads can safely share implementors | |
49 | through a shared reference. | |
50 | ||
3b2f2976 XL |
51 | Much of the Rust standard library also uses Unsafe Rust internally. These |
52 | implementations have generally been rigorously manually checked, so the Safe Rust | |
53 | interfaces built on top of these implementations can be assumed to be safe. | |
3157f602 XL |
54 | |
55 | The need for all of this separation boils down a single fundamental property | |
56 | of Safe Rust: | |
57 | ||
58 | **No matter what, Safe Rust can't cause Undefined Behavior.** | |
59 | ||
3b2f2976 XL |
60 | The design of the safe/unsafe split means that there is an asymmetric trust |
61 | relationship between Safe and Unsafe Rust. Safe Rust inherently has to | |
62 | trust that any Unsafe Rust it touches has been written correctly. | |
63 | On the other hand, Unsafe Rust has to be very careful about trusting Safe Rust. | |
3157f602 XL |
64 | |
65 | As an example, Rust has the `PartialOrd` and `Ord` traits to differentiate | |
3b2f2976 XL |
66 | between types which can "just" be compared, and those that provide a "total" |
67 | ordering (which basically means that comparison behaves reasonably). | |
68 | ||
69 | `BTreeMap` doesn't really make sense for partially-ordered types, and so it | |
70 | requires that its keys implement `Ord`. However, `BTreeMap` has Unsafe Rust code | |
71 | inside of its implementation. Because it would be unacceptable for a sloppy `Ord` | |
72 | implementation (which is Safe to write) to cause Undefined Behavior, the Unsafe | |
73 | code in BTreeMap must be written to be robust against `Ord` implementations which | |
74 | aren't actually total — even though that's the whole point of requiring `Ord`. | |
75 | ||
76 | The Unsafe Rust code just can't trust the Safe Rust code to be written correctly. | |
77 | That said, `BTreeMap` will still behave completely erratically if you feed in | |
78 | values that don't have a total ordering. It just won't ever cause Undefined | |
79 | Behavior. | |
80 | ||
81 | One may wonder, if `BTreeMap` cannot trust `Ord` because it's Safe, why can it | |
82 | trust *any* Safe code? For instance `BTreeMap` relies on integers and slices to | |
83 | be implemented correctly. Those are safe too, right? | |
84 | ||
85 | The difference is one of scope. When `BTreeMap` relies on integers and slices, | |
86 | it's relying on one very specific implementation. This is a measured risk that | |
87 | can be weighed against the benefit. In this case there's basically zero risk; | |
88 | if integers and slices are broken, *everyone* is broken. Also, they're maintained | |
89 | by the same people who maintain `BTreeMap`, so it's easy to keep tabs on them. | |
90 | ||
91 | On the other hand, `BTreeMap`'s key type is generic. Trusting its `Ord` implementation | |
92 | means trusting every `Ord` implementation in the past, present, and future. | |
93 | Here the risk is high: someone somewhere is going to make a mistake and mess up | |
94 | their `Ord` implementation, or even just straight up lie about providing a total | |
95 | ordering because "it seems to work". When that happens, `BTreeMap` needs to be | |
96 | prepared. | |
97 | ||
98 | The same logic applies to trusting a closure that's passed to you to behave | |
99 | correctly. | |
100 | ||
101 | This problem of unbounded generic trust is the problem that `unsafe` traits | |
102 | exist to resolve. The `BTreeMap` type could theoretically require that keys | |
103 | implement a new trait called `UnsafeOrd`, rather than `Ord`, that might look | |
104 | like this: | |
c1a9b12d SL |
105 | |
106 | ```rust | |
3157f602 XL |
107 | use std::cmp::Ordering; |
108 | ||
109 | unsafe trait UnsafeOrd { | |
110 | fn cmp(&self, other: &Self) -> Ordering; | |
c1a9b12d SL |
111 | } |
112 | ``` | |
113 | ||
3157f602 XL |
114 | Then, a type would use `unsafe` to implement `UnsafeOrd`, indicating that |
115 | they've ensured their implementation maintains whatever contracts the | |
116 | trait expects. In this situation, the Unsafe Rust in the internals of | |
3b2f2976 XL |
117 | `BTreeMap` would be justified in trusting that the key type's `UnsafeOrd` |
118 | implementation is correct. If it isn't, it's the fault of the unsafe trait | |
119 | implementation, which is consistent with Rust's safety guarantees. | |
3157f602 XL |
120 | |
121 | The decision of whether to mark a trait `unsafe` is an API design choice. | |
3b2f2976 XL |
122 | Rust has traditionally avoided doing this because it makes Unsafe |
123 | Rust pervasive, which isn't desirable. `Send` and `Sync` are marked unsafe | |
3157f602 XL |
124 | because thread safety is a *fundamental property* that unsafe code can't |
125 | possibly hope to defend against in the way it could defend against a bad | |
126 | `Ord` implementation. The decision of whether to mark your own traits `unsafe` | |
3b2f2976 | 127 | depends on the same sort of consideration. If `unsafe` code can't reasonably |
3157f602 XL |
128 | expect to defend against a bad implementation of the trait, then marking the |
129 | trait `unsafe` is a reasonable choice. | |
130 | ||
3b2f2976 | 131 | As an aside, while `Send` and `Sync` are `unsafe` traits, they are *also* |
3157f602 XL |
132 | automatically implemented for types when such derivations are provably safe |
133 | to do. `Send` is automatically derived for all types composed only of values | |
134 | whose types also implement `Send`. `Sync` is automatically derived for all | |
3b2f2976 XL |
135 | types composed only of values whose types also implement `Sync`. This minimizes |
136 | the pervasive unsafety of making these two traits `unsafe`. | |
3157f602 | 137 | |
3b2f2976 XL |
138 | This is the balance between Safe and Unsafe Rust. The separation is designed to |
139 | make using Safe Rust as ergonomic as possible, but requires extra effort and | |
140 | care when writing Unsafe Rust. The rest of this book is largely a discussion | |
141 | of the sort of care that must be taken, and what contracts Unsafe Rust must uphold. | |
c1a9b12d | 142 | |
c1a9b12d | 143 | [conversions]: conversions.html |
3b2f2976 | 144 | [ptr_offset]: ../std/primitive.pointer.html#method.offset |
3157f602 | 145 |