diff --git a/crates/cranelift/src/func_environ.rs b/crates/cranelift/src/func_environ.rs index 939ef6fde9e6..896a55211ca1 100644 --- a/crates/cranelift/src/func_environ.rs +++ b/crates/cranelift/src/func_environ.rs @@ -563,44 +563,26 @@ impl<'module_environment> FuncEnvironment<'module_environment> { } #[cfg(feature = "wmemcheck")] - fn hook_malloc_exit(&mut self, builder: &mut FunctionBuilder, retvals: &[ir::Value]) { - let check_malloc = self.builtin_functions.check_malloc(builder.func); - let vmctx = self.vmctx_val(&mut builder.cursor()); - let func_args = builder - .func - .dfg - .block_params(builder.func.layout.entry_block().unwrap()); - let len = if func_args.len() < 3 { - return; - } else { - // If a function named `malloc` has at least one argument, we assume the - // first argument is the requested allocation size. - func_args[2] - }; - let retval = if retvals.len() < 1 { - return; - } else { - retvals[0] - }; - builder.ins().call(check_malloc, &[vmctx, retval, len]); - } - - #[cfg(feature = "wmemcheck")] - fn hook_free_exit(&mut self, builder: &mut FunctionBuilder) { - let check_free = self.builtin_functions.check_free(builder.func); + fn hook_memcheck_exit( + &mut self, + builder: &mut FunctionBuilder, + builtin_memcheck_check: ir::FuncRef, + expected_arg_count: usize, + retvals: &[ir::Value], + ) { let vmctx = self.vmctx_val(&mut builder.cursor()); let func_args = builder .func .dfg .block_params(builder.func.layout.entry_block().unwrap()); - let ptr = if func_args.len() < 3 { + if func_args.len() < expected_arg_count + 2 { + // Assume the first n arguments are the expected ones return; - } else { - // If a function named `free` has at least one argument, we assume the - // first argument is a pointer to memory. - func_args[2] - }; - builder.ins().call(check_free, &[vmctx, ptr]); + } + let mut args = vec![vmctx]; + args.extend_from_slice(&retvals); + args.extend_from_slice(&func_args[2..2 + expected_arg_count]); + builder.ins().call(builtin_memcheck_check, &args); } fn epoch_ptr(&mut self, builder: &mut FunctionBuilder<'_>) -> ir::Value { @@ -927,17 +909,10 @@ impl<'module_environment> FuncEnvironment<'module_environment> { } #[cfg(feature = "wmemcheck")] - fn check_malloc_start(&mut self, builder: &mut FunctionBuilder) { - let malloc_start = self.builtin_functions.malloc_start(builder.func); - let vmctx = self.vmctx_val(&mut builder.cursor()); - builder.ins().call(malloc_start, &[vmctx]); - } - - #[cfg(feature = "wmemcheck")] - fn check_free_start(&mut self, builder: &mut FunctionBuilder) { - let free_start = self.builtin_functions.free_start(builder.func); + fn check_allocator_start(&mut self, builder: &mut FunctionBuilder) { + let allocator_start = self.builtin_functions.allocator_start(builder.func); let vmctx = self.vmctx_val(&mut builder.cursor()); - builder.ins().call(free_start, &[vmctx]); + builder.ins().call(allocator_start, &[vmctx]); } #[cfg(feature = "wmemcheck")] @@ -3088,11 +3063,15 @@ impl<'module_environment> crate::translate::FuncEnvironment #[cfg(feature = "wmemcheck")] if self.wmemcheck { - let func_name = self.current_func_name(builder); - if func_name == Some("malloc") { - self.check_malloc_start(builder); - } else if func_name == Some("free") { - self.check_free_start(builder); + match self.current_func_name(builder) { + Some("malloc") + | Some("free") + | Some("calloc") + | Some("realloc") + | Some("posix_memalign") + | Some("aligned_alloc") + | Some("malloc_usable_size") => self.check_allocator_start(builder), + _ => (), } } @@ -3141,11 +3120,41 @@ impl<'module_environment> crate::translate::FuncEnvironment #[cfg(feature = "wmemcheck")] fn handle_before_return(&mut self, retvals: &[ir::Value], builder: &mut FunctionBuilder) { if self.wmemcheck { - let func_name = self.current_func_name(builder); - if func_name == Some("malloc") { - self.hook_malloc_exit(builder, retvals); - } else if func_name == Some("free") { - self.hook_free_exit(builder); + let name = self.current_func_name(builder); + match name { + Some("malloc") => { + let check_malloc = self.builtin_functions.check_malloc(builder.func); + self.hook_memcheck_exit(builder, check_malloc, 1, retvals) + } + Some("free") => { + let check_free = self.builtin_functions.check_free(builder.func); + self.hook_memcheck_exit(builder, check_free, 1, &[]) + } + Some("calloc") => { + let check_calloc = self.builtin_functions.check_calloc(builder.func); + self.hook_memcheck_exit(builder, check_calloc, 2, retvals) + } + Some("realloc") => { + let check_realloc = self.builtin_functions.check_realloc(builder.func); + self.hook_memcheck_exit(builder, check_realloc, 2, retvals) + } + Some("posix_memalign") => { + let check_posix_memalign = + self.builtin_functions.check_posix_memalign(builder.func); + self.hook_memcheck_exit(builder, check_posix_memalign, 3, retvals) + } + Some("aligned_alloc") => { + let check_aligned_alloc = + self.builtin_functions.check_aligned_alloc(builder.func); + self.hook_memcheck_exit(builder, check_aligned_alloc, 2, retvals) + } + Some("malloc_usable_size") => { + let check_malloc_usable_size = self + .builtin_functions + .check_malloc_usable_size(builder.func); + self.hook_memcheck_exit(builder, check_malloc_usable_size, 1, retvals) + } + _ => (), } } } diff --git a/crates/environ/src/builtin.rs b/crates/environ/src/builtin.rs index 090db85bee84..f94a129d7281 100644 --- a/crates/environ/src/builtin.rs +++ b/crates/environ/src/builtin.rs @@ -41,24 +41,36 @@ macro_rules! foreach_builtin_function { out_of_gas(vmctx: vmctx); // Invoked when we reach a new epoch. new_epoch(vmctx: vmctx) -> i64; + // Invoked before memory allocation functions are called. + #[cfg(feature = "wmemcheck")] + allocator_start(vmctx: vmctx); // Invoked before malloc returns. #[cfg(feature = "wmemcheck")] check_malloc(vmctx: vmctx, addr: i32, len: i32) -> i32; // Invoked before the free returns. #[cfg(feature = "wmemcheck")] check_free(vmctx: vmctx, addr: i32) -> i32; + // Invoked before calloc returns. + #[cfg(feature = "wmemcheck")] + check_calloc(vmctx: vmctx, addr: i32, count: i32, size: i32) -> i32; + // Invoked before realloc returns. + #[cfg(feature = "wmemcheck")] + check_realloc(vmctx: vmctx, end_addr: i32, start_addr: i32, len: i32) -> i32; + // Invoked before posix_memalign returns. + #[cfg(feature = "wmemcheck")] + check_posix_memalign(vmctx: vmctx, result: i32, outptr: i32, alignment: i32, size: i32) -> i32; + // Invoked before aligned_alloc returns. + #[cfg(feature = "wmemcheck")] + check_aligned_alloc(vmctx: vmctx, outptr: i32, alignment: i32, size: i32) -> i32; + // Invoked before malloc_usable_size returns. + #[cfg(feature = "wmemcheck")] + check_malloc_usable_size(vmctx: vmctx, len: i32, addr: i32) -> i32; // Invoked before a load is executed. #[cfg(feature = "wmemcheck")] check_load(vmctx: vmctx, num_bytes: i32, addr: i32, offset: i32) -> i32; // Invoked before a store is executed. #[cfg(feature = "wmemcheck")] check_store(vmctx: vmctx, num_bytes: i32, addr: i32, offset: i32) -> i32; - // Invoked after malloc is called. - #[cfg(feature = "wmemcheck")] - malloc_start(vmctx: vmctx); - // Invoked after free is called. - #[cfg(feature = "wmemcheck")] - free_start(vmctx: vmctx); // Invoked when wasm stack pointer is updated. #[cfg(feature = "wmemcheck")] update_stack_pointer(vmctx: vmctx, value: i32); diff --git a/crates/wasmtime/src/runtime/vm/instance.rs b/crates/wasmtime/src/runtime/vm/instance.rs index 7dbf4cf85152..137d84287a08 100644 --- a/crates/wasmtime/src/runtime/vm/instance.rs +++ b/crates/wasmtime/src/runtime/vm/instance.rs @@ -336,7 +336,7 @@ impl Instance { .unwrap_or(0) * 64 * 1024; - Some(Wmemcheck::new(size as usize)) + Some(Wmemcheck::new(size as usize, 4, false)) } else { None } diff --git a/crates/wasmtime/src/runtime/vm/libcalls.rs b/crates/wasmtime/src/runtime/vm/libcalls.rs index f91426d2970f..728193a3a332 100644 --- a/crates/wasmtime/src/runtime/vm/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/libcalls.rs @@ -63,8 +63,11 @@ use core::time::Duration; use wasmtime_environ::Unsigned; use wasmtime_environ::{DataIndex, ElemIndex, FuncIndex, MemoryIndex, TableIndex, Trap}; #[cfg(feature = "wmemcheck")] -use wasmtime_wmemcheck::AccessError::{ - DoubleMalloc, InvalidFree, InvalidRead, InvalidWrite, OutOfBounds, +use wasmtime_wmemcheck::{ + AccessError, + AccessError::{ + DoubleMalloc, InvalidFree, InvalidRead, InvalidRealloc, InvalidWrite, OutOfBounds, + }, }; /// Raw functions which are actually called from compiled code. @@ -1108,6 +1111,28 @@ fn new_epoch(store: &mut dyn VMStore, _instance: &mut Instance) -> Result { store.new_epoch() } +#[cfg(feature = "wmemcheck")] +fn check_memcheck_result(result: Result<(), AccessError>) -> Result { + match result { + Ok(()) => Ok(0), + Err(DoubleMalloc { addr, len }) => { + bail!("Double malloc at addr {:#x} of size {}", addr, len) + } + Err(OutOfBounds { addr, len }) => { + bail!("Malloc out of bounds at addr {:#x} of size {}", addr, len) + } + Err(InvalidFree { addr }) => { + bail!("Invalid free at addr {:#x}", addr) + } + Err(InvalidRealloc { addr }) => { + bail!("Invalid realloc at addr {:#x}", addr) + } + _ => { + panic!("unreachable") + } + } +} + // Hook for validating malloc using wmemcheck_state. #[cfg(feature = "wmemcheck")] unsafe fn check_malloc( @@ -1117,22 +1142,9 @@ unsafe fn check_malloc( len: u32, ) -> Result { if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { - let result = wmemcheck_state.malloc(addr as usize, len as usize); + let result = wmemcheck_state.allocate(addr as usize, len as usize, false); wmemcheck_state.memcheck_on(); - match result { - Ok(()) => { - return Ok(0); - } - Err(DoubleMalloc { addr, len }) => { - bail!("Double malloc at addr {:#x} of size {}", addr, len) - } - Err(OutOfBounds { addr, len }) => { - bail!("Malloc out of bounds at addr {:#x} of size {}", addr, len); - } - _ => { - panic!("unreachable") - } - } + return check_memcheck_result(result); } Ok(0) } @@ -1143,21 +1155,95 @@ unsafe fn check_free(_store: &mut dyn VMStore, instance: &mut Instance, addr: u3 if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { let result = wmemcheck_state.free(addr as usize); wmemcheck_state.memcheck_on(); - match result { - Ok(()) => { - return Ok(0); - } - Err(InvalidFree { addr }) => { - bail!("Invalid free at addr {:#x}", addr) - } - _ => { - panic!("unreachable") + return check_memcheck_result(result); + } + Ok(0) +} + +// Hook for validating calloc using wmemcheck_state. +#[cfg(feature = "wmemcheck")] +unsafe fn check_calloc( + _store: &mut dyn VMStore, + instance: &mut Instance, + addr: u32, + count: u32, + size: u32, +) -> Result { + if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { + let result = wmemcheck_state.allocate(addr as usize, (count * size) as usize, true); + wmemcheck_state.memcheck_on(); + return check_memcheck_result(result); + } + Ok(0) +} + +// Hook for validating realloc using wmemcheck_state. +#[cfg(feature = "wmemcheck")] +unsafe fn check_realloc( + _store: &mut dyn VMStore, + instance: &mut Instance, + end_addr: u32, + start_addr: u32, + len: u32, +) -> Result { + if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { + let result = wmemcheck_state.realloc(end_addr as usize, start_addr as usize, len as usize); + wmemcheck_state.memcheck_on(); + return check_memcheck_result(result); + } + Ok(0) +} + +// Hook for validating posix_memalign using wmemcheck_state. +#[cfg(feature = "wmemcheck")] +unsafe fn check_posix_memalign( + store: &mut dyn VMStore, + instance: &mut Instance, + error: u32, + outptr: u32, + _alignment: u32, + size: u32, +) -> Result { + if let Some(_) = &mut instance.wmemcheck_state { + if error != 0 { + return Ok(0); + } + for (_, entry) in instance.exports() { + if let wasmtime_environ::EntityIndex::Memory(mem_index) = entry { + let mem = instance.get_memory(*mem_index); + let out_ptr = *(mem.base.offset(outptr as isize) as *mut u32); + return check_malloc(store, instance, out_ptr, size); } } + todo!("Why is there no memory?") } Ok(0) } +// Hook for validating aligned_alloc using wmemcheck_state. +#[cfg(feature = "wmemcheck")] +unsafe fn check_aligned_alloc( + store: &mut dyn VMStore, + instance: &mut Instance, + addr: u32, + _alignment: u32, + size: u32, +) -> Result { + check_malloc(store, instance, addr, size) +} + +// Hook for validating malloc_usable_size using wmemcheck_state. +#[cfg(feature = "wmemcheck")] +unsafe fn check_malloc_usable_size( + store: &mut dyn VMStore, + instance: &mut Instance, + len: u32, + addr: u32, +) -> Result { + // Since the wasm program has checked that the entire allocation is usable, mark it as allocated, similar to realloc + check_realloc(store, instance, addr, addr, len) +} + // Hook for validating load using wmemcheck_state. #[cfg(feature = "wmemcheck")] fn check_load( @@ -1216,17 +1302,9 @@ fn check_store( Ok(0) } -// Hook for turning wmemcheck load/store validation off when entering a malloc function. -#[cfg(feature = "wmemcheck")] -fn malloc_start(_store: &mut dyn VMStore, instance: &mut Instance) { - if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { - wmemcheck_state.memcheck_off(); - } -} - -// Hook for turning wmemcheck load/store validation off when entering a free function. +// Hook for turning wmemcheck load/store validation off when entering an allocator function. #[cfg(feature = "wmemcheck")] -fn free_start(_store: &mut dyn VMStore, instance: &mut Instance) { +fn allocator_start(_store: &mut dyn VMStore, instance: &mut Instance) { if let Some(wmemcheck_state) = &mut instance.wmemcheck_state { wmemcheck_state.memcheck_off(); } diff --git a/crates/wmemcheck/src/lib.rs b/crates/wmemcheck/src/lib.rs index 742f090b68af..d991920d94db 100644 --- a/crates/wmemcheck/src/lib.rs +++ b/crates/wmemcheck/src/lib.rs @@ -1,5 +1,6 @@ use std::cmp::*; use std::collections::HashMap; +use std::ops::Range; /// Memory checker for wasm guest. pub struct Wmemcheck { @@ -8,6 +9,9 @@ pub struct Wmemcheck { pub stack_pointer: usize, max_stack_size: usize, pub flag: bool, + /// granularity in bytes of tracked allocations + pub granularity: usize, + pub enforce_uninitialized_reads: bool, } /// Error types for memory checker. @@ -21,6 +25,8 @@ pub enum AccessError { InvalidWrite { addr: usize, len: usize }, /// Free of non-malloc'd pointer. InvalidFree { addr: usize }, + /// Reallocation of non-malloc'd pointer + InvalidRealloc { addr: usize }, /// Access out of bounds of heap or stack. OutOfBounds { addr: usize, len: usize }, } @@ -38,7 +44,13 @@ pub enum MemState { impl Wmemcheck { /// Initializes memory checker instance. - pub fn new(mem_size: usize) -> Wmemcheck { + // TODO: how to make this properly configurable? + pub fn new( + mem_size: usize, + granularity: usize, + enforce_uninitialized_reads: bool, + ) -> Wmemcheck { + // TODO: metadata could be shrunk when granularity is greater than 1 let metadata = vec![MemState::Unallocated; mem_size]; let mallocs = HashMap::new(); Wmemcheck { @@ -47,18 +59,25 @@ impl Wmemcheck { stack_pointer: 0, max_stack_size: 0, flag: true, + granularity, + enforce_uninitialized_reads, } } /// Updates memory checker memory state metadata when malloc is called. - pub fn malloc(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { + pub fn allocate( + &mut self, + addr: usize, + len: usize, + initialized: bool, + ) -> Result<(), AccessError> { if !self.is_in_bounds_heap(addr, len) { return Err(AccessError::OutOfBounds { addr: addr, len: len, }); } - for i in addr..addr + len { + for i in self.granular_range(addr..addr + len) { match self.metadata[i] { MemState::ValidToWrite => { return Err(AccessError::DoubleMalloc { @@ -75,13 +94,41 @@ impl Wmemcheck { _ => {} } } - for i in addr..addr + len { - self.metadata[i] = MemState::ValidToWrite; + for i in self.granular_range(addr..addr + len) { + self.metadata[i] = if initialized { + MemState::ValidToReadWrite + } else { + MemState::ValidToWrite + }; } self.mallocs.insert(addr, len); Ok(()) } + pub fn realloc( + &mut self, + end_addr: usize, + start_addr: usize, + len: usize, + ) -> Result<(), AccessError> { + if start_addr == 0 { + // If ptr is NULL, realloc() is identical to a call to malloc() + return self.allocate(end_addr, len, false); + } + if !self.mallocs.contains_key(&start_addr) { + return Err(AccessError::InvalidRealloc { addr: start_addr }); + } + let start_len = self.mallocs[&start_addr]; + // Copy initialization information from old allocation to new one + let copy_len = start_len.min(len); + let mut copied_metadata: Vec = vec![]; + copied_metadata.extend_from_slice(&self.metadata[start_addr..start_addr + copy_len]); + self.free(start_addr)?; + self.allocate(end_addr, len, false)?; + self.metadata[end_addr..end_addr + copy_len].clone_from_slice(&copied_metadata); + Ok(()) + } + /// Updates memory checker memory state metadata when a load occurs. pub fn read(&mut self, addr: usize, len: usize) -> Result<(), AccessError> { if !self.flag { @@ -102,10 +149,12 @@ impl Wmemcheck { }); } MemState::ValidToWrite => { - return Err(AccessError::InvalidRead { - addr: addr, - len: len, - }); + if self.enforce_uninitialized_reads { + return Err(AccessError::InvalidRead { + addr: addr, + len: len, + }); + } } _ => {} } @@ -124,7 +173,7 @@ impl Wmemcheck { len: len, }); } - for i in addr..addr + len { + for i in self.granular_range(addr..addr + len) { if let MemState::Unallocated = self.metadata[i] { return Err(AccessError::InvalidWrite { addr: addr, @@ -132,7 +181,7 @@ impl Wmemcheck { }); } } - for i in addr..addr + len { + for i in self.granular_range(addr..addr + len) { self.metadata[i] = MemState::ValidToReadWrite; } Ok(()) @@ -140,17 +189,20 @@ impl Wmemcheck { /// Updates memory checker memory state metadata when free is called. pub fn free(&mut self, addr: usize) -> Result<(), AccessError> { + if addr == 0 { + return Ok(()); + } if !self.mallocs.contains_key(&addr) { return Err(AccessError::InvalidFree { addr: addr }); } let len = self.mallocs[&addr]; - for i in addr..addr + len { + for i in self.granular_range(addr..addr + len) { if let MemState::Unallocated = self.metadata[i] { return Err(AccessError::InvalidFree { addr: addr }); } } self.mallocs.remove(&addr); - for i in addr..addr + len { + for i in self.granular_range(addr..addr + len) { self.metadata[i] = MemState::Unallocated; } Ok(()) @@ -172,11 +224,11 @@ impl Wmemcheck { len: new_sp - self.stack_pointer, }); } else if new_sp < self.stack_pointer { - for i in new_sp..self.stack_pointer + 1 { + for i in self.granular_range(new_sp..self.stack_pointer + 1) { self.metadata[i] = MemState::ValidToReadWrite; } } else { - for i in self.stack_pointer..new_sp { + for i in self.granular_range(self.stack_pointer..new_sp) { self.metadata[i] = MemState::Unallocated; } } @@ -208,14 +260,22 @@ impl Wmemcheck { let to_append = vec![MemState::Unallocated; num_bytes]; self.metadata.extend(to_append); } + + fn granular_range(&self, byte_range: Range) -> Range { + // Round start of range down to granularity + let start = (byte_range.start / self.granularity) * self.granularity; + // Round end of range up to granularity + let end = ((byte_range.end + self.granularity - 1) / self.granularity) * self.granularity; + start..end + } } #[test] fn basic_wmemcheck() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); wmemcheck_state.set_stack_size(1024); - assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.allocate(0x1000, 32, false).is_ok()); assert!(wmemcheck_state.write(0x1000, 4).is_ok()); assert!(wmemcheck_state.read(0x1000, 4).is_ok()); assert_eq!(wmemcheck_state.mallocs, HashMap::from([(0x1000, 32)])); @@ -225,9 +285,9 @@ fn basic_wmemcheck() { #[test] fn read_before_initializing() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); - assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.allocate(0x1000, 32, false).is_ok()); assert_eq!( wmemcheck_state.read(0x1000, 4), Err(AccessError::InvalidRead { @@ -241,9 +301,9 @@ fn read_before_initializing() { #[test] fn use_after_free() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); - assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.allocate(0x1000, 32, false).is_ok()); assert!(wmemcheck_state.write(0x1000, 4).is_ok()); assert!(wmemcheck_state.write(0x1000, 4).is_ok()); assert!(wmemcheck_state.free(0x1000).is_ok()); @@ -258,9 +318,9 @@ fn use_after_free() { #[test] fn double_free() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); - assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.allocate(0x1000, 32, false).is_ok()); assert!(wmemcheck_state.write(0x1000, 4).is_ok()); assert!(wmemcheck_state.free(0x1000).is_ok()); assert_eq!( @@ -271,17 +331,17 @@ fn double_free() { #[test] fn out_of_bounds_malloc() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); assert_eq!( - wmemcheck_state.malloc(640 * 1024, 1), + wmemcheck_state.allocate(640 * 1024, 1, false), Err(AccessError::OutOfBounds { addr: 640 * 1024, len: 1 }) ); assert_eq!( - wmemcheck_state.malloc(640 * 1024 - 10, 15), + wmemcheck_state.allocate(640 * 1024 - 10, 15, false), Err(AccessError::OutOfBounds { addr: 640 * 1024 - 10, len: 15 @@ -292,9 +352,9 @@ fn out_of_bounds_malloc() { #[test] fn out_of_bounds_read() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); - assert!(wmemcheck_state.malloc(640 * 1024 - 24, 24).is_ok()); + assert!(wmemcheck_state.allocate(640 * 1024 - 24, 24, false).is_ok()); assert_eq!( wmemcheck_state.read(640 * 1024 - 24, 25), Err(AccessError::OutOfBounds { @@ -306,18 +366,18 @@ fn out_of_bounds_read() { #[test] fn double_malloc() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); - assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.allocate(0x1000, 32, false).is_ok()); assert_eq!( - wmemcheck_state.malloc(0x1000, 32), + wmemcheck_state.allocate(0x1000, 32, false), Err(AccessError::DoubleMalloc { addr: 0x1000, len: 32 }) ); assert_eq!( - wmemcheck_state.malloc(0x1002, 32), + wmemcheck_state.allocate(0x1002, 32, false), Err(AccessError::DoubleMalloc { addr: 0x1002, len: 32 @@ -328,18 +388,18 @@ fn double_malloc() { #[test] fn error_type() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); - assert!(wmemcheck_state.malloc(0x1000, 32).is_ok()); + assert!(wmemcheck_state.allocate(0x1000, 32, false).is_ok()); assert_eq!( - wmemcheck_state.malloc(0x1000, 32), + wmemcheck_state.allocate(0x1000, 32, false), Err(AccessError::DoubleMalloc { addr: 0x1000, len: 32 }) ); assert_eq!( - wmemcheck_state.malloc(640 * 1024, 32), + wmemcheck_state.allocate(640 * 1024, 32, false), Err(AccessError::OutOfBounds { addr: 640 * 1024, len: 32 @@ -350,12 +410,12 @@ fn error_type() { #[test] fn update_sp_no_error() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); wmemcheck_state.set_stack_size(1024); assert!(wmemcheck_state.update_stack_pointer(768).is_ok()); assert_eq!(wmemcheck_state.stack_pointer, 768); - assert!(wmemcheck_state.malloc(1024 * 2, 32).is_ok()); + assert!(wmemcheck_state.allocate(1024 * 2, 32, false).is_ok()); assert!(wmemcheck_state.free(1024 * 2).is_ok()); assert!(wmemcheck_state.update_stack_pointer(896).is_ok()); assert_eq!(wmemcheck_state.stack_pointer, 896); @@ -364,18 +424,18 @@ fn update_sp_no_error() { #[test] fn bad_stack_malloc() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); wmemcheck_state.set_stack_size(1024); assert!(wmemcheck_state.update_stack_pointer(0).is_ok()); assert_eq!(wmemcheck_state.stack_pointer, 0); assert_eq!( - wmemcheck_state.malloc(512, 32), + wmemcheck_state.allocate(512, 32, false), Err(AccessError::OutOfBounds { addr: 512, len: 32 }) ); assert_eq!( - wmemcheck_state.malloc(1022, 32), + wmemcheck_state.allocate(1022, 32, false), Err(AccessError::OutOfBounds { addr: 1022, len: 32 @@ -385,7 +445,7 @@ fn bad_stack_malloc() { #[test] fn stack_full_empty() { - let mut wmemcheck_state = Wmemcheck::new(640 * 1024); + let mut wmemcheck_state = Wmemcheck::new(640 * 1024, 1, true); wmemcheck_state.set_stack_size(1024); @@ -397,7 +457,7 @@ fn stack_full_empty() { #[test] fn from_test_program() { - let mut wmemcheck_state = Wmemcheck::new(1024 * 1024 * 128); + let mut wmemcheck_state = Wmemcheck::new(1024 * 1024 * 128, 1, true); wmemcheck_state.set_stack_size(70864); assert!(wmemcheck_state.write(70832, 1).is_ok()); assert!(wmemcheck_state.read(1138, 1).is_ok());