Skip to content

Commit f68a0f1

Browse files
authored
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 08bb35e + f4adb1e commit f68a0f1

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

0 commit comments

Comments
 (0)