From ffca0fc908639d4c176245b51557a57555794b7d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 16 Nov 2020 11:54:57 -0800 Subject: [PATCH] Fix assertion with cross-store values in `Func::new` If a host-defined `Func::new` closure returns values from the wrong store, this currently trips a debug assertion and causes other issues elsewhere in release mode. This commit adds the same dynamic checks found in `Func::wrap` in the `Func::new` case today. --- crates/wasmtime/src/func.rs | 9 +++++++-- tests/all/funcref.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/crates/wasmtime/src/func.rs b/crates/wasmtime/src/func.rs index a4de5209e6..4225823ad9 100644 --- a/crates/wasmtime/src/func.rs +++ b/crates/wasmtime/src/func.rs @@ -295,14 +295,19 @@ impl Func { // Unlike our arguments we need to dynamically check that the return // values produced are correct. There could be a bug in `func` that - // produces the wrong number or wrong types of values, and we need - // to catch that here. + // produces the wrong number, wrong types, or wrong stores of + // values, and we need to catch that here. for (i, (ret, ty)) in returns.into_iter().zip(ty_clone.results()).enumerate() { if ret.ty() != ty { return Err(Trap::new( "function attempted to return an incompatible value", )); } + if !ret.comes_from_same_store(&store) { + return Err(Trap::new( + "cross-`Store` values are not currently supported", + )); + } unsafe { ret.write_value_to(&store, values_vec.add(i)); } diff --git a/tests/all/funcref.rs b/tests/all/funcref.rs index 4abea9d791..dd1e0cb9db 100644 --- a/tests/all/funcref.rs +++ b/tests/all/funcref.rs @@ -110,3 +110,35 @@ fn wrong_store() -> anyhow::Result<()> { } } } + +#[test] +fn func_new_returns_wrong_store() -> anyhow::Result<()> { + let dropped = Rc::new(Cell::new(false)); + { + let store1 = Store::default(); + let store2 = Store::default(); + + let set = SetOnDrop(dropped.clone()); + let f1 = Func::wrap(&store1, move || drop(&set)); + let f2 = Func::new( + &store2, + FuncType::new(None, Some(ValType::FuncRef)), + move |_, _, results| { + results[0] = f1.clone().into(); + Ok(()) + }, + ); + assert!(f2.call(&[]).is_err()); + } + assert!(dropped.get()); + + return Ok(()); + + struct SetOnDrop(Rc>); + + impl Drop for SetOnDrop { + fn drop(&mut self) { + self.0.set(true); + } + } +}