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> { 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 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 { 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 } 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