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.
This commit is contained in:
@@ -295,14 +295,19 @@ impl Func {
|
|||||||
|
|
||||||
// Unlike our arguments we need to dynamically check that the return
|
// Unlike our arguments we need to dynamically check that the return
|
||||||
// values produced are correct. There could be a bug in `func` that
|
// values produced are correct. There could be a bug in `func` that
|
||||||
// produces the wrong number or wrong types of values, and we need
|
// produces the wrong number, wrong types, or wrong stores of
|
||||||
// to catch that here.
|
// values, and we need to catch that here.
|
||||||
for (i, (ret, ty)) in returns.into_iter().zip(ty_clone.results()).enumerate() {
|
for (i, (ret, ty)) in returns.into_iter().zip(ty_clone.results()).enumerate() {
|
||||||
if ret.ty() != ty {
|
if ret.ty() != ty {
|
||||||
return Err(Trap::new(
|
return Err(Trap::new(
|
||||||
"function attempted to return an incompatible value",
|
"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 {
|
unsafe {
|
||||||
ret.write_value_to(&store, values_vec.add(i));
|
ret.write_value_to(&store, values_vec.add(i));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<Cell<bool>>);
|
||||||
|
|
||||||
|
impl Drop for SetOnDrop {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.0.set(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user