xref: /wasmtime-44.0.1/tests/all/funcref.rs (revision 72004aad)
1 use super::ref_types_module;
2 use std::sync::atomic::{AtomicBool, Ordering::SeqCst};
3 use std::sync::Arc;
4 use wasmtime::*;
5 
6 #[test]
7 #[cfg_attr(miri, ignore)]
8 fn pass_funcref_in_and_out_of_wasm() -> anyhow::Result<()> {
9     let (mut store, module) = ref_types_module(
10         false,
11         r#"
12             (module
13                 (func (export "func") (param funcref) (result funcref)
14                     local.get 0
15                 )
16             )
17         "#,
18     )?;
19 
20     let instance = Instance::new(&mut store, &module, &[])?;
21     let func = instance.get_func(&mut store, "func").unwrap();
22 
23     // Pass in a non-null funcref.
24     {
25         let mut results = [Val::I32(0)];
26         func.call(
27             &mut store,
28             &[Val::FuncRef(Some(func.clone()))],
29             &mut results,
30         )?;
31 
32         // Can't compare `Func` for equality, so this is the best we can do here.
33         let result_func = results[0].unwrap_funcref().unwrap();
34         assert!(FuncType::eq(&func.ty(&store), &result_func.ty(&store)));
35     }
36 
37     // Pass in a null funcref.
38     {
39         let mut results = [Val::I32(0)];
40         func.call(&mut store, &[Val::FuncRef(None)], &mut results)?;
41         let result_func = results[0].unwrap_funcref();
42         assert!(result_func.is_none());
43     }
44 
45     // Pass in a `funcref` from another instance.
46     {
47         let other_instance = Instance::new(&mut store, &module, &[])?;
48         let other_instance_func = other_instance.get_func(&mut store, "func").unwrap();
49 
50         let mut results = [Val::I32(0)];
51         func.call(
52             &mut store,
53             &[Val::FuncRef(Some(other_instance_func.clone()))],
54             &mut results,
55         )?;
56         assert_eq!(results.len(), 1);
57 
58         // Can't compare `Func` for equality, so this is the best we can do here.
59         let result_func = results[0].unwrap_funcref().unwrap();
60         assert!(FuncType::eq(
61             &other_instance_func.ty(&store),
62             &result_func.ty(&store),
63         ));
64     }
65 
66     // Passing in a `funcref` from another store fails.
67     {
68         let (mut other_store, other_module) =
69             ref_types_module(false, r#"(module (func (export "f")))"#)?;
70         let other_store_instance = Instance::new(&mut other_store, &other_module, &[])?;
71         let f = other_store_instance
72             .get_func(&mut other_store, "f")
73             .unwrap();
74 
75         assert!(func
76             .call(&mut store, &[Val::FuncRef(Some(f))], &mut [Val::I32(0)])
77             .is_err());
78     }
79 
80     Ok(())
81 }
82 
83 #[test]
84 #[cfg_attr(miri, ignore)]
85 fn receive_null_funcref_from_wasm() -> anyhow::Result<()> {
86     let (mut store, module) = ref_types_module(
87         false,
88         r#"
89             (module
90                 (func (export "get-null") (result funcref)
91                     ref.null func
92                 )
93             )
94         "#,
95     )?;
96 
97     let instance = Instance::new(&mut store, &module, &[])?;
98     let get_null = instance.get_func(&mut store, "get-null").unwrap();
99 
100     let mut results = [Val::I32(0)];
101     get_null.call(&mut store, &[], &mut results)?;
102     let result_func = results[0].unwrap_funcref();
103     assert!(result_func.is_none());
104 
105     Ok(())
106 }
107 
108 #[test]
109 fn wrong_store() -> anyhow::Result<()> {
110     let dropped = Arc::new(AtomicBool::new(false));
111     {
112         let mut store1 = Store::<()>::default();
113         let mut store2 = Store::<()>::default();
114 
115         let set = SetOnDrop(dropped.clone());
116         let f1 = Func::wrap(&mut store1, move || {
117             let _ = &set;
118         });
119         let f2 = Func::wrap(&mut store2, move || Some(f1.clone()));
120         assert!(f2.call(&mut store2, &[], &mut []).is_err());
121     }
122     assert!(dropped.load(SeqCst));
123 
124     return Ok(());
125 
126     struct SetOnDrop(Arc<AtomicBool>);
127 
128     impl Drop for SetOnDrop {
129         fn drop(&mut self) {
130             self.0.store(true, SeqCst);
131         }
132     }
133 }
134 
135 #[test]
136 #[cfg_attr(miri, ignore)]
137 fn func_new_returns_wrong_store() -> anyhow::Result<()> {
138     let dropped = Arc::new(AtomicBool::new(false));
139     {
140         let mut store1 = Store::<()>::default();
141         let mut store2 = Store::<()>::default();
142 
143         let set = SetOnDrop(dropped.clone());
144         let f1 = Func::wrap(&mut store1, move || {
145             let _ = &set;
146         });
147         let func_ty = FuncType::new(store2.engine(), None, Some(ValType::FUNCREF));
148         let f2 = Func::new(&mut store2, func_ty, move |_, _, results| {
149             results[0] = f1.clone().into();
150             Ok(())
151         });
152         assert!(f2.call(&mut store2, &[], &mut [Val::I32(0)]).is_err());
153     }
154     assert!(dropped.load(SeqCst));
155 
156     return Ok(());
157 
158     struct SetOnDrop(Arc<AtomicBool>);
159 
160     impl Drop for SetOnDrop {
161         fn drop(&mut self) {
162             self.0.store(true, SeqCst);
163         }
164     }
165 }
166