Skip to content

Commit cf863b5

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 1bb71c8 commit cf863b5

1 file changed

Lines changed: 26 additions & 0 deletions

File tree

src/const_eval.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,32 @@ const C: Pair = unsafe {
263263
> 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 it requires (on 64-bit platforms) 8 bytes. Only 4 of those bytes fit in the padding at offset 24, so the remaining bytes of the pointer extend into the `y` field at offset 16. When the fields are initialized, those 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.
264264
>
265265
> The restriction ensures that any bytes with provenance in the final value represent complete, valid pointers in their natural representation. The compiler cannot support pointer fragments because it would be unable to reason about them at compile time.
266+
>
267+
> Reversing the order of the pointer bytes also causes compilation to fail, even though all bytes are present:
268+
>
269+
> ```rust,compile_fail
270+
> # use std::mem::MaybeUninit;
271+
> # #[repr(C)]
272+
> # struct Pair {
273+
> # x: u128,
274+
> # y: MaybeUninit<u64>,
275+
> # }
276+
> const C: Pair = unsafe {
277+
> let mut m = MaybeUninit::<Pair>::uninit();
278+
> let ptr: *const u8 = &0;
279+
> let ptr_bytes = &ptr as *const _ as *const MaybeUninit<u8>;
280+
> // Write pointer bytes in reverse order into the padding.
281+
> let dst = m.as_mut_ptr().cast::<MaybeUninit<u8>>().add(24);
282+
> let mut i = 0;
283+
> while i < 8 {
284+
> dst.add(i).write(ptr_bytes.add(7 - i).read());
285+
> i += 1;
286+
> }
287+
> (*m.as_mut_ptr()).x = 0;
288+
> (*m.as_mut_ptr()).y = MaybeUninit::new(0);
289+
> m.assume_init()
290+
> };
291+
> ```
266292
267293
> [!NOTE]
268294
> Manually initializing (e.g., zeroing) the padding bytes ensures the final value is accepted:

0 commit comments

Comments
 (0)