Skip to content

Commit 32e4186

Browse files
committed
Add example of reversed pointer bytes being rejected
Let's add an example demonstrating that reversing the order of pointer bytes causes compilation to fail, even though all bytes are present. The compiler tracks the position of each byte within its original pointer and only accepts pointers when reassembled in the correct order. This example copies a pointer byte-by-byte in reverse order into the padding of a struct, which fails because the fragment indices don't match up to form a valid pointer. Context: - rust-lang/rust#144081
1 parent 3404252 commit 32e4186

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

src/const_eval.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,28 @@ const C: Pair = unsafe {
264264
> The bytes with provenance must form a complete pointer in the correct order. In the example above, the pointer is written at offset 20, but a pointer requires 8 bytes (assuming an 8-byte pointer). Four of those bytes fit in the `y` field; the rest extend into the padding at offset 24. When the fields are initialized, the `y` bytes get overwritten, leaving only a partial pointer (4 bytes) in the padding. These 4 bytes have provenance but don't form a complete pointer, causing compilation to fail.
265265
>
266266
> This restriction ensures that any bytes with provenance in the final value represent complete pointers. Binary formats such as ELF cannot represent pointer fragments, so the compiler cannot emit them in the final binary.
267+
>
268+
> Reversing the order of the pointer bytes also causes compilation to fail, even though all bytes are present:
269+
>
270+
> ```rust,compile_fail
271+
> # use core::mem::{self, MaybeUninit};
272+
> const PTR_WIDTH: usize = mem::size_of::<*const u8>();
273+
> const _: MaybeUninit<u64> = unsafe {
274+
> // ^^^^^^^^^^^^^^^^
275+
> // ERROR: Partial pointer in final value of constant.
276+
> let mut m = MaybeUninit::<u64>::uninit();
277+
> let ptr: *const u8 = &0;
278+
> let ptr_bytes = &raw const ptr as *const MaybeUninit<u8>;
279+
> // Write pointer bytes in reverse order.
280+
> let dst: *mut MaybeUninit<u8> = m.as_mut_ptr().cast();
281+
> let mut i = 0;
282+
> while i < PTR_WIDTH {
283+
> dst.add(i).write(ptr_bytes.add(PTR_WIDTH - 1 - i).read());
284+
> i += 1;
285+
> }
286+
> m
287+
> };
288+
> ```
267289
268290
> [!NOTE]
269291
> Manually initializing (e.g., zeroing) the padding bytes ensures the final value is accepted:

0 commit comments

Comments
 (0)