diff --git a/crates/wasmtime/src/runtime/store.rs b/crates/wasmtime/src/runtime/store.rs index 1041750ada77..fca2e3a652c4 100644 --- a/crates/wasmtime/src/runtime/store.rs +++ b/crates/wasmtime/src/runtime/store.rs @@ -2055,11 +2055,20 @@ impl StoreOpaque { // If this loop becomes hot in the future, however, it should be // possible to precompute maps about linear memories in a store and have // a quicker lookup. - let mut fault = None; + // + // A shared memory can be defined by more than one instance in a store, + // for example when it's imported through the single-memory instance + // that `SharedMemory::vmimport` creates. Each of those instances + // reports the same fault, so only assert that the faulting address + // doesn't belong to two different memories. The memory size isn't + // compared because a shared memory can grow concurrently. + let mut fault: Option = None; for (_, instance) in self.instances.iter() { if let Some(f) = instance.handle.get().wasm_fault(addr) { - assert!(fault.is_none()); - fault = Some(f); + match &fault { + Some(prev) => assert_eq!(prev.wasm_address, f.wasm_address), + None => fault = Some(f), + } } } if fault.is_some() { diff --git a/tests/misc_testsuite/threads/shared-memory-imported-oob.wast b/tests/misc_testsuite/threads/shared-memory-imported-oob.wast new file mode 100644 index 000000000000..9119bfcb4ec1 --- /dev/null +++ b/tests/misc_testsuite/threads/shared-memory-imported-oob.wast @@ -0,0 +1,10 @@ +;;! threads = true + +;; A shared memory defined in one instance and imported into another must +;; still report an out-of-bounds access as a trap. +(module $a + (memory (export "m") 1 1 shared) + (func (export "ld") (param i32) (result i32) (i32.load (local.get 0)))) +(register "a" $a) +(module $b (import "a" "m" (memory 1 1 shared))) +(assert_trap (invoke $a "ld" (i32.const 0x10000)) "out of bounds memory access")