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