Skip to content

Commit c941723

Browse files
RalfJungGankra
authored andcommitted
fix Nomicon transmute UB
1 parent d1517d4 commit c941723

File tree

1 file changed

+23
-9
lines changed

1 file changed

+23
-9
lines changed

src/transmutes.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,42 @@ to have the same size. The ways to cause Undefined Behavior with this are mind
1212
boggling.
1313

1414
* First and foremost, creating an instance of *any* type with an invalid state
15-
is going to cause arbitrary chaos that can't really be predicted.
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.
1618
* Transmute has an overloaded return type. If you do not specify the return type
1719
it may produce a surprising type to satisfy inference.
18-
* Making a primitive with an invalid value is UB
19-
* Transmuting between non-repr(C) types is UB
20-
* Transmuting an & to &mut is UB
21-
* Transmuting an & to &mut is *always* UB
22-
* No you can't do it
23-
* No you're not special
20+
* Transmuting an & to &mut is UB.
21+
* Transmuting an & to &mut is *always* UB.
22+
* No you can't do it.
23+
* No you're not special.
2424
* Transmuting to a reference without an explicitly provided lifetime
2525
produces an [unbounded lifetime]
26+
* When transmuting between different compound types, you have to make sure they
27+
are laid out the same way! If layouts differ, the wrong fields are going to
28+
get filled with the wrong data, which will make you unhappy and can also be UB
29+
(see above).
30+
31+
So how do you know if the layouts are the same? For `repr(C)` types and
32+
`repr(transparent)` types, layout is precisely defined. But for your
33+
run-of-the-mill `repr(Rust)`, it is not. Even different instances of the same
34+
generic type can have wildly different layout. `Vec<i32>` and `Vec<u32>`
35+
*might* have their fields in the same order, or they might not. The details of
36+
what exactly is and is not guaranteed for data layout are still being worked
37+
out over [at the UCG WG][ucg-layout].
2638

2739
[`mem::transmute_copy<T, U>`][transmute_copy] somehow manages to be *even more*
2840
wildly unsafe than this. It copies `size_of<U>` bytes out of an `&T` and
2941
interprets them as a `U`. The size check that `mem::transmute` has is gone (as
3042
it may be valid to copy out a prefix), though it is Undefined Behavior for `U`
3143
to be larger than `T`.
3244

33-
Also of course you can get most of the functionality of these functions using
34-
pointer casts.
45+
Also of course you can get all of the functionality of these functions using raw
46+
pointer casts or `union`s, but without any of the lints or other basic sanity
47+
checks. Raw pointer casts and `union`s do not magically avoid the above rules.
3548

3649

3750
[unbounded lifetime]: unbounded-lifetimes.html
3851
[transmute]: ../std/mem/fn.transmute.html
3952
[transmute_copy]: ../std/mem/fn.transmute_copy.html
53+
[ucg-layout]: https://rust-lang.github.io/unsafe-code-guidelines/layout.html

0 commit comments

Comments
 (0)