]>
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, | |
29967ef6 | 27 | the index passed to [`slice::get_unchecked`][get_unchecked] is in-bounds. |
3b2f2976 XL |
28 | |
29 | You can use `unsafe` on a trait implementation to declare that the implementation | |
29967ef6 | 30 | upholds the trait's contract. For instance, that a type implementing [`Send`] is |
3b2f2976 | 31 | really safe to move to another thread. |
3157f602 | 32 | |
3157f602 XL |
33 | The standard library has a number of unsafe functions, including: |
34 | ||
29967ef6 XL |
35 | * [`slice::get_unchecked`][get_unchecked], which performs unchecked indexing, |
36 | allowing memory safety to be freely violated. | |
37 | * [`mem::transmute`][transmute] reinterprets some value as having a given type, | |
38 | bypassing type safety in arbitrary ways (see [conversions] for details). | |
39 | * Every raw pointer to a sized type has an [`offset`][ptr_offset] method that | |
3b2f2976 | 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 | 43 | |
13cf67c4 XL |
44 | As of Rust 1.29.2 the standard library defines the following unsafe traits |
45 | (there are others, but they are not stabilized yet and some of them may never | |
46 | be): | |
c1a9b12d | 47 | |
13cf67c4 XL |
48 | * [`Send`] is a marker trait (a trait with no API) that promises implementors |
49 | are safe to send (move) to another thread. | |
50 | * [`Sync`] is a marker trait that promises threads can safely share implementors | |
3157f602 | 51 | through a shared reference. |
13cf67c4 | 52 | * [`GlobalAlloc`] allows customizing the memory allocator of the whole program. |
3157f602 | 53 | |
3b2f2976 XL |
54 | Much of the Rust standard library also uses Unsafe Rust internally. These |
55 | implementations have generally been rigorously manually checked, so the Safe Rust | |
56 | interfaces built on top of these implementations can be assumed to be safe. | |
3157f602 XL |
57 | |
58 | The need for all of this separation boils down a single fundamental property | |
74b04a01 | 59 | of Safe Rust, the *soundness property*: |
3157f602 XL |
60 | |
61 | **No matter what, Safe Rust can't cause Undefined Behavior.** | |
62 | ||
3b2f2976 XL |
63 | The design of the safe/unsafe split means that there is an asymmetric trust |
64 | relationship between Safe and Unsafe Rust. Safe Rust inherently has to | |
65 | trust that any Unsafe Rust it touches has been written correctly. | |
66 | On the other hand, Unsafe Rust has to be very careful about trusting Safe Rust. | |
3157f602 | 67 | |
29967ef6 | 68 | As an example, Rust has the [`PartialOrd`] and [`Ord`] traits to differentiate |
3b2f2976 XL |
69 | between types which can "just" be compared, and those that provide a "total" |
70 | ordering (which basically means that comparison behaves reasonably). | |
71 | ||
29967ef6 | 72 | [`BTreeMap`] doesn't really make sense for partially-ordered types, and so it |
3b2f2976 XL |
73 | requires that its keys implement `Ord`. However, `BTreeMap` has Unsafe Rust code |
74 | inside of its implementation. Because it would be unacceptable for a sloppy `Ord` | |
75 | implementation (which is Safe to write) to cause Undefined Behavior, the Unsafe | |
76 | code in BTreeMap must be written to be robust against `Ord` implementations which | |
77 | aren't actually total — even though that's the whole point of requiring `Ord`. | |
78 | ||
79 | The Unsafe Rust code just can't trust the Safe Rust code to be written correctly. | |
80 | That said, `BTreeMap` will still behave completely erratically if you feed in | |
81 | values that don't have a total ordering. It just won't ever cause Undefined | |
82 | Behavior. | |
83 | ||
84 | One may wonder, if `BTreeMap` cannot trust `Ord` because it's Safe, why can it | |
85 | trust *any* Safe code? For instance `BTreeMap` relies on integers and slices to | |
86 | be implemented correctly. Those are safe too, right? | |
87 | ||
88 | The difference is one of scope. When `BTreeMap` relies on integers and slices, | |
89 | it's relying on one very specific implementation. This is a measured risk that | |
90 | can be weighed against the benefit. In this case there's basically zero risk; | |
91 | if integers and slices are broken, *everyone* is broken. Also, they're maintained | |
92 | by the same people who maintain `BTreeMap`, so it's easy to keep tabs on them. | |
93 | ||
94 | On the other hand, `BTreeMap`'s key type is generic. Trusting its `Ord` implementation | |
95 | means trusting every `Ord` implementation in the past, present, and future. | |
96 | Here the risk is high: someone somewhere is going to make a mistake and mess up | |
97 | their `Ord` implementation, or even just straight up lie about providing a total | |
98 | ordering because "it seems to work". When that happens, `BTreeMap` needs to be | |
99 | prepared. | |
100 | ||
101 | The same logic applies to trusting a closure that's passed to you to behave | |
102 | correctly. | |
103 | ||
104 | This problem of unbounded generic trust is the problem that `unsafe` traits | |
105 | exist to resolve. The `BTreeMap` type could theoretically require that keys | |
106 | implement a new trait called `UnsafeOrd`, rather than `Ord`, that might look | |
107 | like this: | |
c1a9b12d SL |
108 | |
109 | ```rust | |
3157f602 XL |
110 | use std::cmp::Ordering; |
111 | ||
112 | unsafe trait UnsafeOrd { | |
113 | fn cmp(&self, other: &Self) -> Ordering; | |
c1a9b12d SL |
114 | } |
115 | ``` | |
116 | ||
3157f602 XL |
117 | Then, a type would use `unsafe` to implement `UnsafeOrd`, indicating that |
118 | they've ensured their implementation maintains whatever contracts the | |
119 | trait expects. In this situation, the Unsafe Rust in the internals of | |
3b2f2976 XL |
120 | `BTreeMap` would be justified in trusting that the key type's `UnsafeOrd` |
121 | implementation is correct. If it isn't, it's the fault of the unsafe trait | |
122 | implementation, which is consistent with Rust's safety guarantees. | |
3157f602 XL |
123 | |
124 | The decision of whether to mark a trait `unsafe` is an API design choice. | |
3b2f2976 XL |
125 | Rust has traditionally avoided doing this because it makes Unsafe |
126 | Rust pervasive, which isn't desirable. `Send` and `Sync` are marked unsafe | |
3157f602 | 127 | because thread safety is a *fundamental property* that unsafe code can't |
13cf67c4 XL |
128 | possibly hope to defend against in the way it could defend against a buggy |
129 | `Ord` implementation. Similarly, `GlobalAllocator` is keeping accounts of all | |
130 | the memory in the program and other things like `Box` or `Vec` build on top of | |
131 | it. If it does something weird (giving the same chunk of memory to another | |
132 | request when it is still in use), there's no chance to detect that and do | |
133 | anything about it. | |
134 | ||
135 | The decision of whether to mark your own traits `unsafe` depends on the same | |
136 | sort of consideration. If `unsafe` code can't reasonably expect to defend | |
137 | against a broken implementation of the trait, then marking the trait `unsafe` is | |
138 | a reasonable choice. | |
3157f602 | 139 | |
3b2f2976 | 140 | As an aside, while `Send` and `Sync` are `unsafe` traits, they are *also* |
3157f602 XL |
141 | automatically implemented for types when such derivations are provably safe |
142 | to do. `Send` is automatically derived for all types composed only of values | |
143 | whose types also implement `Send`. `Sync` is automatically derived for all | |
3b2f2976 | 144 | types composed only of values whose types also implement `Sync`. This minimizes |
13cf67c4 XL |
145 | the pervasive unsafety of making these two traits `unsafe`. And not many people |
146 | are going to *implement* memory allocators (or use them directly, for that | |
147 | matter). | |
3157f602 | 148 | |
3b2f2976 XL |
149 | This is the balance between Safe and Unsafe Rust. The separation is designed to |
150 | make using Safe Rust as ergonomic as possible, but requires extra effort and | |
151 | care when writing Unsafe Rust. The rest of this book is largely a discussion | |
152 | of the sort of care that must be taken, and what contracts Unsafe Rust must uphold. | |
c1a9b12d | 153 | |
13cf67c4 XL |
154 | [`Send`]: ../std/marker/trait.Send.html |
155 | [`Sync`]: ../std/marker/trait.Sync.html | |
156 | [`GlobalAlloc`]: ../std/alloc/trait.GlobalAlloc.html | |
c1a9b12d | 157 | [conversions]: conversions.html |
3b2f2976 | 158 | [ptr_offset]: ../std/primitive.pointer.html#method.offset |
29967ef6 XL |
159 | [get_unchecked]: ../std/primitive.slice.html#method.get_unchecked |
160 | [transmute]: ../std/mem/fn.transmute.html | |
161 | [`PartialOrd`]: ../std/cmp/trait.PartialOrd.html | |
162 | [`Ord`]: ../std/cmp/trait.Ord.html | |
163 | [`BTreeMap`]: ../std/collections/struct.BTreeMap.html |