1 //! Generate various kinds of Wasm memory. 2 3 use anyhow::Result; 4 use arbitrary::{Arbitrary, Unstructured}; 5 use std::ops::Range; 6 use wasmtime::{LinearMemory, MemoryCreator, MemoryType}; 7 8 /// Configuration for linear memories in Wasmtime. 9 #[derive(Arbitrary, Clone, Debug, Eq, Hash, PartialEq)] 10 pub enum MemoryConfig { 11 /// Configuration for linear memories which correspond to normal 12 /// configuration settings in `wasmtime` itself. This will tweak various 13 /// parameters about static/dynamic memories. 14 Normal(NormalMemoryConfig), 15 16 /// Configuration to force use of a linear memory that's unaligned at its 17 /// base address to force all wasm addresses to be unaligned at the hardware 18 /// level, even if the wasm itself correctly aligns everything internally. 19 CustomUnaligned, 20 } 21 22 /// Represents a normal memory configuration for Wasmtime with the given 23 /// static and dynamic memory sizes. 24 #[derive(Clone, Debug, Eq, Hash, PartialEq)] 25 #[allow(missing_docs)] 26 pub struct NormalMemoryConfig { 27 pub static_memory_maximum_size: Option<u64>, 28 pub static_memory_guard_size: Option<u64>, 29 pub dynamic_memory_guard_size: Option<u64>, 30 pub guard_before_linear_memory: bool, 31 } 32 33 impl<'a> Arbitrary<'a> for NormalMemoryConfig { 34 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> { 35 // This attempts to limit memory and guard sizes to 32-bit ranges so 36 // we don't exhaust a 64-bit address space easily. 37 let mut ret = Self { 38 static_memory_maximum_size: <Option<u32> as Arbitrary>::arbitrary(u)?.map(Into::into), 39 static_memory_guard_size: <Option<u32> as Arbitrary>::arbitrary(u)?.map(Into::into), 40 dynamic_memory_guard_size: <Option<u32> as Arbitrary>::arbitrary(u)?.map(Into::into), 41 guard_before_linear_memory: u.arbitrary()?, 42 }; 43 44 if let Some(dynamic) = ret.dynamic_memory_guard_size { 45 let statik = ret.static_memory_guard_size.unwrap_or(2 << 30); 46 ret.static_memory_guard_size = Some(statik.max(dynamic)); 47 } 48 Ok(ret) 49 } 50 } 51 52 /// A custom "linear memory allocator" for wasm which only works with the 53 /// "dynamic" mode of configuration where wasm always does explicit bounds 54 /// checks. 55 /// 56 /// This memory attempts to always use unaligned host addresses for the base 57 /// address of linear memory with wasm. This means that all jit loads/stores 58 /// should be unaligned, which is a "big hammer way" of testing that all our JIT 59 /// code works with unaligned addresses since alignment is not required for 60 /// correctness in wasm itself. 61 pub struct UnalignedMemory { 62 /// This memory is always one byte larger than the actual size of linear 63 /// memory. 64 src: Vec<u8>, 65 maximum: Option<usize>, 66 } 67 68 unsafe impl LinearMemory for UnalignedMemory { 69 fn byte_size(&self) -> usize { 70 // Chop off the extra byte reserved for the true byte size of this 71 // linear memory. 72 self.src.len() - 1 73 } 74 75 fn maximum_byte_size(&self) -> Option<usize> { 76 self.maximum 77 } 78 79 fn grow_to(&mut self, new_size: usize) -> Result<()> { 80 // Make sure to allocate an extra byte for our "unalignment" 81 self.src.resize(new_size + 1, 0); 82 Ok(()) 83 } 84 85 fn as_ptr(&self) -> *mut u8 { 86 // Return our allocated memory, offset by one, so that the base address 87 // of memory is always unaligned. 88 self.src[1..].as_ptr() as *mut _ 89 } 90 91 fn wasm_accessible(&self) -> Range<usize> { 92 let base = self.as_ptr() as usize; 93 let len = self.byte_size(); 94 base..base + len 95 } 96 } 97 98 /// A mechanism to generate [`UnalignedMemory`] at runtime. 99 pub struct UnalignedMemoryCreator; 100 101 unsafe impl MemoryCreator for UnalignedMemoryCreator { 102 fn new_memory( 103 &self, 104 _ty: MemoryType, 105 minimum: usize, 106 maximum: Option<usize>, 107 reserved_size_in_bytes: Option<usize>, 108 guard_size_in_bytes: usize, 109 ) -> Result<Box<dyn LinearMemory>, String> { 110 assert_eq!(guard_size_in_bytes, 0); 111 assert!(reserved_size_in_bytes.is_none() || reserved_size_in_bytes == Some(0)); 112 Ok(Box::new(UnalignedMemory { 113 src: vec![0; minimum + 1], 114 maximum, 115 })) 116 } 117 } 118