diff --git a/crates/wasm_interp/src/execute.rs b/crates/wasm_interp/src/execute.rs index 7d8a729136..89c55be848 100644 --- a/crates/wasm_interp/src/execute.rs +++ b/crates/wasm_interp/src/execute.rs @@ -36,7 +36,7 @@ impl<'a> ExecutionState<'a> { { let mem_bytes = memory_pages * MemorySection::PAGE_SIZE; ExecutionState { - memory: Vec::with_capacity_in(mem_bytes as usize, arena), + memory: Vec::from_iter_in(iter::repeat(0).take(mem_bytes as usize), arena), call_stack: CallStack::new(arena), value_stack: ValueStack::new(arena), globals: Vec::from_iter_in(globals, arena), @@ -435,9 +435,23 @@ impl<'a> ExecutionState<'a> { self.value_stack.push(Value::I32(size)); } GROWMEMORY => { + let old_bytes = self.memory.len() as u32; + let old_pages = old_bytes / MemorySection::PAGE_SIZE as u32; let grow_pages = self.value_stack.pop_u32(); - let grow_bytes = grow_pages as usize * MemorySection::PAGE_SIZE as usize; - self.memory.extend(iter::repeat(0).take(grow_bytes)); + let grow_bytes = grow_pages * MemorySection::PAGE_SIZE; + let new_bytes = old_bytes + grow_bytes; + + let success = match module.memory.max_bytes().unwrap() { + Some(max_bytes) => new_bytes <= max_bytes, + None => true, + }; + if success { + self.memory + .extend(iter::repeat(0).take(grow_bytes as usize)); + self.value_stack.push(Value::I32(old_pages as i32)); + } else { + self.value_stack.push(Value::I32(-1)); + } } I32CONST => { let value = i32::parse((), &module.code.bytes, &mut self.program_counter).unwrap(); diff --git a/crates/wasm_interp/tests/test_opcodes.rs b/crates/wasm_interp/tests/test_opcodes.rs index a6a4aa05cd..ebeb75d4d9 100644 --- a/crates/wasm_interp/tests/test_opcodes.rs +++ b/crates/wasm_interp/tests/test_opcodes.rs @@ -662,11 +662,39 @@ fn test_i64store32() { ); } -// #[test] -// fn test_currentmemory() {} +#[test] +fn test_currentmemory() { + let arena = Bump::new(); + let mut module = WasmModule::new(&arena); -// #[test] -// fn test_growmemory() {} + let pages = 3; + let pc = 0; + module.memory = MemorySection::new(&arena, pages * MemorySection::PAGE_SIZE); + module.code.bytes.push(OpCode::CURRENTMEMORY as u8); + + let mut state = ExecutionState::new(&arena, pages, pc, []); + state.execute_next_instruction(&module); + assert_eq!(state.value_stack.pop(), Value::I32(3)) +} + +#[test] +fn test_growmemory() { + let arena = Bump::new(); + let mut module = WasmModule::new(&arena); + + let existing_pages = 3; + let grow_pages = 2; + let pc = 0; + module.memory = MemorySection::new(&arena, existing_pages * MemorySection::PAGE_SIZE); + module.code.bytes.push(OpCode::I32CONST as u8); + module.code.bytes.encode_i32(grow_pages); + module.code.bytes.push(OpCode::GROWMEMORY as u8); + + let mut state = ExecutionState::new(&arena, existing_pages, pc, []); + state.execute_next_instruction(&module); + state.execute_next_instruction(&module); + assert_eq!(state.memory.len(), 5 * MemorySection::PAGE_SIZE as usize); +} #[test] fn test_i32const() { diff --git a/crates/wasm_module/src/sections.rs b/crates/wasm_module/src/sections.rs index bf4d12ee05..3d587f6651 100644 --- a/crates/wasm_module/src/sections.rs +++ b/crates/wasm_module/src/sections.rs @@ -790,6 +790,16 @@ impl<'a> MemorySection<'a> { }; Ok(min_pages * MemorySection::PAGE_SIZE) } + + pub fn max_bytes(&self) -> Result, ParseError> { + let mut cursor = 0; + let memory_limits = Limits::parse((), &self.bytes, &mut cursor)?; + let bytes = match memory_limits { + Limits::Min(_) => None, + Limits::MinMax(_, pages) => Some(pages * MemorySection::PAGE_SIZE), + }; + Ok(bytes) + } } section_impl!(MemorySection, SectionId::Memory);