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