Skip to content

Commit 0f61527

Browse files
Rollup merge of rust-lang#122379 - RalfJung:int2ptr-transmute, r=m-ou-se
transmute: caution against int2ptr transmutation This came up in rust-lang#121282. Cc ````@saethlin```` ````@scottmcm```` Eventually we'll add a proper description of provenance that we can reference, but that's a bunch of work and it's unclear who will have the time to do that when. Meanwhile, let's at least do what we can without mentioning provenance explicitly.
2 parents b6681d6 + f4adb1e commit 0f61527

File tree

1 file changed

+33
-8
lines changed

1 file changed

+33
-8
lines changed

library/core/src/intrinsics.rs

+33-8
Original file line numberDiff line numberDiff line change
@@ -1165,14 +1165,6 @@ extern "rust-intrinsic" {
11651165
/// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly
11661166
/// unsafe**. `transmute` should be the absolute last resort.
11671167
///
1168-
/// Transmuting pointers *to* integers in a `const` context is [undefined behavior][ub],
1169-
/// unless the pointer was originally created *from* an integer.
1170-
/// (That includes this function specifically, integer-to-pointer casts, and helpers like [`invalid`][crate::ptr::dangling],
1171-
/// but also semantically-equivalent conversions such as punning through `repr(C)` union fields.)
1172-
/// Any attempt to use the resulting value for integer operations will abort const-evaluation.
1173-
/// (And even outside `const`, such transmutation is touching on many unspecified aspects of the
1174-
/// Rust memory model and should be avoided. See below for alternatives.)
1175-
///
11761168
/// Because `transmute` is a by-value operation, alignment of the *transmuted values
11771169
/// themselves* is not a concern. As with any other function, the compiler already ensures
11781170
/// both `Src` and `Dst` are properly aligned. However, when transmuting values that *point
@@ -1183,6 +1175,39 @@ extern "rust-intrinsic" {
11831175
///
11841176
/// [ub]: ../../reference/behavior-considered-undefined.html
11851177
///
1178+
/// # Transmutation between pointers and integers
1179+
///
1180+
/// Special care has to be taken when transmuting between pointers and integers, e.g.
1181+
/// transmuting between `*const ()` and `usize`.
1182+
///
1183+
/// Transmuting *pointers to integers* in a `const` context is [undefined behavior][ub], unless
1184+
/// the pointer was originally created *from* an integer. (That includes this function
1185+
/// specifically, integer-to-pointer casts, and helpers like [`dangling`][crate::ptr::dangling],
1186+
/// but also semantically-equivalent conversions such as punning through `repr(C)` union
1187+
/// fields.) Any attempt to use the resulting value for integer operations will abort
1188+
/// const-evaluation. (And even outside `const`, such transmutation is touching on many
1189+
/// unspecified aspects of the Rust memory model and should be avoided. See below for
1190+
/// alternatives.)
1191+
///
1192+
/// Transmuting *integers to pointers* is a largely unspecified operation. It is likely *not*
1193+
/// equivalent to an `as` cast. Doing non-zero-sized memory accesses with a pointer constructed
1194+
/// this way is currently considered undefined behavior.
1195+
///
1196+
/// All this also applies when the integer is nested inside an array, tuple, struct, or enum.
1197+
/// However, `MaybeUninit<usize>` is not considered an integer type for the purpose of this
1198+
/// section. Transmuting `*const ()` to `MaybeUninit<usize>` is fine---but then calling
1199+
/// `assume_init()` on that result is considered as completing the pointer-to-integer transmute
1200+
/// and thus runs into the issues discussed above.
1201+
///
1202+
/// In particular, doing a pointer-to-integer-to-pointer roundtrip via `transmute` is *not* a
1203+
/// lossless process. If you want to round-trip a pointer through an integer in a way that you
1204+
/// can get back the original pointer, you need to use `as` casts, or replace the integer type
1205+
/// by `MaybeUninit<$int>` (and never call `assume_init()`). If you are looking for a way to
1206+
/// store data of arbitrary type, also use `MaybeUninit<T>` (that will also handle uninitialized
1207+
/// memory due to padding). If you specifically need to store something that is "either an
1208+
/// integer or a pointer", use `*mut ()`: integers can be converted to pointers and back without
1209+
/// any loss (via `as` casts or via `transmute`).
1210+
///
11861211
/// # Examples
11871212
///
11881213
/// There are a few things that `transmute` is really useful for.

0 commit comments

Comments
 (0)