]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/tests/pass/provenance.rs
Auto merge of #104915 - weihanglo:update-cargo, r=ehuss
[rust.git] / src / tools / miri / tests / pass / provenance.rs
1 #![feature(strict_provenance)]
2 #![feature(pointer_byte_offsets)]
3 use std::{mem, ptr};
4
5 const PTR_SIZE: usize = mem::size_of::<&i32>();
6
7 fn main() {
8     basic();
9     partial_overwrite_then_restore();
10     bytewise_ptr_methods();
11     bytewise_custom_memcpy();
12     bytewise_custom_memcpy_chunked();
13 }
14
15 /// Some basic smoke tests for provenance.
16 fn basic() {
17     let x = &42;
18     let ptr = x as *const i32;
19     let addr: usize = unsafe { mem::transmute(ptr) }; // an integer without provenance
20     // But we can give provenance back via `with_addr`.
21     let ptr_back = ptr.with_addr(addr);
22     assert_eq!(unsafe { *ptr_back }, 42);
23
24     // It is preserved by MaybeUninit.
25     let addr_mu: mem::MaybeUninit<usize> = unsafe { mem::transmute(ptr) };
26     let ptr_back: *const i32 = unsafe { mem::transmute(addr_mu) };
27     assert_eq!(unsafe { *ptr_back }, 42);
28 }
29
30 /// Overwrite one byte of a pointer, then restore it.
31 fn partial_overwrite_then_restore() {
32     unsafe fn ptr_bytes<'x>(ptr: &'x mut *const i32) -> &'x mut [mem::MaybeUninit<u8>; PTR_SIZE] {
33         mem::transmute(ptr)
34     }
35
36     // Returns a value with the same provenance as `x` but 0 for the integer value.
37     // `x` must be initialized.
38     unsafe fn zero_with_provenance(x: mem::MaybeUninit<u8>) -> mem::MaybeUninit<u8> {
39         let ptr = [x; PTR_SIZE];
40         let ptr: *const i32 = mem::transmute(ptr);
41         let mut ptr = ptr.with_addr(0);
42         ptr_bytes(&mut ptr)[0]
43     }
44
45     unsafe {
46         let ptr = &42;
47         let mut ptr = ptr as *const i32;
48         // Get a bytewise view of the pointer.
49         let ptr_bytes = ptr_bytes(&mut ptr);
50
51         // The highest bytes must be 0 for this to work.
52         let hi = if cfg!(target_endian = "little") { ptr_bytes.len() - 1 } else { 0 };
53         assert_eq!(*ptr_bytes[hi].as_ptr().cast::<u8>(), 0);
54         // Overwrite provenance on the last byte.
55         ptr_bytes[hi] = mem::MaybeUninit::new(0);
56         // Restore it from the another byte.
57         ptr_bytes[hi] = zero_with_provenance(ptr_bytes[1]);
58
59         // Now ptr should be good again.
60         assert_eq!(*ptr, 42);
61     }
62 }
63
64 fn bytewise_ptr_methods() {
65     let mut ptr1 = &1;
66     let mut ptr2 = &2;
67
68     // Swap them, bytewise.
69     unsafe {
70         ptr::swap_nonoverlapping(
71             &mut ptr1 as *mut _ as *mut mem::MaybeUninit<u8>,
72             &mut ptr2 as *mut _ as *mut mem::MaybeUninit<u8>,
73             mem::size_of::<&i32>(),
74         );
75     }
76
77     // Make sure they still work.
78     assert_eq!(*ptr1, 2);
79     assert_eq!(*ptr2, 1);
80
81     // TODO: also test ptr::swap, ptr::copy, ptr::copy_nonoverlapping.
82 }
83
84 fn bytewise_custom_memcpy() {
85     unsafe fn memcpy<T>(to: *mut T, from: *const T) {
86         let to = to.cast::<mem::MaybeUninit<u8>>();
87         let from = from.cast::<mem::MaybeUninit<u8>>();
88         for i in 0..mem::size_of::<T>() {
89             let b = from.add(i).read();
90             to.add(i).write(b);
91         }
92     }
93
94     let ptr1 = &1;
95     let mut ptr2 = &2;
96
97     // Copy, bytewise.
98     unsafe { memcpy(&mut ptr2, &ptr1) };
99
100     // Make sure they still work.
101     assert_eq!(*ptr1, 1);
102     assert_eq!(*ptr2, 1);
103 }
104
105 fn bytewise_custom_memcpy_chunked() {
106     unsafe fn memcpy<T>(to: *mut T, from: *const T) {
107         assert!(mem::size_of::<T>() % mem::size_of::<usize>() == 0);
108         let count = mem::size_of::<T>() / mem::size_of::<usize>();
109         let to = to.cast::<mem::MaybeUninit<usize>>();
110         let from = from.cast::<mem::MaybeUninit<usize>>();
111         for i in 0..count {
112             let b = from.add(i).read();
113             to.add(i).write(b);
114         }
115     }
116
117     // Prepare an array where pointers are stored at... interesting... offsets.
118     let mut data = [0usize; 2 * PTR_SIZE];
119     let mut offsets = vec![];
120     for i in 0..mem::size_of::<usize>() {
121         // We have 2*PTR_SIZE room for each of these pointers.
122         let base = i * 2 * PTR_SIZE;
123         // This one is mis-aligned by `i`.
124         let offset = base + i;
125         offsets.push(offset);
126         // Store it there.
127         unsafe { data.as_mut_ptr().byte_add(offset).cast::<&i32>().write_unaligned(&42) };
128     }
129
130     // Now memcpy that.
131     let mut data2 = [0usize; 2 * PTR_SIZE];
132     unsafe { memcpy(&mut data2, &data) };
133
134     // And check the result.
135     for &offset in &offsets {
136         let ptr = unsafe { data2.as_ptr().byte_add(offset).cast::<&i32>().read_unaligned() };
137         assert_eq!(*ptr, 42);
138     }
139 }