use super::ref_types_module; use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering::SeqCst}; use wasmtime::*; #[test] #[cfg_attr(miri, ignore)] fn pass_funcref_in_and_out_of_wasm() -> wasmtime::Result<()> { let (mut store, module) = ref_types_module( false, r#" (module (func (export "func") (param funcref) (result funcref) local.get 0 ) ) "#, )?; let instance = Instance::new(&mut store, &module, &[])?; let func = instance.get_func(&mut store, "func").unwrap(); // Pass in a non-null funcref. { let mut results = [Val::I32(0)]; func.call(&mut store, &[Val::FuncRef(Some(func))], &mut results)?; // Can't compare `Func` for equality, so this is the best we can do here. let result_func = results[0].unwrap_funcref().unwrap(); assert!(FuncType::eq(&func.ty(&store), &result_func.ty(&store))); } // Pass in a null funcref. { let mut results = [Val::I32(0)]; func.call(&mut store, &[Val::FuncRef(None)], &mut results)?; let result_func = results[0].unwrap_funcref(); assert!(result_func.is_none()); } // Pass in a `funcref` from another instance. { let other_instance = Instance::new(&mut store, &module, &[])?; let other_instance_func = other_instance.get_func(&mut store, "func").unwrap(); let mut results = [Val::I32(0)]; func.call( &mut store, &[Val::FuncRef(Some(other_instance_func))], &mut results, )?; assert_eq!(results.len(), 1); // Can't compare `Func` for equality, so this is the best we can do here. let result_func = results[0].unwrap_funcref().unwrap(); assert!(FuncType::eq( &other_instance_func.ty(&store), &result_func.ty(&store), )); } // Passing in a `funcref` from another store fails. { let (mut other_store, other_module) = ref_types_module(false, r#"(module (func (export "f")))"#)?; let other_store_instance = Instance::new(&mut other_store, &other_module, &[])?; let f = other_store_instance .get_func(&mut other_store, "f") .unwrap(); assert!( func.call(&mut store, &[Val::FuncRef(Some(f))], &mut [Val::I32(0)]) .is_err() ); } Ok(()) } #[test] #[cfg_attr(miri, ignore)] fn receive_null_funcref_from_wasm() -> wasmtime::Result<()> { let (mut store, module) = ref_types_module( false, r#" (module (func (export "get-null") (result funcref) ref.null func ) ) "#, )?; let instance = Instance::new(&mut store, &module, &[])?; let get_null = instance.get_func(&mut store, "get-null").unwrap(); let mut results = [Val::I32(0)]; get_null.call(&mut store, &[], &mut results)?; let result_func = results[0].unwrap_funcref(); assert!(result_func.is_none()); Ok(()) } #[test] fn wrong_store() -> wasmtime::Result<()> { let dropped = Arc::new(AtomicBool::new(false)); { let mut store1 = Store::<()>::default(); let mut store2 = Store::<()>::default(); let set = SetOnDrop(dropped.clone()); let f1 = Func::wrap(&mut store1, move || { let _ = &set; }); let f2 = Func::wrap(&mut store2, move || Some(f1)); assert!(f2.call(&mut store2, &[], &mut []).is_err()); } assert!(dropped.load(SeqCst)); return Ok(()); struct SetOnDrop(Arc); impl Drop for SetOnDrop { fn drop(&mut self) { self.0.store(true, SeqCst); } } } #[test] #[cfg_attr(miri, ignore)] fn func_new_returns_wrong_store() -> wasmtime::Result<()> { let dropped = Arc::new(AtomicBool::new(false)); { let mut store1 = Store::<()>::default(); let mut store2 = Store::<()>::default(); let set = SetOnDrop(dropped.clone()); let f1 = Func::wrap(&mut store1, move || { let _ = &set; }); let func_ty = FuncType::new(store2.engine(), None, Some(ValType::FUNCREF)); let f2 = Func::new(&mut store2, func_ty, move |_, _, results| { results[0] = f1.into(); Ok(()) }); assert!(f2.call(&mut store2, &[], &mut [Val::I32(0)]).is_err()); } assert!(dropped.load(SeqCst)); return Ok(()); struct SetOnDrop(Arc); impl Drop for SetOnDrop { fn drop(&mut self) { self.0.store(true, SeqCst); } } }