|
5 | 5 | #![feature(box_as_ptr)] |
6 | 6 |
|
7 | 7 | use std::mem::MaybeUninit; |
| 8 | +use std::ptr::null; |
8 | 9 |
|
9 | 10 | fn main() { |
10 | | - test_modify_int(); |
| 11 | + test_increment_int(); |
11 | 12 |
|
12 | 13 | test_init_int(); |
13 | 14 |
|
14 | 15 | test_init_array(); |
15 | 16 |
|
16 | | - test_init_interior_mutable(); |
| 17 | + test_init_static_inner(); |
| 18 | + |
| 19 | + test_expose_int(); |
17 | 20 |
|
18 | 21 | test_swap_ptr(); |
19 | 22 |
|
20 | | - test_interact_dangling(); |
| 23 | + test_swap_nested_ptr(); |
| 24 | + |
| 25 | + test_swap_tuple(); |
| 26 | + |
| 27 | + test_overwrite_dangling(); |
21 | 28 |
|
22 | | - test_inner_alloc_exposed(); |
| 29 | + test_expose_triple(); |
23 | 30 | } |
24 | 31 |
|
25 | | -fn test_modify_int() { |
| 32 | +// Test function that modifies an int. |
| 33 | +fn test_increment_int() { |
26 | 34 | extern "C" { |
27 | | - fn modify_int(ptr: *mut i32); |
| 35 | + fn increment_int(ptr: *mut i32); |
28 | 36 | } |
29 | 37 |
|
30 | 38 | let mut x = 11; |
31 | | - unsafe { modify_int(&mut x) }; |
32 | 39 |
|
| 40 | + unsafe { increment_int(&mut x) }; |
33 | 41 | assert_eq!(x, 12); |
34 | 42 | } |
35 | 43 |
|
| 44 | +// Test function that initializes an int. |
36 | 45 | fn test_init_int() { |
37 | 46 | extern "C" { |
38 | | - fn init_int(ptr: *mut i32); |
| 47 | + fn init_int(ptr: *mut i32, val: i32); |
39 | 48 | } |
40 | 49 |
|
41 | 50 | let mut x = MaybeUninit::<i32>::uninit(); |
| 51 | + let val = 21; |
| 52 | + |
42 | 53 | let x = unsafe { |
43 | | - init_int(x.as_mut_ptr()); |
| 54 | + init_int(x.as_mut_ptr(), val); |
44 | 55 | x.assume_init() |
45 | 56 | }; |
46 | | - |
47 | | - assert_eq!(x, 21); |
| 57 | + assert_eq!(x, val); |
48 | 58 | } |
49 | 59 |
|
| 60 | +// Test function that initializes an array. |
50 | 61 | fn test_init_array() { |
51 | 62 | extern "C" { |
52 | | - fn init_array(ptr: *mut i32, len: usize); |
| 63 | + fn init_array(ptr: *mut i32, len: usize, val: i32); |
53 | 64 | } |
54 | 65 |
|
55 | 66 | const LEN: usize = 3; |
56 | | - |
57 | 67 | let mut array = MaybeUninit::<[i32; LEN]>::uninit(); |
| 68 | + let val = 31; |
| 69 | + |
58 | 70 | let array = unsafe { |
59 | | - init_array(array.as_mut_ptr().cast::<i32>(), LEN); |
| 71 | + init_array(array.as_mut_ptr().cast::<i32>(), LEN, val); |
60 | 72 | array.assume_init() |
61 | 73 | }; |
62 | | - |
63 | | - assert_eq!(array, [31; LEN]); |
| 74 | + assert_eq!(array, [val; LEN]); |
64 | 75 | } |
65 | 76 |
|
66 | | -fn test_init_interior_mutable() { |
| 77 | +// Test function that initializes an int pointed to by an immutable static. |
| 78 | +fn test_init_static_inner() { |
| 79 | + #[repr(C)] |
| 80 | + struct SyncPtr { |
| 81 | + ptr: *mut i32 |
| 82 | + } |
| 83 | + unsafe impl Sync for SyncPtr {} |
| 84 | + |
67 | 85 | extern "C" { |
68 | | - fn init_interior_mutable(pptr: *const UnsafeInterior); |
| 86 | + fn init_static_inner(s_ptr: *const SyncPtr, val: i32); |
69 | 87 | } |
70 | 88 |
|
71 | | - #[repr(C)] |
72 | | - struct UnsafeInterior { |
73 | | - mut_ptr: *mut i32 |
| 89 | + static mut INNER: MaybeUninit<i32> = MaybeUninit::uninit(); |
| 90 | + #[allow(static_mut_refs)] |
| 91 | + static STATIC: SyncPtr = SyncPtr { ptr: unsafe { INNER.as_mut_ptr() } }; |
| 92 | + let val = 41; |
| 93 | + |
| 94 | + let inner = unsafe { |
| 95 | + init_static_inner(&STATIC, val); |
| 96 | + INNER.assume_init() |
| 97 | + }; |
| 98 | + assert_eq!(inner, val); |
| 99 | +} |
| 100 | + |
| 101 | +// Test function that writes a pointer and exposes the alloc of its int argument. |
| 102 | +fn test_expose_int() { |
| 103 | + extern "C" { |
| 104 | + fn expose_int(int_ptr: *const i32, pptr: *mut *const i32); |
74 | 105 | } |
75 | | - unsafe impl Sync for UnsafeInterior {} |
76 | | - |
77 | | - let mut x = MaybeUninit::<i32>::uninit(); |
78 | | - let unsafe_interior = UnsafeInterior { mut_ptr: x.as_mut_ptr() }; |
79 | | - unsafe { init_interior_mutable(&unsafe_interior) }; |
80 | 106 |
|
81 | | - assert_eq!(unsafe { x.assume_init() }, 51); |
| 107 | + let x = 51; |
| 108 | + let mut ptr = std::ptr::null(); |
| 109 | + |
| 110 | + unsafe { expose_int(&x, &mut ptr) }; |
| 111 | + assert_eq!(unsafe { *ptr }, x); |
82 | 112 | } |
83 | 113 |
|
| 114 | +// Test function that swaps two pointers and exposes the alloc of an int. |
84 | 115 | fn test_swap_ptr() { |
85 | 116 | extern "C" { |
86 | 117 | fn swap_ptr(pptr0: *mut *const i32, pptr1: *mut *const i32); |
87 | 118 | } |
88 | 119 |
|
89 | | - let x = 41; |
90 | | - let mut ptr0 = &raw const x; |
91 | | - let mut ptr1 = std::ptr::null(); |
| 120 | + let x = 61; |
| 121 | + let (mut ptr0, mut ptr1) = (&raw const x, null()); |
| 122 | + |
92 | 123 | unsafe { swap_ptr(&mut ptr0, &mut ptr1) }; |
| 124 | + assert_eq!(unsafe { *ptr1 }, x); |
| 125 | +} |
| 126 | + |
| 127 | +// Test function that swaps two nested pointers and exposes the alloc of an int. |
| 128 | +fn test_swap_nested_ptr() { |
| 129 | + extern "C" { |
| 130 | + fn swap_nested_ptr(ppptr0: *mut *mut *const i32, ppptr1: *mut *mut *const i32); |
| 131 | + } |
| 132 | + |
| 133 | + let x = 71; |
| 134 | + let (mut ptr0, mut ptr1) = (&raw const x, null()); |
| 135 | + let (mut pptr0, mut pptr1) = (&raw mut ptr0, &raw mut ptr1); |
93 | 136 |
|
| 137 | + unsafe { swap_nested_ptr(&mut pptr0, &mut pptr1) } |
94 | 138 | assert_eq!(unsafe { *ptr1 }, x); |
95 | 139 | } |
96 | 140 |
|
97 | | -fn test_interact_dangling() { |
| 141 | +// Test function that swaps two pointers in a struct and exposes the alloc of an int. |
| 142 | +fn test_swap_tuple() { |
| 143 | + #[repr(C)] |
| 144 | + struct Tuple { |
| 145 | + ptr0: *const i32, |
| 146 | + ptr1: *const i32, |
| 147 | + } |
| 148 | + |
| 149 | + extern "C" { |
| 150 | + fn swap_tuple(t_ptr: *mut Tuple); |
| 151 | + } |
| 152 | + |
| 153 | + let x = 81; |
| 154 | + let mut tuple = Tuple { ptr0: &raw const x, ptr1: null() }; |
| 155 | + |
| 156 | + unsafe { swap_tuple(&mut tuple) } |
| 157 | + assert_eq!(unsafe { *tuple.ptr1 }, x); |
| 158 | +} |
| 159 | + |
| 160 | +// Test function that interacts with a dangling pointer. |
| 161 | +fn test_overwrite_dangling() { |
98 | 162 | extern "C" { |
99 | 163 | fn overwrite_ptr(pptr: *mut *const i32); |
100 | 164 | } |
101 | 165 |
|
102 | | - let x = Box::new(61); |
103 | | - let mut ptr = Box::as_ptr(&x); |
104 | | - drop(x); |
| 166 | + let b = Box::new(91); |
| 167 | + let mut ptr = Box::as_ptr(&b); |
| 168 | + drop(b); |
105 | 169 | unsafe { overwrite_ptr(&mut ptr) }; |
106 | 170 |
|
107 | | - assert_eq!(ptr, std::ptr::null()); |
| 171 | + assert_eq!(ptr, null()); |
108 | 172 | } |
109 | 173 |
|
110 | | -// TODO: Write tests for correctly exposing: [initial allocation; recursively all allocations; previously unexposed pointers]. |
111 | | -fn test_inner_alloc_exposed() { |
| 174 | +// Test function that interacts with a struct storing a dangling pointer. |
| 175 | +fn test_expose_triple() { |
| 176 | + #[repr(C)] |
| 177 | + struct Triple { |
| 178 | + ptr0: *const i32, |
| 179 | + ptr1: *const i32, |
| 180 | + ptr2: *const i32, |
| 181 | + } |
| 182 | + |
112 | 183 | extern "C" { |
113 | | - fn blackbox(ptr: *mut *mut *const i32); |
| 184 | + fn expose_triple(t_ptr: *const Triple); |
114 | 185 | } |
115 | 186 |
|
116 | | - let x = 71i32; |
117 | | - let mut ptr = &raw const x; |
118 | | - let mut pptr = &raw mut ptr; |
119 | | - unsafe { blackbox(&mut pptr) } |
| 187 | + let x = 101; |
| 188 | + let y = 111; |
| 189 | + let b = Box::new(121); |
| 190 | + let ptr = Box::as_ptr(&b); |
| 191 | + drop(b); |
| 192 | + let triple = Triple { ptr0: &raw const x, ptr1: ptr, ptr2: &raw const y }; |
120 | 193 |
|
121 | | - assert_eq!(unsafe { *ptr }, x); |
| 194 | + unsafe { expose_triple(&triple) } |
| 195 | + assert_eq!(unsafe { *triple.ptr2 }, y); |
122 | 196 | } |
0 commit comments