use crate::ErrorExt;
use std::sync::{Arc, Mutex};
use wasmtime::component::{Component, Linker as ComponentLinker};
use wasmtime::*;
const SENTINEL: i64 = 0x1122334455667788;
const COLLIDING_MODULE: &str = r#"(module (func (export "f") (param f64)))"#;
const COLLIDING_COMPONENT: &str = r#"
(component
(core module (func (export "f") (param f64)))
)
"#;
fn engine_pair() -> (Engine, Engine) {
(Engine::default(), Engine::default())
}
const OBSERVER_MODULE: &str = r#"
(module
(import "" "" (func $host (param i64)))
(func (export "go")
i64.const 0x1122334455667788
call $host))
"#;
fn observe_i64_in_host(store: &mut Store<()>) -> Result<i64> {
let observed = Arc::new(Mutex::new(0));
let host = Func::wrap(&mut *store, {
let observed = Arc::clone(&observed);
move |x: i64| *observed.lock().unwrap() = x
});
let engine = store.engine().clone();
let module = Module::new(&engine, OBSERVER_MODULE)?;
let instance = Instance::new(&mut *store, &module, &[host.into()])?;
instance
.get_typed_func::<(), ()>(&mut *store, "go")?
.call(&mut *store, ())?;
let observed = *observed.lock().unwrap();
Ok(observed)
}
fn assert_store_is_uncorrupted(store: &mut Store<()>) -> Result<()> {
assert_eq!(observe_i64_in_host(store)?, SENTINEL);
Ok(())
}
#[test]
#[cfg_attr(miri, ignore)]
fn instance_new_rejects_foreign_module() -> Result<()> {
let (a, b) = engine_pair();
let mut store = Store::new(&a, ());
let foreign = Module::new(&b, COLLIDING_MODULE)?;
Instance::new(&mut store, &foreign, &[])
.unwrap_err()
.assert_contains("cross-`Engine`");
assert_store_is_uncorrupted(&mut store)
}
#[test]
#[cfg_attr(miri, ignore)]
fn instance_new_rejects_foreign_module_with_imports() -> Result<()> {
let (a, b) = engine_pair();
let mut store = Store::new(&a, ());
let _ = Func::wrap(&mut store, |_: i32| {});
let host = Func::wrap(&mut store, |_: i64| {});
let foreign = Module::new(&b, r#"(module (import "" "" (func (param i64))))"#)?;
Instance::new(&mut store, &foreign, &[host.into()])
.unwrap_err()
.assert_contains("cross-`Engine`");
assert_store_is_uncorrupted(&mut store)
}
#[test]
#[cfg_attr(miri, ignore)]
fn instantiate_pre_rejects_foreign_definition() -> Result<()> {
let (a, b) = engine_pair();
let mut foreign_store = Store::new(&b, ());
let _ = Func::wrap(&mut foreign_store, |_: i32| {});
let foreign = Func::wrap(&mut foreign_store, |_: f64| {});
let mut linker = Linker::<()>::new(&a);
linker.define(&foreign_store, "", "", foreign)?;
let module = Module::new(&a, r#"(module (import "" "" (func (param i64))))"#)?;
linker
.instantiate_pre(&module)
.err()
.expect("should reject an item defined from a different engine's store")
.assert_contains("cross-`Engine`");
let mut store = Store::new(&a, ());
assert_store_is_uncorrupted(&mut store)
}
#[test]
#[cfg_attr(miri, ignore)]
fn instance_pre_instantiate_rejects_foreign_store() -> Result<()> {
let (a, b) = engine_pair();
let mut store = Store::new(&a, ());
let foreign = Module::new(&b, COLLIDING_MODULE)?;
let pre = Linker::<()>::new(&b).instantiate_pre(&foreign)?;
pre.instantiate(&mut store)
.err()
.expect("should reject a store from a different engine")
.assert_contains("cross-`Engine`");
assert_store_is_uncorrupted(&mut store)
}
#[test]
#[cfg_attr(miri, ignore)]
fn linker_instantiate_pre_rejects_foreign_module() -> Result<()> {
let (a, b) = engine_pair();
let foreign = Module::new(&b, COLLIDING_MODULE)?;
Linker::<()>::new(&a)
.instantiate_pre(&foreign)
.err()
.expect("should reject a module from a different engine")
.assert_contains("cross-`Engine`");
Ok(())
}
#[test]
#[cfg_attr(miri, ignore)]
fn component_linker_instantiate_pre_rejects_foreign_component() -> Result<()> {
let (a, b) = engine_pair();
let foreign = Component::new(&b, COLLIDING_COMPONENT)?;
ComponentLinker::<()>::new(&a)
.instantiate_pre(&foreign)
.err()
.expect("should reject a component from a different engine")
.assert_contains("cross-`Engine`");
Ok(())
}
#[test]
#[cfg_attr(miri, ignore)]
fn component_instance_pre_instantiate_rejects_foreign_store() -> Result<()> {
let (a, b) = engine_pair();
let mut store = Store::new(&a, ());
let foreign = Component::new(&b, COLLIDING_COMPONENT)?;
let pre = ComponentLinker::<()>::new(&b).instantiate_pre(&foreign)?;
pre.instantiate(&mut store)
.err()
.expect("should reject a store from a different engine")
.assert_contains("cross-`Engine`");
assert_store_is_uncorrupted(&mut store)
}