Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/tests/all/component_model/func.rs
3054 views
1
#![cfg(not(miri))]
2
3
use super::{ApiStyle, REALLOC_AND_FREE};
4
use std::sync::Arc;
5
use wasmtime::Result;
6
use wasmtime::component::*;
7
use wasmtime::{Config, Engine, Store, StoreContextMut, Trap};
8
9
const CANON_32BIT_NAN: u32 = 0b01111111110000000000000000000000;
10
const CANON_64BIT_NAN: u64 = 0b0111111111111000000000000000000000000000000000000000000000000000;
11
12
#[test]
13
fn thunks() -> Result<()> {
14
let component = r#"
15
(component
16
(core module $m
17
(func (export "thunk"))
18
(func (export "thunk-trap") unreachable)
19
)
20
(core instance $i (instantiate $m))
21
(func (export "thunk")
22
(canon lift (core func $i "thunk"))
23
)
24
(func (export "thunk-trap")
25
(canon lift (core func $i "thunk-trap"))
26
)
27
)
28
"#;
29
30
let engine = super::engine();
31
let component = Component::new(&engine, component)?;
32
let mut store = Store::new(&engine, ());
33
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
34
instance
35
.get_typed_func::<(), ()>(&mut store, "thunk")?
36
.call(&mut store, ())?;
37
let err = instance
38
.get_typed_func::<(), ()>(&mut store, "thunk-trap")?
39
.call(&mut store, ())
40
.unwrap_err();
41
assert_eq!(err.downcast::<Trap>()?, Trap::UnreachableCodeReached);
42
43
Ok(())
44
}
45
46
#[test]
47
fn typecheck() -> Result<()> {
48
let component = r#"
49
(component
50
(core module $m
51
(func (export "thunk"))
52
(func (export "take-string") (param i32 i32))
53
(func (export "two-args") (param i32 i32 i32))
54
(func (export "ret-one") (result i32) unreachable)
55
56
(memory (export "memory") 1)
57
(func (export "realloc") (param i32 i32 i32 i32) (result i32)
58
unreachable)
59
)
60
(core instance $i (instantiate (module $m)))
61
(func (export "thunk")
62
(canon lift (core func $i "thunk"))
63
)
64
(func (export "take-string") (param "a" string)
65
(canon lift (core func $i "take-string") (memory $i "memory") (realloc (func $i "realloc")))
66
)
67
(func (export "take-two-args") (param "a" s32) (param "b" (list u8))
68
(canon lift (core func $i "two-args") (memory $i "memory") (realloc (func $i "realloc")))
69
)
70
(func (export "ret-tuple") (result (tuple u8 s8))
71
(canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))
72
)
73
(func (export "ret-tuple1") (result (tuple u32))
74
(canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))
75
)
76
(func (export "ret-string") (result string)
77
(canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))
78
)
79
(func (export "ret-list-u8") (result (list u8))
80
(canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))
81
)
82
)
83
"#;
84
85
let engine = Engine::default();
86
let component = Component::new(&engine, component)?;
87
let mut store = Store::new(&engine, ());
88
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
89
let thunk = instance.get_func(&mut store, "thunk").unwrap();
90
let take_string = instance.get_func(&mut store, "take-string").unwrap();
91
let take_two_args = instance.get_func(&mut store, "take-two-args").unwrap();
92
let ret_tuple = instance.get_func(&mut store, "ret-tuple").unwrap();
93
let ret_tuple1 = instance.get_func(&mut store, "ret-tuple1").unwrap();
94
let ret_string = instance.get_func(&mut store, "ret-string").unwrap();
95
let ret_list_u8 = instance.get_func(&mut store, "ret-list-u8").unwrap();
96
assert!(thunk.typed::<(), (u32,)>(&store).is_err());
97
assert!(thunk.typed::<(u32,), ()>(&store).is_err());
98
assert!(thunk.typed::<(), ()>(&store).is_ok());
99
assert!(take_string.typed::<(), ()>(&store).is_err());
100
assert!(take_string.typed::<(String,), ()>(&store).is_ok());
101
assert!(take_string.typed::<(&str,), ()>(&store).is_ok());
102
assert!(take_string.typed::<(&[u8],), ()>(&store).is_err());
103
assert!(take_two_args.typed::<(), ()>(&store).is_err());
104
assert!(take_two_args.typed::<(i32, &[u8]), (u32,)>(&store).is_err());
105
assert!(take_two_args.typed::<(u32, &[u8]), ()>(&store).is_err());
106
assert!(take_two_args.typed::<(i32, &[u8]), ()>(&store).is_ok());
107
assert!(ret_tuple.typed::<(), ()>(&store).is_err());
108
assert!(ret_tuple.typed::<(), (u8,)>(&store).is_err());
109
assert!(ret_tuple.typed::<(), ((u8, i8),)>(&store).is_ok());
110
assert!(ret_tuple1.typed::<(), ((u32,),)>(&store).is_ok());
111
assert!(ret_tuple1.typed::<(), (u32,)>(&store).is_err());
112
assert!(ret_string.typed::<(), ()>(&store).is_err());
113
assert!(ret_string.typed::<(), (WasmStr,)>(&store).is_ok());
114
assert!(ret_list_u8.typed::<(), (WasmList<u16>,)>(&store).is_err());
115
assert!(ret_list_u8.typed::<(), (WasmList<i8>,)>(&store).is_err());
116
assert!(ret_list_u8.typed::<(), (WasmList<u8>,)>(&store).is_ok());
117
118
Ok(())
119
}
120
121
#[test]
122
fn integers() -> Result<()> {
123
let component = r#"
124
(component
125
(core module $m
126
(func (export "take-i32-100") (param i32)
127
local.get 0
128
i32.const 100
129
i32.eq
130
br_if 0
131
unreachable
132
)
133
(func (export "take-i64-100") (param i64)
134
local.get 0
135
i64.const 100
136
i64.eq
137
br_if 0
138
unreachable
139
)
140
(func (export "ret-i32-0") (result i32) i32.const 0)
141
(func (export "ret-i64-0") (result i64) i64.const 0)
142
(func (export "ret-i32-minus-1") (result i32) i32.const -1)
143
(func (export "ret-i64-minus-1") (result i64) i64.const -1)
144
(func (export "ret-i32-100000") (result i32) i32.const 100000)
145
)
146
(core instance $i (instantiate (module $m)))
147
(func (export "take-u8") (param "a" u8) (canon lift (core func $i "take-i32-100")))
148
(func (export "take-s8") (param "a" s8) (canon lift (core func $i "take-i32-100")))
149
(func (export "take-u16") (param "a" u16) (canon lift (core func $i "take-i32-100")))
150
(func (export "take-s16") (param "a" s16) (canon lift (core func $i "take-i32-100")))
151
(func (export "take-u32") (param "a" u32) (canon lift (core func $i "take-i32-100")))
152
(func (export "take-s32") (param "a" s32) (canon lift (core func $i "take-i32-100")))
153
(func (export "take-u64") (param "a" u64) (canon lift (core func $i "take-i64-100")))
154
(func (export "take-s64") (param "a" s64) (canon lift (core func $i "take-i64-100")))
155
156
(func (export "ret-u8") (result u8) (canon lift (core func $i "ret-i32-0")))
157
(func (export "ret-s8") (result s8) (canon lift (core func $i "ret-i32-0")))
158
(func (export "ret-u16") (result u16) (canon lift (core func $i "ret-i32-0")))
159
(func (export "ret-s16") (result s16) (canon lift (core func $i "ret-i32-0")))
160
(func (export "ret-u32") (result u32) (canon lift (core func $i "ret-i32-0")))
161
(func (export "ret-s32") (result s32) (canon lift (core func $i "ret-i32-0")))
162
(func (export "ret-u64") (result u64) (canon lift (core func $i "ret-i64-0")))
163
(func (export "ret-s64") (result s64) (canon lift (core func $i "ret-i64-0")))
164
165
(func (export "retm1-u8") (result u8) (canon lift (core func $i "ret-i32-minus-1")))
166
(func (export "retm1-s8") (result s8) (canon lift (core func $i "ret-i32-minus-1")))
167
(func (export "retm1-u16") (result u16) (canon lift (core func $i "ret-i32-minus-1")))
168
(func (export "retm1-s16") (result s16) (canon lift (core func $i "ret-i32-minus-1")))
169
(func (export "retm1-u32") (result u32) (canon lift (core func $i "ret-i32-minus-1")))
170
(func (export "retm1-s32") (result s32) (canon lift (core func $i "ret-i32-minus-1")))
171
(func (export "retm1-u64") (result u64) (canon lift (core func $i "ret-i64-minus-1")))
172
(func (export "retm1-s64") (result s64) (canon lift (core func $i "ret-i64-minus-1")))
173
174
(func (export "retbig-u8") (result u8) (canon lift (core func $i "ret-i32-100000")))
175
(func (export "retbig-s8") (result s8) (canon lift (core func $i "ret-i32-100000")))
176
(func (export "retbig-u16") (result u16) (canon lift (core func $i "ret-i32-100000")))
177
(func (export "retbig-s16") (result s16) (canon lift (core func $i "ret-i32-100000")))
178
(func (export "retbig-u32") (result u32) (canon lift (core func $i "ret-i32-100000")))
179
(func (export "retbig-s32") (result s32) (canon lift (core func $i "ret-i32-100000")))
180
)
181
"#;
182
183
let engine = super::engine();
184
let component = Component::new(&engine, component)?;
185
let mut store = Store::new(&engine, ());
186
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
187
188
// Passing in 100 is valid for all primitives
189
instance
190
.get_typed_func::<(u8,), ()>(&mut store, "take-u8")?
191
.call(&mut store, (100,))?;
192
instance
193
.get_typed_func::<(i8,), ()>(&mut store, "take-s8")?
194
.call(&mut store, (100,))?;
195
instance
196
.get_typed_func::<(u16,), ()>(&mut store, "take-u16")?
197
.call(&mut store, (100,))?;
198
instance
199
.get_typed_func::<(i16,), ()>(&mut store, "take-s16")?
200
.call(&mut store, (100,))?;
201
instance
202
.get_typed_func::<(u32,), ()>(&mut store, "take-u32")?
203
.call(&mut store, (100,))?;
204
instance
205
.get_typed_func::<(i32,), ()>(&mut store, "take-s32")?
206
.call(&mut store, (100,))?;
207
instance
208
.get_typed_func::<(u64,), ()>(&mut store, "take-u64")?
209
.call(&mut store, (100,))?;
210
instance
211
.get_typed_func::<(i64,), ()>(&mut store, "take-s64")?
212
.call(&mut store, (100,))?;
213
214
// This specific wasm instance traps if any value other than 100 is passed
215
with_new_instance(&engine, &component, |store, instance| {
216
instance
217
.get_typed_func::<(u8,), ()>(&mut *store, "take-u8")?
218
.call(store, (101,))
219
.unwrap_err()
220
.downcast::<Trap>()
221
})?;
222
with_new_instance(&engine, &component, |store, instance| {
223
instance
224
.get_typed_func::<(i8,), ()>(&mut *store, "take-s8")?
225
.call(store, (101,))
226
.unwrap_err()
227
.downcast::<Trap>()
228
})?;
229
with_new_instance(&engine, &component, |store, instance| {
230
instance
231
.get_typed_func::<(u16,), ()>(&mut *store, "take-u16")?
232
.call(store, (101,))
233
.unwrap_err()
234
.downcast::<Trap>()
235
})?;
236
with_new_instance(&engine, &component, |store, instance| {
237
instance
238
.get_typed_func::<(i16,), ()>(&mut *store, "take-s16")?
239
.call(store, (101,))
240
.unwrap_err()
241
.downcast::<Trap>()
242
})?;
243
with_new_instance(&engine, &component, |store, instance| {
244
instance
245
.get_typed_func::<(u32,), ()>(&mut *store, "take-u32")?
246
.call(store, (101,))
247
.unwrap_err()
248
.downcast::<Trap>()
249
})?;
250
with_new_instance(&engine, &component, |store, instance| {
251
instance
252
.get_typed_func::<(i32,), ()>(&mut *store, "take-s32")?
253
.call(store, (101,))
254
.unwrap_err()
255
.downcast::<Trap>()
256
})?;
257
with_new_instance(&engine, &component, |store, instance| {
258
instance
259
.get_typed_func::<(u64,), ()>(&mut *store, "take-u64")?
260
.call(store, (101,))
261
.unwrap_err()
262
.downcast::<Trap>()
263
})?;
264
with_new_instance(&engine, &component, |store, instance| {
265
instance
266
.get_typed_func::<(i64,), ()>(&mut *store, "take-s64")?
267
.call(store, (101,))
268
.unwrap_err()
269
.downcast::<Trap>()
270
})?;
271
272
// Zero can be returned as any integer
273
assert_eq!(
274
instance
275
.get_typed_func::<(), (u8,)>(&mut store, "ret-u8")?
276
.call(&mut store, ())?,
277
(0,)
278
);
279
assert_eq!(
280
instance
281
.get_typed_func::<(), (i8,)>(&mut store, "ret-s8")?
282
.call(&mut store, ())?,
283
(0,)
284
);
285
assert_eq!(
286
instance
287
.get_typed_func::<(), (u16,)>(&mut store, "ret-u16")?
288
.call(&mut store, ())?,
289
(0,)
290
);
291
assert_eq!(
292
instance
293
.get_typed_func::<(), (i16,)>(&mut store, "ret-s16")?
294
.call(&mut store, ())?,
295
(0,)
296
);
297
assert_eq!(
298
instance
299
.get_typed_func::<(), (u32,)>(&mut store, "ret-u32")?
300
.call(&mut store, ())?,
301
(0,)
302
);
303
assert_eq!(
304
instance
305
.get_typed_func::<(), (i32,)>(&mut store, "ret-s32")?
306
.call(&mut store, ())?,
307
(0,)
308
);
309
assert_eq!(
310
instance
311
.get_typed_func::<(), (u64,)>(&mut store, "ret-u64")?
312
.call(&mut store, ())?,
313
(0,)
314
);
315
assert_eq!(
316
instance
317
.get_typed_func::<(), (i64,)>(&mut store, "ret-s64")?
318
.call(&mut store, ())?,
319
(0,)
320
);
321
322
// Returning -1 should reinterpret the bytes as defined by each type.
323
assert_eq!(
324
instance
325
.get_typed_func::<(), (u8,)>(&mut store, "retm1-u8")?
326
.call(&mut store, ())?,
327
(0xff,)
328
);
329
assert_eq!(
330
instance
331
.get_typed_func::<(), (i8,)>(&mut store, "retm1-s8")?
332
.call(&mut store, ())?,
333
(-1,)
334
);
335
assert_eq!(
336
instance
337
.get_typed_func::<(), (u16,)>(&mut store, "retm1-u16")?
338
.call(&mut store, ())?,
339
(0xffff,)
340
);
341
assert_eq!(
342
instance
343
.get_typed_func::<(), (i16,)>(&mut store, "retm1-s16")?
344
.call(&mut store, ())?,
345
(-1,)
346
);
347
assert_eq!(
348
instance
349
.get_typed_func::<(), (u32,)>(&mut store, "retm1-u32")?
350
.call(&mut store, ())?,
351
(0xffffffff,)
352
);
353
assert_eq!(
354
instance
355
.get_typed_func::<(), (i32,)>(&mut store, "retm1-s32")?
356
.call(&mut store, ())?,
357
(-1,)
358
);
359
assert_eq!(
360
instance
361
.get_typed_func::<(), (u64,)>(&mut store, "retm1-u64")?
362
.call(&mut store, ())?,
363
(0xffffffff_ffffffff,)
364
);
365
assert_eq!(
366
instance
367
.get_typed_func::<(), (i64,)>(&mut store, "retm1-s64")?
368
.call(&mut store, ())?,
369
(-1,)
370
);
371
372
// Returning 100000 should chop off bytes as necessary
373
let ret: u32 = 100000;
374
assert_eq!(
375
instance
376
.get_typed_func::<(), (u8,)>(&mut store, "retbig-u8")?
377
.call(&mut store, ())?,
378
(ret as u8,),
379
);
380
assert_eq!(
381
instance
382
.get_typed_func::<(), (i8,)>(&mut store, "retbig-s8")?
383
.call(&mut store, ())?,
384
(ret as i8,),
385
);
386
assert_eq!(
387
instance
388
.get_typed_func::<(), (u16,)>(&mut store, "retbig-u16")?
389
.call(&mut store, ())?,
390
(ret as u16,),
391
);
392
assert_eq!(
393
instance
394
.get_typed_func::<(), (i16,)>(&mut store, "retbig-s16")?
395
.call(&mut store, ())?,
396
(ret as i16,),
397
);
398
assert_eq!(
399
instance
400
.get_typed_func::<(), (u32,)>(&mut store, "retbig-u32")?
401
.call(&mut store, ())?,
402
(ret,),
403
);
404
assert_eq!(
405
instance
406
.get_typed_func::<(), (i32,)>(&mut store, "retbig-s32")?
407
.call(&mut store, ())?,
408
(ret as i32,),
409
);
410
411
Ok(())
412
}
413
414
#[test]
415
fn type_layers() -> Result<()> {
416
let component = r#"
417
(component
418
(core module $m
419
(func (export "take-i32-100") (param i32)
420
local.get 0
421
i32.const 2
422
i32.eq
423
br_if 0
424
unreachable
425
)
426
)
427
(core instance $i (instantiate $m))
428
(func (export "take-u32") (param "a" u32) (canon lift (core func $i "take-i32-100")))
429
)
430
"#;
431
432
let engine = super::engine();
433
let component = Component::new(&engine, component)?;
434
let mut store = Store::new(&engine, ());
435
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
436
437
instance
438
.get_typed_func::<(Box<u32>,), ()>(&mut store, "take-u32")?
439
.call(&mut store, (Box::new(2),))?;
440
instance
441
.get_typed_func::<(&u32,), ()>(&mut store, "take-u32")?
442
.call(&mut store, (&2,))?;
443
instance
444
.get_typed_func::<(Arc<u32>,), ()>(&mut store, "take-u32")?
445
.call(&mut store, (Arc::new(2),))?;
446
instance
447
.get_typed_func::<(&Box<Arc<Box<u32>>>,), ()>(&mut store, "take-u32")?
448
.call(&mut store, (&Box::new(Arc::new(Box::new(2))),))?;
449
450
Ok(())
451
}
452
453
#[test]
454
fn floats() -> Result<()> {
455
let component = r#"
456
(component
457
(core module $m
458
(func (export "i32.reinterpret_f32") (param f32) (result i32)
459
local.get 0
460
i32.reinterpret_f32
461
)
462
(func (export "i64.reinterpret_f64") (param f64) (result i64)
463
local.get 0
464
i64.reinterpret_f64
465
)
466
(func (export "f32.reinterpret_i32") (param i32) (result f32)
467
local.get 0
468
f32.reinterpret_i32
469
)
470
(func (export "f64.reinterpret_i64") (param i64) (result f64)
471
local.get 0
472
f64.reinterpret_i64
473
)
474
)
475
(core instance $i (instantiate $m))
476
477
(func (export "f32-to-u32") (param "a" float32) (result u32)
478
(canon lift (core func $i "i32.reinterpret_f32"))
479
)
480
(func (export "f64-to-u64") (param "a" float64) (result u64)
481
(canon lift (core func $i "i64.reinterpret_f64"))
482
)
483
(func (export "u32-to-f32") (param "a" u32) (result float32)
484
(canon lift (core func $i "f32.reinterpret_i32"))
485
)
486
(func (export "u64-to-f64") (param "a" u64) (result float64)
487
(canon lift (core func $i "f64.reinterpret_i64"))
488
)
489
)
490
"#;
491
492
let engine = super::engine();
493
let component = Component::new(&engine, component)?;
494
let mut store = Store::new(&engine, ());
495
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
496
let f32_to_u32 = instance.get_typed_func::<(f32,), (u32,)>(&mut store, "f32-to-u32")?;
497
let f64_to_u64 = instance.get_typed_func::<(f64,), (u64,)>(&mut store, "f64-to-u64")?;
498
let u32_to_f32 = instance.get_typed_func::<(u32,), (f32,)>(&mut store, "u32-to-f32")?;
499
let u64_to_f64 = instance.get_typed_func::<(u64,), (f64,)>(&mut store, "u64-to-f64")?;
500
501
assert_eq!(f32_to_u32.call(&mut store, (1.0,))?, (1.0f32.to_bits(),));
502
assert_eq!(f64_to_u64.call(&mut store, (2.0,))?, (2.0f64.to_bits(),));
503
assert_eq!(u32_to_f32.call(&mut store, (3.0f32.to_bits(),))?, (3.0,));
504
assert_eq!(u64_to_f64.call(&mut store, (4.0f64.to_bits(),))?, (4.0,));
505
506
assert_eq!(
507
u32_to_f32
508
.call(&mut store, (CANON_32BIT_NAN | 1,))?
509
.0
510
.to_bits(),
511
CANON_32BIT_NAN | 1
512
);
513
assert_eq!(
514
u64_to_f64
515
.call(&mut store, (CANON_64BIT_NAN | 1,))?
516
.0
517
.to_bits(),
518
CANON_64BIT_NAN | 1,
519
);
520
521
assert_eq!(
522
f32_to_u32.call(&mut store, (f32::from_bits(CANON_32BIT_NAN | 1),))?,
523
(CANON_32BIT_NAN | 1,)
524
);
525
assert_eq!(
526
f64_to_u64.call(&mut store, (f64::from_bits(CANON_64BIT_NAN | 1),))?,
527
(CANON_64BIT_NAN | 1,)
528
);
529
530
Ok(())
531
}
532
533
#[test]
534
fn bools() -> Result<()> {
535
let component = r#"
536
(component
537
(core module $m
538
(func (export "pass") (param i32) (result i32) local.get 0)
539
)
540
(core instance $i (instantiate $m))
541
542
(func (export "u32-to-bool") (param "a" u32) (result bool)
543
(canon lift (core func $i "pass"))
544
)
545
(func (export "bool-to-u32") (param "a" bool) (result u32)
546
(canon lift (core func $i "pass"))
547
)
548
)
549
"#;
550
551
let engine = super::engine();
552
let component = Component::new(&engine, component)?;
553
let mut store = Store::new(&engine, ());
554
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
555
let u32_to_bool = instance.get_typed_func::<(u32,), (bool,)>(&mut store, "u32-to-bool")?;
556
let bool_to_u32 = instance.get_typed_func::<(bool,), (u32,)>(&mut store, "bool-to-u32")?;
557
558
assert_eq!(bool_to_u32.call(&mut store, (false,))?, (0,));
559
assert_eq!(bool_to_u32.call(&mut store, (true,))?, (1,));
560
assert_eq!(u32_to_bool.call(&mut store, (0,))?, (false,));
561
assert_eq!(u32_to_bool.call(&mut store, (1,))?, (true,));
562
assert_eq!(u32_to_bool.call(&mut store, (2,))?, (true,));
563
564
Ok(())
565
}
566
567
#[test]
568
fn chars() -> Result<()> {
569
let component = r#"
570
(component
571
(core module $m
572
(func (export "pass") (param i32) (result i32) local.get 0)
573
)
574
(core instance $i (instantiate $m))
575
576
(func (export "u32-to-char") (param "a" u32) (result char)
577
(canon lift (core func $i "pass"))
578
)
579
(func (export "char-to-u32") (param "a" char) (result u32)
580
(canon lift (core func $i "pass"))
581
)
582
)
583
"#;
584
585
let engine = super::engine();
586
let component = Component::new(&engine, component)?;
587
let mut store = Store::new(&engine, ());
588
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
589
let u32_to_char = instance.get_typed_func::<(u32,), (char,)>(&mut store, "u32-to-char")?;
590
let char_to_u32 = instance.get_typed_func::<(char,), (u32,)>(&mut store, "char-to-u32")?;
591
592
let mut roundtrip = |x: char| -> Result<()> {
593
assert_eq!(char_to_u32.call(&mut store, (x,))?, (x as u32,));
594
assert_eq!(u32_to_char.call(&mut store, (x as u32,))?, (x,));
595
Ok(())
596
};
597
598
roundtrip('x')?;
599
roundtrip('a')?;
600
roundtrip('\0')?;
601
roundtrip('\n')?;
602
roundtrip('')?;
603
604
let u32_to_char = |store: &mut Store<()>| {
605
Linker::new(&engine)
606
.instantiate(&mut *store, &component)?
607
.get_typed_func::<(u32,), (char,)>(&mut *store, "u32-to-char")
608
};
609
let err = u32_to_char(&mut store)?
610
.call(&mut store, (0xd800,))
611
.unwrap_err();
612
assert!(err.to_string().contains("integer out of range"), "{}", err);
613
let err = u32_to_char(&mut store)?
614
.call(&mut store, (0xdfff,))
615
.unwrap_err();
616
assert!(err.to_string().contains("integer out of range"), "{}", err);
617
let err = u32_to_char(&mut store)?
618
.call(&mut store, (0x110000,))
619
.unwrap_err();
620
assert!(err.to_string().contains("integer out of range"), "{}", err);
621
let err = u32_to_char(&mut store)?
622
.call(&mut store, (u32::MAX,))
623
.unwrap_err();
624
assert!(err.to_string().contains("integer out of range"), "{}", err);
625
626
Ok(())
627
}
628
629
#[test]
630
fn tuple_result() -> Result<()> {
631
let component = r#"
632
(component
633
(core module $m
634
(memory (export "memory") 1)
635
(func (export "foo") (param i32 i32 f32 f64) (result i32)
636
(local $base i32)
637
(local.set $base (i32.const 8))
638
(i32.store8 offset=0 (local.get $base) (local.get 0))
639
(i32.store16 offset=2 (local.get $base) (local.get 1))
640
(f32.store offset=4 (local.get $base) (local.get 2))
641
(f64.store offset=8 (local.get $base) (local.get 3))
642
local.get $base
643
)
644
645
(func (export "invalid") (result i32)
646
i32.const -8
647
)
648
)
649
(core instance $i (instantiate $m))
650
651
(type $result (tuple s8 u16 float32 float64))
652
(func (export "tuple")
653
(param "a" s8) (param "b" u16) (param "c" float32) (param "d" float64) (result $result)
654
(canon lift (core func $i "foo") (memory $i "memory"))
655
)
656
(func (export "invalid") (result $result)
657
(canon lift (core func $i "invalid") (memory $i "memory"))
658
)
659
)
660
"#;
661
662
let engine = super::engine();
663
let component = Component::new(&engine, component)?;
664
let mut store = Store::new(&engine, ());
665
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
666
667
let input = (-1, 100, 3.0, 100.0);
668
let output = instance
669
.get_typed_func::<(i8, u16, f32, f64), ((i8, u16, f32, f64),)>(&mut store, "tuple")?
670
.call(&mut store, input)?;
671
assert_eq!((input,), output);
672
673
let invalid_func =
674
instance.get_typed_func::<(), ((i8, u16, f32, f64),)>(&mut store, "invalid")?;
675
let err = invalid_func.call(&mut store, ()).err().unwrap();
676
assert!(
677
err.to_string().contains("pointer out of bounds of memory"),
678
"{}",
679
err
680
);
681
682
Ok(())
683
}
684
685
#[test]
686
fn strings() -> Result<()> {
687
let component = format!(
688
r#"(component
689
(core module $m
690
(memory (export "memory") 1)
691
(func (export "roundtrip") (param i32 i32) (result i32)
692
(local $base i32)
693
(local.set $base
694
(call $realloc
695
(i32.const 0)
696
(i32.const 0)
697
(i32.const 4)
698
(i32.const 8)))
699
(i32.store offset=0
700
(local.get $base)
701
(local.get 0))
702
(i32.store offset=4
703
(local.get $base)
704
(local.get 1))
705
(local.get $base)
706
)
707
708
{REALLOC_AND_FREE}
709
)
710
(core instance $i (instantiate $m))
711
712
(func (export "list8-to-str") (param "a" (list u8)) (result string)
713
(canon lift
714
(core func $i "roundtrip")
715
(memory $i "memory")
716
(realloc (func $i "realloc"))
717
)
718
)
719
(func (export "str-to-list8") (param "a" string) (result (list u8))
720
(canon lift
721
(core func $i "roundtrip")
722
(memory $i "memory")
723
(realloc (func $i "realloc"))
724
)
725
)
726
(func (export "list16-to-str") (param "a" (list u16)) (result string)
727
(canon lift
728
(core func $i "roundtrip")
729
string-encoding=utf16
730
(memory $i "memory")
731
(realloc (func $i "realloc"))
732
)
733
)
734
(func (export "str-to-list16") (param "a" string) (result (list u16))
735
(canon lift
736
(core func $i "roundtrip")
737
string-encoding=utf16
738
(memory $i "memory")
739
(realloc (func $i "realloc"))
740
)
741
)
742
)"#
743
);
744
745
let engine = super::engine();
746
let component = Component::new(&engine, component)?;
747
let mut store = Store::new(&engine, ());
748
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
749
let list8_to_str =
750
instance.get_typed_func::<(&[u8],), (WasmStr,)>(&mut store, "list8-to-str")?;
751
let str_to_list8 =
752
instance.get_typed_func::<(&str,), (WasmList<u8>,)>(&mut store, "str-to-list8")?;
753
let list16_to_str =
754
instance.get_typed_func::<(&[u16],), (WasmStr,)>(&mut store, "list16-to-str")?;
755
let str_to_list16 =
756
instance.get_typed_func::<(&str,), (WasmList<u16>,)>(&mut store, "str-to-list16")?;
757
758
let mut roundtrip = |x: &str| -> Result<()> {
759
let ret = list8_to_str.call(&mut store, (x.as_bytes(),))?.0;
760
assert_eq!(ret.to_str(&store)?, x);
761
762
let utf16 = x.encode_utf16().collect::<Vec<_>>();
763
let ret = list16_to_str.call(&mut store, (&utf16[..],))?.0;
764
assert_eq!(ret.to_str(&store)?, x);
765
766
let ret = str_to_list8.call(&mut store, (x,))?.0;
767
assert_eq!(
768
ret.iter(&mut store).collect::<Result<Vec<_>>>()?,
769
x.as_bytes()
770
);
771
772
let ret = str_to_list16.call(&mut store, (x,))?.0;
773
assert_eq!(ret.iter(&mut store).collect::<Result<Vec<_>>>()?, utf16,);
774
775
Ok(())
776
};
777
778
roundtrip("")?;
779
roundtrip("foo")?;
780
roundtrip("hello there")?;
781
roundtrip("💝")?;
782
roundtrip("Löwe 老虎 Léopard")?;
783
784
let ret = list8_to_str.call(&mut store, (b"\xff",))?.0;
785
let err = ret.to_str(&store).unwrap_err();
786
assert!(err.to_string().contains("invalid utf-8"), "{}", err);
787
788
let ret = list8_to_str
789
.call(&mut store, (b"hello there \xff invalid",))?
790
.0;
791
let err = ret.to_str(&store).unwrap_err();
792
assert!(err.to_string().contains("invalid utf-8"), "{}", err);
793
794
let ret = list16_to_str.call(&mut store, (&[0xd800],))?.0;
795
let err = ret.to_str(&store).unwrap_err();
796
assert!(err.to_string().contains("unpaired surrogate"), "{}", err);
797
798
let ret = list16_to_str.call(&mut store, (&[0xdfff],))?.0;
799
let err = ret.to_str(&store).unwrap_err();
800
assert!(err.to_string().contains("unpaired surrogate"), "{}", err);
801
802
let ret = list16_to_str.call(&mut store, (&[0xd800, 0xff00],))?.0;
803
let err = ret.to_str(&store).unwrap_err();
804
assert!(err.to_string().contains("unpaired surrogate"), "{}", err);
805
806
Ok(())
807
}
808
809
#[tokio::test]
810
async fn async_reentrance() -> Result<()> {
811
_ = env_logger::try_init();
812
813
let component = r#"
814
(component
815
(core module $shim
816
(import "" "task.return" (func $task-return (param i32)))
817
(table (export "funcs") 1 1 funcref)
818
(func (export "export") (param i32) (result i32)
819
(call_indirect (i32.const 0) (local.get 0))
820
)
821
(func (export "callback") (param i32 i32 i32) (result i32) unreachable)
822
)
823
(core func $task-return (canon task.return (result u32)))
824
(core instance $shim (instantiate $shim
825
(with "" (instance (export "task.return" (func $task-return))))
826
))
827
(func $shim-export (param "p1" u32) (result u32)
828
(canon lift (core func $shim "export") async (callback (func $shim "callback")))
829
)
830
831
(component $inner
832
(import "import" (func $import (param "p1" u32) (result u32)))
833
(core module $libc (memory (export "memory") 1))
834
(core instance $libc (instantiate $libc))
835
(core func $import (canon lower (func $import) async (memory $libc "memory")))
836
837
(core module $m
838
(import "libc" "memory" (memory 1))
839
(import "" "import" (func $import (param i32 i32) (result i32)))
840
(import "" "task.return" (func $task-return (param i32)))
841
(func (export "export") (param i32) (result i32)
842
(i32.store offset=0 (i32.const 1200) (local.get 0))
843
(call $import (i32.const 1200) (i32.const 1204))
844
drop
845
(call $task-return (i32.load offset=0 (i32.const 1204)))
846
i32.const 0
847
)
848
(func (export "callback") (param i32 i32 i32) (result i32) unreachable)
849
)
850
(core type $task-return-type (func (param i32)))
851
(core func $task-return (canon task.return (result u32)))
852
(core instance $i (instantiate $m
853
(with "" (instance
854
(export "task.return" (func $task-return))
855
(export "import" (func $import))
856
))
857
(with "libc" (instance $libc))
858
))
859
(func (export "export") (param "p1" u32) (result u32)
860
(canon lift (core func $i "export") async (callback (func $i "callback")))
861
)
862
)
863
(instance $inner (instantiate $inner (with "import" (func $shim-export))))
864
865
(core module $libc (memory (export "memory") 1))
866
(core instance $libc (instantiate $libc))
867
(core func $inner-export (canon lower (func $inner "export") async (memory $libc "memory")))
868
869
(core module $donut
870
(import "" "funcs" (table 1 1 funcref))
871
(import "libc" "memory" (memory 1))
872
(import "" "import" (func $import (param i32 i32) (result i32)))
873
(import "" "task.return" (func $task-return (param i32)))
874
(func $host-export (export "export") (param i32) (result i32)
875
(i32.store offset=0 (i32.const 1200) (local.get 0))
876
(call $import (i32.const 1200) (i32.const 1204))
877
drop
878
(call $task-return (i32.load offset=0 (i32.const 1204)))
879
i32.const 0
880
)
881
(func $guest-export (export "guest-export") (param i32) (result i32) unreachable)
882
(func (export "callback") (param i32 i32 i32) (result i32) unreachable)
883
(func $start
884
(table.set (i32.const 0) (ref.func $guest-export))
885
)
886
(start $start)
887
)
888
889
(core instance $donut (instantiate $donut
890
(with "" (instance
891
(export "task.return" (func $task-return))
892
(export "import" (func $inner-export))
893
(export "funcs" (table $shim "funcs"))
894
))
895
(with "libc" (instance $libc))
896
))
897
(func (export "export") (param "p1" u32) (result u32)
898
(canon lift (core func $donut "export") async (callback (func $donut "callback")))
899
)
900
)"#;
901
902
let mut config = Config::new();
903
config.wasm_component_model_async(true);
904
config.wasm_component_model_async_stackful(true);
905
config.wasm_component_model_threading(true);
906
let engine = &Engine::new(&config)?;
907
let component = Component::new(&engine, component)?;
908
let mut store = Store::new(&engine, ());
909
910
let instance = Linker::new(&engine)
911
.instantiate_async(&mut store, &component)
912
.await?;
913
let func = instance.get_typed_func::<(u32,), (u32,)>(&mut store, "export")?;
914
let message = "cannot enter component instance";
915
match store
916
.run_concurrent(async move |accessor| {
917
wasmtime::error::Ok(func.call_concurrent(accessor, (42,)).await?.0)
918
})
919
.await
920
{
921
Ok(_) => panic!(),
922
Err(e) => assert!(
923
format!("{e:?}").contains(message),
924
"expected `{message}`; got `{e:?}`"
925
),
926
}
927
928
Ok(())
929
}
930
931
#[tokio::test]
932
async fn missing_task_return_call_stackless() -> Result<()> {
933
task_return_trap(
934
r#"(component
935
(core module $m
936
(import "" "task.return" (func $task-return))
937
(func (export "foo") (result i32)
938
i32.const 0
939
)
940
(func (export "callback") (param i32 i32 i32) (result i32) unreachable)
941
)
942
(core func $task-return (canon task.return))
943
(core instance $i (instantiate $m
944
(with "" (instance (export "task.return" (func $task-return))))
945
))
946
(func (export "foo") (canon lift (core func $i "foo") async (callback (func $i "callback"))))
947
)"#,
948
"wasm trap: async-lifted export failed to produce a result",
949
)
950
.await
951
}
952
953
#[tokio::test]
954
async fn missing_task_return_call_stackless_explicit_thread() -> Result<()> {
955
task_return_trap(
956
r#"(component
957
(core module $libc
958
(table (export "__indirect_function_table") 1 funcref))
959
(core module $m
960
(import "" "task.return" (func $task-return))
961
(import "" "thread.new-indirect" (func $thread-new-indirect (param i32 i32) (result i32)))
962
(import "" "thread.resume-later" (func $thread-resume-later (param i32)))
963
(import "libc" "__indirect_function_table" (table $indirect-function-table 1 funcref))
964
(func $thread-start (param i32) (; empty ;))
965
(elem (table $indirect-function-table) (i32.const 0) func $thread-start)
966
(func (export "foo") (result i32)
967
(call $thread-resume-later
968
(call $thread-new-indirect (i32.const 0) (i32.const 0)))
969
i32.const 0
970
)
971
(func (export "callback") (param i32 i32 i32) (result i32) unreachable)
972
)
973
(core instance $libc (instantiate $libc))
974
(core type $start-func-ty (func (param i32)))
975
(alias core export $libc "__indirect_function_table" (core table $indirect-function-table))
976
(core func $thread-new-indirect
977
(canon thread.new-indirect $start-func-ty (table $indirect-function-table)))
978
(core func $thread-resume-later (canon thread.resume-later))
979
(core func $task-return (canon task.return))
980
(core instance $i (instantiate $m
981
(with "" (instance
982
(export "thread.new-indirect" (func $thread-new-indirect))
983
(export "thread.resume-later" (func $thread-resume-later))
984
(export "task.return" (func $task-return))
985
))
986
(with "libc" (instance $libc))
987
))
988
(func (export "foo") (canon lift (core func $i "foo") async (callback (func $i "callback"))))
989
)"#,
990
"wasm trap: async-lifted export failed to produce a result",
991
)
992
.await
993
}
994
995
#[tokio::test]
996
async fn missing_task_return_call_stackful_explicit_thread() -> Result<()> {
997
task_return_trap(
998
r#"(component
999
(core module $libc
1000
(table (export "__indirect_function_table") 1 funcref))
1001
(core module $m
1002
(import "" "task.return" (func $task-return))
1003
(import "" "thread.new-indirect" (func $thread-new-indirect (param i32 i32) (result i32)))
1004
(import "" "thread.resume-later" (func $thread-resume-later (param i32)))
1005
(import "libc" "__indirect_function_table" (table $indirect-function-table 1 funcref))
1006
(func $thread-start (param i32) (; empty ;))
1007
(elem (table $indirect-function-table) (i32.const 0) func $thread-start)
1008
(func (export "foo")
1009
(call $thread-resume-later
1010
(call $thread-new-indirect (i32.const 0) (i32.const 0)))
1011
)
1012
)
1013
(core instance $libc (instantiate $libc))
1014
(core type $start-func-ty (func (param i32)))
1015
(alias core export $libc "__indirect_function_table" (core table $indirect-function-table))
1016
(core func $thread-new-indirect
1017
(canon thread.new-indirect $start-func-ty (table $indirect-function-table)))
1018
(core func $thread-resume-later (canon thread.resume-later))
1019
(core func $task-return (canon task.return))
1020
(core instance $i (instantiate $m
1021
(with "" (instance
1022
(export "thread.new-indirect" (func $thread-new-indirect))
1023
(export "thread.resume-later" (func $thread-resume-later))
1024
(export "task.return" (func $task-return))
1025
))
1026
(with "libc" (instance $libc))
1027
))
1028
(func (export "foo") (canon lift (core func $i "foo") async))
1029
)"#,
1030
"wasm trap: async-lifted export failed to produce a result",
1031
)
1032
.await
1033
}
1034
1035
#[tokio::test]
1036
async fn missing_task_return_call_stackful() -> Result<()> {
1037
task_return_trap(
1038
r#"(component
1039
(core module $m
1040
(import "" "task.return" (func $task-return))
1041
(func (export "foo"))
1042
)
1043
(core func $task-return (canon task.return))
1044
(core instance $i (instantiate $m
1045
(with "" (instance (export "task.return" (func $task-return))))
1046
))
1047
(func (export "foo") (canon lift (core func $i "foo") async))
1048
)"#,
1049
"wasm trap: async-lifted export failed to produce a result",
1050
)
1051
.await
1052
}
1053
1054
#[tokio::test]
1055
async fn task_return_type_mismatch() -> Result<()> {
1056
task_return_trap(
1057
r#"(component
1058
(core module $m
1059
(import "" "task.return" (func $task-return (param i32)))
1060
(func (export "foo") (call $task-return (i32.const 42)))
1061
)
1062
(core func $task-return (canon task.return (result u32)))
1063
(core instance $i (instantiate $m
1064
(with "" (instance (export "task.return" (func $task-return))))
1065
))
1066
(func (export "foo") (canon lift (core func $i "foo") async))
1067
)"#,
1068
"invalid `task.return` signature and/or options for current task",
1069
)
1070
.await
1071
}
1072
1073
#[tokio::test]
1074
async fn task_return_memory_mismatch() -> Result<()> {
1075
task_return_trap(
1076
r#"(component
1077
(core module $libc (memory (export "memory") 1))
1078
(core instance $libc (instantiate $libc))
1079
(core module $m
1080
(import "" "task.return" (func $task-return))
1081
(func (export "foo") (call $task-return))
1082
)
1083
(core func $task-return (canon task.return (memory $libc "memory")))
1084
(core instance $i (instantiate $m
1085
(with "" (instance (export "task.return" (func $task-return))))
1086
))
1087
(func (export "foo") (canon lift (core func $i "foo") async))
1088
)"#,
1089
"invalid `task.return` signature and/or options for current task",
1090
)
1091
.await
1092
}
1093
1094
#[tokio::test]
1095
async fn task_return_string_encoding_mismatch() -> Result<()> {
1096
task_return_trap(
1097
r#"(component
1098
(core module $m
1099
(import "" "task.return" (func $task-return))
1100
(func (export "foo") (call $task-return))
1101
)
1102
(core func $task-return (canon task.return string-encoding=utf16))
1103
(core instance $i (instantiate $m
1104
(with "" (instance (export "task.return" (func $task-return))))
1105
))
1106
(func (export "foo") (canon lift (core func $i "foo") async))
1107
)"#,
1108
"invalid `task.return` signature and/or options for current task",
1109
)
1110
.await
1111
}
1112
1113
async fn task_return_trap(component: &str, substring: &str) -> Result<()> {
1114
let mut config = Config::new();
1115
config.wasm_component_model_async(true);
1116
config.wasm_component_model_async_stackful(true);
1117
config.wasm_component_model_threading(true);
1118
let engine = &Engine::new(&config)?;
1119
let component = Component::new(&engine, component)?;
1120
let mut store = Store::new(&engine, ());
1121
1122
let instance = Linker::new(&engine)
1123
.instantiate_async(&mut store, &component)
1124
.await?;
1125
1126
let func = instance.get_typed_func::<(), ()>(&mut store, "foo")?;
1127
match store
1128
.run_concurrent(async move |accessor| {
1129
wasmtime::error::Ok(func.call_concurrent(accessor, ()).await?.0)
1130
})
1131
.await
1132
{
1133
Ok(_) => panic!(),
1134
Err(e) => {
1135
assert!(
1136
format!("{e:?}").contains(substring),
1137
"could not find `{substring}` in `{e:?}`"
1138
)
1139
}
1140
}
1141
1142
Ok(())
1143
}
1144
1145
#[tokio::test]
1146
async fn many_parameters() -> Result<()> {
1147
test_many_parameters(false, false).await
1148
}
1149
1150
#[tokio::test]
1151
async fn many_parameters_concurrent() -> Result<()> {
1152
test_many_parameters(false, true).await
1153
}
1154
1155
#[tokio::test]
1156
async fn many_parameters_dynamic() -> Result<()> {
1157
test_many_parameters(true, false).await
1158
}
1159
1160
#[tokio::test]
1161
async fn many_parameters_dynamic_concurrent() -> Result<()> {
1162
test_many_parameters(true, true).await
1163
}
1164
1165
async fn test_many_parameters(dynamic: bool, concurrent: bool) -> Result<()> {
1166
let (body, async_opts) = if concurrent {
1167
(
1168
r#"
1169
(call $task-return
1170
(i32.const 0)
1171
(i32.mul
1172
(memory.size)
1173
(i32.const 65536)
1174
)
1175
(local.get 0)
1176
)
1177
1178
(i32.const 0)
1179
"#,
1180
r#"async (callback (func $i "callback"))"#,
1181
)
1182
} else {
1183
(
1184
r#"
1185
(local $base i32)
1186
1187
;; Allocate space for the return
1188
(local.set $base
1189
(call $realloc
1190
(i32.const 0)
1191
(i32.const 0)
1192
(i32.const 4)
1193
(i32.const 12)))
1194
1195
;; Store the pointer/length of the entire linear memory
1196
;; so we have access to everything.
1197
(i32.store offset=0
1198
(local.get $base)
1199
(i32.const 0))
1200
(i32.store offset=4
1201
(local.get $base)
1202
(i32.mul
1203
(memory.size)
1204
(i32.const 65536)))
1205
1206
;; And also store our pointer parameter
1207
(i32.store offset=8
1208
(local.get $base)
1209
(local.get 0))
1210
1211
(local.get $base)
1212
"#,
1213
"",
1214
)
1215
};
1216
1217
let component = format!(
1218
r#"(component
1219
(core module $libc
1220
(memory (export "memory") 1)
1221
1222
{REALLOC_AND_FREE}
1223
)
1224
(core instance $libc (instantiate $libc))
1225
(core module $m
1226
(import "libc" "memory" (memory 1))
1227
(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
1228
(import "" "task.return" (func $task-return (param i32 i32 i32)))
1229
(func (export "foo") (param i32) (result i32)
1230
{body}
1231
)
1232
(func (export "callback") (param i32 i32 i32) (result i32) unreachable)
1233
)
1234
(type $tuple (tuple (list u8) u32))
1235
(core func $task-return (canon task.return
1236
(result $tuple)
1237
(memory $libc "memory")
1238
))
1239
(core instance $i (instantiate $m
1240
(with "" (instance (export "task.return" (func $task-return))))
1241
(with "libc" (instance $libc))
1242
))
1243
1244
(type $t (func
1245
(param "p1" s8) ;; offset 0, size 1
1246
(param "p2" u64) ;; offset 8, size 8
1247
(param "p3" float32) ;; offset 16, size 4
1248
(param "p4" u8) ;; offset 20, size 1
1249
(param "p5" s16) ;; offset 22, size 2
1250
(param "p6" string) ;; offset 24, size 8
1251
(param "p7" (list u32)) ;; offset 32, size 8
1252
(param "p8" bool) ;; offset 40, size 1
1253
(param "p9" bool) ;; offset 41, size 1
1254
(param "p0" char) ;; offset 44, size 4
1255
(param "pa" (list bool)) ;; offset 48, size 8
1256
(param "pb" (list char)) ;; offset 56, size 8
1257
(param "pc" (list string)) ;; offset 64, size 8
1258
1259
(result $tuple)
1260
))
1261
(func (export "many-param") (type $t)
1262
(canon lift
1263
(core func $i "foo")
1264
(memory $libc "memory")
1265
(realloc (func $libc "realloc"))
1266
{async_opts}
1267
)
1268
)
1269
)"#
1270
);
1271
1272
let mut config = Config::new();
1273
config.wasm_component_model_async(true);
1274
let engine = &Engine::new(&config)?;
1275
let component = Component::new(&engine, component)?;
1276
let mut store = Store::new(&engine, ());
1277
1278
let instance = Linker::new(&engine)
1279
.instantiate_async(&mut store, &component)
1280
.await?;
1281
1282
let input = (
1283
-100,
1284
u64::MAX / 2,
1285
f32::from_bits(CANON_32BIT_NAN | 1),
1286
38,
1287
18831,
1288
"this is the first string",
1289
[1, 2, 3, 4, 5, 6, 7, 8].as_slice(),
1290
true,
1291
false,
1292
'',
1293
[false, true, false, true, true].as_slice(),
1294
['', '', '', '', ''].as_slice(),
1295
[
1296
"the quick",
1297
"brown fox",
1298
"was too lazy",
1299
"to jump over the dog",
1300
"what a demanding dog",
1301
]
1302
.as_slice(),
1303
);
1304
1305
let (memory, pointer) = if dynamic {
1306
let input = vec![
1307
Val::S8(input.0),
1308
Val::U64(input.1),
1309
Val::Float32(input.2),
1310
Val::U8(input.3),
1311
Val::S16(input.4),
1312
Val::String(input.5.into()),
1313
Val::List(input.6.iter().copied().map(Val::U32).collect()),
1314
Val::Bool(input.7),
1315
Val::Bool(input.8),
1316
Val::Char(input.9),
1317
Val::List(input.10.iter().copied().map(Val::Bool).collect()),
1318
Val::List(input.11.iter().copied().map(Val::Char).collect()),
1319
Val::List(input.12.iter().map(|&s| Val::String(s.into())).collect()),
1320
];
1321
let func = instance.get_func(&mut store, "many-param").unwrap();
1322
1323
let mut results = vec![Val::Bool(false)];
1324
if concurrent {
1325
store
1326
.run_concurrent(async |store| {
1327
func.call_concurrent(store, &input, &mut results).await?;
1328
wasmtime::error::Ok(())
1329
})
1330
.await??;
1331
} else {
1332
func.call_async(&mut store, &input, &mut results).await?;
1333
};
1334
let mut results = results.into_iter();
1335
let Some(Val::Tuple(results)) = results.next() else {
1336
panic!()
1337
};
1338
let mut results = results.into_iter();
1339
let Some(Val::List(memory)) = results.next() else {
1340
panic!()
1341
};
1342
let Some(Val::U32(pointer)) = results.next() else {
1343
panic!()
1344
};
1345
(
1346
memory
1347
.into_iter()
1348
.map(|v| if let Val::U8(v) = v { v } else { panic!() })
1349
.collect(),
1350
pointer,
1351
)
1352
} else {
1353
let func = instance.get_typed_func::<(
1354
i8,
1355
u64,
1356
f32,
1357
u8,
1358
i16,
1359
&str,
1360
&[u32],
1361
bool,
1362
bool,
1363
char,
1364
&[bool],
1365
&[char],
1366
&[&str],
1367
), ((Vec<u8>, u32),)>(&mut store, "many-param")?;
1368
1369
if concurrent {
1370
store
1371
.run_concurrent(async move |accessor| {
1372
wasmtime::error::Ok(func.call_concurrent(accessor, input).await?.0)
1373
})
1374
.await??
1375
.0
1376
} else {
1377
func.call_async(&mut store, input).await?.0
1378
}
1379
};
1380
let memory = &memory[..];
1381
1382
let mut actual = &memory[pointer as usize..][..72];
1383
assert_eq!(i8::from_le_bytes(*actual.take_n::<1>()), input.0);
1384
actual.skip::<7>();
1385
assert_eq!(u64::from_le_bytes(*actual.take_n::<8>()), input.1);
1386
assert_eq!(
1387
u32::from_le_bytes(*actual.take_n::<4>()),
1388
CANON_32BIT_NAN | 1
1389
);
1390
assert_eq!(u8::from_le_bytes(*actual.take_n::<1>()), input.3);
1391
actual.skip::<1>();
1392
assert_eq!(i16::from_le_bytes(*actual.take_n::<2>()), input.4);
1393
assert_eq!(actual.ptr_len(memory, 1), input.5.as_bytes());
1394
let mut mem = actual.ptr_len(memory, 4);
1395
for expected in input.6.iter() {
1396
assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected);
1397
}
1398
assert!(mem.is_empty());
1399
assert_eq!(actual.take_n::<1>(), &[input.7 as u8]);
1400
assert_eq!(actual.take_n::<1>(), &[input.8 as u8]);
1401
actual.skip::<2>();
1402
assert_eq!(u32::from_le_bytes(*actual.take_n::<4>()), input.9 as u32);
1403
1404
// (list bool)
1405
mem = actual.ptr_len(memory, 1);
1406
for expected in input.10.iter() {
1407
assert_eq!(mem.take_n::<1>(), &[*expected as u8]);
1408
}
1409
assert!(mem.is_empty());
1410
1411
// (list char)
1412
mem = actual.ptr_len(memory, 4);
1413
for expected in input.11.iter() {
1414
assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected as u32);
1415
}
1416
assert!(mem.is_empty());
1417
1418
// (list string)
1419
mem = actual.ptr_len(memory, 8);
1420
for expected in input.12.iter() {
1421
let actual = mem.ptr_len(memory, 1);
1422
assert_eq!(actual, expected.as_bytes());
1423
}
1424
assert!(mem.is_empty());
1425
assert!(actual.is_empty());
1426
1427
Ok(())
1428
}
1429
1430
#[tokio::test]
1431
async fn many_results() -> Result<()> {
1432
test_many_results(false, false).await
1433
}
1434
1435
#[tokio::test]
1436
async fn many_results_concurrent() -> Result<()> {
1437
test_many_results(false, true).await
1438
}
1439
1440
#[tokio::test]
1441
async fn many_results_dynamic() -> Result<()> {
1442
test_many_results(true, false).await
1443
}
1444
1445
#[tokio::test]
1446
async fn many_results_dynamic_concurrent() -> Result<()> {
1447
test_many_results(true, true).await
1448
}
1449
1450
async fn test_many_results(dynamic: bool, concurrent: bool) -> Result<()> {
1451
let (ret, async_opts) = if concurrent {
1452
(
1453
r#"
1454
call $task-return
1455
i32.const 0
1456
"#,
1457
r#"async (callback (func $i "callback"))"#,
1458
)
1459
} else {
1460
("", "")
1461
};
1462
1463
let my_nan = CANON_32BIT_NAN | 1;
1464
1465
let component = format!(
1466
r#"(component
1467
(core module $libc
1468
(memory (export "memory") 1)
1469
1470
{REALLOC_AND_FREE}
1471
)
1472
(core instance $libc (instantiate $libc))
1473
(core module $m
1474
(import "libc" "memory" (memory 1))
1475
(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
1476
(import "" "task.return" (func $task-return (param i32)))
1477
(func (export "foo") (result i32)
1478
(local $base i32)
1479
(local $string i32)
1480
(local $list i32)
1481
1482
(local.set $base
1483
(call $realloc
1484
(i32.const 0)
1485
(i32.const 0)
1486
(i32.const 8)
1487
(i32.const 72)))
1488
1489
(i32.store8 offset=0
1490
(local.get $base)
1491
(i32.const -100))
1492
1493
(i64.store offset=8
1494
(local.get $base)
1495
(i64.const 9223372036854775807))
1496
1497
(f32.store offset=16
1498
(local.get $base)
1499
(f32.reinterpret_i32 (i32.const {my_nan})))
1500
1501
(i32.store8 offset=20
1502
(local.get $base)
1503
(i32.const 38))
1504
1505
(i32.store16 offset=22
1506
(local.get $base)
1507
(i32.const 18831))
1508
1509
(local.set $string
1510
(call $realloc
1511
(i32.const 0)
1512
(i32.const 0)
1513
(i32.const 1)
1514
(i32.const 6)))
1515
1516
(i32.store8 offset=0
1517
(local.get $string)
1518
(i32.const 97)) ;; 'a'
1519
(i32.store8 offset=1
1520
(local.get $string)
1521
(i32.const 98)) ;; 'b'
1522
(i32.store8 offset=2
1523
(local.get $string)
1524
(i32.const 99)) ;; 'c'
1525
(i32.store8 offset=3
1526
(local.get $string)
1527
(i32.const 100)) ;; 'd'
1528
(i32.store8 offset=4
1529
(local.get $string)
1530
(i32.const 101)) ;; 'e'
1531
(i32.store8 offset=5
1532
(local.get $string)
1533
(i32.const 102)) ;; 'f'
1534
1535
(i32.store offset=24
1536
(local.get $base)
1537
(local.get $string))
1538
1539
(i32.store offset=28
1540
(local.get $base)
1541
(i32.const 2))
1542
1543
(local.set $list
1544
(call $realloc
1545
(i32.const 0)
1546
(i32.const 0)
1547
(i32.const 4)
1548
(i32.const 32)))
1549
1550
(i32.store offset=0
1551
(local.get $list)
1552
(i32.const 1))
1553
(i32.store offset=4
1554
(local.get $list)
1555
(i32.const 2))
1556
(i32.store offset=8
1557
(local.get $list)
1558
(i32.const 3))
1559
(i32.store offset=12
1560
(local.get $list)
1561
(i32.const 4))
1562
(i32.store offset=16
1563
(local.get $list)
1564
(i32.const 5))
1565
(i32.store offset=20
1566
(local.get $list)
1567
(i32.const 6))
1568
(i32.store offset=24
1569
(local.get $list)
1570
(i32.const 7))
1571
(i32.store offset=28
1572
(local.get $list)
1573
(i32.const 8))
1574
1575
(i32.store offset=32
1576
(local.get $base)
1577
(local.get $list))
1578
1579
(i32.store offset=36
1580
(local.get $base)
1581
(i32.const 8))
1582
1583
(i32.store8 offset=40
1584
(local.get $base)
1585
(i32.const 1))
1586
1587
(i32.store8 offset=41
1588
(local.get $base)
1589
(i32.const 0))
1590
1591
(i32.store offset=44
1592
(local.get $base)
1593
(i32.const 128681)) ;; '🚩'
1594
1595
(local.set $list
1596
(call $realloc
1597
(i32.const 0)
1598
(i32.const 0)
1599
(i32.const 1)
1600
(i32.const 5)))
1601
1602
(i32.store8 offset=0
1603
(local.get $list)
1604
(i32.const 0))
1605
(i32.store8 offset=1
1606
(local.get $list)
1607
(i32.const 1))
1608
(i32.store8 offset=2
1609
(local.get $list)
1610
(i32.const 0))
1611
(i32.store8 offset=3
1612
(local.get $list)
1613
(i32.const 1))
1614
(i32.store8 offset=4
1615
(local.get $list)
1616
(i32.const 1))
1617
1618
(i32.store offset=48
1619
(local.get $base)
1620
(local.get $list))
1621
1622
(i32.store offset=52
1623
(local.get $base)
1624
(i32.const 5))
1625
1626
(local.set $list
1627
(call $realloc
1628
(i32.const 0)
1629
(i32.const 0)
1630
(i32.const 4)
1631
(i32.const 20)))
1632
1633
(i32.store offset=0
1634
(local.get $list)
1635
(i32.const 127820)) ;; '🍌'
1636
(i32.store offset=4
1637
(local.get $list)
1638
(i32.const 129360)) ;; '🥐'
1639
(i32.store offset=8
1640
(local.get $list)
1641
(i32.const 127831)) ;; '🍗'
1642
(i32.store offset=12
1643
(local.get $list)
1644
(i32.const 127833)) ;; '🍙'
1645
(i32.store offset=16
1646
(local.get $list)
1647
(i32.const 127841)) ;; '🍡'
1648
1649
(i32.store offset=56
1650
(local.get $base)
1651
(local.get $list))
1652
1653
(i32.store offset=60
1654
(local.get $base)
1655
(i32.const 5))
1656
1657
(local.set $list
1658
(call $realloc
1659
(i32.const 0)
1660
(i32.const 0)
1661
(i32.const 4)
1662
(i32.const 16)))
1663
1664
(i32.store offset=0
1665
(local.get $list)
1666
(i32.add (local.get $string) (i32.const 2)))
1667
(i32.store offset=4
1668
(local.get $list)
1669
(i32.const 2))
1670
(i32.store offset=8
1671
(local.get $list)
1672
(i32.add (local.get $string) (i32.const 4)))
1673
(i32.store offset=12
1674
(local.get $list)
1675
(i32.const 2))
1676
1677
(i32.store offset=64
1678
(local.get $base)
1679
(local.get $list))
1680
1681
(i32.store offset=68
1682
(local.get $base)
1683
(i32.const 2))
1684
1685
local.get $base
1686
1687
{ret}
1688
)
1689
(func (export "callback") (param i32 i32 i32) (result i32) unreachable)
1690
)
1691
(type $tuple (tuple
1692
s8
1693
u64
1694
float32
1695
u8
1696
s16
1697
string
1698
(list u32)
1699
bool
1700
bool
1701
char
1702
(list bool)
1703
(list char)
1704
(list string)
1705
))
1706
(core func $task-return (canon task.return
1707
(result $tuple)
1708
(memory $libc "memory")
1709
))
1710
(core instance $i (instantiate $m
1711
(with "" (instance (export "task.return" (func $task-return))))
1712
(with "libc" (instance $libc))
1713
))
1714
1715
(type $t (func (result $tuple)))
1716
(func (export "many-results") (type $t)
1717
(canon lift
1718
(core func $i "foo")
1719
(memory $libc "memory")
1720
(realloc (func $libc "realloc"))
1721
{async_opts}
1722
)
1723
)
1724
)"#
1725
);
1726
1727
let mut config = Config::new();
1728
config.wasm_component_model_async(true);
1729
let engine = &Engine::new(&config)?;
1730
let component = Component::new(&engine, component)?;
1731
let mut store = Store::new(&engine, ());
1732
1733
let instance = Linker::new(&engine)
1734
.instantiate_async(&mut store, &component)
1735
.await?;
1736
1737
let expected = (
1738
-100i8,
1739
u64::MAX / 2,
1740
f32::from_bits(CANON_32BIT_NAN | 1),
1741
38u8,
1742
18831i16,
1743
"ab".to_string(),
1744
vec![1u32, 2, 3, 4, 5, 6, 7, 8],
1745
true,
1746
false,
1747
'',
1748
vec![false, true, false, true, true],
1749
vec!['', '', '', '', ''],
1750
vec!["cd".to_string(), "ef".to_string()],
1751
);
1752
1753
let actual = if dynamic {
1754
let func = instance.get_func(&mut store, "many-results").unwrap();
1755
1756
let mut results = vec![Val::Bool(false)];
1757
if concurrent {
1758
store
1759
.run_concurrent(async |store| {
1760
func.call_concurrent(store, &[], &mut results).await?;
1761
wasmtime::error::Ok(())
1762
})
1763
.await??;
1764
} else {
1765
func.call_async(&mut store, &[], &mut results).await?;
1766
};
1767
let mut results = results.into_iter();
1768
1769
let Some(Val::Tuple(results)) = results.next() else {
1770
panic!()
1771
};
1772
let mut results = results.into_iter();
1773
let Some(Val::S8(p1)) = results.next() else {
1774
panic!()
1775
};
1776
let Some(Val::U64(p2)) = results.next() else {
1777
panic!()
1778
};
1779
let Some(Val::Float32(p3)) = results.next() else {
1780
panic!()
1781
};
1782
let Some(Val::U8(p4)) = results.next() else {
1783
panic!()
1784
};
1785
let Some(Val::S16(p5)) = results.next() else {
1786
panic!()
1787
};
1788
let Some(Val::String(p6)) = results.next() else {
1789
panic!()
1790
};
1791
let Some(Val::List(p7)) = results.next() else {
1792
panic!()
1793
};
1794
let p7 = p7
1795
.into_iter()
1796
.map(|v| if let Val::U32(v) = v { v } else { panic!() })
1797
.collect();
1798
let Some(Val::Bool(p8)) = results.next() else {
1799
panic!()
1800
};
1801
let Some(Val::Bool(p9)) = results.next() else {
1802
panic!()
1803
};
1804
let Some(Val::Char(p0)) = results.next() else {
1805
panic!()
1806
};
1807
let Some(Val::List(pa)) = results.next() else {
1808
panic!()
1809
};
1810
let pa = pa
1811
.into_iter()
1812
.map(|v| if let Val::Bool(v) = v { v } else { panic!() })
1813
.collect();
1814
let Some(Val::List(pb)) = results.next() else {
1815
panic!()
1816
};
1817
let pb = pb
1818
.into_iter()
1819
.map(|v| if let Val::Char(v) = v { v } else { panic!() })
1820
.collect();
1821
let Some(Val::List(pc)) = results.next() else {
1822
panic!()
1823
};
1824
let pc = pc
1825
.into_iter()
1826
.map(|v| if let Val::String(v) = v { v } else { panic!() })
1827
.collect();
1828
1829
(p1, p2, p3, p4, p5, p6, p7, p8, p9, p0, pa, pb, pc)
1830
} else {
1831
let func = instance.get_typed_func::<(), ((
1832
i8,
1833
u64,
1834
f32,
1835
u8,
1836
i16,
1837
String,
1838
Vec<u32>,
1839
bool,
1840
bool,
1841
char,
1842
Vec<bool>,
1843
Vec<char>,
1844
Vec<String>,
1845
),)>(&mut store, "many-results")?;
1846
1847
if concurrent {
1848
store
1849
.run_concurrent(async move |accessor| {
1850
wasmtime::error::Ok(func.call_concurrent(accessor, ()).await?.0)
1851
})
1852
.await??
1853
.0
1854
} else {
1855
func.call_async(&mut store, ()).await?.0
1856
}
1857
};
1858
1859
assert_eq!(expected.0, actual.0);
1860
assert_eq!(expected.1, actual.1);
1861
assert!(expected.2.is_nan());
1862
assert!(actual.2.is_nan());
1863
assert_eq!(expected.3, actual.3);
1864
assert_eq!(expected.4, actual.4);
1865
assert_eq!(expected.5, actual.5);
1866
assert_eq!(expected.6, actual.6);
1867
assert_eq!(expected.7, actual.7);
1868
assert_eq!(expected.8, actual.8);
1869
assert_eq!(expected.9, actual.9);
1870
assert_eq!(expected.10, actual.10);
1871
assert_eq!(expected.11, actual.11);
1872
assert_eq!(expected.12, actual.12);
1873
1874
Ok(())
1875
}
1876
1877
#[test]
1878
fn some_traps() -> Result<()> {
1879
let middle_of_memory = (i32::MAX / 2) & (!0xff);
1880
let component = format!(
1881
r#"(component
1882
(core module $m
1883
(memory (export "memory") 1)
1884
(func (export "take-many") (param i32))
1885
(func (export "take-list") (param i32 i32))
1886
1887
(func (export "realloc") (param i32 i32 i32 i32) (result i32)
1888
unreachable)
1889
)
1890
(core instance $i (instantiate $m))
1891
1892
(func (export "take-list-unreachable") (param "a" (list u8))
1893
(canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc")))
1894
)
1895
(func (export "take-string-unreachable") (param "a" string)
1896
(canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc")))
1897
)
1898
1899
(type $t (func
1900
(param "s1" string)
1901
(param "s2" string)
1902
(param "s3" string)
1903
(param "s4" string)
1904
(param "s5" string)
1905
(param "s6" string)
1906
(param "s7" string)
1907
(param "s8" string)
1908
(param "s9" string)
1909
(param "s10" string)
1910
))
1911
(func (export "take-many-unreachable") (type $t)
1912
(canon lift (core func $i "take-many") (memory $i "memory") (realloc (func $i "realloc")))
1913
)
1914
1915
(core module $m2
1916
(memory (export "memory") 1)
1917
(func (export "take-many") (param i32))
1918
(func (export "take-list") (param i32 i32))
1919
1920
(func (export "realloc") (param i32 i32 i32 i32) (result i32)
1921
i32.const {middle_of_memory})
1922
)
1923
(core instance $i2 (instantiate $m2))
1924
1925
(func (export "take-list-base-oob") (param "a" (list u8))
1926
(canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1927
)
1928
(func (export "take-string-base-oob") (param "a" string)
1929
(canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1930
)
1931
(func (export "take-many-base-oob") (type $t)
1932
(canon lift (core func $i2 "take-many") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1933
)
1934
1935
(core module $m3
1936
(memory (export "memory") 1)
1937
(func (export "take-many") (param i32))
1938
(func (export "take-list") (param i32 i32))
1939
1940
(func (export "realloc") (param i32 i32 i32 i32) (result i32)
1941
i32.const 65532)
1942
)
1943
(core instance $i3 (instantiate $m3))
1944
1945
(func (export "take-list-end-oob") (param "a" (list u8))
1946
(canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1947
)
1948
(func (export "take-string-end-oob") (param "a" string)
1949
(canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1950
)
1951
(func (export "take-many-end-oob") (type $t)
1952
(canon lift (core func $i3 "take-many") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1953
)
1954
1955
(core module $m4
1956
(memory (export "memory") 1)
1957
(func (export "take-many") (param i32))
1958
1959
(global $cnt (mut i32) (i32.const 0))
1960
(func (export "realloc") (param i32 i32 i32 i32) (result i32)
1961
global.get $cnt
1962
if (result i32)
1963
i32.const 100000
1964
else
1965
i32.const 1
1966
global.set $cnt
1967
i32.const 0
1968
end
1969
)
1970
)
1971
(core instance $i4 (instantiate $m4))
1972
1973
(func (export "take-many-second-oob") (type $t)
1974
(canon lift (core func $i4 "take-many") (memory $i4 "memory") (realloc (func $i4 "realloc")))
1975
)
1976
)"#
1977
);
1978
1979
let engine = super::engine();
1980
let component = Component::new(&engine, component)?;
1981
1982
// This should fail when calling the allocator function for the argument
1983
let err = with_new_instance(&engine, &component, |store, instance| {
1984
instance
1985
.get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-unreachable")?
1986
.call(store, (&[],))
1987
.unwrap_err()
1988
.downcast::<Trap>()
1989
})?;
1990
assert_eq!(err, Trap::UnreachableCodeReached);
1991
1992
// This should fail when calling the allocator function for the argument
1993
let err = with_new_instance(&engine, &component, |store, instance| {
1994
instance
1995
.get_typed_func::<(&str,), ()>(&mut *store, "take-string-unreachable")?
1996
.call(store, ("",))
1997
.unwrap_err()
1998
.downcast::<Trap>()
1999
})?;
2000
assert_eq!(err, Trap::UnreachableCodeReached);
2001
2002
// This should fail when calling the allocator function for the space
2003
// to store the arguments (before arguments are even lowered)
2004
let err = with_new_instance(&engine, &component, |store, instance| {
2005
instance
2006
.get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2007
&mut *store,
2008
"take-many-unreachable",
2009
)?
2010
.call(store, ("", "", "", "", "", "", "", "", "", ""))
2011
.unwrap_err()
2012
.downcast::<Trap>()
2013
})?;
2014
assert_eq!(err, Trap::UnreachableCodeReached);
2015
2016
// Assert that when the base pointer returned by malloc is out of bounds
2017
// that errors are reported as such. Both empty and lists with contents
2018
// should all be invalid here.
2019
//
2020
// FIXME(WebAssembly/component-model#32) confirm the semantics here are
2021
// what's desired.
2022
#[track_caller]
2023
fn assert_oob(err: &wasmtime::Error) {
2024
assert!(
2025
err.to_string()
2026
.contains("realloc return: beyond end of memory"),
2027
"{err:?}",
2028
);
2029
}
2030
let err = with_new_instance(&engine, &component, |store, instance| {
2031
instance
2032
.get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-base-oob")?
2033
.call(store, (&[],))
2034
})
2035
.unwrap_err();
2036
assert_oob(&err);
2037
let err = with_new_instance(&engine, &component, |store, instance| {
2038
instance
2039
.get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-base-oob")?
2040
.call(store, (&[1],))
2041
})
2042
.unwrap_err();
2043
assert_oob(&err);
2044
let err = with_new_instance(&engine, &component, |store, instance| {
2045
instance
2046
.get_typed_func::<(&str,), ()>(&mut *store, "take-string-base-oob")?
2047
.call(store, ("",))
2048
})
2049
.unwrap_err();
2050
assert_oob(&err);
2051
let err = with_new_instance(&engine, &component, |store, instance| {
2052
instance
2053
.get_typed_func::<(&str,), ()>(&mut *store, "take-string-base-oob")?
2054
.call(store, ("x",))
2055
})
2056
.unwrap_err();
2057
assert_oob(&err);
2058
let err = with_new_instance(&engine, &component, |store, instance| {
2059
instance
2060
.get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2061
&mut *store,
2062
"take-many-base-oob",
2063
)?
2064
.call(store, ("", "", "", "", "", "", "", "", "", ""))
2065
})
2066
.unwrap_err();
2067
assert_oob(&err);
2068
2069
// Test here that when the returned pointer from malloc is one byte from the
2070
// end of memory that empty things are fine, but larger things are not.
2071
2072
with_new_instance(&engine, &component, |store, instance| {
2073
instance
2074
.get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-end-oob")?
2075
.call(store, (&[],))
2076
})?;
2077
with_new_instance(&engine, &component, |store, instance| {
2078
instance
2079
.get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-end-oob")?
2080
.call(store, (&[1, 2, 3, 4],))
2081
})?;
2082
let err = with_new_instance(&engine, &component, |store, instance| {
2083
instance
2084
.get_typed_func::<(&[u8],), ()>(&mut *store, "take-list-end-oob")?
2085
.call(store, (&[1, 2, 3, 4, 5],))
2086
})
2087
.unwrap_err();
2088
assert_oob(&err);
2089
with_new_instance(&engine, &component, |store, instance| {
2090
instance
2091
.get_typed_func::<(&str,), ()>(&mut *store, "take-string-end-oob")?
2092
.call(store, ("",))
2093
})?;
2094
with_new_instance(&engine, &component, |store, instance| {
2095
instance
2096
.get_typed_func::<(&str,), ()>(&mut *store, "take-string-end-oob")?
2097
.call(store, ("abcd",))
2098
})?;
2099
let err = with_new_instance(&engine, &component, |store, instance| {
2100
instance
2101
.get_typed_func::<(&str,), ()>(&mut *store, "take-string-end-oob")?
2102
.call(store, ("abcde",))
2103
})
2104
.unwrap_err();
2105
assert_oob(&err);
2106
let err = with_new_instance(&engine, &component, |store, instance| {
2107
instance
2108
.get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2109
&mut *store,
2110
"take-many-end-oob",
2111
)?
2112
.call(store, ("", "", "", "", "", "", "", "", "", ""))
2113
})
2114
.unwrap_err();
2115
assert_oob(&err);
2116
2117
// For this function the first allocation, the space to store all the
2118
// arguments, is in-bounds but then all further allocations, such as for
2119
// each individual string, are all out of bounds.
2120
let err = with_new_instance(&engine, &component, |store, instance| {
2121
instance
2122
.get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2123
&mut *store,
2124
"take-many-second-oob",
2125
)?
2126
.call(store, ("", "", "", "", "", "", "", "", "", ""))
2127
})
2128
.unwrap_err();
2129
assert_oob(&err);
2130
let err = with_new_instance(&engine, &component, |store, instance| {
2131
instance
2132
.get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2133
&mut *store,
2134
"take-many-second-oob",
2135
)?
2136
.call(store, ("", "", "", "", "", "", "", "", "", "x"))
2137
})
2138
.unwrap_err();
2139
assert_oob(&err);
2140
Ok(())
2141
}
2142
2143
#[test]
2144
fn char_bool_memory() -> Result<()> {
2145
let component = format!(
2146
r#"(component
2147
(core module $m
2148
(memory (export "memory") 1)
2149
(func (export "ret-tuple") (param i32 i32) (result i32)
2150
(local $base i32)
2151
2152
;; Allocate space for the return
2153
(local.set $base
2154
(call $realloc
2155
(i32.const 0)
2156
(i32.const 0)
2157
(i32.const 4)
2158
(i32.const 8)))
2159
2160
;; store the boolean
2161
(i32.store offset=0
2162
(local.get $base)
2163
(local.get 0))
2164
2165
;; store the char
2166
(i32.store offset=4
2167
(local.get $base)
2168
(local.get 1))
2169
2170
(local.get $base)
2171
)
2172
2173
{REALLOC_AND_FREE}
2174
)
2175
(core instance $i (instantiate $m))
2176
2177
(func (export "ret-tuple") (param "a" u32) (param "b" u32) (result (tuple bool char))
2178
(canon lift (core func $i "ret-tuple")
2179
(memory $i "memory")
2180
(realloc (func $i "realloc")))
2181
)
2182
)"#
2183
);
2184
2185
let engine = super::engine();
2186
let component = Component::new(&engine, component)?;
2187
let mut store = Store::new(&engine, ());
2188
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2189
let func = instance.get_typed_func::<(u32, u32), ((bool, char),)>(&mut store, "ret-tuple")?;
2190
2191
let (ret,) = func.call(&mut store, (0, 'a' as u32))?;
2192
assert_eq!(ret, (false, 'a'));
2193
2194
let (ret,) = func.call(&mut store, (1, '' as u32))?;
2195
assert_eq!(ret, (true, ''));
2196
2197
let (ret,) = func.call(&mut store, (2, 'a' as u32))?;
2198
assert_eq!(ret, (true, 'a'));
2199
2200
assert!(func.call(&mut store, (0, 0xd800)).is_err());
2201
2202
Ok(())
2203
}
2204
2205
#[test]
2206
fn string_list_oob() -> Result<()> {
2207
let component = format!(
2208
r#"(component
2209
(core module $m
2210
(memory (export "memory") 1)
2211
(func (export "ret-list") (result i32)
2212
(local $base i32)
2213
2214
;; Allocate space for the return
2215
(local.set $base
2216
(call $realloc
2217
(i32.const 0)
2218
(i32.const 0)
2219
(i32.const 4)
2220
(i32.const 8)))
2221
2222
(i32.store offset=0
2223
(local.get $base)
2224
(i32.const 100000))
2225
(i32.store offset=4
2226
(local.get $base)
2227
(i32.const 1))
2228
2229
(local.get $base)
2230
)
2231
2232
{REALLOC_AND_FREE}
2233
)
2234
(core instance $i (instantiate $m))
2235
2236
(func (export "ret-list-u8") (result (list u8))
2237
(canon lift (core func $i "ret-list")
2238
(memory $i "memory")
2239
(realloc (func $i "realloc"))
2240
)
2241
)
2242
(func (export "ret-string") (result string)
2243
(canon lift (core func $i "ret-list")
2244
(memory $i "memory")
2245
(realloc (func $i "realloc"))
2246
)
2247
)
2248
)"#
2249
);
2250
2251
let engine = super::engine();
2252
let component = Component::new(&engine, component)?;
2253
let mut store = Store::new(&engine, ());
2254
let ret_list_u8 = Linker::new(&engine)
2255
.instantiate(&mut store, &component)?
2256
.get_typed_func::<(), (WasmList<u8>,)>(&mut store, "ret-list-u8")?;
2257
let ret_string = Linker::new(&engine)
2258
.instantiate(&mut store, &component)?
2259
.get_typed_func::<(), (WasmStr,)>(&mut store, "ret-string")?;
2260
2261
let err = ret_list_u8.call(&mut store, ()).err().unwrap();
2262
assert!(err.to_string().contains("out of bounds"), "{}", err);
2263
2264
let err = ret_string.call(&mut store, ()).err().unwrap();
2265
assert!(err.to_string().contains("out of bounds"), "{}", err);
2266
2267
Ok(())
2268
}
2269
2270
#[test]
2271
fn tuples() -> Result<()> {
2272
let component = format!(
2273
r#"(component
2274
(core module $m
2275
(memory (export "memory") 1)
2276
(func (export "foo")
2277
(param i32 f64 i32)
2278
(result i32)
2279
2280
local.get 0
2281
i32.const 0
2282
i32.ne
2283
if unreachable end
2284
2285
local.get 1
2286
f64.const 1
2287
f64.ne
2288
if unreachable end
2289
2290
local.get 2
2291
i32.const 2
2292
i32.ne
2293
if unreachable end
2294
2295
i32.const 3
2296
)
2297
)
2298
(core instance $i (instantiate $m))
2299
2300
(func (export "foo")
2301
(param "a" (tuple s32 float64))
2302
(param "b" (tuple s8))
2303
(result (tuple u16))
2304
(canon lift (core func $i "foo"))
2305
)
2306
)"#
2307
);
2308
2309
let engine = super::engine();
2310
let component = Component::new(&engine, component)?;
2311
let mut store = Store::new(&engine, ());
2312
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2313
let foo = instance.get_typed_func::<((i32, f64), (i8,)), ((u16,),)>(&mut store, "foo")?;
2314
assert_eq!(foo.call(&mut store, ((0, 1.0), (2,)))?, ((3,),));
2315
2316
Ok(())
2317
}
2318
2319
#[test]
2320
fn option() -> Result<()> {
2321
let component = format!(
2322
r#"(component
2323
(core module $m
2324
(memory (export "memory") 1)
2325
(func (export "pass1") (param i32 i32) (result i32)
2326
(local $base i32)
2327
(local.set $base
2328
(call $realloc
2329
(i32.const 0)
2330
(i32.const 0)
2331
(i32.const 4)
2332
(i32.const 8)))
2333
2334
(i32.store offset=0
2335
(local.get $base)
2336
(local.get 0))
2337
(i32.store offset=4
2338
(local.get $base)
2339
(local.get 1))
2340
2341
(local.get $base)
2342
)
2343
(func (export "pass2") (param i32 i32 i32) (result i32)
2344
(local $base i32)
2345
(local.set $base
2346
(call $realloc
2347
(i32.const 0)
2348
(i32.const 0)
2349
(i32.const 4)
2350
(i32.const 12)))
2351
2352
(i32.store offset=0
2353
(local.get $base)
2354
(local.get 0))
2355
(i32.store offset=4
2356
(local.get $base)
2357
(local.get 1))
2358
(i32.store offset=8
2359
(local.get $base)
2360
(local.get 2))
2361
2362
(local.get $base)
2363
)
2364
2365
{REALLOC_AND_FREE}
2366
)
2367
(core instance $i (instantiate $m))
2368
2369
(func (export "option-u8-to-tuple") (param "a" (option u8)) (result (tuple u32 u32))
2370
(canon lift (core func $i "pass1") (memory $i "memory"))
2371
)
2372
(func (export "option-u32-to-tuple") (param "a" (option u32)) (result (tuple u32 u32))
2373
(canon lift (core func $i "pass1") (memory $i "memory"))
2374
)
2375
(func (export "option-string-to-tuple") (param "a" (option string)) (result (tuple u32 string))
2376
(canon lift
2377
(core func $i "pass2")
2378
(memory $i "memory")
2379
(realloc (func $i "realloc"))
2380
)
2381
)
2382
(func (export "to-option-u8") (param "a" u32) (param "b" u32) (result (option u8))
2383
(canon lift (core func $i "pass1") (memory $i "memory"))
2384
)
2385
(func (export "to-option-u32") (param "a" u32) (param "b" u32) (result (option u32))
2386
(canon lift
2387
(core func $i "pass1")
2388
(memory $i "memory")
2389
)
2390
)
2391
(func (export "to-option-string") (param "a" u32) (param "b" string) (result (option string))
2392
(canon lift
2393
(core func $i "pass2")
2394
(memory $i "memory")
2395
(realloc (func $i "realloc"))
2396
)
2397
)
2398
)"#
2399
);
2400
2401
let engine = super::engine();
2402
let component = Component::new(&engine, component)?;
2403
let mut store = Store::new(&engine, ());
2404
let linker = Linker::new(&engine);
2405
let instance = linker.instantiate(&mut store, &component)?;
2406
2407
let option_u8_to_tuple = instance
2408
.get_typed_func::<(Option<u8>,), ((u32, u32),)>(&mut store, "option-u8-to-tuple")?;
2409
assert_eq!(option_u8_to_tuple.call(&mut store, (None,))?, ((0, 0),));
2410
assert_eq!(option_u8_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),));
2411
assert_eq!(
2412
option_u8_to_tuple.call(&mut store, (Some(100),))?,
2413
((1, 100),)
2414
);
2415
2416
let option_u32_to_tuple = instance
2417
.get_typed_func::<(Option<u32>,), ((u32, u32),)>(&mut store, "option-u32-to-tuple")?;
2418
assert_eq!(option_u32_to_tuple.call(&mut store, (None,))?, ((0, 0),));
2419
assert_eq!(option_u32_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),));
2420
assert_eq!(
2421
option_u32_to_tuple.call(&mut store, (Some(100),))?,
2422
((1, 100),)
2423
);
2424
2425
let option_string_to_tuple = instance.get_typed_func::<(Option<&str>,), ((u32, WasmStr),)>(
2426
&mut store,
2427
"option-string-to-tuple",
2428
)?;
2429
let ((a, b),) = option_string_to_tuple.call(&mut store, (None,))?;
2430
assert_eq!(a, 0);
2431
assert_eq!(b.to_str(&store)?, "");
2432
let ((a, b),) = option_string_to_tuple.call(&mut store, (Some(""),))?;
2433
assert_eq!(a, 1);
2434
assert_eq!(b.to_str(&store)?, "");
2435
let ((a, b),) = option_string_to_tuple.call(&mut store, (Some("hello"),))?;
2436
assert_eq!(a, 1);
2437
assert_eq!(b.to_str(&store)?, "hello");
2438
2439
let instance = linker.instantiate(&mut store, &component)?;
2440
let to_option_u8 =
2441
instance.get_typed_func::<(u32, u32), (Option<u8>,)>(&mut store, "to-option-u8")?;
2442
assert_eq!(to_option_u8.call(&mut store, (0x00_00, 0))?, (None,));
2443
assert_eq!(to_option_u8.call(&mut store, (0x00_01, 0))?, (Some(0),));
2444
assert_eq!(to_option_u8.call(&mut store, (0xfd_01, 0))?, (Some(0xfd),));
2445
assert!(to_option_u8.call(&mut store, (0x00_02, 0)).is_err());
2446
2447
let instance = linker.instantiate(&mut store, &component)?;
2448
let to_option_u32 =
2449
instance.get_typed_func::<(u32, u32), (Option<u32>,)>(&mut store, "to-option-u32")?;
2450
assert_eq!(to_option_u32.call(&mut store, (0, 0))?, (None,));
2451
assert_eq!(to_option_u32.call(&mut store, (1, 0))?, (Some(0),));
2452
assert_eq!(
2453
to_option_u32.call(&mut store, (1, 0x1234fead))?,
2454
(Some(0x1234fead),)
2455
);
2456
assert!(to_option_u32.call(&mut store, (2, 0)).is_err());
2457
2458
let instance = linker.instantiate(&mut store, &component)?;
2459
let to_option_string = instance
2460
.get_typed_func::<(u32, &str), (Option<WasmStr>,)>(&mut store, "to-option-string")?;
2461
let ret = to_option_string.call(&mut store, (0, ""))?.0;
2462
assert!(ret.is_none());
2463
let ret = to_option_string.call(&mut store, (1, ""))?.0;
2464
assert_eq!(ret.unwrap().to_str(&store)?, "");
2465
let ret = to_option_string.call(&mut store, (1, "cheesecake"))?.0;
2466
assert_eq!(ret.unwrap().to_str(&store)?, "cheesecake");
2467
assert!(to_option_string.call(&mut store, (2, "")).is_err());
2468
2469
Ok(())
2470
}
2471
2472
#[test]
2473
fn expected() -> Result<()> {
2474
let component = format!(
2475
r#"(component
2476
(core module $m
2477
(memory (export "memory") 1)
2478
(func (export "pass0") (param i32) (result i32)
2479
local.get 0
2480
)
2481
(func (export "pass1") (param i32 i32) (result i32)
2482
(local $base i32)
2483
(local.set $base
2484
(call $realloc
2485
(i32.const 0)
2486
(i32.const 0)
2487
(i32.const 4)
2488
(i32.const 8)))
2489
2490
(i32.store offset=0
2491
(local.get $base)
2492
(local.get 0))
2493
(i32.store offset=4
2494
(local.get $base)
2495
(local.get 1))
2496
2497
(local.get $base)
2498
)
2499
(func (export "pass2") (param i32 i32 i32) (result i32)
2500
(local $base i32)
2501
(local.set $base
2502
(call $realloc
2503
(i32.const 0)
2504
(i32.const 0)
2505
(i32.const 4)
2506
(i32.const 12)))
2507
2508
(i32.store offset=0
2509
(local.get $base)
2510
(local.get 0))
2511
(i32.store offset=4
2512
(local.get $base)
2513
(local.get 1))
2514
(i32.store offset=8
2515
(local.get $base)
2516
(local.get 2))
2517
2518
(local.get $base)
2519
)
2520
2521
{REALLOC_AND_FREE}
2522
)
2523
(core instance $i (instantiate $m))
2524
2525
(func (export "take-expected-unit") (param "a" (result)) (result u32)
2526
(canon lift (core func $i "pass0"))
2527
)
2528
(func (export "take-expected-u8-f32") (param "a" (result u8 (error float32))) (result (tuple u32 u32))
2529
(canon lift (core func $i "pass1") (memory $i "memory"))
2530
)
2531
(type $list (list u8))
2532
(func (export "take-expected-string") (param "a" (result string (error $list))) (result (tuple u32 string))
2533
(canon lift
2534
(core func $i "pass2")
2535
(memory $i "memory")
2536
(realloc (func $i "realloc"))
2537
)
2538
)
2539
(func (export "to-expected-unit") (param "a" u32) (result (result))
2540
(canon lift (core func $i "pass0"))
2541
)
2542
(func (export "to-expected-s16-f32") (param "a" u32) (param "b" u32) (result (result s16 (error float32)))
2543
(canon lift
2544
(core func $i "pass1")
2545
(memory $i "memory")
2546
(realloc (func $i "realloc"))
2547
)
2548
)
2549
)"#
2550
);
2551
2552
let engine = super::engine();
2553
let component = Component::new(&engine, component)?;
2554
let mut store = Store::new(&engine, ());
2555
let linker = Linker::new(&engine);
2556
let instance = linker.instantiate(&mut store, &component)?;
2557
let take_expected_unit =
2558
instance.get_typed_func::<(Result<(), ()>,), (u32,)>(&mut store, "take-expected-unit")?;
2559
assert_eq!(take_expected_unit.call(&mut store, (Ok(()),))?, (0,));
2560
assert_eq!(take_expected_unit.call(&mut store, (Err(()),))?, (1,));
2561
2562
let take_expected_u8_f32 = instance
2563
.get_typed_func::<(Result<u8, f32>,), ((u32, u32),)>(&mut store, "take-expected-u8-f32")?;
2564
assert_eq!(take_expected_u8_f32.call(&mut store, (Ok(1),))?, ((0, 1),));
2565
assert_eq!(
2566
take_expected_u8_f32.call(&mut store, (Err(2.0),))?,
2567
((1, 2.0f32.to_bits()),)
2568
);
2569
2570
let take_expected_string = instance
2571
.get_typed_func::<(Result<&str, &[u8]>,), ((u32, WasmStr),)>(
2572
&mut store,
2573
"take-expected-string",
2574
)?;
2575
let ((a, b),) = take_expected_string.call(&mut store, (Ok("hello"),))?;
2576
assert_eq!(a, 0);
2577
assert_eq!(b.to_str(&store)?, "hello");
2578
let ((a, b),) = take_expected_string.call(&mut store, (Err(b"goodbye"),))?;
2579
assert_eq!(a, 1);
2580
assert_eq!(b.to_str(&store)?, "goodbye");
2581
2582
let instance = linker.instantiate(&mut store, &component)?;
2583
let to_expected_unit =
2584
instance.get_typed_func::<(u32,), (Result<(), ()>,)>(&mut store, "to-expected-unit")?;
2585
assert_eq!(to_expected_unit.call(&mut store, (0,))?, (Ok(()),));
2586
assert_eq!(to_expected_unit.call(&mut store, (1,))?, (Err(()),));
2587
let err = to_expected_unit.call(&mut store, (2,)).unwrap_err();
2588
assert!(err.to_string().contains("invalid expected"), "{}", err);
2589
2590
let instance = linker.instantiate(&mut store, &component)?;
2591
let to_expected_s16_f32 = instance
2592
.get_typed_func::<(u32, u32), (Result<i16, f32>,)>(&mut store, "to-expected-s16-f32")?;
2593
assert_eq!(to_expected_s16_f32.call(&mut store, (0, 0))?, (Ok(0),));
2594
assert_eq!(to_expected_s16_f32.call(&mut store, (0, 100))?, (Ok(100),));
2595
assert_eq!(
2596
to_expected_s16_f32.call(&mut store, (1, 1.0f32.to_bits()))?,
2597
(Err(1.0),)
2598
);
2599
let ret = to_expected_s16_f32
2600
.call(&mut store, (1, CANON_32BIT_NAN | 1))?
2601
.0;
2602
assert_eq!(ret.unwrap_err().to_bits(), CANON_32BIT_NAN | 1);
2603
assert!(to_expected_s16_f32.call(&mut store, (2, 0)).is_err());
2604
2605
Ok(())
2606
}
2607
2608
#[test]
2609
fn fancy_list() -> Result<()> {
2610
let component = format!(
2611
r#"(component
2612
(core module $m
2613
(memory (export "memory") 1)
2614
(func (export "take") (param i32 i32) (result i32)
2615
(local $base i32)
2616
(local.set $base
2617
(call $realloc
2618
(i32.const 0)
2619
(i32.const 0)
2620
(i32.const 4)
2621
(i32.const 16)))
2622
2623
(i32.store offset=0
2624
(local.get $base)
2625
(local.get 0))
2626
(i32.store offset=4
2627
(local.get $base)
2628
(local.get 1))
2629
(i32.store offset=8
2630
(local.get $base)
2631
(i32.const 0))
2632
(i32.store offset=12
2633
(local.get $base)
2634
(i32.mul
2635
(memory.size)
2636
(i32.const 65536)))
2637
2638
(local.get $base)
2639
)
2640
2641
{REALLOC_AND_FREE}
2642
)
2643
(core instance $i (instantiate $m))
2644
2645
(type $a (option u8))
2646
(type $b (result (error string)))
2647
(type $input (list (tuple $a $b)))
2648
(func (export "take")
2649
(param "a" $input)
2650
(result (tuple u32 u32 (list u8)))
2651
(canon lift
2652
(core func $i "take")
2653
(memory $i "memory")
2654
(realloc (func $i "realloc"))
2655
)
2656
)
2657
)"#
2658
);
2659
2660
let engine = super::engine();
2661
let component = Component::new(&engine, component)?;
2662
let mut store = Store::new(&engine, ());
2663
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2664
2665
let func = instance
2666
.get_typed_func::<(&[(Option<u8>, Result<(), &str>)],), ((u32, u32, WasmList<u8>),)>(
2667
&mut store, "take",
2668
)?;
2669
2670
let input = [
2671
(None, Ok(())),
2672
(Some(2), Err("hello there")),
2673
(Some(200), Err("general kenobi")),
2674
];
2675
let ((ptr, len, list),) = func.call(&mut store, (&input,))?;
2676
let memory = list.as_le_slice(&store);
2677
let ptr = usize::try_from(ptr).unwrap();
2678
let len = usize::try_from(len).unwrap();
2679
let mut array = &memory[ptr..][..len * 16];
2680
2681
for (a, b) in input.iter() {
2682
match a {
2683
Some(val) => {
2684
assert_eq!(*array.take_n::<2>(), [1, *val]);
2685
}
2686
None => {
2687
assert_eq!(*array.take_n::<1>(), [0]);
2688
array.skip::<1>();
2689
}
2690
}
2691
array.skip::<2>();
2692
match b {
2693
Ok(()) => {
2694
assert_eq!(*array.take_n::<1>(), [0]);
2695
array.skip::<11>();
2696
}
2697
Err(s) => {
2698
assert_eq!(*array.take_n::<1>(), [1]);
2699
array.skip::<3>();
2700
assert_eq!(array.ptr_len(memory, 1), s.as_bytes());
2701
}
2702
}
2703
}
2704
assert!(array.is_empty());
2705
2706
Ok(())
2707
}
2708
2709
trait SliceExt<'a> {
2710
fn take_n<const N: usize>(&mut self) -> &'a [u8; N];
2711
2712
fn skip<const N: usize>(&mut self) {
2713
self.take_n::<N>();
2714
}
2715
2716
fn ptr_len<'b>(&mut self, all_memory: &'b [u8], size: usize) -> &'b [u8] {
2717
let ptr = u32::from_le_bytes(*self.take_n::<4>());
2718
let len = u32::from_le_bytes(*self.take_n::<4>());
2719
let ptr = usize::try_from(ptr).unwrap();
2720
let len = usize::try_from(len).unwrap();
2721
&all_memory[ptr..][..len * size]
2722
}
2723
}
2724
2725
impl<'a> SliceExt<'a> for &'a [u8] {
2726
fn take_n<const N: usize>(&mut self) -> &'a [u8; N] {
2727
let (a, b) = self.split_at(N);
2728
*self = b;
2729
a.try_into().unwrap()
2730
}
2731
}
2732
2733
#[test]
2734
fn invalid_alignment() -> Result<()> {
2735
let component = format!(
2736
r#"(component
2737
(core module $m
2738
(memory (export "memory") 1)
2739
(func (export "realloc") (param i32 i32 i32 i32) (result i32)
2740
i32.const 1)
2741
2742
(func (export "take-i32") (param i32))
2743
(func (export "ret-1") (result i32) i32.const 1)
2744
(func (export "ret-unaligned-list") (result i32)
2745
(i32.store offset=0 (i32.const 8) (i32.const 1))
2746
(i32.store offset=4 (i32.const 8) (i32.const 1))
2747
i32.const 8)
2748
)
2749
(core instance $i (instantiate $m))
2750
2751
(func (export "many-params")
2752
(param "s1" string) (param "s2" string) (param "s3" string) (param "s4" string)
2753
(param "s5" string) (param "s6" string) (param "s7" string) (param "s8" string)
2754
(param "s9" string) (param "s10" string) (param "s11" string) (param "s12" string)
2755
(canon lift
2756
(core func $i "take-i32")
2757
(memory $i "memory")
2758
(realloc (func $i "realloc"))
2759
)
2760
)
2761
(func (export "string-ret") (result string)
2762
(canon lift
2763
(core func $i "ret-1")
2764
(memory $i "memory")
2765
(realloc (func $i "realloc"))
2766
)
2767
)
2768
(func (export "list-u32-ret") (result (list u32))
2769
(canon lift
2770
(core func $i "ret-unaligned-list")
2771
(memory $i "memory")
2772
(realloc (func $i "realloc"))
2773
)
2774
)
2775
)"#
2776
);
2777
2778
let engine = super::engine();
2779
let component = Component::new(&engine, component)?;
2780
let mut store = Store::new(&engine, ());
2781
let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component);
2782
2783
let err = instance(&mut store)?
2784
.get_typed_func::<(
2785
&str,
2786
&str,
2787
&str,
2788
&str,
2789
&str,
2790
&str,
2791
&str,
2792
&str,
2793
&str,
2794
&str,
2795
&str,
2796
&str,
2797
), ()>(&mut store, "many-params")?
2798
.call(&mut store, ("", "", "", "", "", "", "", "", "", "", "", ""))
2799
.unwrap_err();
2800
assert!(
2801
err.to_string()
2802
.contains("realloc return: result not aligned"),
2803
"{}",
2804
err
2805
);
2806
2807
let err = instance(&mut store)?
2808
.get_typed_func::<(), (WasmStr,)>(&mut store, "string-ret")?
2809
.call(&mut store, ())
2810
.err()
2811
.unwrap();
2812
assert!(
2813
err.to_string().contains("return pointer not aligned"),
2814
"{}",
2815
err
2816
);
2817
2818
let err = instance(&mut store)?
2819
.get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32-ret")?
2820
.call(&mut store, ())
2821
.err()
2822
.unwrap();
2823
assert!(
2824
err.to_string().contains("list pointer is not aligned"),
2825
"{}",
2826
err
2827
);
2828
2829
Ok(())
2830
}
2831
2832
#[test]
2833
fn drop_component_still_works() -> Result<()> {
2834
let component = r#"
2835
(component
2836
(import "f" (func $f))
2837
2838
(core func $f_lower
2839
(canon lower (func $f))
2840
)
2841
(core module $m
2842
(import "" "" (func $f))
2843
2844
(func $f2
2845
call $f
2846
call $f
2847
)
2848
2849
(export "f" (func $f2))
2850
)
2851
(core instance $i (instantiate $m
2852
(with "" (instance
2853
(export "" (func $f_lower))
2854
))
2855
))
2856
(func (export "g")
2857
(canon lift
2858
(core func $i "f")
2859
)
2860
)
2861
)
2862
"#;
2863
2864
let (mut store, instance) = {
2865
let engine = super::engine();
2866
let component = Component::new(&engine, component)?;
2867
let mut store = Store::new(&engine, 0);
2868
let mut linker = Linker::new(&engine);
2869
linker.root().func_wrap(
2870
"f",
2871
|mut store: StoreContextMut<'_, u32>, _: ()| -> Result<()> {
2872
*store.data_mut() += 1;
2873
Ok(())
2874
},
2875
)?;
2876
let instance = linker.instantiate(&mut store, &component)?;
2877
(store, instance)
2878
};
2879
2880
let f = instance.get_typed_func::<(), ()>(&mut store, "g")?;
2881
assert_eq!(*store.data(), 0);
2882
f.call(&mut store, ())?;
2883
assert_eq!(*store.data(), 2);
2884
2885
Ok(())
2886
}
2887
2888
#[test]
2889
fn raw_slice_of_various_types() -> Result<()> {
2890
let component = r#"
2891
(component
2892
(core module $m
2893
(memory (export "memory") 1)
2894
2895
(func (export "list8") (result i32)
2896
(call $setup_list (i32.const 16))
2897
)
2898
(func (export "list16") (result i32)
2899
(call $setup_list (i32.const 8))
2900
)
2901
(func (export "list32") (result i32)
2902
(call $setup_list (i32.const 4))
2903
)
2904
(func (export "list64") (result i32)
2905
(call $setup_list (i32.const 2))
2906
)
2907
2908
(func $setup_list (param i32) (result i32)
2909
(i32.store offset=0 (i32.const 100) (i32.const 8))
2910
(i32.store offset=4 (i32.const 100) (local.get 0))
2911
i32.const 100
2912
)
2913
2914
(data (i32.const 8) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f")
2915
)
2916
(core instance $i (instantiate $m))
2917
(func (export "list-u8") (result (list u8))
2918
(canon lift (core func $i "list8") (memory $i "memory"))
2919
)
2920
(func (export "list-i8") (result (list s8))
2921
(canon lift (core func $i "list8") (memory $i "memory"))
2922
)
2923
(func (export "list-u16") (result (list u16))
2924
(canon lift (core func $i "list16") (memory $i "memory"))
2925
)
2926
(func (export "list-i16") (result (list s16))
2927
(canon lift (core func $i "list16") (memory $i "memory"))
2928
)
2929
(func (export "list-u32") (result (list u32))
2930
(canon lift (core func $i "list32") (memory $i "memory"))
2931
)
2932
(func (export "list-i32") (result (list s32))
2933
(canon lift (core func $i "list32") (memory $i "memory"))
2934
)
2935
(func (export "list-u64") (result (list u64))
2936
(canon lift (core func $i "list64") (memory $i "memory"))
2937
)
2938
(func (export "list-i64") (result (list s64))
2939
(canon lift (core func $i "list64") (memory $i "memory"))
2940
)
2941
)
2942
"#;
2943
2944
let (mut store, instance) = {
2945
let engine = super::engine();
2946
let component = Component::new(&engine, component)?;
2947
let mut store = Store::new(&engine, ());
2948
let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2949
(store, instance)
2950
};
2951
2952
let list = instance
2953
.get_typed_func::<(), (WasmList<u8>,)>(&mut store, "list-u8")?
2954
.call(&mut store, ())?
2955
.0;
2956
assert_eq!(
2957
list.as_le_slice(&store),
2958
[
2959
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
2960
0x0e, 0x0f,
2961
]
2962
);
2963
let list = instance
2964
.get_typed_func::<(), (WasmList<i8>,)>(&mut store, "list-i8")?
2965
.call(&mut store, ())?
2966
.0;
2967
assert_eq!(
2968
list.as_le_slice(&store),
2969
[
2970
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
2971
0x0e, 0x0f,
2972
]
2973
);
2974
2975
let list = instance
2976
.get_typed_func::<(), (WasmList<u16>,)>(&mut store, "list-u16")?
2977
.call(&mut store, ())?
2978
.0;
2979
assert_eq!(
2980
list.as_le_slice(&store),
2981
[
2982
u16::to_le(0x01_00),
2983
u16::to_le(0x03_02),
2984
u16::to_le(0x05_04),
2985
u16::to_le(0x07_06),
2986
u16::to_le(0x09_08),
2987
u16::to_le(0x0b_0a),
2988
u16::to_le(0x0d_0c),
2989
u16::to_le(0x0f_0e),
2990
]
2991
);
2992
let list = instance
2993
.get_typed_func::<(), (WasmList<i16>,)>(&mut store, "list-i16")?
2994
.call(&mut store, ())?
2995
.0;
2996
assert_eq!(
2997
list.as_le_slice(&store),
2998
[
2999
i16::to_le(0x01_00),
3000
i16::to_le(0x03_02),
3001
i16::to_le(0x05_04),
3002
i16::to_le(0x07_06),
3003
i16::to_le(0x09_08),
3004
i16::to_le(0x0b_0a),
3005
i16::to_le(0x0d_0c),
3006
i16::to_le(0x0f_0e),
3007
]
3008
);
3009
let list = instance
3010
.get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32")?
3011
.call(&mut store, ())?
3012
.0;
3013
assert_eq!(
3014
list.as_le_slice(&store),
3015
[
3016
u32::to_le(0x03_02_01_00),
3017
u32::to_le(0x07_06_05_04),
3018
u32::to_le(0x0b_0a_09_08),
3019
u32::to_le(0x0f_0e_0d_0c),
3020
]
3021
);
3022
let list = instance
3023
.get_typed_func::<(), (WasmList<i32>,)>(&mut store, "list-i32")?
3024
.call(&mut store, ())?
3025
.0;
3026
assert_eq!(
3027
list.as_le_slice(&store),
3028
[
3029
i32::to_le(0x03_02_01_00),
3030
i32::to_le(0x07_06_05_04),
3031
i32::to_le(0x0b_0a_09_08),
3032
i32::to_le(0x0f_0e_0d_0c),
3033
]
3034
);
3035
let list = instance
3036
.get_typed_func::<(), (WasmList<u64>,)>(&mut store, "list-u64")?
3037
.call(&mut store, ())?
3038
.0;
3039
assert_eq!(
3040
list.as_le_slice(&store),
3041
[
3042
u64::to_le(0x07_06_05_04_03_02_01_00),
3043
u64::to_le(0x0f_0e_0d_0c_0b_0a_09_08),
3044
]
3045
);
3046
let list = instance
3047
.get_typed_func::<(), (WasmList<i64>,)>(&mut store, "list-i64")?
3048
.call(&mut store, ())?
3049
.0;
3050
assert_eq!(
3051
list.as_le_slice(&store),
3052
[
3053
i64::to_le(0x07_06_05_04_03_02_01_00),
3054
i64::to_le(0x0f_0e_0d_0c_0b_0a_09_08),
3055
]
3056
);
3057
3058
Ok(())
3059
}
3060
3061
#[test]
3062
fn lower_then_lift() -> Result<()> {
3063
// First test simple integers when the import/export ABI happen to line up
3064
let component = r#"
3065
(component $c
3066
(import "f" (func $f (result u32)))
3067
3068
(core func $f_lower
3069
(canon lower (func $f))
3070
)
3071
(func $f2 (result s32)
3072
(canon lift (core func $f_lower))
3073
)
3074
(export "f2" (func $f2))
3075
)
3076
"#;
3077
3078
let engine = super::engine();
3079
let component = Component::new(&engine, component)?;
3080
let mut store = Store::new(&engine, ());
3081
let mut linker = Linker::new(&engine);
3082
linker.root().func_wrap("f", |_, _: ()| Ok((2u32,)))?;
3083
let instance = linker.instantiate(&mut store, &component)?;
3084
3085
let f = instance.get_typed_func::<(), (i32,)>(&mut store, "f2")?;
3086
assert_eq!(f.call(&mut store, ())?, (2,));
3087
3088
// First test strings when the import/export ABI happen to line up
3089
let component = format!(
3090
r#"
3091
(component $c
3092
(import "s" (func $f (param "a" string)))
3093
3094
(core module $libc
3095
(memory (export "memory") 1)
3096
{REALLOC_AND_FREE}
3097
)
3098
(core instance $libc (instantiate $libc))
3099
3100
(core func $f_lower
3101
(canon lower (func $f) (memory $libc "memory"))
3102
)
3103
(func $f2 (param "a" string)
3104
(canon lift (core func $f_lower)
3105
(memory $libc "memory")
3106
(realloc (func $libc "realloc"))
3107
)
3108
)
3109
(export "f" (func $f2))
3110
)
3111
"#
3112
);
3113
3114
let component = Component::new(&engine, component)?;
3115
let mut store = Store::new(&engine, ());
3116
linker
3117
.root()
3118
.func_wrap("s", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| {
3119
assert_eq!(x.to_str(&store)?, "hello");
3120
Ok(())
3121
})?;
3122
let instance = linker.instantiate(&mut store, &component)?;
3123
3124
let f = instance.get_typed_func::<(&str,), ()>(&mut store, "f")?;
3125
f.call(&mut store, ("hello",))?;
3126
3127
// Next test "type punning" where return values are reinterpreted just
3128
// because the return ABI happens to line up.
3129
let component = format!(
3130
r#"
3131
(component $c
3132
(import "s2" (func $f (param "a" string) (result u32)))
3133
3134
(core module $libc
3135
(memory (export "memory") 1)
3136
{REALLOC_AND_FREE}
3137
)
3138
(core instance $libc (instantiate $libc))
3139
3140
(core func $f_lower
3141
(canon lower (func $f) (memory $libc "memory"))
3142
)
3143
(func $f2 (param "a" string) (result string)
3144
(canon lift (core func $f_lower)
3145
(memory $libc "memory")
3146
(realloc (func $libc "realloc"))
3147
)
3148
)
3149
(export "f" (func $f2))
3150
)
3151
"#
3152
);
3153
3154
let component = Component::new(&engine, component)?;
3155
let mut store = Store::new(&engine, ());
3156
linker
3157
.root()
3158
.func_wrap("s2", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| {
3159
assert_eq!(x.to_str(&store)?, "hello");
3160
Ok((u32::MAX,))
3161
})?;
3162
let instance = linker.instantiate(&mut store, &component)?;
3163
3164
let f = instance.get_typed_func::<(&str,), (WasmStr,)>(&mut store, "f")?;
3165
let err = f.call(&mut store, ("hello",)).err().unwrap();
3166
assert!(
3167
err.to_string().contains("return pointer not aligned"),
3168
"{}",
3169
err
3170
);
3171
3172
Ok(())
3173
}
3174
3175
#[test]
3176
fn errors_that_poison_instance() -> Result<()> {
3177
let component = format!(
3178
r#"
3179
(component $c
3180
(core module $m1
3181
(func (export "f1") unreachable)
3182
(func (export "f2"))
3183
)
3184
(core instance $m1 (instantiate $m1))
3185
(func (export "f1") (canon lift (core func $m1 "f1")))
3186
(func (export "f2") (canon lift (core func $m1 "f2")))
3187
3188
(core module $m2
3189
(func (export "f") (param i32 i32))
3190
(func (export "r") (param i32 i32 i32 i32) (result i32) unreachable)
3191
(memory (export "m") 1)
3192
)
3193
(core instance $m2 (instantiate $m2))
3194
(func (export "f3") (param "a" string)
3195
(canon lift (core func $m2 "f") (realloc (func $m2 "r")) (memory $m2 "m"))
3196
)
3197
3198
(core module $m3
3199
(func (export "f") (result i32) i32.const 1)
3200
(memory (export "m") 1)
3201
)
3202
(core instance $m3 (instantiate $m3))
3203
(func (export "f4") (result string)
3204
(canon lift (core func $m3 "f") (memory $m3 "m"))
3205
)
3206
)
3207
"#
3208
);
3209
3210
let engine = super::engine();
3211
let component = Component::new(&engine, component)?;
3212
let linker = Linker::new(&engine);
3213
3214
{
3215
let mut store = Store::new(&engine, ());
3216
let instance = linker.instantiate(&mut store, &component)?;
3217
let f1 = instance.get_typed_func::<(), ()>(&mut store, "f1")?;
3218
let f2 = instance.get_typed_func::<(), ()>(&mut store, "f2")?;
3219
assert_unreachable(f1.call(&mut store, ()));
3220
assert_poisoned(f1.call(&mut store, ()));
3221
assert_poisoned(f2.call(&mut store, ()));
3222
}
3223
3224
{
3225
let mut store = Store::new(&engine, ());
3226
let instance = linker.instantiate(&mut store, &component)?;
3227
let f3 = instance.get_typed_func::<(&str,), ()>(&mut store, "f3")?;
3228
assert_unreachable(f3.call(&mut store, ("x",)));
3229
assert_poisoned(f3.call(&mut store, ("x",)));
3230
3231
// Since we actually poison the store, even an unrelated instance will
3232
// be considered poisoned:
3233
let instance = linker.instantiate(&mut store, &component)?;
3234
let f3 = instance.get_typed_func::<(&str,), ()>(&mut store, "f3")?;
3235
assert_poisoned(f3.call(&mut store, ("x",)));
3236
}
3237
3238
{
3239
let mut store = Store::new(&engine, ());
3240
let instance = linker.instantiate(&mut store, &component)?;
3241
let f4 = instance.get_typed_func::<(), (WasmStr,)>(&mut store, "f4")?;
3242
assert!(f4.call(&mut store, ()).is_err());
3243
assert_poisoned(f4.call(&mut store, ()));
3244
}
3245
3246
return Ok(());
3247
3248
#[track_caller]
3249
fn assert_unreachable<T>(err: Result<T>) {
3250
let err = match err {
3251
Ok(_) => panic!("expected an error"),
3252
Err(e) => e,
3253
};
3254
assert_eq!(
3255
err.downcast::<Trap>().unwrap(),
3256
Trap::UnreachableCodeReached
3257
);
3258
}
3259
3260
#[track_caller]
3261
fn assert_poisoned<T>(err: Result<T>) {
3262
let err = match err {
3263
Ok(_) => panic!("expected an error"),
3264
Err(e) => e,
3265
};
3266
assert_eq!(
3267
err.downcast_ref::<Trap>(),
3268
Some(&Trap::CannotEnterComponent),
3269
"{err}",
3270
);
3271
}
3272
}
3273
3274
#[test]
3275
fn run_export_with_internal_adapter() -> Result<()> {
3276
let component = r#"
3277
(component
3278
(type $t (func (param "a" u32) (result u32)))
3279
(component $a
3280
(core module $m
3281
(func (export "add-five") (param i32) (result i32)
3282
local.get 0
3283
i32.const 5
3284
i32.add)
3285
)
3286
(core instance $m (instantiate $m))
3287
(func (export "add-five") (type $t) (canon lift (core func $m "add-five")))
3288
)
3289
(component $b
3290
(import "interface-v1" (instance $i
3291
(export "add-five" (func (type $t)))))
3292
(core module $m
3293
(func $add-five (import "interface-0.1.0" "add-five") (param i32) (result i32))
3294
(func) ;; causes index out of bounds
3295
(func (export "run") (result i32) i32.const 0 call $add-five)
3296
)
3297
(core func $add-five (canon lower (func $i "add-five")))
3298
(core instance $i (instantiate 0
3299
(with "interface-0.1.0" (instance
3300
(export "add-five" (func $add-five))
3301
))
3302
))
3303
(func (result u32) (canon lift (core func $i "run")))
3304
(export "run" (func 1))
3305
)
3306
(instance $a (instantiate $a))
3307
(instance $b (instantiate $b (with "interface-v1" (instance $a))))
3308
(export "run" (func $b "run"))
3309
)
3310
"#;
3311
let engine = super::engine();
3312
let component = Component::new(&engine, component)?;
3313
let mut store = Store::new(&engine, ());
3314
let linker = Linker::new(&engine);
3315
let instance = linker.instantiate(&mut store, &component)?;
3316
let run = instance.get_typed_func::<(), (u32,)>(&mut store, "run")?;
3317
assert_eq!(run.call(&mut store, ())?, (5,));
3318
Ok(())
3319
}
3320
3321
enum RecurseKind {
3322
AThenA,
3323
AThenB,
3324
AThenBThenA,
3325
}
3326
3327
#[test]
3328
fn recurse() -> Result<()> {
3329
test_recurse(RecurseKind::AThenB)
3330
}
3331
3332
#[test]
3333
fn recurse_trap() -> Result<()> {
3334
let error = test_recurse(RecurseKind::AThenA).unwrap_err();
3335
3336
assert_eq!(error.downcast::<Trap>()?, Trap::CannotEnterComponent);
3337
3338
Ok(())
3339
}
3340
3341
#[test]
3342
fn recurse_more_trap() -> Result<()> {
3343
let error = test_recurse(RecurseKind::AThenBThenA).unwrap_err();
3344
3345
assert_eq!(error.downcast::<Trap>()?, Trap::CannotEnterComponent);
3346
3347
Ok(())
3348
}
3349
3350
fn test_recurse(kind: RecurseKind) -> Result<()> {
3351
#[derive(Default)]
3352
struct Ctx {
3353
instances: Vec<Arc<Instance>>,
3354
}
3355
3356
let component = r#"
3357
(component
3358
(import "import" (func $import))
3359
(core func $import (canon lower (func $import)))
3360
(core module $m
3361
(func $import (import "" "import"))
3362
(func (export "export") call $import)
3363
)
3364
(core instance $m (instantiate $m (with "" (instance
3365
(export "import" (func $import))
3366
))))
3367
(func (export "export") (canon lift (core func $m "export")))
3368
)
3369
"#;
3370
let engine = super::engine();
3371
let component = Component::new(&engine, component)?;
3372
let mut store = Store::new(&engine, Ctx::default());
3373
let mut linker = Linker::<Ctx>::new(&engine);
3374
linker.root().func_wrap("import", |mut store, (): ()| {
3375
if let Some(instance) = store.data_mut().instances.pop() {
3376
let run = instance.get_typed_func::<(), ()>(&mut store, "export")?;
3377
run.call(&mut store, ())?;
3378
store.data_mut().instances.push(instance);
3379
}
3380
Ok(())
3381
})?;
3382
let instance = Arc::new(linker.instantiate(&mut store, &component)?);
3383
let instance = match kind {
3384
RecurseKind::AThenA => {
3385
store.data_mut().instances.push(instance.clone());
3386
instance
3387
}
3388
RecurseKind::AThenB => {
3389
let other = Arc::new(linker.instantiate(&mut store, &component)?);
3390
store.data_mut().instances.push(other);
3391
instance
3392
}
3393
RecurseKind::AThenBThenA => {
3394
store.data_mut().instances.push(instance.clone());
3395
let other = Arc::new(linker.instantiate(&mut store, &component)?);
3396
store.data_mut().instances.push(other);
3397
instance
3398
}
3399
};
3400
3401
let export = instance.get_typed_func::<(), ()>(&mut store, "export")?;
3402
export.call(&mut store, ())?;
3403
Ok(())
3404
}
3405
3406
#[tokio::test]
3407
async fn thread_index_via_instantiation_sync() -> Result<()> {
3408
thread_index_via_instantiation(ApiStyle::Sync).await
3409
}
3410
3411
#[tokio::test]
3412
async fn thread_index_via_instantiation_async() -> Result<()> {
3413
thread_index_via_instantiation(ApiStyle::Async).await
3414
}
3415
3416
async fn thread_index_via_instantiation(style: ApiStyle) -> Result<()> {
3417
let component = r#"
3418
(component
3419
(core module $m
3420
(import "" "thread.index" (func $thread-index (result i32)))
3421
(func $start
3422
(if (i32.eqz (call $thread-index)) (then unreachable))
3423
)
3424
(start $start)
3425
)
3426
(core func $thread-index (canon thread.index))
3427
(core instance $m (instantiate $m (with "" (instance
3428
(export "thread.index" (func $thread-index))
3429
))))
3430
)
3431
"#;
3432
let engine = Engine::new(&style.config())?;
3433
let component = Component::new(&engine, component)?;
3434
let mut store = Store::new(&engine, ());
3435
let linker = Linker::new(&engine);
3436
style.instantiate(&mut store, &linker, &component).await?;
3437
Ok(())
3438
}
3439
3440
#[tokio::test]
3441
async fn thread_index_via_call_sync() -> Result<()> {
3442
thread_index_via_call(ApiStyle::Sync).await
3443
}
3444
3445
#[tokio::test]
3446
async fn thread_index_via_call_async() -> Result<()> {
3447
thread_index_via_call(ApiStyle::Async).await
3448
}
3449
3450
#[tokio::test]
3451
async fn thread_index_via_call_concurrent() -> Result<()> {
3452
thread_index_via_call(ApiStyle::Concurrent).await
3453
}
3454
3455
async fn thread_index_via_call(style: ApiStyle) -> Result<()> {
3456
let component = r#"
3457
(component
3458
(core module $m
3459
(import "" "thread.index" (func $thread-index (result i32)))
3460
(func (export "run")
3461
(if (i32.eqz (call $thread-index)) (then unreachable))
3462
)
3463
)
3464
(core func $thread-index (canon thread.index))
3465
(core instance $m (instantiate $m (with "" (instance
3466
(export "thread.index" (func $thread-index))
3467
))))
3468
(func (export "run") (canon lift (core func $m "run")))
3469
)
3470
"#;
3471
let engine = Engine::new(&style.config())?;
3472
let component = Component::new(&engine, component)?;
3473
let mut store = Store::new(&engine, ());
3474
let linker = Linker::new(&engine);
3475
let instance = style.instantiate(&mut store, &linker, &component).await?;
3476
let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
3477
style.call(&mut store, run, ()).await?;
3478
Ok(())
3479
}
3480
3481
#[tokio::test]
3482
async fn thread_index_via_post_return_sync() -> Result<()> {
3483
thread_index_via_post_return(ApiStyle::Sync).await
3484
}
3485
3486
#[tokio::test]
3487
async fn thread_index_via_post_return_async() -> Result<()> {
3488
thread_index_via_post_return(ApiStyle::Async).await
3489
}
3490
3491
#[tokio::test]
3492
async fn thread_index_via_post_return_concurrent() -> Result<()> {
3493
thread_index_via_post_return(ApiStyle::Concurrent).await
3494
}
3495
3496
async fn thread_index_via_post_return(style: ApiStyle) -> Result<()> {
3497
let component = r#"
3498
(component
3499
(core module $m
3500
(import "" "thread.index" (func $thread-index (result i32)))
3501
(global $index (mut i32) (i32.const 0))
3502
(func (export "run")
3503
(global.set $index (call $thread-index))
3504
(if (i32.eqz (global.get $index)) (then unreachable))
3505
)
3506
(func (export "run-post-return")
3507
(local $index i32)
3508
(local.set $index (call $thread-index))
3509
(if (i32.eqz (local.get $index)) (then unreachable))
3510
(if (i32.ne (local.get $index) (global.get $index)) (then unreachable))
3511
)
3512
)
3513
(core func $thread-index (canon thread.index))
3514
(core instance $m (instantiate $m (with "" (instance
3515
(export "thread.index" (func $thread-index))
3516
))))
3517
(func (export "run") (canon lift (core func $m "run") (post-return (func $m "run-post-return"))))
3518
)
3519
"#;
3520
let engine = Engine::new(&style.config())?;
3521
let component = Component::new(&engine, component)?;
3522
let mut store = Store::new(&engine, ());
3523
let linker = Linker::new(&engine);
3524
let instance = style.instantiate(&mut store, &linker, &component).await?;
3525
let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
3526
style.call(&mut store, run, ()).await?;
3527
Ok(())
3528
}
3529
3530
#[tokio::test]
3531
async fn thread_index_via_cabi_realloc_sync() -> Result<()> {
3532
thread_index_via_cabi_realloc(ApiStyle::Sync).await
3533
}
3534
3535
#[tokio::test]
3536
async fn thread_index_via_cabi_realloc_async() -> Result<()> {
3537
thread_index_via_cabi_realloc(ApiStyle::Async).await
3538
}
3539
3540
#[tokio::test]
3541
async fn thread_index_via_cabi_realloc_concurrent() -> Result<()> {
3542
thread_index_via_cabi_realloc(ApiStyle::Concurrent).await
3543
}
3544
3545
async fn thread_index_via_cabi_realloc(style: ApiStyle) -> Result<()> {
3546
let component = r#"
3547
(component
3548
(core module $m
3549
(import "" "thread.index" (func $thread-index (result i32)))
3550
(global $index (mut i32) (i32.const 0))
3551
(memory (export "memory") 1)
3552
(func (export "realloc") (param i32 i32 i32 i32) (result i32)
3553
(global.set $index (call $thread-index))
3554
(if (i32.eqz (global.get $index)) (then unreachable))
3555
(i32.const 100)
3556
)
3557
(func (export "run") (param i32 i32)
3558
(local $index i32)
3559
(local.set $index (call $thread-index))
3560
(if (i32.eqz (local.get $index)) (then unreachable))
3561
(if (i32.ne (local.get $index) (global.get $index)) (then unreachable))
3562
)
3563
)
3564
(core func $thread-index (canon thread.index))
3565
(core instance $m (instantiate $m (with "" (instance
3566
(export "thread.index" (func $thread-index))
3567
))))
3568
(func (export "run") (param "s" string) (canon lift
3569
(core func $m "run")
3570
(memory $m "memory")
3571
(realloc (func $m "realloc"))
3572
))
3573
)
3574
"#;
3575
let engine = Engine::new(&style.config())?;
3576
let component = Component::new(&engine, component)?;
3577
let mut store = Store::new(&engine, ());
3578
let linker = Linker::new(&engine);
3579
let instance = style.instantiate(&mut store, &linker, &component).await?;
3580
let run = instance.get_typed_func::<(String,), ()>(&mut store, "run")?;
3581
style.call(&mut store, run, ("hola".to_string(),)).await?;
3582
Ok(())
3583
}
3584
3585
#[tokio::test]
3586
async fn thread_index_via_resource_drop_sync() -> Result<()> {
3587
thread_index_via_resource_drop(ApiStyle::Sync).await
3588
}
3589
3590
#[tokio::test]
3591
async fn thread_index_via_resource_drop_async() -> Result<()> {
3592
thread_index_via_resource_drop(ApiStyle::Async).await
3593
}
3594
3595
#[tokio::test]
3596
async fn thread_index_via_resource_drop_concurrent() -> Result<()> {
3597
thread_index_via_resource_drop(ApiStyle::Concurrent).await
3598
}
3599
3600
async fn thread_index_via_resource_drop(style: ApiStyle) -> Result<()> {
3601
let component = r#"
3602
(component
3603
(core module $m
3604
(import "" "thread.index" (func $thread-index (result i32)))
3605
(func (export "dtor") (param i32)
3606
(if (i32.eqz (call $thread-index)) (then unreachable))
3607
)
3608
)
3609
(core func $thread-index (canon thread.index))
3610
(core instance $m (instantiate $m (with "" (instance
3611
(export "thread.index" (func $thread-index))
3612
))))
3613
(type $r (resource (rep i32) (dtor (func $m "dtor"))))
3614
(core func $new (canon resource.new $r))
3615
(core module $m2
3616
(import "" "new" (func $new (param i32) (result i32)))
3617
(func (export "new") (result i32)
3618
(call $new (i32.const 100))
3619
)
3620
)
3621
(core instance $m2 (instantiate $m2 (with "" (instance
3622
(export "new" (func $new))
3623
))))
3624
(func $new (result (own $r)) (canon lift (core func $m2 "new")))
3625
(component $c
3626
(import "r" (type $r (sub resource)))
3627
(import "new" (func $new (result (own $r))))
3628
(export $r-export "r" (type $r))
3629
(export "new" (func $new) (func (result (own $r-export))))
3630
)
3631
(instance $c (instantiate $c
3632
(with "r" (type $r))
3633
(with "new" (func $new))
3634
))
3635
(export "i" (instance $c))
3636
)
3637
"#;
3638
let engine = Engine::new(&style.config())?;
3639
let component = Component::new(&engine, component)?;
3640
let mut store = Store::new(&engine, ());
3641
let linker = Linker::new(&engine);
3642
let instance = style.instantiate(&mut store, &linker, &component).await?;
3643
let instance_index = instance.get_export_index(&mut store, None, "i").unwrap();
3644
let func_index = instance
3645
.get_export_index(&mut store, Some(&instance_index), "new")
3646
.unwrap();
3647
let run = instance.get_typed_func::<(), (ResourceAny,)>(&mut store, &func_index)?;
3648
let (resource,) = style.call(&mut store, run, ()).await?;
3649
style.resource_drop(&mut store, resource).await?;
3650
Ok(())
3651
}
3652
3653
#[tokio::test]
3654
async fn thread_index_via_guest_call_sync() -> Result<()> {
3655
thread_index_via_guest_call(ApiStyle::Sync).await
3656
}
3657
3658
#[tokio::test]
3659
async fn thread_index_via_guest_call_async() -> Result<()> {
3660
thread_index_via_guest_call(ApiStyle::Async).await
3661
}
3662
3663
#[tokio::test]
3664
async fn thread_index_via_guest_call_concurrent() -> Result<()> {
3665
thread_index_via_guest_call(ApiStyle::Concurrent).await
3666
}
3667
3668
async fn thread_index_via_guest_call(style: ApiStyle) -> Result<()> {
3669
let component = r#"
3670
(component
3671
(component $c
3672
(core module $m
3673
(import "" "thread.index" (func $thread-index (result i32)))
3674
(func (export "run") (result i32)
3675
(call $thread-index)
3676
)
3677
)
3678
(core func $thread-index (canon thread.index))
3679
(core instance $m (instantiate $m (with "" (instance
3680
(export "thread.index" (func $thread-index))
3681
))))
3682
(func (export "run") (result u32) (canon lift (core func $m "run")))
3683
)
3684
(instance $c (instantiate $c))
3685
3686
(component $d
3687
(import "c" (instance $c
3688
(export "run" (func (result u32)))
3689
))
3690
(core func $run (canon lower (func $c "run")))
3691
(core module $m
3692
(import "" "thread.index" (func $thread-index (result i32)))
3693
(import "" "run" (func $run (result i32)))
3694
(func (export "run")
3695
(local $mine i32)
3696
(local $theirs i32)
3697
(local.set $mine (call $thread-index))
3698
(if (i32.eqz (local.get $mine)) (then unreachable))
3699
(local.set $theirs (call $run))
3700
(if (i32.eqz (local.get $theirs)) (then unreachable))
3701
)
3702
)
3703
(core func $thread-index (canon thread.index))
3704
(core instance $m (instantiate $m (with "" (instance
3705
(export "thread.index" (func $thread-index))
3706
(export "run" (func $run))
3707
))))
3708
(func (export "run") (canon lift (core func $m "run")))
3709
)
3710
(instance $d (instantiate $d (with "c" (instance $c))))
3711
(func (export "run") (alias export $d "run"))
3712
)
3713
"#;
3714
let engine = Engine::new(&style.config())?;
3715
let component = Component::new(&engine, component)?;
3716
let mut store = Store::new(&engine, ());
3717
let linker = Linker::new(&engine);
3718
let instance = style.instantiate(&mut store, &linker, &component).await?;
3719
let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;
3720
style.call(&mut store, run, ()).await?;
3721
Ok(())
3722
}
3723
3724
fn with_new_instance<T>(
3725
engine: &Engine,
3726
component: &Component,
3727
fun: impl Fn(&mut Store<()>, Instance) -> wasmtime::Result<T>,
3728
) -> wasmtime::Result<T> {
3729
let mut store = Store::new(engine, ());
3730
let instance = Linker::new(engine).instantiate(&mut store, component)?;
3731
fun(&mut store, instance)
3732
}
3733
3734