]> git.lizzy.rs Git - rust.git/blob - src/tools/miri/tests/pass/intptrcast.rs
Rollup merge of #105784 - yanns:update_stdarch, r=Amanieu
[rust.git] / src / tools / miri / tests / pass / intptrcast.rs
1 //@compile-flags: -Zmiri-permissive-provenance
2
3 use std::mem;
4
5 // This strips provenance
6 fn transmute_ptr_to_int<T>(x: *const T) -> usize {
7     unsafe { std::mem::transmute(x) }
8 }
9
10 fn cast() {
11     // Some casting-to-int with arithmetic.
12     let x = &42 as *const i32 as usize;
13     let y = x * 2;
14     assert_eq!(y, x + x);
15     let z = y as u8 as usize;
16     assert_eq!(z, y % 256);
17 }
18
19 /// Test usize->ptr cast for dangling and OOB address.
20 /// That is safe, and thus has to work.
21 fn cast_dangling() {
22     let b = Box::new(0);
23     let x = &*b as *const i32 as usize;
24     drop(b);
25     let _val = x as *const i32;
26
27     let b = Box::new(0);
28     let mut x = &*b as *const i32 as usize;
29     x += 0x100;
30     let _val = x as *const i32;
31 }
32
33 fn format() {
34     // Pointer string formatting! We can't check the output as it changes when libstd changes,
35     // but we can make sure Miri does not error.
36     format!("{:?}", &mut 13 as *mut _);
37 }
38
39 fn transmute() {
40     // Check that intptrcast is triggered for explicit casts and that it is consistent with
41     // transmuting.
42     let a: *const i32 = &42;
43     let b = transmute_ptr_to_int(a) as u8;
44     let c = a as u8;
45     assert_eq!(b, c);
46 }
47
48 fn ptr_bitops1() {
49     let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9];
50     let one = bytes.as_ptr().wrapping_offset(1);
51     let three = bytes.as_ptr().wrapping_offset(3);
52     let res = (one as usize) | (three as usize);
53     format!("{}", res);
54 }
55
56 fn ptr_bitops2() {
57     let val = 13usize;
58     let addr = &val as *const _ as usize;
59     let _val = addr & 13;
60 }
61
62 fn ptr_eq_dangling() {
63     let b = Box::new(0);
64     let x = &*b as *const i32; // soon-to-be dangling
65     drop(b);
66     let b = Box::new(0);
67     let y = &*b as *const i32; // different allocation
68     // They *could* be equal if memory was reused, but probably are not.
69     assert!(x != y);
70 }
71
72 fn ptr_eq_out_of_bounds() {
73     let b = Box::new(0);
74     let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds
75     let b = Box::new(0);
76     let y = &*b as *const i32; // different allocation
77     // They *could* be equal (with the right base addresses), but probably are not.
78     assert!(x != y);
79 }
80
81 fn ptr_eq_out_of_bounds_null() {
82     let b = Box::new(0);
83     let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds
84     // This *could* be NULL (with the right base address), but probably is not.
85     assert!(x != std::ptr::null());
86 }
87
88 fn ptr_eq_integer() {
89     let b = Box::new(0);
90     let x = &*b as *const i32;
91     // These *could* be equal (with the right base address), but probably are not.
92     assert!(x != 64 as *const i32);
93 }
94
95 fn zst_deref_of_dangling() {
96     let b = Box::new(0);
97     let addr = &*b as *const _ as usize;
98     drop(b);
99     // Now if we cast `addr` to a ptr it might pick up the dangling provenance.
100     // But if we only do a ZST deref there is no UB here!
101     let zst = addr as *const ();
102     let _val = unsafe { *zst };
103 }
104
105 fn functions() {
106     // Roundtrip a few functions through integers. Do this multiple times to make sure this does not
107     // work by chance. If we did not give unique addresses to ZST allocations -- which fn
108     // allocations are -- then we might be unable to cast back, or we might call the wrong function!
109     // Every function gets at most one address so doing a loop would not help...
110     fn fn0() -> i32 {
111         0
112     }
113     fn fn1() -> i32 {
114         1
115     }
116     fn fn2() -> i32 {
117         2
118     }
119     fn fn3() -> i32 {
120         3
121     }
122     fn fn4() -> i32 {
123         4
124     }
125     fn fn5() -> i32 {
126         5
127     }
128     fn fn6() -> i32 {
129         6
130     }
131     fn fn7() -> i32 {
132         7
133     }
134     let fns = [
135         fn0 as fn() -> i32 as *const () as usize,
136         fn1 as fn() -> i32 as *const () as usize,
137         fn2 as fn() -> i32 as *const () as usize,
138         fn3 as fn() -> i32 as *const () as usize,
139         fn4 as fn() -> i32 as *const () as usize,
140         fn5 as fn() -> i32 as *const () as usize,
141         fn6 as fn() -> i32 as *const () as usize,
142         fn7 as fn() -> i32 as *const () as usize,
143     ];
144     for (idx, &addr) in fns.iter().enumerate() {
145         let fun: fn() -> i32 = unsafe { mem::transmute(addr as *const ()) };
146         assert_eq!(fun(), idx as i32);
147     }
148 }
149
150 fn main() {
151     cast();
152     cast_dangling();
153     format();
154     transmute();
155     ptr_bitops1();
156     ptr_bitops2();
157     ptr_eq_dangling();
158     ptr_eq_out_of_bounds();
159     ptr_eq_out_of_bounds_null();
160     ptr_eq_integer();
161     zst_deref_of_dangling();
162     functions();
163 }