1 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
2 use wasmtime::bail;
3 use wasmtime::*;
4
5 #[test]
wrap_func() -> Result<()>6 fn wrap_func() -> Result<()> {
7 let engine = Engine::default();
8 let mut linker = Linker::<()>::new(&engine);
9 linker.allow_shadowing(true);
10
11 linker.func_wrap("", "", || {})?;
12 linker.func_wrap("m", "f", |_: i32| {})?;
13 linker.func_wrap("m", "f2", |_: i32, _: i64| {})?;
14 linker.func_wrap("m2", "f", |_: f32, _: f64| {})?;
15 linker.func_wrap("m2", "f2", || -> i32 { 0 })?;
16 linker.func_wrap("", "", || -> i64 { 0 })?;
17 linker.func_wrap("m", "f", || -> f32 { 0.0 })?;
18 linker.func_wrap("m2", "f", || -> f64 { 0.0 })?;
19 linker.func_wrap("m3", "", || -> Option<Rooted<ExternRef>> { None })?;
20 linker.func_wrap("m3", "f", || -> Option<Func> { None })?;
21
22 linker.func_wrap("", "f1", || -> Result<()> {
23 loop {}
24 })?;
25 linker.func_wrap("", "f2", || -> Result<i32> {
26 loop {}
27 })?;
28 linker.func_wrap("", "f3", || -> Result<i64> {
29 loop {}
30 })?;
31 linker.func_wrap("", "f4", || -> Result<f32> {
32 loop {}
33 })?;
34 linker.func_wrap("", "f5", || -> Result<f64> {
35 loop {}
36 })?;
37 linker.func_wrap("", "f6", || -> Result<Option<Rooted<ExternRef>>> {
38 loop {}
39 })?;
40 linker.func_wrap("", "f7", || -> Result<Option<Func>> {
41 loop {}
42 })?;
43 Ok(())
44 }
45
46 #[test]
drop_func() -> Result<()>47 fn drop_func() -> Result<()> {
48 static HITS: AtomicUsize = AtomicUsize::new(0);
49 struct A;
50
51 impl Drop for A {
52 fn drop(&mut self) {
53 HITS.fetch_add(1, SeqCst);
54 }
55 }
56
57 let engine = Engine::default();
58 let mut linker = Linker::<()>::new(&engine);
59 linker.allow_shadowing(true);
60
61 let a = A;
62 linker.func_wrap("", "", move || {
63 let _ = &a;
64 })?;
65
66 assert_eq!(HITS.load(SeqCst), 0);
67
68 // Define the function again to ensure redefined functions are dropped
69
70 let a = A;
71 linker.func_wrap("", "", move || {
72 let _ = &a;
73 })?;
74
75 assert_eq!(HITS.load(SeqCst), 1);
76
77 drop(linker);
78
79 assert_eq!(HITS.load(SeqCst), 2);
80
81 Ok(())
82 }
83
84 #[test]
85 #[cfg_attr(miri, ignore)]
drop_delayed() -> Result<()>86 fn drop_delayed() -> Result<()> {
87 static HITS: AtomicUsize = AtomicUsize::new(0);
88
89 struct A;
90
91 impl Drop for A {
92 fn drop(&mut self) {
93 HITS.fetch_add(1, SeqCst);
94 }
95 }
96
97 let engine = Engine::default();
98 let mut linker = Linker::<()>::new(&engine);
99
100 let a = A;
101 linker.func_wrap("", "", move || {
102 let _ = &a;
103 })?;
104
105 assert_eq!(HITS.load(SeqCst), 0);
106
107 let module = Module::new(&engine, &wat::parse_str(r#"(import "" "" (func))"#)?)?;
108
109 let mut store = Store::new(&engine, ());
110 let func = linker.get(&mut store, "", "").unwrap();
111 Instance::new(&mut store, &module, &[func])?;
112
113 drop(store);
114
115 assert_eq!(HITS.load(SeqCst), 0);
116
117 let mut store = Store::new(&engine, ());
118 let func = linker.get(&mut store, "", "").unwrap();
119 Instance::new(&mut store, &module, &[func])?;
120
121 drop(store);
122
123 assert_eq!(HITS.load(SeqCst), 0);
124
125 drop(linker);
126
127 assert_eq!(HITS.load(SeqCst), 1);
128
129 Ok(())
130 }
131
132 #[test]
signatures_match() -> Result<()>133 fn signatures_match() -> Result<()> {
134 let engine = Engine::default();
135 let mut linker = Linker::<()>::new(&engine);
136
137 linker.func_wrap("", "f1", || {})?;
138 linker.func_wrap("", "f2", || -> i32 {
139 loop {}
140 })?;
141 linker.func_wrap("", "f3", || -> i64 {
142 loop {}
143 })?;
144 linker.func_wrap("", "f4", || -> f32 {
145 loop {}
146 })?;
147 linker.func_wrap("", "f5", || -> f64 {
148 loop {}
149 })?;
150 linker.func_wrap(
151 "",
152 "f6",
153 |_: f32,
154 _: f64,
155 _: i32,
156 _: i64,
157 _: i32,
158 _: Option<Rooted<ExternRef>>,
159 _: Option<Func>|
160 -> f64 { loop {} },
161 )?;
162
163 let mut store = Store::new(&engine, ());
164
165 let f = linker
166 .get(&mut store, "", "f1")
167 .unwrap()
168 .into_func()
169 .unwrap();
170 assert_eq!(f.ty(&store).params().len(), 0);
171 assert_eq!(f.ty(&store).results().len(), 0);
172
173 let f = linker
174 .get(&mut store, "", "f2")
175 .unwrap()
176 .into_func()
177 .unwrap();
178 assert_eq!(f.ty(&store).params().len(), 0);
179 assert_eq!(f.ty(&store).results().len(), 1);
180 assert!(f.ty(&store).results().nth(0).unwrap().is_i32());
181
182 let f = linker
183 .get(&mut store, "", "f3")
184 .unwrap()
185 .into_func()
186 .unwrap();
187 assert_eq!(f.ty(&store).params().len(), 0);
188 assert_eq!(f.ty(&store).results().len(), 1);
189 assert!(f.ty(&store).results().nth(0).unwrap().is_i64());
190
191 let f = linker
192 .get(&mut store, "", "f4")
193 .unwrap()
194 .into_func()
195 .unwrap();
196 assert_eq!(f.ty(&store).params().len(), 0);
197 assert_eq!(f.ty(&store).results().len(), 1);
198 assert!(f.ty(&store).results().nth(0).unwrap().is_f32());
199
200 let f = linker
201 .get(&mut store, "", "f5")
202 .unwrap()
203 .into_func()
204 .unwrap();
205 assert_eq!(f.ty(&store).params().len(), 0);
206 assert_eq!(f.ty(&store).results().len(), 1);
207 assert!(f.ty(&store).results().nth(0).unwrap().is_f64());
208
209 let f = linker
210 .get(&mut store, "", "f6")
211 .unwrap()
212 .into_func()
213 .unwrap();
214
215 assert_eq!(f.ty(&store).params().len(), 7);
216 assert!(f.ty(&store).params().nth(0).unwrap().is_f32());
217 assert!(f.ty(&store).params().nth(1).unwrap().is_f64());
218 assert!(f.ty(&store).params().nth(2).unwrap().is_i32());
219 assert!(f.ty(&store).params().nth(3).unwrap().is_i64());
220 assert!(f.ty(&store).params().nth(4).unwrap().is_i32());
221 assert!(f.ty(&store).params().nth(5).unwrap().is_externref());
222 assert!(f.ty(&store).params().nth(6).unwrap().is_funcref());
223
224 assert_eq!(f.ty(&store).results().len(), 1);
225 assert!(f.ty(&store).results().nth(0).unwrap().is_f64());
226
227 Ok(())
228 }
229
230 #[test]
231 #[cfg_attr(miri, ignore)]
import_works() -> Result<()>232 fn import_works() -> Result<()> {
233 static HITS: AtomicUsize = AtomicUsize::new(0);
234
235 let wasm = wat::parse_str(
236 r#"
237 (import "" "f1" (func))
238 (import "" "f2" (func (param i32) (result i32)))
239 (import "" "f3" (func (param i32) (param i64)))
240 (import "" "f4" (func (param i32 i64 i32 f32 f64 externref funcref)))
241
242 (func (export "run") (param externref funcref)
243 call 0
244 i32.const 0
245 call 1
246 i32.const 1
247 i32.add
248 i64.const 3
249 call 2
250
251 i32.const 100
252 i64.const 200
253 i32.const 300
254 f32.const 400
255 f64.const 500
256 local.get 0
257 local.get 1
258 call 3
259 )
260 "#,
261 )?;
262
263 let engine = Engine::default();
264 let mut linker = Linker::<()>::new(&engine);
265
266 linker.func_wrap("", "f1", || {
267 assert_eq!(HITS.fetch_add(1, SeqCst), 0);
268 })?;
269
270 linker.func_wrap("", "f2", |x: i32| -> i32 {
271 assert_eq!(x, 0);
272 assert_eq!(HITS.fetch_add(1, SeqCst), 1);
273 1
274 })?;
275
276 linker.func_wrap("", "f3", |x: i32, y: i64| {
277 assert_eq!(x, 2);
278 assert_eq!(y, 3);
279 assert_eq!(HITS.fetch_add(1, SeqCst), 2);
280 })?;
281
282 linker.func_wrap(
283 "",
284 "f4",
285 |mut caller: Caller<'_, _>,
286 a: i32,
287 b: i64,
288 c: i32,
289 d: f32,
290 e: f64,
291 f: Option<Rooted<ExternRef>>,
292 g: Option<Func>| {
293 assert_eq!(a, 100);
294 assert_eq!(b, 200);
295 assert_eq!(c, 300);
296 assert_eq!(d, 400.0);
297 assert_eq!(e, 500.0);
298 assert_eq!(
299 f.as_ref()
300 .unwrap()
301 .data(&caller)
302 .unwrap()
303 .unwrap()
304 .downcast_ref::<String>()
305 .unwrap(),
306 "hello"
307 );
308 let mut results = [Val::I32(0)];
309 g.as_ref()
310 .unwrap()
311 .call(&mut caller, &[], &mut results)
312 .unwrap();
313 assert_eq!(results[0].unwrap_i32(), 42);
314 assert_eq!(HITS.fetch_add(1, SeqCst), 3);
315 },
316 )?;
317
318 let module = Module::new(&engine, &wasm)?;
319
320 let mut store = Store::new(&engine, ());
321 let instance = linker.instantiate(&mut store, &module)?;
322 let run = instance.get_func(&mut store, "run").unwrap();
323 let funcref = Val::FuncRef(Some(Func::wrap(&mut store, || -> i32 { 42 })));
324 let externref = Val::ExternRef(Some(ExternRef::new(&mut store, "hello".to_string())?));
325 run.call(&mut store, &[externref, funcref], &mut [])?;
326
327 assert_eq!(HITS.load(SeqCst), 4);
328
329 Ok(())
330 }
331
332 #[test]
333 #[cfg_attr(miri, ignore)]
call_import_many_args() -> Result<()>334 fn call_import_many_args() -> Result<()> {
335 let wasm = wat::parse_str(
336 r#"
337 (import "" "host" (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)))
338 (func (export "run")
339 i32.const 1
340 i32.const 2
341 i32.const 3
342 i32.const 4
343 i32.const 5
344 i32.const 6
345 i32.const 7
346 i32.const 8
347 i32.const 9
348 i32.const 10
349 call 0
350 )
351 "#,
352 )?;
353
354 let engine = Engine::default();
355 let mut linker = Linker::<()>::new(&engine);
356
357 linker.func_wrap(
358 "",
359 "host",
360 |x1: i32,
361 x2: i32,
362 x3: i32,
363 x4: i32,
364 x5: i32,
365 x6: i32,
366 x7: i32,
367 x8: i32,
368 x9: i32,
369 x10: i32| {
370 assert_eq!(x1, 1);
371 assert_eq!(x2, 2);
372 assert_eq!(x3, 3);
373 assert_eq!(x4, 4);
374 assert_eq!(x5, 5);
375 assert_eq!(x6, 6);
376 assert_eq!(x7, 7);
377 assert_eq!(x8, 8);
378 assert_eq!(x9, 9);
379 assert_eq!(x10, 10);
380 },
381 )?;
382
383 let module = Module::new(&engine, &wasm)?;
384 let mut store = Store::new(&engine, ());
385 let instance = linker.instantiate(&mut store, &module)?;
386 let run = instance.get_func(&mut store, "run").unwrap();
387 run.call(&mut store, &[], &mut [])?;
388
389 Ok(())
390 }
391
392 #[test]
393 #[cfg_attr(miri, ignore)]
call_wasm_many_args() -> Result<()>394 fn call_wasm_many_args() -> Result<()> {
395 let wasm = wat::parse_str(
396 r#"
397 (func (export "run") (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
398 i32.const 1
399 local.get 0
400 i32.ne
401 if
402 unreachable
403 end
404
405 i32.const 10
406 local.get 9
407 i32.ne
408 if
409 unreachable
410 end
411 )
412
413 (func (export "test")
414 i32.const 1
415 i32.const 2
416 i32.const 3
417 i32.const 4
418 i32.const 5
419 i32.const 6
420 i32.const 7
421 i32.const 8
422 i32.const 9
423 i32.const 10
424 call 0
425 )
426 "#,
427 )?;
428
429 let engine = Engine::default();
430 let module = Module::new(&engine, &wasm)?;
431
432 let mut store = Store::new(&engine, ());
433 let instance = Instance::new(&mut store, &module, &[])?;
434
435 let run = instance.get_func(&mut store, "run").unwrap();
436 run.call(
437 &mut store,
438 &[
439 1.into(),
440 2.into(),
441 3.into(),
442 4.into(),
443 5.into(),
444 6.into(),
445 7.into(),
446 8.into(),
447 9.into(),
448 10.into(),
449 ],
450 &mut [],
451 )?;
452
453 let typed_run = instance
454 .get_typed_func::<(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32), ()>(
455 &mut store, "run",
456 )?;
457 typed_run.call(&mut store, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10))?;
458
459 let test = instance.get_func(&mut store, "test").unwrap();
460 test.call(&mut store, &[], &mut [])?;
461
462 Ok(())
463 }
464
465 #[test]
466 #[cfg_attr(miri, ignore)]
trap_smoke() -> Result<()>467 fn trap_smoke() -> Result<()> {
468 let engine = Engine::default();
469 let mut linker = Linker::<()>::new(&engine);
470 linker.func_wrap("", "", || -> Result<()> { bail!("test") })?;
471
472 let mut store = Store::new(&engine, ());
473
474 let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap();
475
476 let err = f.call(&mut store, &[], &mut []).unwrap_err();
477
478 assert!(err.to_string().contains("test"));
479
480 Ok(())
481 }
482
483 #[test]
484 #[cfg_attr(miri, ignore)]
trap_import() -> Result<()>485 fn trap_import() -> Result<()> {
486 let wasm = wat::parse_str(
487 r#"
488 (import "" "" (func))
489 (start 0)
490 "#,
491 )?;
492
493 let engine = Engine::default();
494 let mut linker = Linker::new(&engine);
495 linker.func_wrap("", "", || -> Result<()> { bail!("foo") })?;
496
497 let module = Module::new(&engine, &wasm)?;
498 let mut store = Store::new(&engine, ());
499
500 let trap = linker.instantiate(&mut store, &module).unwrap_err();
501
502 assert!(trap.to_string().contains("foo"));
503
504 Ok(())
505 }
506
507 #[test]
508 #[cfg_attr(miri, ignore)]
new_from_signature() -> Result<()>509 fn new_from_signature() -> Result<()> {
510 let engine = Engine::default();
511 let mut linker = Linker::new(&engine);
512
513 let ty = FuncType::new(&engine, None, None);
514 linker.func_new("", "f1", ty, |_, _, _| panic!())?;
515
516 let ty = FuncType::new(&engine, Some(ValType::I32), Some(ValType::F64));
517 linker.func_new("", "f2", ty, |_, _, _| panic!())?;
518
519 let mut store = Store::new(&engine, ());
520
521 let f = linker
522 .get(&mut store, "", "f1")
523 .unwrap()
524 .into_func()
525 .unwrap();
526 assert!(f.typed::<(), ()>(&store).is_ok());
527 assert!(f.typed::<(), i32>(&store).is_err());
528 assert!(f.typed::<i32, ()>(&store).is_err());
529
530 let f = linker
531 .get(&mut store, "", "f2")
532 .unwrap()
533 .into_func()
534 .unwrap();
535 assert!(f.typed::<(), ()>(&store).is_err());
536 assert!(f.typed::<(), i32>(&store).is_err());
537 assert!(f.typed::<i32, ()>(&store).is_err());
538 assert!(f.typed::<i32, f64>(&store).is_ok());
539
540 Ok(())
541 }
542
543 #[test]
call_wrapped_func() -> Result<()>544 fn call_wrapped_func() -> Result<()> {
545 let engine = Engine::default();
546 let mut linker = Linker::new(&engine);
547 let mut results = [Val::I32(0)];
548
549 linker.func_wrap("", "f1", |a: i32, b: i64, c: f32, d: f64| {
550 assert_eq!(a, 1);
551 assert_eq!(b, 2);
552 assert_eq!(c, 3.0);
553 assert_eq!(d, 4.0);
554 })?;
555
556 linker.func_wrap("", "f2", || 1i32)?;
557
558 linker.func_wrap("", "f3", || 2i64)?;
559
560 linker.func_wrap("", "f4", || 3.0f32)?;
561
562 linker.func_wrap("", "f5", || 4.0f64)?;
563
564 let mut store = Store::new(&engine, ());
565
566 let f = linker
567 .get(&mut store, "", "f1")
568 .unwrap()
569 .into_func()
570 .unwrap();
571 f.call(
572 &mut store,
573 &[Val::I32(1), Val::I64(2), 3.0f32.into(), 4.0f64.into()],
574 &mut [],
575 )?;
576 f.typed::<(i32, i64, f32, f64), ()>(&store)?
577 .call(&mut store, (1, 2, 3.0, 4.0))?;
578
579 let f = linker
580 .get(&mut store, "", "f2")
581 .unwrap()
582 .into_func()
583 .unwrap();
584 f.call(&mut store, &[], &mut results)?;
585 assert_eq!(results[0].unwrap_i32(), 1);
586 assert_eq!(f.typed::<(), i32>(&store)?.call(&mut store, ())?, 1);
587
588 let f = linker
589 .get(&mut store, "", "f3")
590 .unwrap()
591 .into_func()
592 .unwrap();
593 f.call(&mut store, &[], &mut results)?;
594 assert_eq!(results[0].unwrap_i64(), 2);
595 assert_eq!(f.typed::<(), i64>(&store)?.call(&mut store, ())?, 2);
596
597 let f = linker
598 .get(&mut store, "", "f4")
599 .unwrap()
600 .into_func()
601 .unwrap();
602 f.call(&mut store, &[], &mut results)?;
603 assert_eq!(results[0].unwrap_f32(), 3.0);
604 assert_eq!(f.typed::<(), f32>(&store)?.call(&mut store, ())?, 3.0);
605
606 let f = linker
607 .get(&mut store, "", "f5")
608 .unwrap()
609 .into_func()
610 .unwrap();
611 f.call(&mut store, &[], &mut results)?;
612 assert_eq!(results[0].unwrap_f64(), 4.0);
613 assert_eq!(f.typed::<(), f64>(&store)?.call(&mut store, ())?, 4.0);
614
615 Ok(())
616 }
617
618 #[test]
619 #[cfg_attr(miri, ignore)]
func_return_nothing() -> Result<()>620 fn func_return_nothing() -> Result<()> {
621 let engine = Engine::default();
622 let mut linker = Linker::new(&engine);
623 let ty = FuncType::new(&engine, None, Some(ValType::I32));
624 linker.func_new("", "", ty, |_, _, _| Ok(()))?;
625
626 let mut store = Store::new(&engine, ());
627 let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap();
628 let err = f.call(&mut store, &[], &mut [Val::I32(0)]).unwrap_err();
629 assert!(
630 err.to_string()
631 .contains("function attempted to return an incompatible value")
632 );
633 Ok(())
634 }
635
636 #[test]
637 #[cfg_attr(miri, ignore)]
call_via_funcref() -> Result<()>638 fn call_via_funcref() -> Result<()> {
639 static HITS: AtomicUsize = AtomicUsize::new(0);
640
641 struct A;
642
643 impl Drop for A {
644 fn drop(&mut self) {
645 HITS.fetch_add(1, SeqCst);
646 }
647 }
648
649 let wasm = wat::parse_str(
650 r#"
651 (table $t 1 funcref)
652 (type $add (func (param i32 i32) (result i32)))
653 (func (export "call") (param funcref) (result i32 funcref)
654 (table.set $t (i32.const 0) (local.get 0))
655 (call_indirect (type $add) (i32.const 3) (i32.const 4) (i32.const 0))
656 (local.get 0)
657 )
658 "#,
659 )?;
660
661 let engine = Engine::default();
662 let mut linker = Linker::new(&engine);
663 let a = A;
664 linker.func_wrap("", "", move |x: i32, y: i32| {
665 let _ = &a;
666 x + y
667 })?;
668
669 let module = Module::new(&engine, &wasm)?;
670 let mut store = Store::new(&engine, ());
671 let instance = Instance::new(&mut store, &module, &[])?;
672
673 let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap();
674 let mut results = [Val::I32(0), Val::I32(0)];
675 instance
676 .get_func(&mut store, "call")
677 .unwrap()
678 .call(&mut store, &[f.into()], &mut results)?;
679 assert_eq!(results[0].unwrap_i32(), 7);
680
681 {
682 let f = results[1].unwrap_funcref().unwrap();
683 let mut results = [Val::I32(0)];
684 f.call(&mut store, &[1.into(), 2.into()], &mut results)?;
685 assert_eq!(results[0].unwrap_i32(), 3);
686 }
687
688 assert_eq!(HITS.load(SeqCst), 0);
689
690 drop(store);
691
692 assert_eq!(HITS.load(SeqCst), 0);
693
694 drop(linker);
695
696 assert_eq!(HITS.load(SeqCst), 1);
697
698 Ok(())
699 }
700
701 #[test]
store_with_context() -> Result<()>702 fn store_with_context() -> Result<()> {
703 struct Ctx {
704 called: bool,
705 }
706
707 let engine = Engine::default();
708 let mut linker = Linker::new(&engine);
709
710 linker.func_wrap("", "", |mut caller: Caller<'_, Ctx>| {
711 caller.data_mut().called = true;
712 })?;
713
714 let mut store = Store::new(&engine, Ctx { called: false });
715
716 let f = linker.get(&mut store, "", "").unwrap().into_func().unwrap();
717 f.call(&mut store, &[], &mut [])?;
718
719 assert!(store.data().called);
720
721 Ok(())
722 }
723
724 #[test]
725 #[cfg_attr(miri, ignore)]
wasi_imports() -> Result<()>726 fn wasi_imports() -> Result<()> {
727 let engine = Engine::default();
728 let mut linker = Linker::new(&engine);
729 wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |t| t)?;
730
731 let wasm = wat::parse_str(
732 r#"
733 (import "wasi_snapshot_preview1" "proc_exit" (func $__wasi_proc_exit (param i32)))
734 (memory (export "memory") 0)
735 (func (export "_start")
736 (call $__wasi_proc_exit (i32.const 123))
737 )
738 "#,
739 )?;
740
741 let module = Module::new(&engine, wasm)?;
742 let mut store = Store::new(&engine, wasmtime_wasi::WasiCtxBuilder::new().build_p1());
743 let instance = linker.instantiate(&mut store, &module)?;
744
745 let start = instance.get_typed_func::<(), ()>(&mut store, "_start")?;
746 let exit = start
747 .call(&mut store, ())
748 .unwrap_err()
749 .downcast::<wasmtime_wasi::I32Exit>()?;
750 assert_eq!(exit.0, 123);
751
752 Ok(())
753 }
754