diff --git a/tests/all/winch.rs b/tests/all/winch.rs index d8a7075161dc..fc8a66744419 100644 --- a/tests/all/winch.rs +++ b/tests/all/winch.rs @@ -239,3 +239,74 @@ fn wasm_to_native_trap() -> Result<()> { Ok(()) } + +#[test] +#[cfg_attr(miri, ignore)] +fn dynamic_heap() -> Result<()> { + let mut c = Config::new(); + + c.strategy(Strategy::Winch); + c.static_memory_maximum_size(0); + c.static_memory_guard_size(0); + c.guard_before_linear_memory(false); + c.dynamic_memory_guard_size(0); + + let engine = Engine::new(&c)?; + let wat = r#" + (module + (type (;0;) (func (result i32))) + (func (;0;) (type 0) (result i32) + (local i32 i64) + global.get 0 + i32.eqz + if ;; label = @1 + unreachable + end + global.get 0 + i32.const 1 + i32.sub + global.set 0 + memory.size + local.set 0 + block ;; label = @1 + block ;; label = @2 + memory.size + i32.const 65536 + i32.mul + i32.const 65511 + local.get 0 + i32.add + i32.le_u + br_if 0 (;@2;) + local.get 0 + i32.const 0 + i32.le_s + br_if 0 (;@2;) + local.get 0 + i64.load8_s offset=65503 + local.set 1 + br 1 (;@1;) + end + i64.const 0 + local.set 1 + end + local.get 1 + drop + i32.const 0 + ) + (memory (;0;) 1 3) + (global (;0;) (mut i32) i32.const 1000) + (export " " (func 0)) + (export "" (memory 0)) + ) + "#; + let mut store = Store::new(&engine, ()); + let module = Module::new(&engine, wat)?; + let instance = Instance::new(&mut store, &module, &[])?; + let f = instance.get_typed_func::<(), i32>(&mut store, " ")?; + let result = f.call(&mut store, ())?; + + assert!(result == 0); + + Ok(()) +} diff --git a/winch/codegen/src/codegen/mod.rs b/winch/codegen/src/codegen/mod.rs index caf76f668406..8e933ed74104 100644 --- a/winch/codegen/src/codegen/mod.rs +++ b/winch/codegen/src/codegen/mod.rs @@ -494,6 +494,7 @@ where let index = Index::from_typed_reg(self.context.pop_to_reg(self.masm, None)); let offset = bounds::ensure_index_and_offset(self.masm, index, memarg.offset, ptr_size); let offset_with_access_size = add_offset_and_access_size(offset, access_size); + let scratch = ::scratch_reg(); let addr = match heap.style { // == Dynamic Heaps == @@ -508,12 +509,17 @@ where bounds::load_dynamic_heap_bounds(&mut self.context, self.masm, &heap, ptr_size); let index_reg = index.as_typed_reg().reg; + + // Move the value of the index to the scratch register + // to perform the overflow check to avoid clobbering the + // initial index value. + self.masm.mov(index_reg.into(), scratch, heap.ty.into()); // Perform // index = index + offset + access_size, trapping if the // addition overflows. self.masm.checked_uadd( - index_reg, - index_reg, + scratch, + scratch, RegImm::i64(offset_with_access_size as i64), ptr_size, TrapCode::HeapOutOfBounds,