|
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