From 7de8d546d3eba2069b75047d48fb23a5999d3d25 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 15 Jul 2022 15:56:40 -0500 Subject: [PATCH] Fix a possible panic with null-containing element segments (#4457) This commit fixes an issue with the initialization of element segments when one of the elements in the element segment is `ref.func null`. Previously the contents of a table were accidentally initialized with the raw value of the `*mut VMCallerCheckedAnyfunc` which bypassed the "this is initialized" encoding of function table entries that Wasmtime uses for lazy table initialization. The fix here was to ensure that the encoded form is used. The impact of this issue is that a module could panic at runtime when accessing a table element that was initialized with an element segment containing a `ref.null func` entry. This only happens with imported tables in a WebAssembly module where the table itself was defined on the host. If the table was defined in another wasm module or in the local wasm module this bug would not occur. Additionally this bug requires enabling the reference types proposal for WebAssembly (which is enabled by default) due to the usage of encodings for null funcrefs in element segments. --- crates/runtime/src/table.rs | 4 +++- tests/all/table.rs | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/crates/runtime/src/table.rs b/crates/runtime/src/table.rs index b71d21ffc6d..ca13a846b13 100644 --- a/crates/runtime/src/table.rs +++ b/crates/runtime/src/table.rs @@ -280,7 +280,9 @@ impl Table { }; for (item, slot) in items.zip(elements) { - *slot = item as usize; + unsafe { + *slot = TableElement::FuncRef(item).into_table_value(); + } } Ok(()) } diff --git a/tests/all/table.rs b/tests/all/table.rs index 2dc29516838..8bc62f4f1a1 100644 --- a/tests/all/table.rs +++ b/tests/all/table.rs @@ -1,3 +1,4 @@ +use anyhow::Result; use wasmtime::*; #[test] @@ -50,3 +51,27 @@ fn copy_wrong() { "tables do not have the same element type" ); } + +#[test] +fn null_elem_segment_works_with_imported_table() -> Result<()> { + let mut store = Store::<()>::default(); + let ty = TableType::new(ValType::FuncRef, 1, None); + let table = Table::new(&mut store, ty, Val::FuncRef(None))?; + let module = Module::new( + store.engine(), + r#" +(module + (import "" "" (table (;0;) 1 funcref)) + (func + i32.const 0 + table.get 0 + drop + ) + (start 0) + (elem (;0;) (i32.const 0) funcref (ref.null func)) +) +"#, + )?; + Instance::new(&mut store, &module, &[table.into()])?; + Ok(()) +}