1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
Description: prevent using shared memories
This commit fixes a few issues
where it was possible to represent a wasm shared linear memory
with the `wasmtime::Memory` type.
This is not sound because `wasmtime::Memory` provides safe Rust access
to the bytes where that is not possible with wasm shared memories.
Shared memories in Rust must be represented by `SharedMemory`,
not `wasmtime::Memory`.
.
Specifically this commit prevents two vectors of this happening:
1. `Memory::new` now requires
that the memory type specified is non-shared.
Instead `SharedMemory::new` must be used instead.
2. Core dumps now skip over shared memories
when iterating over all memories in the store.
Supporting shared memories is a more invasive change
and will happen on Wasmtime's `main` branch.
Author: Alex Crichton <alex@alexcrichton.com>
Bug: https://github.com/bytecodealliance/wasmtime/issues/12017
Bug-Debian: https://bugs.debian.org/1120699
Last-Update: 2025-11-14
---
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
--- a/crates/wasmtime/src/runtime/coredump.rs
+++ b/crates/wasmtime/src/runtime/coredump.rs
@@ -41,7 +41,8 @@
pub(crate) fn new(store: &mut StoreOpaque, backtrace: WasmBacktrace) -> WasmCoreDump {
let modules: Vec<_> = store.modules().all_modules().cloned().collect();
let instances: Vec<Instance> = store.all_instances().collect();
- let store_memories: Vec<Memory> = store.all_memories().collect();
+ let mut store_memories: Vec<Memory> = store.all_memories().collect();
+ store_memories.retain(|m| !m.wasmtime_ty(store.store_data()).shared);
let mut store_globals: Vec<Global> = vec![];
store.for_each_global(|_store, global| store_globals.push(global));
@@ -256,7 +257,12 @@
.all_memories(&mut store.0)
.collect::<Vec<_>>()
.into_iter()
- .map(|(_i, memory)| memory_to_idx[&memory.hash_key(&store.0)])
+ .map(|(_i, memory)| {
+ memory_to_idx
+ .get(&memory.hash_key(&store.0))
+ .copied()
+ .unwrap_or(u32::MAX)
+ })
.collect::<Vec<_>>();
let globals = instance
--- a/crates/wasmtime/src/runtime/memory.rs
+++ b/crates/wasmtime/src/runtime/memory.rs
@@ -263,6 +263,9 @@
/// Helper function for attaching the memory to a "frankenstein" instance
fn _new(store: &mut StoreOpaque, ty: MemoryType) -> Result<Memory> {
+ if ty.is_shared() {
+ bail!("shared memories must be created through `SharedMemory`")
+ }
unsafe {
let export = generate_memory_export(store, &ty, None)?;
Ok(Memory::from_wasmtime_memory(export, store))
--- a/crates/wast/Cargo.toml
+++ b/crates/wast/Cargo.toml
@@ -15,7 +15,7 @@
[dependencies]
anyhow = { workspace = true }
-wasmtime = { workspace = true, features = ['cranelift', 'wat', 'runtime', 'gc'] }
+wasmtime = { workspace = true, features = ['cranelift', 'wat', 'runtime', 'gc', 'threads'] }
wast = { workspace = true }
log = { workspace = true }
--- a/crates/wast/src/spectest.rs
+++ b/crates/wast/src/spectest.rs
@@ -80,7 +80,7 @@
if config.use_shared_memory {
let ty = MemoryType::shared(1, 1);
- let memory = Memory::new(&mut *store, ty)?;
+ let memory = SharedMemory::new(store.engine(), ty)?;
linker.define(&mut *store, "spectest", "shared_memory", memory)?;
}
--- a/tests/all/coredump.rs
+++ b/tests/all/coredump.rs
@@ -258,3 +258,33 @@
Ok(())
}
+
+#[test]
+#[cfg_attr(miri, ignore)]
+fn core_dump_with_shared_memory() -> Result<()> {
+ let mut config = Config::new();
+ config.coredump_on_trap(true);
+ let engine = Engine::new(&config)?;
+ let mut store = Store::new(&engine, ());
+ let wat = r#"(module
+ (memory 1 1 shared)
+ (func (export "foo") unreachable)
+ (data (i32.const 0) "a")
+ )"#;
+ let module = Module::new(&engine, wat)?;
+ let instance = Instance::new(&mut store, &module, &[])?;
+ let foo = instance.get_typed_func::<(), ()>(&mut store, "foo")?;
+ let err = foo.call(&mut store, ()).unwrap_err();
+ let coredump = err.downcast_ref::<WasmCoreDump>().unwrap();
+ assert!(coredump.memories().is_empty());
+
+ let bytes = coredump.serialize(&mut store, "howdy");
+ for payload in wasmparser::Parser::new(0).parse_all(&bytes) {
+ let payload = payload?;
+ if let wasmparser::Payload::DataSection(s) = payload {
+ assert_eq!(s.count(), 0);
+ }
+ }
+
+ Ok(())
+}
--- a/tests/all/threads.rs
+++ b/tests/all/threads.rs
@@ -277,3 +277,11 @@
Ok(())
}
+
+#[test]
+fn create_shared_memory_through_memory() -> Result<()> {
+ let engine = Engine::default();
+ let mut store = Store::new(&engine, ());
+ assert!(Memory::new(&mut store, MemoryType::shared(1, 1)).is_err());
+ Ok(())
+}
|