]>
Commit | Line | Data |
---|---|---|
8bb4bdeb | 1 | # Transmutes |
c1a9b12d SL |
2 | |
3 | Get out of our way type system! We're going to reinterpret these bits or die | |
4 | trying! Even though this book is all about doing things that are unsafe, I | |
5 | really can't emphasize that you should deeply think about finding Another Way | |
6 | than the operations covered in this section. This is really, truly, the most | |
416331ca | 7 | horribly unsafe thing you can do in Rust. The guardrails here are dental floss. |
c1a9b12d | 8 | |
48663c56 XL |
9 | [`mem::transmute<T, U>`][transmute] takes a value of type `T` and reinterprets |
10 | it to have type `U`. The only restriction is that the `T` and `U` are verified | |
11 | to have the same size. The ways to cause Undefined Behavior with this are mind | |
12 | boggling. | |
c1a9b12d SL |
13 | |
14 | * First and foremost, creating an instance of *any* type with an invalid state | |
f035d41b XL |
15 | is going to cause arbitrary chaos that can't really be predicted. Do not |
16 | transmute `3` to `bool`. Even if you never *do* anything with the `bool`. Just | |
17 | don't. | |
29967ef6 | 18 | |
c1a9b12d SL |
19 | * Transmute has an overloaded return type. If you do not specify the return type |
20 | it may produce a surprising type to satisfy inference. | |
29967ef6 XL |
21 | |
22 | * Transmuting an `&` to `&mut` is UB. | |
23 | * Transmuting an `&` to `&mut` is *always* UB. | |
f035d41b XL |
24 | * No you can't do it. |
25 | * No you're not special. | |
29967ef6 | 26 | |
c1a9b12d | 27 | * Transmuting to a reference without an explicitly provided lifetime |
29967ef6 XL |
28 | produces an [unbounded lifetime]. |
29 | ||
f035d41b XL |
30 | * When transmuting between different compound types, you have to make sure they |
31 | are laid out the same way! If layouts differ, the wrong fields are going to | |
32 | get filled with the wrong data, which will make you unhappy and can also be UB | |
33 | (see above). | |
34 | ||
29967ef6 | 35 | So how do you know if the layouts are the same? For `repr(C)` types and |
f035d41b XL |
36 | `repr(transparent)` types, layout is precisely defined. But for your |
37 | run-of-the-mill `repr(Rust)`, it is not. Even different instances of the same | |
38 | generic type can have wildly different layout. `Vec<i32>` and `Vec<u32>` | |
39 | *might* have their fields in the same order, or they might not. The details of | |
40 | what exactly is and is not guaranteed for data layout are still being worked | |
41 | out over [at the UCG WG][ucg-layout]. | |
c1a9b12d | 42 | |
48663c56 XL |
43 | [`mem::transmute_copy<T, U>`][transmute_copy] somehow manages to be *even more* |
44 | wildly unsafe than this. It copies `size_of<U>` bytes out of an `&T` and | |
45 | interprets them as a `U`. The size check that `mem::transmute` has is gone (as | |
46 | it may be valid to copy out a prefix), though it is Undefined Behavior for `U` | |
47 | to be larger than `T`. | |
c1a9b12d | 48 | |
f035d41b XL |
49 | Also of course you can get all of the functionality of these functions using raw |
50 | pointer casts or `union`s, but without any of the lints or other basic sanity | |
51 | checks. Raw pointer casts and `union`s do not magically avoid the above rules. | |
c1a9b12d SL |
52 | |
53 | ||
29967ef6 | 54 | [unbounded lifetime]: ./unbounded-lifetimes.md |
48663c56 | 55 | [transmute]: ../std/mem/fn.transmute.html |
e1599b0c | 56 | [transmute_copy]: ../std/mem/fn.transmute_copy.html |
f035d41b | 57 | [ucg-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout.html |