1 #![cfg(not(miri))] // not testing unsafe code
2
3 use wasmtime::*;
4
async_store() -> Store<()>5 fn async_store() -> Store<()> {
6 let engine = Engine::default();
7 let mut store = Store::new(&engine, ());
8 Func::wrap_async(&mut store, |_, ()| Box::new(async {}));
9 return store;
10 }
11
12 struct MyAsyncLimiter;
13
14 #[async_trait::async_trait]
15 impl ResourceLimiterAsync for MyAsyncLimiter {
memory_growing( &mut self, _current: usize, _desired: usize, _maximum: Option<usize>, ) -> Result<bool>16 async fn memory_growing(
17 &mut self,
18 _current: usize,
19 _desired: usize,
20 _maximum: Option<usize>,
21 ) -> Result<bool> {
22 Ok(true)
23 }
24
table_growing( &mut self, _current: usize, _desired: usize, _maximum: Option<usize>, ) -> Result<bool>25 async fn table_growing(
26 &mut self,
27 _current: usize,
28 _desired: usize,
29 _maximum: Option<usize>,
30 ) -> Result<bool> {
31 Ok(true)
32 }
33 }
34
async_limiter_store() -> Store<MyAsyncLimiter>35 fn async_limiter_store() -> Store<MyAsyncLimiter> {
36 let engine = Engine::default();
37 let mut store = Store::new(&engine, MyAsyncLimiter);
38 store.limiter_async(|x| x);
39 return store;
40 }
41
assert_requires_async<T>(store: &mut Store<T>)42 fn assert_requires_async<T>(store: &mut Store<T>) {
43 let module = Module::new(store.engine(), "(module)").unwrap();
44 assert!(Instance::new(&mut *store, &module, &[]).is_err());
45 }
46
47 #[test]
require_async_after_func_wrap()48 fn require_async_after_func_wrap() {
49 let engine = Engine::default();
50 let mut store = Store::new(&engine, ());
51 Func::wrap_async(&mut store, |_, ()| Box::new(async {}));
52 assert_requires_async(&mut store);
53 }
54
55 #[test]
require_async_after_func_new()56 fn require_async_after_func_new() {
57 let engine = Engine::default();
58 let mut store = Store::new(&engine, ());
59 let ty = FuncType::new(store.engine(), [], []);
60 Func::new_async(&mut store, ty, |_, _, _| Box::new(async { Ok(()) }));
61 assert_requires_async(&mut store);
62 }
63
64 #[tokio::test]
require_async_after_linker_with_func_wrap() -> Result<()>65 async fn require_async_after_linker_with_func_wrap() -> Result<()> {
66 let engine = Engine::default();
67 let mut store = Store::new(&engine, ());
68 let mut linker = Linker::new(store.engine());
69 linker.func_wrap_async("", "", |_, ()| Box::new(async {}))?;
70 let module = Module::new(store.engine(), r#"(module (import "" "" (func)))"#)?;
71 linker.instantiate_async(&mut store, &module).await?;
72 assert_requires_async(&mut store);
73 Ok(())
74 }
75
76 #[tokio::test]
require_async_after_linker_with_func_new() -> Result<()>77 async fn require_async_after_linker_with_func_new() -> Result<()> {
78 let engine = Engine::default();
79 let mut store = Store::new(&engine, ());
80 let mut linker = Linker::new(store.engine());
81 let ty = FuncType::new(store.engine(), [], []);
82 linker.func_new_async("", "", ty, |_, _, _| Box::new(async { Ok(()) }))?;
83 let module = Module::new(store.engine(), r#"(module (import "" "" (func)))"#)?;
84 linker.instantiate_async(&mut store, &module).await?;
85 assert_requires_async(&mut store);
86 Ok(())
87 }
88
89 #[test]
require_async_after_epochs() -> Result<()>90 fn require_async_after_epochs() -> Result<()> {
91 let mut config = Config::new();
92 config.epoch_interruption(true);
93 let engine = Engine::new(&config)?;
94 let mut store = Store::new(&engine, ());
95 store.epoch_deadline_async_yield_and_update(1);
96 assert_requires_async(&mut store);
97 Ok(())
98 }
99
100 #[test]
require_async_after_fuel() -> Result<()>101 fn require_async_after_fuel() -> Result<()> {
102 let mut config = Config::new();
103 config.consume_fuel(true);
104 let engine = Engine::new(&config)?;
105 let mut store = Store::new(&engine, ());
106 store.fuel_async_yield_interval(Some(1))?;
107 assert_requires_async(&mut store);
108 Ok(())
109 }
110
111 #[test]
require_async_after_async_limiter() -> Result<()>112 fn require_async_after_async_limiter() -> Result<()> {
113 let mut store = async_limiter_store();
114 assert_requires_async(&mut store);
115 Ok(())
116 }
117
118 #[tokio::test]
require_async_with_linker_func_wrap() -> Result<()>119 async fn require_async_with_linker_func_wrap() -> Result<()> {
120 let engine = Engine::default();
121 let mut store = Store::new(&engine, ());
122 let mut linker = Linker::new(store.engine());
123 linker.func_wrap_async("", "", |_, ()| Box::new(async {}))?;
124 let module = Module::new(store.engine(), r#"(module (import "" "" (func)))"#)?;
125 assert!(linker.instantiate(&mut store, &module).is_err());
126 linker.instantiate_async(&mut store, &module).await?;
127 Ok(())
128 }
129
130 #[test]
require_async_with_debug_handler() -> Result<()>131 fn require_async_with_debug_handler() -> Result<()> {
132 let mut config = Config::new();
133 config.guest_debug(true);
134 let engine = Engine::new(&config)?;
135 let mut store = Store::new(&engine, ());
136 store.set_debug_handler(MyDebugHandler);
137 assert_requires_async(&mut store);
138 return Ok(());
139
140 #[derive(Clone)]
141 struct MyDebugHandler;
142
143 impl DebugHandler for MyDebugHandler {
144 type Data = ();
145
146 async fn handle(&self, _: StoreContextMut<'_, ()>, _: DebugEvent<'_>) {}
147 }
148 }
149
150 struct MyAsyncCallHook;
151
152 #[async_trait::async_trait]
153 impl CallHookHandler<()> for MyAsyncCallHook {
handle_call_event(&self, _: StoreContextMut<'_, ()>, _: CallHook) -> Result<()>154 async fn handle_call_event(&self, _: StoreContextMut<'_, ()>, _: CallHook) -> Result<()> {
155 Ok(())
156 }
157 }
158
159 #[test]
require_async_with_async_call_hook() -> Result<()>160 fn require_async_with_async_call_hook() -> Result<()> {
161 let engine = Engine::default();
162 let mut store = Store::new(&engine, ());
163 store.call_hook_async(MyAsyncCallHook);
164 assert_requires_async(&mut store);
165 Ok(())
166 }
167
168 #[tokio::test]
async_disallows_instance_new() -> Result<()>169 async fn async_disallows_instance_new() -> Result<()> {
170 let mut store = async_store();
171 let module = Module::new(store.engine(), "(module)")?;
172 assert!(Instance::new(&mut store, &module, &[]).is_err());
173 Instance::new_async(&mut store, &module, &[]).await?;
174 Ok(())
175 }
176
177 #[tokio::test]
async_disallows_linker_instantiate() -> Result<()>178 async fn async_disallows_linker_instantiate() -> Result<()> {
179 let mut store = async_store();
180 let module = Module::new(store.engine(), "(module)")?;
181 let linker = Linker::new(store.engine());
182 assert!(linker.instantiate(&mut store, &module).is_err());
183 linker.instantiate_async(&mut store, &module).await?;
184 Ok(())
185 }
186
187 #[tokio::test]
async_disallows_func_call() -> Result<()>188 async fn async_disallows_func_call() -> Result<()> {
189 let mut store = async_store();
190 let func = Func::wrap(&mut store, || {});
191 assert!(func.call(&mut store, &[], &mut []).is_err());
192 func.call_async(&mut store, &[], &mut []).await?;
193 Ok(())
194 }
195
196 #[tokio::test]
async_disallows_typed_func_call() -> Result<()>197 async fn async_disallows_typed_func_call() -> Result<()> {
198 let mut store = async_store();
199 let func = Func::wrap(&mut store, || {});
200 let func = func.typed::<(), ()>(&mut store)?;
201 assert!(func.call(&mut store, ()).is_err());
202 func.call_async(&mut store, ()).await?;
203 Ok(())
204 }
205
206 #[tokio::test]
async_disallows_gc() -> Result<()>207 async fn async_disallows_gc() -> Result<()> {
208 let mut store = async_limiter_store();
209 assert!(store.gc(None).is_err());
210 store.gc_async(None).await;
211 Ok(())
212 }
213
214 #[tokio::test]
async_disallows_array_ref_new() -> Result<()>215 async fn async_disallows_array_ref_new() -> Result<()> {
216 let mut store = async_limiter_store();
217 let ty = ArrayType::new(
218 store.engine(),
219 FieldType::new(Mutability::Var, StorageType::I8),
220 );
221 let pre = ArrayRefPre::new(&mut store, ty);
222 assert!(ArrayRef::new(&mut store, &pre, &Val::I32(0), 10).is_err());
223 ArrayRef::new_async(&mut store, &pre, &Val::I32(0), 10).await?;
224 Ok(())
225 }
226
227 #[tokio::test]
async_disallows_array_ref_new_fixed() -> Result<()>228 async fn async_disallows_array_ref_new_fixed() -> Result<()> {
229 let mut store = async_limiter_store();
230 let ty = ArrayType::new(
231 store.engine(),
232 FieldType::new(Mutability::Var, StorageType::I8),
233 );
234 let pre = ArrayRefPre::new(&mut store, ty);
235 assert!(ArrayRef::new_fixed(&mut store, &pre, &[Val::I32(0)]).is_err());
236 ArrayRef::new_fixed_async(&mut store, &pre, &[Val::I32(0)]).await?;
237 Ok(())
238 }
239
240 #[tokio::test]
async_disallows_exnref_new() -> Result<()>241 async fn async_disallows_exnref_new() -> Result<()> {
242 let mut store = async_limiter_store();
243 let ty = ExnType::new(store.engine(), [])?;
244 let pre = ExnRefPre::new(&mut store, ty);
245 let fty = FuncType::new(store.engine(), [], []);
246 let tag = Tag::new(&mut store, &TagType::new(fty))?;
247 assert!(ExnRef::new(&mut store, &pre, &tag, &[]).is_err());
248 ExnRef::new_async(&mut store, &pre, &tag, &[]).await?;
249 Ok(())
250 }
251
252 #[tokio::test]
async_disallows_externref_new() -> Result<()>253 async fn async_disallows_externref_new() -> Result<()> {
254 let mut store = async_limiter_store();
255 assert!(ExternRef::new(&mut store, 1).is_err());
256 ExternRef::new_async(&mut store, 1).await?;
257 Ok(())
258 }
259
260 #[tokio::test]
async_disallows_structref_new() -> Result<()>261 async fn async_disallows_structref_new() -> Result<()> {
262 let mut store = async_limiter_store();
263 let ty = StructType::new(
264 store.engine(),
265 [FieldType::new(Mutability::Var, StorageType::I8)],
266 )?;
267 let pre = StructRefPre::new(&mut store, ty);
268 assert!(StructRef::new(&mut store, &pre, &[Val::I32(0)]).is_err());
269 StructRef::new_async(&mut store, &pre, &[Val::I32(0)]).await?;
270 Ok(())
271 }
272
273 #[test]
epoch_yield_disallowed_without_async() -> Result<()>274 fn epoch_yield_disallowed_without_async() -> Result<()> {
275 let mut config = Config::new();
276 config.epoch_interruption(true);
277 let engine = Engine::new(&config)?;
278 let mut store = Store::new(&engine, ());
279
280 let module = Module::new(&engine, r#"(module (func (export "") (loop br 0)))"#)?;
281 let instance = Instance::new(&mut store, &module, &[])?;
282 let func = instance.get_typed_func::<(), ()>(&mut store, "")?;
283
284 store.epoch_deadline_callback(|_store| Ok(UpdateDeadline::Yield(1)));
285 assert!(func.call(&mut store, ()).is_err());
286
287 store.epoch_deadline_callback(|_store| Ok(UpdateDeadline::YieldCustom(1, Box::pin(async {}))));
288 assert!(func.call(&mut store, ()).is_err());
289
290 store.epoch_deadline_trap();
291 let err = func.call(&mut store, ()).unwrap_err().downcast::<Trap>()?;
292 assert_eq!(err, Trap::Interrupt);
293 Ok(())
294 }
295
296 #[test]
start_sync_then_configure_async_then_do_async() -> Result<()>297 fn start_sync_then_configure_async_then_do_async() -> Result<()> {
298 let mut config = Config::new();
299 config.consume_fuel(true);
300 let engine = Engine::new(&config)?;
301 let mut store = Store::new(&engine, MyAsyncLimiter);
302
303 let module = Module::new(
304 &engine,
305 r#"
306 (module
307 (import "" "" (func $host))
308 (memory 1)
309 (func (export "")
310 call $host
311 (loop br 0)
312 )
313 )
314 "#,
315 )?;
316
317 let mut linker = Linker::new(&engine);
318 linker.func_wrap("", "", |mut store: Caller<'_, MyAsyncLimiter>| {
319 store.as_context_mut().fuel_async_yield_interval(Some(1))
320 })?;
321 store.set_fuel(100)?;
322 let instance = linker.instantiate(&mut store, &module)?;
323 let func = instance.get_typed_func::<(), ()>(&mut store, "")?;
324 let err = func.call(&mut store, ()).unwrap_err();
325 assert!(
326 format!("{err:?}").contains("configured to do async things"),
327 "bad error {err:?}",
328 );
329 Ok(())
330 }
331
332 #[tokio::test]
async_limiter_disallows_table_new() -> Result<()>333 async fn async_limiter_disallows_table_new() -> Result<()> {
334 let mut store = async_limiter_store();
335 let ty = TableType::new(RefType::FUNCREF, 1, None);
336 assert!(Table::new(&mut store, ty.clone(), Ref::Func(None)).is_err());
337 Table::new_async(&mut store, ty, Ref::Func(None)).await?;
338 Ok(())
339 }
340
341 #[tokio::test]
async_limiter_disallows_table_grow() -> Result<()>342 async fn async_limiter_disallows_table_grow() -> Result<()> {
343 let mut store = async_limiter_store();
344 let ty = TableType::new(RefType::FUNCREF, 1, None);
345 let table = Table::new_async(&mut store, ty, Ref::Func(None)).await?;
346 assert!(table.grow(&mut store, 1, Ref::Func(None)).is_err());
347 table.grow_async(&mut store, 1, Ref::Func(None)).await?;
348 Ok(())
349 }
350
351 #[tokio::test]
async_limiter_disallows_memory_new() -> Result<()>352 async fn async_limiter_disallows_memory_new() -> Result<()> {
353 let mut store = async_limiter_store();
354 let ty = MemoryType::new(1, None);
355 assert!(Memory::new(&mut store, ty.clone()).is_err());
356 Memory::new_async(&mut store, ty).await?;
357 Ok(())
358 }
359
360 #[tokio::test]
async_limiter_disallows_memory_grow() -> Result<()>361 async fn async_limiter_disallows_memory_grow() -> Result<()> {
362 let mut store = async_limiter_store();
363 let ty = MemoryType::new(1, None);
364 let mem = Memory::new_async(&mut store, ty).await?;
365 assert!(mem.grow(&mut store, 1).is_err());
366 mem.grow_async(&mut store, 1).await?;
367 Ok(())
368 }
369