1 use proptest::prelude::*;
2 use wiggle::{GuestMemory, GuestPtr};
3 use wiggle_test::{HostMemory, MemArea, WasiCtx, impl_errno};
4
5 wiggle::from_witx!({
6 witx: ["tests/pointers.witx"],
7 });
8
9 impl_errno!(types::Errno);
10
11 impl<'a> pointers::Pointers for WasiCtx<'a> {
pointers_and_enums( &mut self, memory: &mut GuestMemory<'_>, input1: types::Excuse, input2_ptr: GuestPtr<types::Excuse>, input3_ptr: GuestPtr<types::Excuse>, input4_ptr_ptr: GuestPtr<GuestPtr<types::Excuse>>, ) -> Result<(), types::Errno>12 fn pointers_and_enums(
13 &mut self,
14 memory: &mut GuestMemory<'_>,
15 input1: types::Excuse,
16 input2_ptr: GuestPtr<types::Excuse>,
17 input3_ptr: GuestPtr<types::Excuse>,
18 input4_ptr_ptr: GuestPtr<GuestPtr<types::Excuse>>,
19 ) -> Result<(), types::Errno> {
20 println!("BAZ input1 {input1:?}");
21 let input2: types::Excuse = memory.read(input2_ptr).map_err(|e| {
22 eprintln!("input2_ptr error: {e}");
23 types::Errno::InvalidArg
24 })?;
25 println!("input2 {input2:?}");
26
27 // Read enum value from immutable ptr:
28 let input3 = memory.read(input3_ptr).map_err(|e| {
29 eprintln!("input3_ptr error: {e}");
30 types::Errno::InvalidArg
31 })?;
32 println!("input3 {input3:?}");
33
34 // Write enum to mutable ptr:
35 memory.write(input2_ptr, input3).map_err(|e| {
36 eprintln!("input2_ptr error: {e}");
37 types::Errno::InvalidArg
38 })?;
39 println!("wrote to input2_ref {input3:?}");
40
41 // Read ptr value from mutable ptr:
42 let input4_ptr: GuestPtr<types::Excuse> = memory.read(input4_ptr_ptr).map_err(|e| {
43 eprintln!("input4_ptr_ptr error: {e}");
44 types::Errno::InvalidArg
45 })?;
46
47 // Read enum value from that ptr:
48 let input4: types::Excuse = memory.read(input4_ptr).map_err(|e| {
49 eprintln!("input4_ptr error: {e}");
50 types::Errno::InvalidArg
51 })?;
52 println!("input4 {input4:?}");
53
54 // Write ptr value to mutable ptr:
55 memory.write(input4_ptr_ptr, input2_ptr).map_err(|e| {
56 eprintln!("input4_ptr_ptr error: {e}");
57 types::Errno::InvalidArg
58 })?;
59
60 Ok(())
61 }
62 }
63
excuse_strat() -> impl Strategy<Value = types::Excuse>64 fn excuse_strat() -> impl Strategy<Value = types::Excuse> {
65 prop_oneof![
66 Just(types::Excuse::DogAte),
67 Just(types::Excuse::Traffic),
68 Just(types::Excuse::Sleeping),
69 ]
70 .boxed()
71 }
72
73 #[derive(Debug)]
74 struct PointersAndEnumsExercise {
75 pub input1: types::Excuse,
76 pub input2: types::Excuse,
77 pub input2_loc: MemArea,
78 pub input3: types::Excuse,
79 pub input3_loc: MemArea,
80 pub input4: types::Excuse,
81 pub input4_loc: MemArea,
82 pub input4_ptr_loc: MemArea,
83 }
84
85 impl PointersAndEnumsExercise {
strat() -> BoxedStrategy<Self>86 pub fn strat() -> BoxedStrategy<Self> {
87 (
88 excuse_strat(),
89 excuse_strat(),
90 HostMemory::mem_area_strat(4),
91 excuse_strat(),
92 HostMemory::mem_area_strat(4),
93 excuse_strat(),
94 HostMemory::mem_area_strat(4),
95 HostMemory::mem_area_strat(4),
96 )
97 .prop_map(
98 |(
99 input1,
100 input2,
101 input2_loc,
102 input3,
103 input3_loc,
104 input4,
105 input4_loc,
106 input4_ptr_loc,
107 )| PointersAndEnumsExercise {
108 input1,
109 input2,
110 input2_loc,
111 input3,
112 input3_loc,
113 input4,
114 input4_loc,
115 input4_ptr_loc,
116 },
117 )
118 .prop_filter("non-overlapping pointers", |e| {
119 MemArea::non_overlapping_set(&[
120 e.input2_loc,
121 e.input3_loc,
122 e.input4_loc,
123 e.input4_ptr_loc,
124 ])
125 })
126 .boxed()
127 }
test(&self)128 pub fn test(&self) {
129 let mut ctx = WasiCtx::new();
130 let mut host_memory = HostMemory::new();
131 let mut memory = host_memory.guest_memory();
132
133 memory
134 .write(GuestPtr::new(self.input2_loc.ptr), self.input2)
135 .expect("input2 ref_mut");
136
137 memory
138 .write(GuestPtr::new(self.input3_loc.ptr), self.input3)
139 .expect("input3 ref_mut");
140
141 memory
142 .write(GuestPtr::new(self.input4_loc.ptr), self.input4)
143 .expect("input4 ref_mut");
144
145 memory
146 .write(GuestPtr::new(self.input4_ptr_loc.ptr), self.input4_loc.ptr)
147 .expect("input4 ptr ref_mut");
148
149 let e = pointers::pointers_and_enums(
150 &mut ctx,
151 &mut memory,
152 self.input1 as i32,
153 self.input2_loc.ptr as i32,
154 self.input3_loc.ptr as i32,
155 self.input4_ptr_loc.ptr as i32,
156 )
157 .unwrap();
158 assert_eq!(e, types::Errno::Ok as i32, "errno");
159
160 // Implementation of pointers_and_enums writes input3 to the input2_loc:
161 let written_to_input2_loc: i32 = memory
162 .read(GuestPtr::new(self.input2_loc.ptr))
163 .expect("input2 ref");
164
165 assert_eq!(
166 written_to_input2_loc, self.input3 as i32,
167 "pointers_and_enums written to input2"
168 );
169
170 // Implementation of pointers_and_enums writes input2_loc to input4_ptr_loc:
171 let written_to_input4_ptr: u32 = memory
172 .read(GuestPtr::new(self.input4_ptr_loc.ptr))
173 .expect("input4_ptr_loc ref");
174
175 assert_eq!(
176 written_to_input4_ptr, self.input2_loc.ptr,
177 "pointers_and_enums written to input4_ptr"
178 );
179 }
180 }
181 proptest! {
182 #[test]
183 fn pointers_and_enums(e in PointersAndEnumsExercise::strat()) {
184 e.test();
185 }
186 }
187