1 #[cfg(not(target_os = "windows"))] 2 mod not_for_windows { 3 use wasmtime::*; 4 use wasmtime_environ::{WASM32_MAX_PAGES, WASM_PAGE_SIZE}; 5 6 use rsix::io::{mmap_anonymous, mprotect, munmap, MapFlags, MprotectFlags, ProtFlags}; 7 8 use std::convert::TryFrom; 9 use std::ptr::null_mut; 10 use std::sync::{Arc, Mutex}; 11 12 struct CustomMemory { 13 mem: usize, 14 size: usize, 15 guard_size: usize, 16 used_wasm_bytes: usize, 17 glob_bytes_counter: Arc<Mutex<usize>>, 18 } 19 20 impl CustomMemory { 21 unsafe fn new(minimum: usize, maximum: usize, glob_counter: Arc<Mutex<usize>>) -> Self { 22 let page_size = rsix::process::page_size(); 23 let guard_size = page_size; 24 let size = maximum + guard_size; 25 assert_eq!(size % page_size, 0); // we rely on WASM_PAGE_SIZE being multiple of host page size 26 27 let mem = mmap_anonymous(null_mut(), size, ProtFlags::empty(), MapFlags::PRIVATE) 28 .expect("mmap failed"); 29 30 mprotect(mem, minimum, MprotectFlags::READ | MprotectFlags::WRITE) 31 .expect("mprotect failed"); 32 *glob_counter.lock().unwrap() += minimum; 33 34 Self { 35 mem: mem as usize, 36 size, 37 guard_size, 38 used_wasm_bytes: minimum, 39 glob_bytes_counter: glob_counter, 40 } 41 } 42 } 43 44 impl Drop for CustomMemory { 45 fn drop(&mut self) { 46 *self.glob_bytes_counter.lock().unwrap() -= self.used_wasm_bytes; 47 unsafe { munmap(self.mem as *mut _, self.size).expect("munmap failed") }; 48 } 49 } 50 51 unsafe impl LinearMemory for CustomMemory { 52 fn byte_size(&self) -> usize { 53 self.used_wasm_bytes 54 } 55 56 fn maximum_byte_size(&self) -> Option<usize> { 57 Some(self.size - self.guard_size) 58 } 59 60 fn grow_to(&mut self, new_size: usize) -> Result<(), anyhow::Error> { 61 println!("grow to {:x}", new_size); 62 let delta = new_size - self.used_wasm_bytes; 63 unsafe { 64 let start = (self.mem as *mut u8).add(self.used_wasm_bytes) as _; 65 mprotect(start, delta, MprotectFlags::READ | MprotectFlags::WRITE) 66 .expect("mprotect failed"); 67 } 68 69 *self.glob_bytes_counter.lock().unwrap() += delta; 70 self.used_wasm_bytes = new_size; 71 Ok(()) 72 } 73 74 fn as_ptr(&self) -> *mut u8 { 75 self.mem as *mut u8 76 } 77 } 78 79 struct CustomMemoryCreator { 80 pub num_created_memories: Mutex<usize>, 81 pub num_total_bytes: Arc<Mutex<usize>>, 82 } 83 84 impl CustomMemoryCreator { 85 pub fn new() -> Self { 86 Self { 87 num_created_memories: Mutex::new(0), 88 num_total_bytes: Arc::new(Mutex::new(0)), 89 } 90 } 91 } 92 93 unsafe impl MemoryCreator for CustomMemoryCreator { 94 fn new_memory( 95 &self, 96 ty: MemoryType, 97 minimum: usize, 98 maximum: Option<usize>, 99 reserved_size: Option<usize>, 100 guard_size: usize, 101 ) -> Result<Box<dyn LinearMemory>, String> { 102 assert_eq!(guard_size, 0); 103 assert!(reserved_size.is_none()); 104 assert!(!ty.is_64()); 105 unsafe { 106 let mem = Box::new(CustomMemory::new( 107 minimum, 108 maximum.unwrap_or( 109 usize::try_from(WASM32_MAX_PAGES * u64::from(WASM_PAGE_SIZE)).unwrap(), 110 ), 111 self.num_total_bytes.clone(), 112 )); 113 *self.num_created_memories.lock().unwrap() += 1; 114 Ok(mem) 115 } 116 } 117 } 118 119 fn config() -> (Store<()>, Arc<CustomMemoryCreator>) { 120 let mem_creator = Arc::new(CustomMemoryCreator::new()); 121 let mut config = Config::new(); 122 config 123 .with_host_memory(mem_creator.clone()) 124 .static_memory_maximum_size(0) 125 .dynamic_memory_guard_size(0); 126 (Store::new(&Engine::new(&config).unwrap(), ()), mem_creator) 127 } 128 129 #[test] 130 fn host_memory() -> anyhow::Result<()> { 131 let (mut store, mem_creator) = config(); 132 let module = Module::new( 133 store.engine(), 134 r#" 135 (module 136 (memory (export "memory") 1) 137 ) 138 "#, 139 )?; 140 Instance::new(&mut store, &module, &[])?; 141 142 assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 1); 143 144 Ok(()) 145 } 146 147 #[test] 148 fn host_memory_grow() -> anyhow::Result<()> { 149 let (mut store, mem_creator) = config(); 150 let module = Module::new( 151 store.engine(), 152 r#" 153 (module 154 (func $f (drop (memory.grow (i32.const 1)))) 155 (memory (export "memory") 1 2) 156 (start $f) 157 ) 158 "#, 159 )?; 160 161 Instance::new(&mut store, &module, &[])?; 162 let instance2 = Instance::new(&mut store, &module, &[])?; 163 164 assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 2); 165 166 assert_eq!( 167 instance2 168 .get_memory(&mut store, "memory") 169 .unwrap() 170 .size(&store), 171 2 172 ); 173 174 // we take the lock outside the assert, so it won't get poisoned on assert failure 175 let tot_pages = *mem_creator.num_total_bytes.lock().unwrap(); 176 assert_eq!(tot_pages, (4 * WASM_PAGE_SIZE) as usize); 177 178 drop(store); 179 let tot_pages = *mem_creator.num_total_bytes.lock().unwrap(); 180 assert_eq!(tot_pages, 0); 181 182 Ok(()) 183 } 184 } 185