use wasmer::{Array, Memory, WasmPtr}; use crate::{Error, Result}; pub trait MemoryManipulation { fn write(&self, mem_offset: u32, value_slice: &[u8]) -> Result<()>; fn read(&self, mem_offset: u32, value_len: usize) -> Option<&[u8]>; } impl MemoryManipulation for Memory { fn write(&self, mem_offset: u32, value_slice: &[u8]) -> Result<()> { // Prepare WasmPtr let target_ptr: WasmPtr = WasmPtr::new(mem_offset); // Allocate necessary memory space on guest let guest_value_slice = match target_ptr.deref(self, 0, value_slice.len() as u32) { Some(slice) => slice, None => [].to_vec(), }; if guest_value_slice.is_empty() { return Err(Error::WasmerOomError) } // Copy bytes to guest for i in 0..value_slice.len() { guest_value_slice[i].set(value_slice[i]); } Ok(()) } fn read(&self, mem_offset: u32, value_len: usize) -> Option<&[u8]> { let memory_size = self.size().bytes().0; if mem_offset as usize + value_len > memory_size || mem_offset as usize >= memory_size { return None } let ptr = unsafe { self.view::().as_ptr().add(mem_offset as usize) as *const u8 }; unsafe { Some(std::slice::from_raw_parts(ptr, value_len)) } } } #[cfg(test)] mod tests { use super::*; use wasmer::{imports, wat2wasm, Instance, Module, Store}; fn wasmer_instance() -> Instance { let wasm_bytes = wat2wasm( br#" (module (type $add_one_t (func (param i32) (result i32))) (func $add_one_f (type $add_one_t) (param $value i32) (result i32) local.get $value i32.const 1 i32.add) (export "add_one" (func $add_one_f)) (memory $memory (export "memory") 17)) "#, ) .unwrap(); let store = Store::default(); let module = Module::new(&store, wasm_bytes).unwrap(); let import_object = imports! {}; Instance::new(&module, &import_object).unwrap() } #[test] fn can_write_on_memory() { let wasmer_instance = wasmer_instance(); let memory = wasmer_instance.exports.get_memory("memory").unwrap(); let data = String::from("data_test"); let mem_addr = 0x2220; memory.write(mem_addr as u32, data.as_bytes()).unwrap(); let ptr = unsafe { memory.view::().as_ptr().add(mem_addr as usize) as *const u8 }; let slice_raw = unsafe { std::slice::from_raw_parts(ptr, data.len()) }; assert_eq!(data.as_bytes(), slice_raw); } #[test] fn can_read_from_memory() { let wasmer_instance = wasmer_instance(); let memory = wasmer_instance.exports.get_memory("memory").unwrap(); let data = String::from("data_test"); let mem_addr = 0x2220; memory.write(mem_addr as u32, data.as_bytes()).unwrap(); let slice_raw = memory.read(mem_addr as u32, data.as_bytes().len()).unwrap(); assert_eq!(data.as_bytes(), slice_raw); } }