1 #![cfg(not(miri))]
2 
3 use super::{REALLOC_AND_FREE, TypedFuncExt};
4 use anyhow::Result;
5 use std::sync::Arc;
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_and_post_return(&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 new_instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component);
187     let instance = new_instance(&mut store)?;
188 
189     // Passing in 100 is valid for all primitives
190     instance
191         .get_typed_func::<(u8,), ()>(&mut store, "take-u8")?
192         .call_and_post_return(&mut store, (100,))?;
193     instance
194         .get_typed_func::<(i8,), ()>(&mut store, "take-s8")?
195         .call_and_post_return(&mut store, (100,))?;
196     instance
197         .get_typed_func::<(u16,), ()>(&mut store, "take-u16")?
198         .call_and_post_return(&mut store, (100,))?;
199     instance
200         .get_typed_func::<(i16,), ()>(&mut store, "take-s16")?
201         .call_and_post_return(&mut store, (100,))?;
202     instance
203         .get_typed_func::<(u32,), ()>(&mut store, "take-u32")?
204         .call_and_post_return(&mut store, (100,))?;
205     instance
206         .get_typed_func::<(i32,), ()>(&mut store, "take-s32")?
207         .call_and_post_return(&mut store, (100,))?;
208     instance
209         .get_typed_func::<(u64,), ()>(&mut store, "take-u64")?
210         .call_and_post_return(&mut store, (100,))?;
211     instance
212         .get_typed_func::<(i64,), ()>(&mut store, "take-s64")?
213         .call_and_post_return(&mut store, (100,))?;
214 
215     // This specific wasm instance traps if any value other than 100 is passed
216     new_instance(&mut store)?
217         .get_typed_func::<(u8,), ()>(&mut store, "take-u8")?
218         .call(&mut store, (101,))
219         .unwrap_err()
220         .downcast::<Trap>()?;
221     new_instance(&mut store)?
222         .get_typed_func::<(i8,), ()>(&mut store, "take-s8")?
223         .call(&mut store, (101,))
224         .unwrap_err()
225         .downcast::<Trap>()?;
226     new_instance(&mut store)?
227         .get_typed_func::<(u16,), ()>(&mut store, "take-u16")?
228         .call(&mut store, (101,))
229         .unwrap_err()
230         .downcast::<Trap>()?;
231     new_instance(&mut store)?
232         .get_typed_func::<(i16,), ()>(&mut store, "take-s16")?
233         .call(&mut store, (101,))
234         .unwrap_err()
235         .downcast::<Trap>()?;
236     new_instance(&mut store)?
237         .get_typed_func::<(u32,), ()>(&mut store, "take-u32")?
238         .call(&mut store, (101,))
239         .unwrap_err()
240         .downcast::<Trap>()?;
241     new_instance(&mut store)?
242         .get_typed_func::<(i32,), ()>(&mut store, "take-s32")?
243         .call(&mut store, (101,))
244         .unwrap_err()
245         .downcast::<Trap>()?;
246     new_instance(&mut store)?
247         .get_typed_func::<(u64,), ()>(&mut store, "take-u64")?
248         .call(&mut store, (101,))
249         .unwrap_err()
250         .downcast::<Trap>()?;
251     new_instance(&mut store)?
252         .get_typed_func::<(i64,), ()>(&mut store, "take-s64")?
253         .call(&mut store, (101,))
254         .unwrap_err()
255         .downcast::<Trap>()?;
256 
257     // Zero can be returned as any integer
258     assert_eq!(
259         instance
260             .get_typed_func::<(), (u8,)>(&mut store, "ret-u8")?
261             .call_and_post_return(&mut store, ())?,
262         (0,)
263     );
264     assert_eq!(
265         instance
266             .get_typed_func::<(), (i8,)>(&mut store, "ret-s8")?
267             .call_and_post_return(&mut store, ())?,
268         (0,)
269     );
270     assert_eq!(
271         instance
272             .get_typed_func::<(), (u16,)>(&mut store, "ret-u16")?
273             .call_and_post_return(&mut store, ())?,
274         (0,)
275     );
276     assert_eq!(
277         instance
278             .get_typed_func::<(), (i16,)>(&mut store, "ret-s16")?
279             .call_and_post_return(&mut store, ())?,
280         (0,)
281     );
282     assert_eq!(
283         instance
284             .get_typed_func::<(), (u32,)>(&mut store, "ret-u32")?
285             .call_and_post_return(&mut store, ())?,
286         (0,)
287     );
288     assert_eq!(
289         instance
290             .get_typed_func::<(), (i32,)>(&mut store, "ret-s32")?
291             .call_and_post_return(&mut store, ())?,
292         (0,)
293     );
294     assert_eq!(
295         instance
296             .get_typed_func::<(), (u64,)>(&mut store, "ret-u64")?
297             .call_and_post_return(&mut store, ())?,
298         (0,)
299     );
300     assert_eq!(
301         instance
302             .get_typed_func::<(), (i64,)>(&mut store, "ret-s64")?
303             .call_and_post_return(&mut store, ())?,
304         (0,)
305     );
306 
307     // Returning -1 should reinterpret the bytes as defined by each type.
308     assert_eq!(
309         instance
310             .get_typed_func::<(), (u8,)>(&mut store, "retm1-u8")?
311             .call_and_post_return(&mut store, ())?,
312         (0xff,)
313     );
314     assert_eq!(
315         instance
316             .get_typed_func::<(), (i8,)>(&mut store, "retm1-s8")?
317             .call_and_post_return(&mut store, ())?,
318         (-1,)
319     );
320     assert_eq!(
321         instance
322             .get_typed_func::<(), (u16,)>(&mut store, "retm1-u16")?
323             .call_and_post_return(&mut store, ())?,
324         (0xffff,)
325     );
326     assert_eq!(
327         instance
328             .get_typed_func::<(), (i16,)>(&mut store, "retm1-s16")?
329             .call_and_post_return(&mut store, ())?,
330         (-1,)
331     );
332     assert_eq!(
333         instance
334             .get_typed_func::<(), (u32,)>(&mut store, "retm1-u32")?
335             .call_and_post_return(&mut store, ())?,
336         (0xffffffff,)
337     );
338     assert_eq!(
339         instance
340             .get_typed_func::<(), (i32,)>(&mut store, "retm1-s32")?
341             .call_and_post_return(&mut store, ())?,
342         (-1,)
343     );
344     assert_eq!(
345         instance
346             .get_typed_func::<(), (u64,)>(&mut store, "retm1-u64")?
347             .call_and_post_return(&mut store, ())?,
348         (0xffffffff_ffffffff,)
349     );
350     assert_eq!(
351         instance
352             .get_typed_func::<(), (i64,)>(&mut store, "retm1-s64")?
353             .call_and_post_return(&mut store, ())?,
354         (-1,)
355     );
356 
357     // Returning 100000 should chop off bytes as necessary
358     let ret: u32 = 100000;
359     assert_eq!(
360         instance
361             .get_typed_func::<(), (u8,)>(&mut store, "retbig-u8")?
362             .call_and_post_return(&mut store, ())?,
363         (ret as u8,),
364     );
365     assert_eq!(
366         instance
367             .get_typed_func::<(), (i8,)>(&mut store, "retbig-s8")?
368             .call_and_post_return(&mut store, ())?,
369         (ret as i8,),
370     );
371     assert_eq!(
372         instance
373             .get_typed_func::<(), (u16,)>(&mut store, "retbig-u16")?
374             .call_and_post_return(&mut store, ())?,
375         (ret as u16,),
376     );
377     assert_eq!(
378         instance
379             .get_typed_func::<(), (i16,)>(&mut store, "retbig-s16")?
380             .call_and_post_return(&mut store, ())?,
381         (ret as i16,),
382     );
383     assert_eq!(
384         instance
385             .get_typed_func::<(), (u32,)>(&mut store, "retbig-u32")?
386             .call_and_post_return(&mut store, ())?,
387         (ret,),
388     );
389     assert_eq!(
390         instance
391             .get_typed_func::<(), (i32,)>(&mut store, "retbig-s32")?
392             .call_and_post_return(&mut store, ())?,
393         (ret as i32,),
394     );
395 
396     Ok(())
397 }
398 
399 #[test]
400 fn type_layers() -> Result<()> {
401     let component = r#"
402         (component
403             (core module $m
404                 (func (export "take-i32-100") (param i32)
405                     local.get 0
406                     i32.const 2
407                     i32.eq
408                     br_if 0
409                     unreachable
410                 )
411             )
412             (core instance $i (instantiate $m))
413             (func (export "take-u32") (param "a" u32) (canon lift (core func $i "take-i32-100")))
414         )
415     "#;
416 
417     let engine = super::engine();
418     let component = Component::new(&engine, component)?;
419     let mut store = Store::new(&engine, ());
420     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
421 
422     instance
423         .get_typed_func::<(Box<u32>,), ()>(&mut store, "take-u32")?
424         .call_and_post_return(&mut store, (Box::new(2),))?;
425     instance
426         .get_typed_func::<(&u32,), ()>(&mut store, "take-u32")?
427         .call_and_post_return(&mut store, (&2,))?;
428     instance
429         .get_typed_func::<(Arc<u32>,), ()>(&mut store, "take-u32")?
430         .call_and_post_return(&mut store, (Arc::new(2),))?;
431     instance
432         .get_typed_func::<(&Box<Arc<Box<u32>>>,), ()>(&mut store, "take-u32")?
433         .call_and_post_return(&mut store, (&Box::new(Arc::new(Box::new(2))),))?;
434 
435     Ok(())
436 }
437 
438 #[test]
439 fn floats() -> Result<()> {
440     let component = r#"
441         (component
442             (core module $m
443                 (func (export "i32.reinterpret_f32") (param f32) (result i32)
444                     local.get 0
445                     i32.reinterpret_f32
446                 )
447                 (func (export "i64.reinterpret_f64") (param f64) (result i64)
448                     local.get 0
449                     i64.reinterpret_f64
450                 )
451                 (func (export "f32.reinterpret_i32") (param i32) (result f32)
452                     local.get 0
453                     f32.reinterpret_i32
454                 )
455                 (func (export "f64.reinterpret_i64") (param i64) (result f64)
456                     local.get 0
457                     f64.reinterpret_i64
458                 )
459             )
460             (core instance $i (instantiate $m))
461 
462             (func (export "f32-to-u32") (param "a" float32) (result u32)
463                 (canon lift (core func $i "i32.reinterpret_f32"))
464             )
465             (func (export "f64-to-u64") (param "a" float64) (result u64)
466                 (canon lift (core func $i "i64.reinterpret_f64"))
467             )
468             (func (export "u32-to-f32") (param "a" u32) (result float32)
469                 (canon lift (core func $i "f32.reinterpret_i32"))
470             )
471             (func (export "u64-to-f64") (param "a" u64) (result float64)
472                 (canon lift (core func $i "f64.reinterpret_i64"))
473             )
474         )
475     "#;
476 
477     let engine = super::engine();
478     let component = Component::new(&engine, component)?;
479     let mut store = Store::new(&engine, ());
480     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
481     let f32_to_u32 = instance.get_typed_func::<(f32,), (u32,)>(&mut store, "f32-to-u32")?;
482     let f64_to_u64 = instance.get_typed_func::<(f64,), (u64,)>(&mut store, "f64-to-u64")?;
483     let u32_to_f32 = instance.get_typed_func::<(u32,), (f32,)>(&mut store, "u32-to-f32")?;
484     let u64_to_f64 = instance.get_typed_func::<(u64,), (f64,)>(&mut store, "u64-to-f64")?;
485 
486     assert_eq!(f32_to_u32.call(&mut store, (1.0,))?, (1.0f32.to_bits(),));
487     f32_to_u32.post_return(&mut store)?;
488     assert_eq!(f64_to_u64.call(&mut store, (2.0,))?, (2.0f64.to_bits(),));
489     f64_to_u64.post_return(&mut store)?;
490     assert_eq!(u32_to_f32.call(&mut store, (3.0f32.to_bits(),))?, (3.0,));
491     u32_to_f32.post_return(&mut store)?;
492     assert_eq!(u64_to_f64.call(&mut store, (4.0f64.to_bits(),))?, (4.0,));
493     u64_to_f64.post_return(&mut store)?;
494 
495     assert_eq!(
496         u32_to_f32
497             .call(&mut store, (CANON_32BIT_NAN | 1,))?
498             .0
499             .to_bits(),
500         CANON_32BIT_NAN | 1
501     );
502     u32_to_f32.post_return(&mut store)?;
503     assert_eq!(
504         u64_to_f64
505             .call(&mut store, (CANON_64BIT_NAN | 1,))?
506             .0
507             .to_bits(),
508         CANON_64BIT_NAN | 1,
509     );
510     u64_to_f64.post_return(&mut store)?;
511 
512     assert_eq!(
513         f32_to_u32.call(&mut store, (f32::from_bits(CANON_32BIT_NAN | 1),))?,
514         (CANON_32BIT_NAN | 1,)
515     );
516     f32_to_u32.post_return(&mut store)?;
517     assert_eq!(
518         f64_to_u64.call(&mut store, (f64::from_bits(CANON_64BIT_NAN | 1),))?,
519         (CANON_64BIT_NAN | 1,)
520     );
521     f64_to_u64.post_return(&mut store)?;
522 
523     Ok(())
524 }
525 
526 #[test]
527 fn bools() -> Result<()> {
528     let component = r#"
529         (component
530             (core module $m
531                 (func (export "pass") (param i32) (result i32) local.get 0)
532             )
533             (core instance $i (instantiate $m))
534 
535             (func (export "u32-to-bool") (param "a" u32) (result bool)
536                 (canon lift (core func $i "pass"))
537             )
538             (func (export "bool-to-u32") (param "a" bool) (result u32)
539                 (canon lift (core func $i "pass"))
540             )
541         )
542     "#;
543 
544     let engine = super::engine();
545     let component = Component::new(&engine, component)?;
546     let mut store = Store::new(&engine, ());
547     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
548     let u32_to_bool = instance.get_typed_func::<(u32,), (bool,)>(&mut store, "u32-to-bool")?;
549     let bool_to_u32 = instance.get_typed_func::<(bool,), (u32,)>(&mut store, "bool-to-u32")?;
550 
551     assert_eq!(bool_to_u32.call(&mut store, (false,))?, (0,));
552     bool_to_u32.post_return(&mut store)?;
553     assert_eq!(bool_to_u32.call(&mut store, (true,))?, (1,));
554     bool_to_u32.post_return(&mut store)?;
555     assert_eq!(u32_to_bool.call(&mut store, (0,))?, (false,));
556     u32_to_bool.post_return(&mut store)?;
557     assert_eq!(u32_to_bool.call(&mut store, (1,))?, (true,));
558     u32_to_bool.post_return(&mut store)?;
559     assert_eq!(u32_to_bool.call(&mut store, (2,))?, (true,));
560     u32_to_bool.post_return(&mut store)?;
561 
562     Ok(())
563 }
564 
565 #[test]
566 fn chars() -> Result<()> {
567     let component = r#"
568         (component
569             (core module $m
570                 (func (export "pass") (param i32) (result i32) local.get 0)
571             )
572             (core instance $i (instantiate $m))
573 
574             (func (export "u32-to-char") (param "a" u32) (result char)
575                 (canon lift (core func $i "pass"))
576             )
577             (func (export "char-to-u32") (param "a" char) (result u32)
578                 (canon lift (core func $i "pass"))
579             )
580         )
581     "#;
582 
583     let engine = super::engine();
584     let component = Component::new(&engine, component)?;
585     let mut store = Store::new(&engine, ());
586     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
587     let u32_to_char = instance.get_typed_func::<(u32,), (char,)>(&mut store, "u32-to-char")?;
588     let char_to_u32 = instance.get_typed_func::<(char,), (u32,)>(&mut store, "char-to-u32")?;
589 
590     let mut roundtrip = |x: char| -> Result<()> {
591         assert_eq!(char_to_u32.call(&mut store, (x,))?, (x as u32,));
592         char_to_u32.post_return(&mut store)?;
593         assert_eq!(u32_to_char.call(&mut store, (x as u32,))?, (x,));
594         u32_to_char.post_return(&mut store)?;
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_and_post_return(&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         list8_to_str.post_return(&mut store)?;
762 
763         let utf16 = x.encode_utf16().collect::<Vec<_>>();
764         let ret = list16_to_str.call(&mut store, (&utf16[..],))?.0;
765         assert_eq!(ret.to_str(&store)?, x);
766         list16_to_str.post_return(&mut store)?;
767 
768         let ret = str_to_list8.call(&mut store, (x,))?.0;
769         assert_eq!(
770             ret.iter(&mut store).collect::<Result<Vec<_>>>()?,
771             x.as_bytes()
772         );
773         str_to_list8.post_return(&mut store)?;
774 
775         let ret = str_to_list16.call(&mut store, (x,))?.0;
776         assert_eq!(ret.iter(&mut store).collect::<Result<Vec<_>>>()?, utf16,);
777         str_to_list16.post_return(&mut store)?;
778 
779         Ok(())
780     };
781 
782     roundtrip("")?;
783     roundtrip("foo")?;
784     roundtrip("hello there")?;
785     roundtrip("��")?;
786     roundtrip("Löwe 老虎 Léopard")?;
787 
788     let ret = list8_to_str.call(&mut store, (b"\xff",))?.0;
789     let err = ret.to_str(&store).unwrap_err();
790     assert!(err.to_string().contains("invalid utf-8"), "{}", err);
791     list8_to_str.post_return(&mut store)?;
792 
793     let ret = list8_to_str
794         .call(&mut store, (b"hello there \xff invalid",))?
795         .0;
796     let err = ret.to_str(&store).unwrap_err();
797     assert!(err.to_string().contains("invalid utf-8"), "{}", err);
798     list8_to_str.post_return(&mut store)?;
799 
800     let ret = list16_to_str.call(&mut store, (&[0xd800],))?.0;
801     let err = ret.to_str(&store).unwrap_err();
802     assert!(err.to_string().contains("unpaired surrogate"), "{}", err);
803     list16_to_str.post_return(&mut store)?;
804 
805     let ret = list16_to_str.call(&mut store, (&[0xdfff],))?.0;
806     let err = ret.to_str(&store).unwrap_err();
807     assert!(err.to_string().contains("unpaired surrogate"), "{}", err);
808     list16_to_str.post_return(&mut store)?;
809 
810     let ret = list16_to_str.call(&mut store, (&[0xd800, 0xff00],))?.0;
811     let err = ret.to_str(&store).unwrap_err();
812     assert!(err.to_string().contains("unpaired surrogate"), "{}", err);
813     list16_to_str.post_return(&mut store)?;
814 
815     Ok(())
816 }
817 
818 #[tokio::test]
819 async fn async_reentrance() -> Result<()> {
820     _ = env_logger::try_init();
821 
822     let component = r#"
823         (component
824             (core module $shim
825                 (import "" "task.return" (func $task-return (param i32)))
826                 (table (export "funcs") 1 1 funcref)
827                 (func (export "export") (param i32) (result i32)
828                     (call_indirect (i32.const 0) (local.get 0))
829                 )
830                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
831             )
832             (core func $task-return (canon task.return (result u32)))
833             (core instance $shim (instantiate $shim
834                 (with "" (instance (export "task.return" (func $task-return))))
835             ))
836             (func $shim-export (param "p1" u32) (result u32)
837                 (canon lift (core func $shim "export") async (callback (func $shim "callback")))
838             )
839 
840             (component $inner
841                 (import "import" (func $import (param "p1" u32) (result u32)))
842                 (core module $libc (memory (export "memory") 1))
843                 (core instance $libc (instantiate $libc))
844                 (core func $import (canon lower (func $import) async (memory $libc "memory")))
845 
846                 (core module $m
847                     (import "libc" "memory" (memory 1))
848                     (import "" "import" (func $import (param i32 i32) (result i32)))
849                     (import "" "task.return" (func $task-return (param i32)))
850                     (func (export "export") (param i32) (result i32)
851                         (i32.store offset=0 (i32.const 1200) (local.get 0))
852                         (call $import (i32.const 1200) (i32.const 1204))
853                         drop
854                         (call $task-return (i32.load offset=0 (i32.const 1204)))
855                         i32.const 0
856                     )
857                     (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
858                 )
859                 (core type $task-return-type (func (param i32)))
860                 (core func $task-return (canon task.return (result u32)))
861                 (core instance $i (instantiate $m
862                     (with "" (instance
863                         (export "task.return" (func $task-return))
864                         (export "import" (func $import))
865                     ))
866                     (with "libc" (instance $libc))
867                 ))
868                 (func (export "export") (param "p1" u32) (result u32)
869                     (canon lift (core func $i "export") async (callback (func $i "callback")))
870                 )
871             )
872             (instance $inner (instantiate $inner (with "import" (func $shim-export))))
873 
874             (core module $libc (memory (export "memory") 1))
875             (core instance $libc (instantiate $libc))
876             (core func $inner-export (canon lower (func $inner "export") async (memory $libc "memory")))
877 
878             (core module $donut
879                 (import "" "funcs" (table 1 1 funcref))
880                 (import "libc" "memory" (memory 1))
881                 (import "" "import" (func $import (param i32 i32) (result i32)))
882                 (import "" "task.return" (func $task-return (param i32)))
883                 (func $host-export (export "export") (param i32) (result i32)
884                     (i32.store offset=0 (i32.const 1200) (local.get 0))
885                     (call $import (i32.const 1200) (i32.const 1204))
886                     drop
887                     (call $task-return (i32.load offset=0 (i32.const 1204)))
888                     i32.const 0
889                 )
890                 (func $guest-export (export "guest-export") (param i32) (result i32) unreachable)
891                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
892                 (func $start
893                     (table.set (i32.const 0) (ref.func $guest-export))
894                 )
895                 (start $start)
896             )
897 
898             (core instance $donut (instantiate $donut
899                 (with "" (instance
900                     (export "task.return" (func $task-return))
901                     (export "import" (func $inner-export))
902                     (export "funcs" (table $shim "funcs"))
903                 ))
904                 (with "libc" (instance $libc))
905             ))
906             (func (export "export") (param "p1" u32) (result u32)
907                 (canon lift (core func $donut "export") async (callback (func $donut "callback")))
908             )
909         )"#;
910 
911     let mut config = Config::new();
912     config.wasm_component_model_async(true);
913     config.async_support(true);
914     let engine = &Engine::new(&config)?;
915     let component = Component::new(&engine, component)?;
916     let mut store = Store::new(&engine, ());
917 
918     let instance = Linker::new(&engine)
919         .instantiate_async(&mut store, &component)
920         .await?;
921     let func = instance.get_typed_func::<(u32,), (u32,)>(&mut store, "export")?;
922     let message = "cannot enter component instance";
923     match instance
924         .run_concurrent(&mut store, async move |accessor| {
925             anyhow::Ok(func.call_concurrent(accessor, (42,)).await?.0)
926         })
927         .await
928     {
929         Ok(_) => panic!(),
930         Err(e) => assert!(
931             format!("{e:?}").contains(message),
932             "expected `{message}`; got `{e:?}`"
933         ),
934     }
935 
936     Ok(())
937 }
938 
939 #[tokio::test]
940 async fn missing_task_return_call_stackless() -> Result<()> {
941     task_return_trap(
942         r#"(component
943             (core module $m
944                 (import "" "task.return" (func $task-return))
945                 (func (export "foo") (result i32)
946                     i32.const 0
947                 )
948                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
949             )
950             (core func $task-return (canon task.return))
951             (core instance $i (instantiate $m
952                 (with "" (instance (export "task.return" (func $task-return))))
953             ))
954             (func (export "foo") (canon lift (core func $i "foo") async (callback (func $i "callback"))))
955         )"#,
956         "wasm trap: async-lifted export failed to produce a result",
957     )
958     .await
959 }
960 
961 #[tokio::test]
962 async fn missing_task_return_call_stackful() -> Result<()> {
963     task_return_trap(
964         r#"(component
965             (core module $m
966                 (import "" "task.return" (func $task-return))
967                 (func (export "foo"))
968             )
969             (core func $task-return (canon task.return))
970             (core instance $i (instantiate $m
971                 (with "" (instance (export "task.return" (func $task-return))))
972             ))
973             (func (export "foo") (canon lift (core func $i "foo") async))
974         )"#,
975         "wasm trap: async-lifted export failed to produce a result",
976     )
977     .await
978 }
979 
980 #[tokio::test]
981 async fn task_return_type_mismatch() -> Result<()> {
982     task_return_trap(
983         r#"(component
984             (core module $m
985                 (import "" "task.return" (func $task-return (param i32)))
986                 (func (export "foo") (call $task-return (i32.const 42)))
987             )
988             (core func $task-return (canon task.return (result u32)))
989             (core instance $i (instantiate $m
990                 (with "" (instance (export "task.return" (func $task-return))))
991             ))
992             (func (export "foo") (canon lift (core func $i "foo") async))
993         )"#,
994         "invalid `task.return` signature and/or options for current task",
995     )
996     .await
997 }
998 
999 #[tokio::test]
1000 async fn task_return_memory_mismatch() -> Result<()> {
1001     task_return_trap(
1002         r#"(component
1003             (core module $libc (memory (export "memory") 1))
1004             (core instance $libc (instantiate $libc))
1005             (core module $m
1006                 (import "" "task.return" (func $task-return))
1007                 (func (export "foo") (call $task-return))
1008             )
1009             (core func $task-return (canon task.return (memory $libc "memory")))
1010             (core instance $i (instantiate $m
1011                 (with "" (instance (export "task.return" (func $task-return))))
1012             ))
1013             (func (export "foo") (canon lift (core func $i "foo") async))
1014         )"#,
1015         "invalid `task.return` signature and/or options for current task",
1016     )
1017     .await
1018 }
1019 
1020 #[tokio::test]
1021 async fn task_return_string_encoding_mismatch() -> Result<()> {
1022     task_return_trap(
1023         r#"(component
1024             (core module $m
1025                 (import "" "task.return" (func $task-return))
1026                 (func (export "foo") (call $task-return))
1027             )
1028             (core func $task-return (canon task.return string-encoding=utf16))
1029             (core instance $i (instantiate $m
1030                 (with "" (instance (export "task.return" (func $task-return))))
1031             ))
1032             (func (export "foo") (canon lift (core func $i "foo") async))
1033         )"#,
1034         "invalid `task.return` signature and/or options for current task",
1035     )
1036     .await
1037 }
1038 
1039 async fn task_return_trap(component: &str, substring: &str) -> Result<()> {
1040     let mut config = Config::new();
1041     config.wasm_component_model_async(true);
1042     config.wasm_component_model_async_stackful(true);
1043     config.async_support(true);
1044     let engine = &Engine::new(&config)?;
1045     let component = Component::new(&engine, component)?;
1046     let mut store = Store::new(&engine, ());
1047 
1048     let instance = Linker::new(&engine)
1049         .instantiate_async(&mut store, &component)
1050         .await?;
1051 
1052     let func = instance.get_typed_func::<(), ()>(&mut store, "foo")?;
1053     match instance
1054         .run_concurrent(&mut store, async move |accessor| {
1055             anyhow::Ok(func.call_concurrent(accessor, ()).await?.0)
1056         })
1057         .await
1058     {
1059         Ok(_) => panic!(),
1060         Err(e) => {
1061             assert!(
1062                 format!("{e:?}").contains(substring),
1063                 "could not find `{substring}` in `{e:?}`"
1064             )
1065         }
1066     }
1067 
1068     Ok(())
1069 }
1070 
1071 #[tokio::test]
1072 async fn many_parameters() -> Result<()> {
1073     test_many_parameters(false, false).await
1074 }
1075 
1076 #[tokio::test]
1077 async fn many_parameters_concurrent() -> Result<()> {
1078     test_many_parameters(false, true).await
1079 }
1080 
1081 #[tokio::test]
1082 async fn many_parameters_dynamic() -> Result<()> {
1083     test_many_parameters(true, false).await
1084 }
1085 
1086 #[tokio::test]
1087 async fn many_parameters_dynamic_concurrent() -> Result<()> {
1088     test_many_parameters(true, true).await
1089 }
1090 
1091 async fn test_many_parameters(dynamic: bool, concurrent: bool) -> Result<()> {
1092     let (body, async_opts) = if concurrent {
1093         (
1094             r#"
1095                     (call $task-return
1096                         (i32.const 0)
1097                         (i32.mul
1098                             (memory.size)
1099                             (i32.const 65536)
1100                         )
1101                         (local.get 0)
1102                     )
1103 
1104                     (i32.const 0)
1105             "#,
1106             r#"async (callback (func $i "callback"))"#,
1107         )
1108     } else {
1109         (
1110             r#"
1111                     (local $base i32)
1112 
1113                     ;; Allocate space for the return
1114                     (local.set $base
1115                         (call $realloc
1116                             (i32.const 0)
1117                             (i32.const 0)
1118                             (i32.const 4)
1119                             (i32.const 12)))
1120 
1121                     ;; Store the pointer/length of the entire linear memory
1122                     ;; so we have access to everything.
1123                     (i32.store offset=0
1124                         (local.get $base)
1125                         (i32.const 0))
1126                     (i32.store offset=4
1127                         (local.get $base)
1128                         (i32.mul
1129                             (memory.size)
1130                             (i32.const 65536)))
1131 
1132                     ;; And also store our pointer parameter
1133                     (i32.store offset=8
1134                         (local.get $base)
1135                         (local.get 0))
1136 
1137                     (local.get $base)
1138             "#,
1139             "",
1140         )
1141     };
1142 
1143     let component = format!(
1144         r#"(component
1145             (core module $libc
1146                 (memory (export "memory") 1)
1147 
1148                 {REALLOC_AND_FREE}
1149             )
1150             (core instance $libc (instantiate $libc))
1151             (core module $m
1152                 (import "libc" "memory" (memory 1))
1153                 (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
1154                 (import "" "task.return" (func $task-return (param i32 i32 i32)))
1155                 (func (export "foo") (param i32) (result i32)
1156                     {body}
1157                 )
1158                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
1159             )
1160             (type $tuple (tuple (list u8) u32))
1161             (core func $task-return (canon task.return
1162                 (result $tuple)
1163                 (memory $libc "memory")
1164             ))
1165             (core instance $i (instantiate $m
1166                 (with "" (instance (export "task.return" (func $task-return))))
1167                 (with "libc" (instance $libc))
1168             ))
1169 
1170             (type $t (func
1171                 (param "p1" s8)              ;; offset  0, size 1
1172                 (param "p2" u64)             ;; offset  8, size 8
1173                 (param "p3" float32)         ;; offset 16, size 4
1174                 (param "p4" u8)              ;; offset 20, size 1
1175                 (param "p5" s16)             ;; offset 22, size 2
1176                 (param "p6" string)          ;; offset 24, size 8
1177                 (param "p7" (list u32))      ;; offset 32, size 8
1178                 (param "p8" bool)            ;; offset 40, size 1
1179                 (param "p9" bool)            ;; offset 41, size 1
1180                 (param "p0" char)            ;; offset 44, size 4
1181                 (param "pa" (list bool))     ;; offset 48, size 8
1182                 (param "pb" (list char))     ;; offset 56, size 8
1183                 (param "pc" (list string))   ;; offset 64, size 8
1184 
1185                 (result $tuple)
1186             ))
1187             (func (export "many-param") (type $t)
1188                 (canon lift
1189                     (core func $i "foo")
1190                     (memory $libc "memory")
1191                     (realloc (func $libc "realloc"))
1192                     {async_opts}
1193                 )
1194             )
1195         )"#
1196     );
1197 
1198     let mut config = Config::new();
1199     config.wasm_component_model_async(true);
1200     config.async_support(true);
1201     let engine = &Engine::new(&config)?;
1202     let component = Component::new(&engine, component)?;
1203     let mut store = Store::new(&engine, ());
1204 
1205     let instance = Linker::new(&engine)
1206         .instantiate_async(&mut store, &component)
1207         .await?;
1208 
1209     let input = (
1210         -100,
1211         u64::MAX / 2,
1212         f32::from_bits(CANON_32BIT_NAN | 1),
1213         38,
1214         18831,
1215         "this is the first string",
1216         [1, 2, 3, 4, 5, 6, 7, 8].as_slice(),
1217         true,
1218         false,
1219         '��',
1220         [false, true, false, true, true].as_slice(),
1221         ['��', '��', '��', '��', '��'].as_slice(),
1222         [
1223             "the quick",
1224             "brown fox",
1225             "was too lazy",
1226             "to jump over the dog",
1227             "what a demanding dog",
1228         ]
1229         .as_slice(),
1230     );
1231 
1232     let (memory, pointer) = if dynamic {
1233         let input = vec![
1234             Val::S8(input.0),
1235             Val::U64(input.1),
1236             Val::Float32(input.2),
1237             Val::U8(input.3),
1238             Val::S16(input.4),
1239             Val::String(input.5.into()),
1240             Val::List(input.6.iter().copied().map(Val::U32).collect()),
1241             Val::Bool(input.7),
1242             Val::Bool(input.8),
1243             Val::Char(input.9),
1244             Val::List(input.10.iter().copied().map(Val::Bool).collect()),
1245             Val::List(input.11.iter().copied().map(Val::Char).collect()),
1246             Val::List(input.12.iter().map(|&s| Val::String(s.into())).collect()),
1247         ];
1248         let func = instance.get_func(&mut store, "many-param").unwrap();
1249 
1250         let mut results = vec![Val::Bool(false)];
1251         if concurrent {
1252             instance
1253                 .run_concurrent(&mut store, async |store| {
1254                     func.call_concurrent(store, &input, &mut results).await?;
1255                     anyhow::Ok(())
1256                 })
1257                 .await??;
1258         } else {
1259             func.call_async(&mut store, &input, &mut results).await?;
1260         };
1261         let mut results = results.into_iter();
1262         let Some(Val::Tuple(results)) = results.next() else {
1263             panic!()
1264         };
1265         let mut results = results.into_iter();
1266         let Some(Val::List(memory)) = results.next() else {
1267             panic!()
1268         };
1269         let Some(Val::U32(pointer)) = results.next() else {
1270             panic!()
1271         };
1272         (
1273             memory
1274                 .into_iter()
1275                 .map(|v| if let Val::U8(v) = v { v } else { panic!() })
1276                 .collect(),
1277             pointer,
1278         )
1279     } else {
1280         let func = instance.get_typed_func::<(
1281             i8,
1282             u64,
1283             f32,
1284             u8,
1285             i16,
1286             &str,
1287             &[u32],
1288             bool,
1289             bool,
1290             char,
1291             &[bool],
1292             &[char],
1293             &[&str],
1294         ), ((Vec<u8>, u32),)>(&mut store, "many-param")?;
1295 
1296         if concurrent {
1297             instance
1298                 .run_concurrent(&mut store, async move |accessor| {
1299                     anyhow::Ok(func.call_concurrent(accessor, input).await?.0)
1300                 })
1301                 .await??
1302                 .0
1303         } else {
1304             func.call_async(&mut store, input).await?.0
1305         }
1306     };
1307     let memory = &memory[..];
1308 
1309     let mut actual = &memory[pointer as usize..][..72];
1310     assert_eq!(i8::from_le_bytes(*actual.take_n::<1>()), input.0);
1311     actual.skip::<7>();
1312     assert_eq!(u64::from_le_bytes(*actual.take_n::<8>()), input.1);
1313     assert_eq!(
1314         u32::from_le_bytes(*actual.take_n::<4>()),
1315         CANON_32BIT_NAN | 1
1316     );
1317     assert_eq!(u8::from_le_bytes(*actual.take_n::<1>()), input.3);
1318     actual.skip::<1>();
1319     assert_eq!(i16::from_le_bytes(*actual.take_n::<2>()), input.4);
1320     assert_eq!(actual.ptr_len(memory, 1), input.5.as_bytes());
1321     let mut mem = actual.ptr_len(memory, 4);
1322     for expected in input.6.iter() {
1323         assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected);
1324     }
1325     assert!(mem.is_empty());
1326     assert_eq!(actual.take_n::<1>(), &[input.7 as u8]);
1327     assert_eq!(actual.take_n::<1>(), &[input.8 as u8]);
1328     actual.skip::<2>();
1329     assert_eq!(u32::from_le_bytes(*actual.take_n::<4>()), input.9 as u32);
1330 
1331     // (list bool)
1332     mem = actual.ptr_len(memory, 1);
1333     for expected in input.10.iter() {
1334         assert_eq!(mem.take_n::<1>(), &[*expected as u8]);
1335     }
1336     assert!(mem.is_empty());
1337 
1338     // (list char)
1339     mem = actual.ptr_len(memory, 4);
1340     for expected in input.11.iter() {
1341         assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected as u32);
1342     }
1343     assert!(mem.is_empty());
1344 
1345     // (list string)
1346     mem = actual.ptr_len(memory, 8);
1347     for expected in input.12.iter() {
1348         let actual = mem.ptr_len(memory, 1);
1349         assert_eq!(actual, expected.as_bytes());
1350     }
1351     assert!(mem.is_empty());
1352     assert!(actual.is_empty());
1353 
1354     Ok(())
1355 }
1356 
1357 #[tokio::test]
1358 async fn many_results() -> Result<()> {
1359     test_many_results(false, false).await
1360 }
1361 
1362 #[tokio::test]
1363 async fn many_results_concurrent() -> Result<()> {
1364     test_many_results(false, true).await
1365 }
1366 
1367 #[tokio::test]
1368 async fn many_results_dynamic() -> Result<()> {
1369     test_many_results(true, false).await
1370 }
1371 
1372 #[tokio::test]
1373 async fn many_results_dynamic_concurrent() -> Result<()> {
1374     test_many_results(true, true).await
1375 }
1376 
1377 async fn test_many_results(dynamic: bool, concurrent: bool) -> Result<()> {
1378     let (ret, async_opts) = if concurrent {
1379         (
1380             r#"
1381                    call $task-return
1382                    i32.const 0
1383             "#,
1384             r#"async (callback (func $i "callback"))"#,
1385         )
1386     } else {
1387         ("", "")
1388     };
1389 
1390     let my_nan = CANON_32BIT_NAN | 1;
1391 
1392     let component = format!(
1393         r#"(component
1394             (core module $libc
1395                 (memory (export "memory") 1)
1396 
1397                 {REALLOC_AND_FREE}
1398             )
1399             (core instance $libc (instantiate $libc))
1400             (core module $m
1401                 (import "libc" "memory" (memory 1))
1402                 (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
1403                 (import "" "task.return" (func $task-return (param i32)))
1404                 (func (export "foo") (result i32)
1405                     (local $base i32)
1406                     (local $string i32)
1407                     (local $list i32)
1408 
1409                     (local.set $base
1410                         (call $realloc
1411                             (i32.const 0)
1412                             (i32.const 0)
1413                             (i32.const 8)
1414                             (i32.const 72)))
1415 
1416                     (i32.store8 offset=0
1417                         (local.get $base)
1418                         (i32.const -100))
1419 
1420                     (i64.store offset=8
1421                         (local.get $base)
1422                         (i64.const 9223372036854775807))
1423 
1424                     (f32.store offset=16
1425                         (local.get $base)
1426                         (f32.reinterpret_i32 (i32.const {my_nan})))
1427 
1428                     (i32.store8 offset=20
1429                         (local.get $base)
1430                         (i32.const 38))
1431 
1432                     (i32.store16 offset=22
1433                         (local.get $base)
1434                         (i32.const 18831))
1435 
1436                     (local.set $string
1437                         (call $realloc
1438                             (i32.const 0)
1439                             (i32.const 0)
1440                             (i32.const 1)
1441                             (i32.const 6)))
1442 
1443                     (i32.store8 offset=0
1444                         (local.get $string)
1445                         (i32.const 97)) ;; 'a'
1446                     (i32.store8 offset=1
1447                         (local.get $string)
1448                         (i32.const 98)) ;; 'b'
1449                     (i32.store8 offset=2
1450                         (local.get $string)
1451                         (i32.const 99)) ;; 'c'
1452                     (i32.store8 offset=3
1453                         (local.get $string)
1454                         (i32.const 100)) ;; 'd'
1455                     (i32.store8 offset=4
1456                         (local.get $string)
1457                         (i32.const 101)) ;; 'e'
1458                     (i32.store8 offset=5
1459                         (local.get $string)
1460                         (i32.const 102)) ;; 'f'
1461 
1462                     (i32.store offset=24
1463                         (local.get $base)
1464                         (local.get $string))
1465 
1466                     (i32.store offset=28
1467                         (local.get $base)
1468                         (i32.const 2))
1469 
1470                     (local.set $list
1471                         (call $realloc
1472                             (i32.const 0)
1473                             (i32.const 0)
1474                             (i32.const 4)
1475                             (i32.const 32)))
1476 
1477                     (i32.store offset=0
1478                         (local.get $list)
1479                         (i32.const 1))
1480                     (i32.store offset=4
1481                         (local.get $list)
1482                         (i32.const 2))
1483                     (i32.store offset=8
1484                         (local.get $list)
1485                         (i32.const 3))
1486                     (i32.store offset=12
1487                         (local.get $list)
1488                         (i32.const 4))
1489                     (i32.store offset=16
1490                         (local.get $list)
1491                         (i32.const 5))
1492                     (i32.store offset=20
1493                         (local.get $list)
1494                         (i32.const 6))
1495                     (i32.store offset=24
1496                         (local.get $list)
1497                         (i32.const 7))
1498                     (i32.store offset=28
1499                         (local.get $list)
1500                         (i32.const 8))
1501 
1502                     (i32.store offset=32
1503                         (local.get $base)
1504                         (local.get $list))
1505 
1506                     (i32.store offset=36
1507                         (local.get $base)
1508                         (i32.const 8))
1509 
1510                     (i32.store8 offset=40
1511                         (local.get $base)
1512                         (i32.const 1))
1513 
1514                     (i32.store8 offset=41
1515                         (local.get $base)
1516                         (i32.const 0))
1517 
1518                     (i32.store offset=44
1519                         (local.get $base)
1520                         (i32.const 128681)) ;; '��'
1521 
1522                     (local.set $list
1523                         (call $realloc
1524                             (i32.const 0)
1525                             (i32.const 0)
1526                             (i32.const 1)
1527                             (i32.const 5)))
1528 
1529                     (i32.store8 offset=0
1530                         (local.get $list)
1531                         (i32.const 0))
1532                     (i32.store8 offset=1
1533                         (local.get $list)
1534                         (i32.const 1))
1535                     (i32.store8 offset=2
1536                         (local.get $list)
1537                         (i32.const 0))
1538                     (i32.store8 offset=3
1539                         (local.get $list)
1540                         (i32.const 1))
1541                     (i32.store8 offset=4
1542                         (local.get $list)
1543                         (i32.const 1))
1544 
1545                     (i32.store offset=48
1546                         (local.get $base)
1547                         (local.get $list))
1548 
1549                     (i32.store offset=52
1550                         (local.get $base)
1551                         (i32.const 5))
1552 
1553                     (local.set $list
1554                         (call $realloc
1555                             (i32.const 0)
1556                             (i32.const 0)
1557                             (i32.const 4)
1558                             (i32.const 20)))
1559 
1560                     (i32.store offset=0
1561                         (local.get $list)
1562                         (i32.const 127820)) ;; '��'
1563                     (i32.store offset=4
1564                         (local.get $list)
1565                         (i32.const 129360)) ;; '��'
1566                     (i32.store offset=8
1567                         (local.get $list)
1568                         (i32.const 127831)) ;; '��'
1569                     (i32.store offset=12
1570                         (local.get $list)
1571                         (i32.const 127833)) ;; '��'
1572                     (i32.store offset=16
1573                         (local.get $list)
1574                         (i32.const 127841)) ;; '��'
1575 
1576                     (i32.store offset=56
1577                         (local.get $base)
1578                         (local.get $list))
1579 
1580                     (i32.store offset=60
1581                         (local.get $base)
1582                         (i32.const 5))
1583 
1584                     (local.set $list
1585                         (call $realloc
1586                             (i32.const 0)
1587                             (i32.const 0)
1588                             (i32.const 4)
1589                             (i32.const 16)))
1590 
1591                     (i32.store offset=0
1592                         (local.get $list)
1593                         (i32.add (local.get $string) (i32.const 2)))
1594                     (i32.store offset=4
1595                         (local.get $list)
1596                         (i32.const 2))
1597                     (i32.store offset=8
1598                         (local.get $list)
1599                         (i32.add (local.get $string) (i32.const 4)))
1600                     (i32.store offset=12
1601                         (local.get $list)
1602                         (i32.const 2))
1603 
1604                     (i32.store offset=64
1605                         (local.get $base)
1606                         (local.get $list))
1607 
1608                     (i32.store offset=68
1609                         (local.get $base)
1610                         (i32.const 2))
1611 
1612                     local.get $base
1613 
1614                     {ret}
1615                 )
1616                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
1617             )
1618             (type $tuple (tuple
1619                 s8
1620                 u64
1621                 float32
1622                 u8
1623                 s16
1624                 string
1625                 (list u32)
1626                 bool
1627                 bool
1628                 char
1629                 (list bool)
1630                 (list char)
1631                 (list string)
1632             ))
1633             (core func $task-return (canon task.return
1634                 (result $tuple)
1635                 (memory $libc "memory")
1636             ))
1637             (core instance $i (instantiate $m
1638                 (with "" (instance (export "task.return" (func $task-return))))
1639                 (with "libc" (instance $libc))
1640             ))
1641 
1642             (type $t (func (result $tuple)))
1643             (func (export "many-results") (type $t)
1644                 (canon lift
1645                     (core func $i "foo")
1646                     (memory $libc "memory")
1647                     (realloc (func $libc "realloc"))
1648                     {async_opts}
1649                 )
1650             )
1651         )"#
1652     );
1653 
1654     let mut config = Config::new();
1655     config.wasm_component_model_async(true);
1656     config.async_support(true);
1657     let engine = &Engine::new(&config)?;
1658     let component = Component::new(&engine, component)?;
1659     let mut store = Store::new(&engine, ());
1660 
1661     let instance = Linker::new(&engine)
1662         .instantiate_async(&mut store, &component)
1663         .await?;
1664 
1665     let expected = (
1666         -100i8,
1667         u64::MAX / 2,
1668         f32::from_bits(CANON_32BIT_NAN | 1),
1669         38u8,
1670         18831i16,
1671         "ab".to_string(),
1672         vec![1u32, 2, 3, 4, 5, 6, 7, 8],
1673         true,
1674         false,
1675         '��',
1676         vec![false, true, false, true, true],
1677         vec!['��', '��', '��', '��', '��'],
1678         vec!["cd".to_string(), "ef".to_string()],
1679     );
1680 
1681     let actual = if dynamic {
1682         let func = instance.get_func(&mut store, "many-results").unwrap();
1683 
1684         let mut results = vec![Val::Bool(false)];
1685         if concurrent {
1686             instance
1687                 .run_concurrent(&mut store, async |store| {
1688                     func.call_concurrent(store, &[], &mut results).await?;
1689                     anyhow::Ok(())
1690                 })
1691                 .await??;
1692         } else {
1693             func.call_async(&mut store, &[], &mut results).await?;
1694         };
1695         let mut results = results.into_iter();
1696 
1697         let Some(Val::Tuple(results)) = results.next() else {
1698             panic!()
1699         };
1700         let mut results = results.into_iter();
1701         let Some(Val::S8(p1)) = results.next() else {
1702             panic!()
1703         };
1704         let Some(Val::U64(p2)) = results.next() else {
1705             panic!()
1706         };
1707         let Some(Val::Float32(p3)) = results.next() else {
1708             panic!()
1709         };
1710         let Some(Val::U8(p4)) = results.next() else {
1711             panic!()
1712         };
1713         let Some(Val::S16(p5)) = results.next() else {
1714             panic!()
1715         };
1716         let Some(Val::String(p6)) = results.next() else {
1717             panic!()
1718         };
1719         let Some(Val::List(p7)) = results.next() else {
1720             panic!()
1721         };
1722         let p7 = p7
1723             .into_iter()
1724             .map(|v| if let Val::U32(v) = v { v } else { panic!() })
1725             .collect();
1726         let Some(Val::Bool(p8)) = results.next() else {
1727             panic!()
1728         };
1729         let Some(Val::Bool(p9)) = results.next() else {
1730             panic!()
1731         };
1732         let Some(Val::Char(p0)) = results.next() else {
1733             panic!()
1734         };
1735         let Some(Val::List(pa)) = results.next() else {
1736             panic!()
1737         };
1738         let pa = pa
1739             .into_iter()
1740             .map(|v| if let Val::Bool(v) = v { v } else { panic!() })
1741             .collect();
1742         let Some(Val::List(pb)) = results.next() else {
1743             panic!()
1744         };
1745         let pb = pb
1746             .into_iter()
1747             .map(|v| if let Val::Char(v) = v { v } else { panic!() })
1748             .collect();
1749         let Some(Val::List(pc)) = results.next() else {
1750             panic!()
1751         };
1752         let pc = pc
1753             .into_iter()
1754             .map(|v| if let Val::String(v) = v { v } else { panic!() })
1755             .collect();
1756 
1757         (p1, p2, p3, p4, p5, p6, p7, p8, p9, p0, pa, pb, pc)
1758     } else {
1759         let func = instance.get_typed_func::<(), ((
1760             i8,
1761             u64,
1762             f32,
1763             u8,
1764             i16,
1765             String,
1766             Vec<u32>,
1767             bool,
1768             bool,
1769             char,
1770             Vec<bool>,
1771             Vec<char>,
1772             Vec<String>,
1773         ),)>(&mut store, "many-results")?;
1774 
1775         if concurrent {
1776             instance
1777                 .run_concurrent(&mut store, async move |accessor| {
1778                     anyhow::Ok(func.call_concurrent(accessor, ()).await?.0)
1779                 })
1780                 .await??
1781                 .0
1782         } else {
1783             func.call_async(&mut store, ()).await?.0
1784         }
1785     };
1786 
1787     assert_eq!(expected.0, actual.0);
1788     assert_eq!(expected.1, actual.1);
1789     assert!(expected.2.is_nan());
1790     assert!(actual.2.is_nan());
1791     assert_eq!(expected.3, actual.3);
1792     assert_eq!(expected.4, actual.4);
1793     assert_eq!(expected.5, actual.5);
1794     assert_eq!(expected.6, actual.6);
1795     assert_eq!(expected.7, actual.7);
1796     assert_eq!(expected.8, actual.8);
1797     assert_eq!(expected.9, actual.9);
1798     assert_eq!(expected.10, actual.10);
1799     assert_eq!(expected.11, actual.11);
1800     assert_eq!(expected.12, actual.12);
1801 
1802     Ok(())
1803 }
1804 
1805 #[test]
1806 fn some_traps() -> Result<()> {
1807     let middle_of_memory = (i32::MAX / 2) & (!0xff);
1808     let component = format!(
1809         r#"(component
1810             (core module $m
1811                 (memory (export "memory") 1)
1812                 (func (export "take-many") (param i32))
1813                 (func (export "take-list") (param i32 i32))
1814 
1815                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1816                     unreachable)
1817             )
1818             (core instance $i (instantiate $m))
1819 
1820             (func (export "take-list-unreachable") (param "a" (list u8))
1821                 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc")))
1822             )
1823             (func (export "take-string-unreachable") (param "a" string)
1824                 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc")))
1825             )
1826 
1827             (type $t (func
1828                 (param "s1" string)
1829                 (param "s2" string)
1830                 (param "s3" string)
1831                 (param "s4" string)
1832                 (param "s5" string)
1833                 (param "s6" string)
1834                 (param "s7" string)
1835                 (param "s8" string)
1836                 (param "s9" string)
1837                 (param "s10" string)
1838             ))
1839             (func (export "take-many-unreachable") (type $t)
1840                 (canon lift (core func $i "take-many") (memory $i "memory") (realloc (func $i "realloc")))
1841             )
1842 
1843             (core module $m2
1844                 (memory (export "memory") 1)
1845                 (func (export "take-many") (param i32))
1846                 (func (export "take-list") (param i32 i32))
1847 
1848                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1849                     i32.const {middle_of_memory})
1850             )
1851             (core instance $i2 (instantiate $m2))
1852 
1853             (func (export "take-list-base-oob") (param "a" (list u8))
1854                 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1855             )
1856             (func (export "take-string-base-oob") (param "a" string)
1857                 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1858             )
1859             (func (export "take-many-base-oob") (type $t)
1860                 (canon lift (core func $i2 "take-many") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1861             )
1862 
1863             (core module $m3
1864                 (memory (export "memory") 1)
1865                 (func (export "take-many") (param i32))
1866                 (func (export "take-list") (param i32 i32))
1867 
1868                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1869                     i32.const 65532)
1870             )
1871             (core instance $i3 (instantiate $m3))
1872 
1873             (func (export "take-list-end-oob") (param "a" (list u8))
1874                 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1875             )
1876             (func (export "take-string-end-oob") (param "a" string)
1877                 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1878             )
1879             (func (export "take-many-end-oob") (type $t)
1880                 (canon lift (core func $i3 "take-many") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1881             )
1882 
1883             (core module $m4
1884                 (memory (export "memory") 1)
1885                 (func (export "take-many") (param i32))
1886 
1887                 (global $cnt (mut i32) (i32.const 0))
1888                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1889                     global.get $cnt
1890                     if (result i32)
1891                         i32.const 100000
1892                     else
1893                         i32.const 1
1894                         global.set $cnt
1895                         i32.const 0
1896                     end
1897                 )
1898             )
1899             (core instance $i4 (instantiate $m4))
1900 
1901             (func (export "take-many-second-oob") (type $t)
1902                 (canon lift (core func $i4 "take-many") (memory $i4 "memory") (realloc (func $i4 "realloc")))
1903             )
1904         )"#
1905     );
1906 
1907     let engine = super::engine();
1908     let component = Component::new(&engine, component)?;
1909     let mut store = Store::new(&engine, ());
1910     let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component);
1911 
1912     // This should fail when calling the allocator function for the argument
1913     let err = instance(&mut store)?
1914         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-unreachable")?
1915         .call(&mut store, (&[],))
1916         .unwrap_err()
1917         .downcast::<Trap>()?;
1918     assert_eq!(err, Trap::UnreachableCodeReached);
1919 
1920     // This should fail when calling the allocator function for the argument
1921     let err = instance(&mut store)?
1922         .get_typed_func::<(&str,), ()>(&mut store, "take-string-unreachable")?
1923         .call(&mut store, ("",))
1924         .unwrap_err()
1925         .downcast::<Trap>()?;
1926     assert_eq!(err, Trap::UnreachableCodeReached);
1927 
1928     // This should fail when calling the allocator function for the space
1929     // to store the arguments (before arguments are even lowered)
1930     let err = instance(&mut store)?
1931         .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
1932             &mut store,
1933             "take-many-unreachable",
1934         )?
1935         .call(&mut store, ("", "", "", "", "", "", "", "", "", ""))
1936         .unwrap_err()
1937         .downcast::<Trap>()?;
1938     assert_eq!(err, Trap::UnreachableCodeReached);
1939 
1940     // Assert that when the base pointer returned by malloc is out of bounds
1941     // that errors are reported as such. Both empty and lists with contents
1942     // should all be invalid here.
1943     //
1944     // FIXME(WebAssembly/component-model#32) confirm the semantics here are
1945     // what's desired.
1946     #[track_caller]
1947     fn assert_oob(err: &anyhow::Error) {
1948         assert!(
1949             err.to_string()
1950                 .contains("realloc return: beyond end of memory"),
1951             "{err:?}",
1952         );
1953     }
1954     let err = instance(&mut store)?
1955         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-base-oob")?
1956         .call(&mut store, (&[],))
1957         .unwrap_err();
1958     assert_oob(&err);
1959     let err = instance(&mut store)?
1960         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-base-oob")?
1961         .call(&mut store, (&[1],))
1962         .unwrap_err();
1963     assert_oob(&err);
1964     let err = instance(&mut store)?
1965         .get_typed_func::<(&str,), ()>(&mut store, "take-string-base-oob")?
1966         .call(&mut store, ("",))
1967         .unwrap_err();
1968     assert_oob(&err);
1969     let err = instance(&mut store)?
1970         .get_typed_func::<(&str,), ()>(&mut store, "take-string-base-oob")?
1971         .call(&mut store, ("x",))
1972         .unwrap_err();
1973     assert_oob(&err);
1974     let err = instance(&mut store)?
1975         .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
1976             &mut store,
1977             "take-many-base-oob",
1978         )?
1979         .call(&mut store, ("", "", "", "", "", "", "", "", "", ""))
1980         .unwrap_err();
1981     assert_oob(&err);
1982 
1983     // Test here that when the returned pointer from malloc is one byte from the
1984     // end of memory that empty things are fine, but larger things are not.
1985 
1986     instance(&mut store)?
1987         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")?
1988         .call_and_post_return(&mut store, (&[],))?;
1989     instance(&mut store)?
1990         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")?
1991         .call_and_post_return(&mut store, (&[1, 2, 3, 4],))?;
1992     let err = instance(&mut store)?
1993         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")?
1994         .call(&mut store, (&[1, 2, 3, 4, 5],))
1995         .unwrap_err();
1996     assert_oob(&err);
1997     instance(&mut store)?
1998         .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")?
1999         .call_and_post_return(&mut store, ("",))?;
2000     instance(&mut store)?
2001         .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")?
2002         .call_and_post_return(&mut store, ("abcd",))?;
2003     let err = instance(&mut store)?
2004         .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")?
2005         .call(&mut store, ("abcde",))
2006         .unwrap_err();
2007     assert_oob(&err);
2008     let err = instance(&mut store)?
2009         .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2010             &mut store,
2011             "take-many-end-oob",
2012         )?
2013         .call(&mut store, ("", "", "", "", "", "", "", "", "", ""))
2014         .unwrap_err();
2015     assert_oob(&err);
2016 
2017     // For this function the first allocation, the space to store all the
2018     // arguments, is in-bounds but then all further allocations, such as for
2019     // each individual string, are all out of bounds.
2020     let err = instance(&mut store)?
2021         .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2022             &mut store,
2023             "take-many-second-oob",
2024         )?
2025         .call(&mut store, ("", "", "", "", "", "", "", "", "", ""))
2026         .unwrap_err();
2027     assert_oob(&err);
2028     let err = instance(&mut store)?
2029         .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2030             &mut store,
2031             "take-many-second-oob",
2032         )?
2033         .call(&mut store, ("", "", "", "", "", "", "", "", "", "x"))
2034         .unwrap_err();
2035     assert_oob(&err);
2036     Ok(())
2037 }
2038 
2039 #[test]
2040 fn char_bool_memory() -> Result<()> {
2041     let component = format!(
2042         r#"(component
2043             (core module $m
2044                 (memory (export "memory") 1)
2045                 (func (export "ret-tuple") (param i32 i32) (result i32)
2046                     (local $base i32)
2047 
2048                     ;; Allocate space for the return
2049                     (local.set $base
2050                         (call $realloc
2051                             (i32.const 0)
2052                             (i32.const 0)
2053                             (i32.const 4)
2054                             (i32.const 8)))
2055 
2056                     ;; store the boolean
2057                     (i32.store offset=0
2058                         (local.get $base)
2059                         (local.get 0))
2060 
2061                     ;; store the char
2062                     (i32.store offset=4
2063                         (local.get $base)
2064                         (local.get 1))
2065 
2066                     (local.get $base)
2067                 )
2068 
2069                 {REALLOC_AND_FREE}
2070             )
2071             (core instance $i (instantiate $m))
2072 
2073             (func (export "ret-tuple") (param "a" u32) (param "b" u32) (result (tuple bool char))
2074                 (canon lift (core func $i "ret-tuple")
2075                     (memory $i "memory")
2076                     (realloc (func $i "realloc")))
2077             )
2078         )"#
2079     );
2080 
2081     let engine = super::engine();
2082     let component = Component::new(&engine, component)?;
2083     let mut store = Store::new(&engine, ());
2084     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2085     let func = instance.get_typed_func::<(u32, u32), ((bool, char),)>(&mut store, "ret-tuple")?;
2086 
2087     let (ret,) = func.call(&mut store, (0, 'a' as u32))?;
2088     assert_eq!(ret, (false, 'a'));
2089     func.post_return(&mut store)?;
2090 
2091     let (ret,) = func.call(&mut store, (1, '��' as u32))?;
2092     assert_eq!(ret, (true, '��'));
2093     func.post_return(&mut store)?;
2094 
2095     let (ret,) = func.call(&mut store, (2, 'a' as u32))?;
2096     assert_eq!(ret, (true, 'a'));
2097     func.post_return(&mut store)?;
2098 
2099     assert!(func.call(&mut store, (0, 0xd800)).is_err());
2100 
2101     Ok(())
2102 }
2103 
2104 #[test]
2105 fn string_list_oob() -> Result<()> {
2106     let component = format!(
2107         r#"(component
2108             (core module $m
2109                 (memory (export "memory") 1)
2110                 (func (export "ret-list") (result i32)
2111                     (local $base i32)
2112 
2113                     ;; Allocate space for the return
2114                     (local.set $base
2115                         (call $realloc
2116                             (i32.const 0)
2117                             (i32.const 0)
2118                             (i32.const 4)
2119                             (i32.const 8)))
2120 
2121                     (i32.store offset=0
2122                         (local.get $base)
2123                         (i32.const 100000))
2124                     (i32.store offset=4
2125                         (local.get $base)
2126                         (i32.const 1))
2127 
2128                     (local.get $base)
2129                 )
2130 
2131                 {REALLOC_AND_FREE}
2132             )
2133             (core instance $i (instantiate $m))
2134 
2135             (func (export "ret-list-u8") (result (list u8))
2136                 (canon lift (core func $i "ret-list")
2137                     (memory $i "memory")
2138                     (realloc (func $i "realloc"))
2139                 )
2140             )
2141             (func (export "ret-string") (result string)
2142                 (canon lift (core func $i "ret-list")
2143                     (memory $i "memory")
2144                     (realloc (func $i "realloc"))
2145                 )
2146             )
2147         )"#
2148     );
2149 
2150     let engine = super::engine();
2151     let component = Component::new(&engine, component)?;
2152     let mut store = Store::new(&engine, ());
2153     let ret_list_u8 = Linker::new(&engine)
2154         .instantiate(&mut store, &component)?
2155         .get_typed_func::<(), (WasmList<u8>,)>(&mut store, "ret-list-u8")?;
2156     let ret_string = Linker::new(&engine)
2157         .instantiate(&mut store, &component)?
2158         .get_typed_func::<(), (WasmStr,)>(&mut store, "ret-string")?;
2159 
2160     let err = ret_list_u8.call(&mut store, ()).err().unwrap();
2161     assert!(err.to_string().contains("out of bounds"), "{}", err);
2162 
2163     let err = ret_string.call(&mut store, ()).err().unwrap();
2164     assert!(err.to_string().contains("out of bounds"), "{}", err);
2165 
2166     Ok(())
2167 }
2168 
2169 #[test]
2170 fn tuples() -> Result<()> {
2171     let component = format!(
2172         r#"(component
2173             (core module $m
2174                 (memory (export "memory") 1)
2175                 (func (export "foo")
2176                     (param i32 f64 i32)
2177                     (result i32)
2178 
2179                     local.get 0
2180                     i32.const 0
2181                     i32.ne
2182                     if unreachable end
2183 
2184                     local.get 1
2185                     f64.const 1
2186                     f64.ne
2187                     if unreachable end
2188 
2189                     local.get 2
2190                     i32.const 2
2191                     i32.ne
2192                     if unreachable end
2193 
2194                     i32.const 3
2195                 )
2196             )
2197             (core instance $i (instantiate $m))
2198 
2199             (func (export "foo")
2200                 (param "a" (tuple s32 float64))
2201                 (param "b" (tuple s8))
2202                 (result (tuple u16))
2203                 (canon lift (core func $i "foo"))
2204             )
2205         )"#
2206     );
2207 
2208     let engine = super::engine();
2209     let component = Component::new(&engine, component)?;
2210     let mut store = Store::new(&engine, ());
2211     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2212     let foo = instance.get_typed_func::<((i32, f64), (i8,)), ((u16,),)>(&mut store, "foo")?;
2213     assert_eq!(foo.call(&mut store, ((0, 1.0), (2,)))?, ((3,),));
2214 
2215     Ok(())
2216 }
2217 
2218 #[test]
2219 fn option() -> Result<()> {
2220     let component = format!(
2221         r#"(component
2222             (core module $m
2223                 (memory (export "memory") 1)
2224                 (func (export "pass1") (param i32 i32) (result i32)
2225                     (local $base i32)
2226                     (local.set $base
2227                         (call $realloc
2228                             (i32.const 0)
2229                             (i32.const 0)
2230                             (i32.const 4)
2231                             (i32.const 8)))
2232 
2233                     (i32.store offset=0
2234                         (local.get $base)
2235                         (local.get 0))
2236                     (i32.store offset=4
2237                         (local.get $base)
2238                         (local.get 1))
2239 
2240                     (local.get $base)
2241                 )
2242                 (func (export "pass2") (param i32 i32 i32) (result i32)
2243                     (local $base i32)
2244                     (local.set $base
2245                         (call $realloc
2246                             (i32.const 0)
2247                             (i32.const 0)
2248                             (i32.const 4)
2249                             (i32.const 12)))
2250 
2251                     (i32.store offset=0
2252                         (local.get $base)
2253                         (local.get 0))
2254                     (i32.store offset=4
2255                         (local.get $base)
2256                         (local.get 1))
2257                     (i32.store offset=8
2258                         (local.get $base)
2259                         (local.get 2))
2260 
2261                     (local.get $base)
2262                 )
2263 
2264                 {REALLOC_AND_FREE}
2265             )
2266             (core instance $i (instantiate $m))
2267 
2268             (func (export "option-u8-to-tuple") (param "a" (option u8)) (result (tuple u32 u32))
2269                 (canon lift (core func $i "pass1") (memory $i "memory"))
2270             )
2271             (func (export "option-u32-to-tuple") (param "a" (option u32)) (result (tuple u32 u32))
2272                 (canon lift (core func $i "pass1") (memory $i "memory"))
2273             )
2274             (func (export "option-string-to-tuple") (param "a" (option string)) (result (tuple u32 string))
2275                 (canon lift
2276                     (core func $i "pass2")
2277                     (memory $i "memory")
2278                     (realloc (func $i "realloc"))
2279                 )
2280             )
2281             (func (export "to-option-u8") (param "a" u32) (param "b" u32) (result (option u8))
2282                 (canon lift (core func $i "pass1") (memory $i "memory"))
2283             )
2284             (func (export "to-option-u32") (param "a" u32) (param "b" u32) (result (option u32))
2285                 (canon lift
2286                     (core func $i "pass1")
2287                     (memory $i "memory")
2288                 )
2289             )
2290             (func (export "to-option-string") (param "a" u32) (param "b" string) (result (option string))
2291                 (canon lift
2292                     (core func $i "pass2")
2293                     (memory $i "memory")
2294                     (realloc (func $i "realloc"))
2295                 )
2296             )
2297         )"#
2298     );
2299 
2300     let engine = super::engine();
2301     let component = Component::new(&engine, component)?;
2302     let mut store = Store::new(&engine, ());
2303     let linker = Linker::new(&engine);
2304     let instance = linker.instantiate(&mut store, &component)?;
2305 
2306     let option_u8_to_tuple = instance
2307         .get_typed_func::<(Option<u8>,), ((u32, u32),)>(&mut store, "option-u8-to-tuple")?;
2308     assert_eq!(option_u8_to_tuple.call(&mut store, (None,))?, ((0, 0),));
2309     option_u8_to_tuple.post_return(&mut store)?;
2310     assert_eq!(option_u8_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),));
2311     option_u8_to_tuple.post_return(&mut store)?;
2312     assert_eq!(
2313         option_u8_to_tuple.call(&mut store, (Some(100),))?,
2314         ((1, 100),)
2315     );
2316     option_u8_to_tuple.post_return(&mut store)?;
2317 
2318     let option_u32_to_tuple = instance
2319         .get_typed_func::<(Option<u32>,), ((u32, u32),)>(&mut store, "option-u32-to-tuple")?;
2320     assert_eq!(option_u32_to_tuple.call(&mut store, (None,))?, ((0, 0),));
2321     option_u32_to_tuple.post_return(&mut store)?;
2322     assert_eq!(option_u32_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),));
2323     option_u32_to_tuple.post_return(&mut store)?;
2324     assert_eq!(
2325         option_u32_to_tuple.call(&mut store, (Some(100),))?,
2326         ((1, 100),)
2327     );
2328     option_u32_to_tuple.post_return(&mut store)?;
2329 
2330     let option_string_to_tuple = instance.get_typed_func::<(Option<&str>,), ((u32, WasmStr),)>(
2331         &mut store,
2332         "option-string-to-tuple",
2333     )?;
2334     let ((a, b),) = option_string_to_tuple.call(&mut store, (None,))?;
2335     assert_eq!(a, 0);
2336     assert_eq!(b.to_str(&store)?, "");
2337     option_string_to_tuple.post_return(&mut store)?;
2338     let ((a, b),) = option_string_to_tuple.call(&mut store, (Some(""),))?;
2339     assert_eq!(a, 1);
2340     assert_eq!(b.to_str(&store)?, "");
2341     option_string_to_tuple.post_return(&mut store)?;
2342     let ((a, b),) = option_string_to_tuple.call(&mut store, (Some("hello"),))?;
2343     assert_eq!(a, 1);
2344     assert_eq!(b.to_str(&store)?, "hello");
2345     option_string_to_tuple.post_return(&mut store)?;
2346 
2347     let instance = linker.instantiate(&mut store, &component)?;
2348     let to_option_u8 =
2349         instance.get_typed_func::<(u32, u32), (Option<u8>,)>(&mut store, "to-option-u8")?;
2350     assert_eq!(to_option_u8.call(&mut store, (0x00_00, 0))?, (None,));
2351     to_option_u8.post_return(&mut store)?;
2352     assert_eq!(to_option_u8.call(&mut store, (0x00_01, 0))?, (Some(0),));
2353     to_option_u8.post_return(&mut store)?;
2354     assert_eq!(to_option_u8.call(&mut store, (0xfd_01, 0))?, (Some(0xfd),));
2355     to_option_u8.post_return(&mut store)?;
2356     assert!(to_option_u8.call(&mut store, (0x00_02, 0)).is_err());
2357 
2358     let instance = linker.instantiate(&mut store, &component)?;
2359     let to_option_u32 =
2360         instance.get_typed_func::<(u32, u32), (Option<u32>,)>(&mut store, "to-option-u32")?;
2361     assert_eq!(to_option_u32.call(&mut store, (0, 0))?, (None,));
2362     to_option_u32.post_return(&mut store)?;
2363     assert_eq!(to_option_u32.call(&mut store, (1, 0))?, (Some(0),));
2364     to_option_u32.post_return(&mut store)?;
2365     assert_eq!(
2366         to_option_u32.call(&mut store, (1, 0x1234fead))?,
2367         (Some(0x1234fead),)
2368     );
2369     to_option_u32.post_return(&mut store)?;
2370     assert!(to_option_u32.call(&mut store, (2, 0)).is_err());
2371 
2372     let instance = linker.instantiate(&mut store, &component)?;
2373     let to_option_string = instance
2374         .get_typed_func::<(u32, &str), (Option<WasmStr>,)>(&mut store, "to-option-string")?;
2375     let ret = to_option_string.call(&mut store, (0, ""))?.0;
2376     assert!(ret.is_none());
2377     to_option_string.post_return(&mut store)?;
2378     let ret = to_option_string.call(&mut store, (1, ""))?.0;
2379     assert_eq!(ret.unwrap().to_str(&store)?, "");
2380     to_option_string.post_return(&mut store)?;
2381     let ret = to_option_string.call(&mut store, (1, "cheesecake"))?.0;
2382     assert_eq!(ret.unwrap().to_str(&store)?, "cheesecake");
2383     to_option_string.post_return(&mut store)?;
2384     assert!(to_option_string.call(&mut store, (2, "")).is_err());
2385 
2386     Ok(())
2387 }
2388 
2389 #[test]
2390 fn expected() -> Result<()> {
2391     let component = format!(
2392         r#"(component
2393             (core module $m
2394                 (memory (export "memory") 1)
2395                 (func (export "pass0") (param i32) (result i32)
2396                     local.get 0
2397                 )
2398                 (func (export "pass1") (param i32 i32) (result i32)
2399                     (local $base i32)
2400                     (local.set $base
2401                         (call $realloc
2402                             (i32.const 0)
2403                             (i32.const 0)
2404                             (i32.const 4)
2405                             (i32.const 8)))
2406 
2407                     (i32.store offset=0
2408                         (local.get $base)
2409                         (local.get 0))
2410                     (i32.store offset=4
2411                         (local.get $base)
2412                         (local.get 1))
2413 
2414                     (local.get $base)
2415                 )
2416                 (func (export "pass2") (param i32 i32 i32) (result i32)
2417                     (local $base i32)
2418                     (local.set $base
2419                         (call $realloc
2420                             (i32.const 0)
2421                             (i32.const 0)
2422                             (i32.const 4)
2423                             (i32.const 12)))
2424 
2425                     (i32.store offset=0
2426                         (local.get $base)
2427                         (local.get 0))
2428                     (i32.store offset=4
2429                         (local.get $base)
2430                         (local.get 1))
2431                     (i32.store offset=8
2432                         (local.get $base)
2433                         (local.get 2))
2434 
2435                     (local.get $base)
2436                 )
2437 
2438                 {REALLOC_AND_FREE}
2439             )
2440             (core instance $i (instantiate $m))
2441 
2442             (func (export "take-expected-unit") (param "a" (result)) (result u32)
2443                 (canon lift (core func $i "pass0"))
2444             )
2445             (func (export "take-expected-u8-f32") (param "a" (result u8 (error float32))) (result (tuple u32 u32))
2446                 (canon lift (core func $i "pass1") (memory $i "memory"))
2447             )
2448             (type $list (list u8))
2449             (func (export "take-expected-string") (param "a" (result string (error $list))) (result (tuple u32 string))
2450                 (canon lift
2451                     (core func $i "pass2")
2452                     (memory $i "memory")
2453                     (realloc (func $i "realloc"))
2454                 )
2455             )
2456             (func (export "to-expected-unit") (param "a" u32) (result (result))
2457                 (canon lift (core func $i "pass0"))
2458             )
2459             (func (export "to-expected-s16-f32") (param "a" u32) (param "b" u32) (result (result s16 (error float32)))
2460                 (canon lift
2461                     (core func $i "pass1")
2462                     (memory $i "memory")
2463                     (realloc (func $i "realloc"))
2464                 )
2465             )
2466         )"#
2467     );
2468 
2469     let engine = super::engine();
2470     let component = Component::new(&engine, component)?;
2471     let mut store = Store::new(&engine, ());
2472     let linker = Linker::new(&engine);
2473     let instance = linker.instantiate(&mut store, &component)?;
2474     let take_expected_unit =
2475         instance.get_typed_func::<(Result<(), ()>,), (u32,)>(&mut store, "take-expected-unit")?;
2476     assert_eq!(take_expected_unit.call(&mut store, (Ok(()),))?, (0,));
2477     take_expected_unit.post_return(&mut store)?;
2478     assert_eq!(take_expected_unit.call(&mut store, (Err(()),))?, (1,));
2479     take_expected_unit.post_return(&mut store)?;
2480 
2481     let take_expected_u8_f32 = instance
2482         .get_typed_func::<(Result<u8, f32>,), ((u32, u32),)>(&mut store, "take-expected-u8-f32")?;
2483     assert_eq!(take_expected_u8_f32.call(&mut store, (Ok(1),))?, ((0, 1),));
2484     take_expected_u8_f32.post_return(&mut store)?;
2485     assert_eq!(
2486         take_expected_u8_f32.call(&mut store, (Err(2.0),))?,
2487         ((1, 2.0f32.to_bits()),)
2488     );
2489     take_expected_u8_f32.post_return(&mut store)?;
2490 
2491     let take_expected_string = instance
2492         .get_typed_func::<(Result<&str, &[u8]>,), ((u32, WasmStr),)>(
2493             &mut store,
2494             "take-expected-string",
2495         )?;
2496     let ((a, b),) = take_expected_string.call(&mut store, (Ok("hello"),))?;
2497     assert_eq!(a, 0);
2498     assert_eq!(b.to_str(&store)?, "hello");
2499     take_expected_string.post_return(&mut store)?;
2500     let ((a, b),) = take_expected_string.call(&mut store, (Err(b"goodbye"),))?;
2501     assert_eq!(a, 1);
2502     assert_eq!(b.to_str(&store)?, "goodbye");
2503     take_expected_string.post_return(&mut store)?;
2504 
2505     let instance = linker.instantiate(&mut store, &component)?;
2506     let to_expected_unit =
2507         instance.get_typed_func::<(u32,), (Result<(), ()>,)>(&mut store, "to-expected-unit")?;
2508     assert_eq!(to_expected_unit.call(&mut store, (0,))?, (Ok(()),));
2509     to_expected_unit.post_return(&mut store)?;
2510     assert_eq!(to_expected_unit.call(&mut store, (1,))?, (Err(()),));
2511     to_expected_unit.post_return(&mut store)?;
2512     let err = to_expected_unit.call(&mut store, (2,)).unwrap_err();
2513     assert!(err.to_string().contains("invalid expected"), "{}", err);
2514 
2515     let instance = linker.instantiate(&mut store, &component)?;
2516     let to_expected_s16_f32 = instance
2517         .get_typed_func::<(u32, u32), (Result<i16, f32>,)>(&mut store, "to-expected-s16-f32")?;
2518     assert_eq!(to_expected_s16_f32.call(&mut store, (0, 0))?, (Ok(0),));
2519     to_expected_s16_f32.post_return(&mut store)?;
2520     assert_eq!(to_expected_s16_f32.call(&mut store, (0, 100))?, (Ok(100),));
2521     to_expected_s16_f32.post_return(&mut store)?;
2522     assert_eq!(
2523         to_expected_s16_f32.call(&mut store, (1, 1.0f32.to_bits()))?,
2524         (Err(1.0),)
2525     );
2526     to_expected_s16_f32.post_return(&mut store)?;
2527     let ret = to_expected_s16_f32
2528         .call(&mut store, (1, CANON_32BIT_NAN | 1))?
2529         .0;
2530     assert_eq!(ret.unwrap_err().to_bits(), CANON_32BIT_NAN | 1);
2531     to_expected_s16_f32.post_return(&mut store)?;
2532     assert!(to_expected_s16_f32.call(&mut store, (2, 0)).is_err());
2533 
2534     Ok(())
2535 }
2536 
2537 #[test]
2538 fn fancy_list() -> Result<()> {
2539     let component = format!(
2540         r#"(component
2541             (core module $m
2542                 (memory (export "memory") 1)
2543                 (func (export "take") (param i32 i32) (result i32)
2544                     (local $base i32)
2545                     (local.set $base
2546                         (call $realloc
2547                             (i32.const 0)
2548                             (i32.const 0)
2549                             (i32.const 4)
2550                             (i32.const 16)))
2551 
2552                     (i32.store offset=0
2553                         (local.get $base)
2554                         (local.get 0))
2555                     (i32.store offset=4
2556                         (local.get $base)
2557                         (local.get 1))
2558                     (i32.store offset=8
2559                         (local.get $base)
2560                         (i32.const 0))
2561                     (i32.store offset=12
2562                         (local.get $base)
2563                         (i32.mul
2564                             (memory.size)
2565                             (i32.const 65536)))
2566 
2567                     (local.get $base)
2568                 )
2569 
2570                 {REALLOC_AND_FREE}
2571             )
2572             (core instance $i (instantiate $m))
2573 
2574             (type $a (option u8))
2575             (type $b (result (error string)))
2576             (type $input (list (tuple $a $b)))
2577             (func (export "take")
2578                 (param "a" $input)
2579                 (result (tuple u32 u32 (list u8)))
2580                 (canon lift
2581                     (core func $i "take")
2582                     (memory $i "memory")
2583                     (realloc (func $i "realloc"))
2584                 )
2585             )
2586         )"#
2587     );
2588 
2589     let engine = super::engine();
2590     let component = Component::new(&engine, component)?;
2591     let mut store = Store::new(&engine, ());
2592     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2593 
2594     let func = instance
2595         .get_typed_func::<(&[(Option<u8>, Result<(), &str>)],), ((u32, u32, WasmList<u8>),)>(
2596             &mut store, "take",
2597         )?;
2598 
2599     let input = [
2600         (None, Ok(())),
2601         (Some(2), Err("hello there")),
2602         (Some(200), Err("general kenobi")),
2603     ];
2604     let ((ptr, len, list),) = func.call(&mut store, (&input,))?;
2605     let memory = list.as_le_slice(&store);
2606     let ptr = usize::try_from(ptr).unwrap();
2607     let len = usize::try_from(len).unwrap();
2608     let mut array = &memory[ptr..][..len * 16];
2609 
2610     for (a, b) in input.iter() {
2611         match a {
2612             Some(val) => {
2613                 assert_eq!(*array.take_n::<2>(), [1, *val]);
2614             }
2615             None => {
2616                 assert_eq!(*array.take_n::<1>(), [0]);
2617                 array.skip::<1>();
2618             }
2619         }
2620         array.skip::<2>();
2621         match b {
2622             Ok(()) => {
2623                 assert_eq!(*array.take_n::<1>(), [0]);
2624                 array.skip::<11>();
2625             }
2626             Err(s) => {
2627                 assert_eq!(*array.take_n::<1>(), [1]);
2628                 array.skip::<3>();
2629                 assert_eq!(array.ptr_len(memory, 1), s.as_bytes());
2630             }
2631         }
2632     }
2633     assert!(array.is_empty());
2634 
2635     Ok(())
2636 }
2637 
2638 trait SliceExt<'a> {
2639     fn take_n<const N: usize>(&mut self) -> &'a [u8; N];
2640 
2641     fn skip<const N: usize>(&mut self) {
2642         self.take_n::<N>();
2643     }
2644 
2645     fn ptr_len<'b>(&mut self, all_memory: &'b [u8], size: usize) -> &'b [u8] {
2646         let ptr = u32::from_le_bytes(*self.take_n::<4>());
2647         let len = u32::from_le_bytes(*self.take_n::<4>());
2648         let ptr = usize::try_from(ptr).unwrap();
2649         let len = usize::try_from(len).unwrap();
2650         &all_memory[ptr..][..len * size]
2651     }
2652 }
2653 
2654 impl<'a> SliceExt<'a> for &'a [u8] {
2655     fn take_n<const N: usize>(&mut self) -> &'a [u8; N] {
2656         let (a, b) = self.split_at(N);
2657         *self = b;
2658         a.try_into().unwrap()
2659     }
2660 }
2661 
2662 #[test]
2663 fn invalid_alignment() -> Result<()> {
2664     let component = format!(
2665         r#"(component
2666             (core module $m
2667                 (memory (export "memory") 1)
2668                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
2669                     i32.const 1)
2670 
2671                 (func (export "take-i32") (param i32))
2672                 (func (export "ret-1") (result i32) i32.const 1)
2673                 (func (export "ret-unaligned-list") (result i32)
2674                     (i32.store offset=0 (i32.const 8) (i32.const 1))
2675                     (i32.store offset=4 (i32.const 8) (i32.const 1))
2676                     i32.const 8)
2677             )
2678             (core instance $i (instantiate $m))
2679 
2680             (func (export "many-params")
2681                 (param "s1" string) (param "s2" string) (param "s3" string) (param "s4" string)
2682                 (param "s5" string) (param "s6" string) (param "s7" string) (param "s8" string)
2683                 (param "s9" string) (param "s10" string) (param "s11" string) (param "s12" string)
2684                 (canon lift
2685                     (core func $i "take-i32")
2686                     (memory $i "memory")
2687                     (realloc (func $i "realloc"))
2688                 )
2689             )
2690             (func (export "string-ret") (result string)
2691                 (canon lift
2692                     (core func $i "ret-1")
2693                     (memory $i "memory")
2694                     (realloc (func $i "realloc"))
2695                 )
2696             )
2697             (func (export "list-u32-ret") (result (list u32))
2698                 (canon lift
2699                     (core func $i "ret-unaligned-list")
2700                     (memory $i "memory")
2701                     (realloc (func $i "realloc"))
2702                 )
2703             )
2704         )"#
2705     );
2706 
2707     let engine = super::engine();
2708     let component = Component::new(&engine, component)?;
2709     let mut store = Store::new(&engine, ());
2710     let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component);
2711 
2712     let err = instance(&mut store)?
2713         .get_typed_func::<(
2714             &str,
2715             &str,
2716             &str,
2717             &str,
2718             &str,
2719             &str,
2720             &str,
2721             &str,
2722             &str,
2723             &str,
2724             &str,
2725             &str,
2726         ), ()>(&mut store, "many-params")?
2727         .call(&mut store, ("", "", "", "", "", "", "", "", "", "", "", ""))
2728         .unwrap_err();
2729     assert!(
2730         err.to_string()
2731             .contains("realloc return: result not aligned"),
2732         "{}",
2733         err
2734     );
2735 
2736     let err = instance(&mut store)?
2737         .get_typed_func::<(), (WasmStr,)>(&mut store, "string-ret")?
2738         .call(&mut store, ())
2739         .err()
2740         .unwrap();
2741     assert!(
2742         err.to_string().contains("return pointer not aligned"),
2743         "{}",
2744         err
2745     );
2746 
2747     let err = instance(&mut store)?
2748         .get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32-ret")?
2749         .call(&mut store, ())
2750         .err()
2751         .unwrap();
2752     assert!(
2753         err.to_string().contains("list pointer is not aligned"),
2754         "{}",
2755         err
2756     );
2757 
2758     Ok(())
2759 }
2760 
2761 #[test]
2762 fn drop_component_still_works() -> Result<()> {
2763     let component = r#"
2764         (component
2765             (import "f" (func $f))
2766 
2767             (core func $f_lower
2768                 (canon lower (func $f))
2769             )
2770             (core module $m
2771                 (import "" "" (func $f))
2772 
2773                 (func $f2
2774                     call $f
2775                     call $f
2776                 )
2777 
2778                 (export "f" (func $f2))
2779             )
2780             (core instance $i (instantiate $m
2781                 (with "" (instance
2782                     (export "" (func $f_lower))
2783                 ))
2784             ))
2785             (func (export "g")
2786                 (canon lift
2787                     (core func $i "f")
2788                 )
2789             )
2790         )
2791     "#;
2792 
2793     let (mut store, instance) = {
2794         let engine = super::engine();
2795         let component = Component::new(&engine, component)?;
2796         let mut store = Store::new(&engine, 0);
2797         let mut linker = Linker::new(&engine);
2798         linker.root().func_wrap(
2799             "f",
2800             |mut store: StoreContextMut<'_, u32>, _: ()| -> Result<()> {
2801                 *store.data_mut() += 1;
2802                 Ok(())
2803             },
2804         )?;
2805         let instance = linker.instantiate(&mut store, &component)?;
2806         (store, instance)
2807     };
2808 
2809     let f = instance.get_typed_func::<(), ()>(&mut store, "g")?;
2810     assert_eq!(*store.data(), 0);
2811     f.call(&mut store, ())?;
2812     assert_eq!(*store.data(), 2);
2813 
2814     Ok(())
2815 }
2816 
2817 #[test]
2818 fn raw_slice_of_various_types() -> Result<()> {
2819     let component = r#"
2820         (component
2821             (core module $m
2822                 (memory (export "memory") 1)
2823 
2824                 (func (export "list8") (result i32)
2825                     (call $setup_list (i32.const 16))
2826                 )
2827                 (func (export "list16") (result i32)
2828                     (call $setup_list (i32.const 8))
2829                 )
2830                 (func (export "list32") (result i32)
2831                     (call $setup_list (i32.const 4))
2832                 )
2833                 (func (export "list64") (result i32)
2834                     (call $setup_list (i32.const 2))
2835                 )
2836 
2837                 (func $setup_list (param i32) (result i32)
2838                     (i32.store offset=0 (i32.const 100) (i32.const 8))
2839                     (i32.store offset=4 (i32.const 100) (local.get 0))
2840                     i32.const 100
2841                 )
2842 
2843                 (data (i32.const 8) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f")
2844             )
2845             (core instance $i (instantiate $m))
2846             (func (export "list-u8") (result (list u8))
2847                 (canon lift (core func $i "list8") (memory $i "memory"))
2848             )
2849             (func (export "list-i8") (result (list s8))
2850                 (canon lift (core func $i "list8") (memory $i "memory"))
2851             )
2852             (func (export "list-u16") (result (list u16))
2853                 (canon lift (core func $i "list16") (memory $i "memory"))
2854             )
2855             (func (export "list-i16") (result (list s16))
2856                 (canon lift (core func $i "list16") (memory $i "memory"))
2857             )
2858             (func (export "list-u32") (result (list u32))
2859                 (canon lift (core func $i "list32") (memory $i "memory"))
2860             )
2861             (func (export "list-i32") (result (list s32))
2862                 (canon lift (core func $i "list32") (memory $i "memory"))
2863             )
2864             (func (export "list-u64") (result (list u64))
2865                 (canon lift (core func $i "list64") (memory $i "memory"))
2866             )
2867             (func (export "list-i64") (result (list s64))
2868                 (canon lift (core func $i "list64") (memory $i "memory"))
2869             )
2870         )
2871     "#;
2872 
2873     let (mut store, instance) = {
2874         let engine = super::engine();
2875         let component = Component::new(&engine, component)?;
2876         let mut store = Store::new(&engine, ());
2877         let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2878         (store, instance)
2879     };
2880 
2881     let list = instance
2882         .get_typed_func::<(), (WasmList<u8>,)>(&mut store, "list-u8")?
2883         .call_and_post_return(&mut store, ())?
2884         .0;
2885     assert_eq!(
2886         list.as_le_slice(&store),
2887         [
2888             0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
2889             0x0e, 0x0f,
2890         ]
2891     );
2892     let list = instance
2893         .get_typed_func::<(), (WasmList<i8>,)>(&mut store, "list-i8")?
2894         .call_and_post_return(&mut store, ())?
2895         .0;
2896     assert_eq!(
2897         list.as_le_slice(&store),
2898         [
2899             0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
2900             0x0e, 0x0f,
2901         ]
2902     );
2903 
2904     let list = instance
2905         .get_typed_func::<(), (WasmList<u16>,)>(&mut store, "list-u16")?
2906         .call_and_post_return(&mut store, ())?
2907         .0;
2908     assert_eq!(
2909         list.as_le_slice(&store),
2910         [
2911             u16::to_le(0x01_00),
2912             u16::to_le(0x03_02),
2913             u16::to_le(0x05_04),
2914             u16::to_le(0x07_06),
2915             u16::to_le(0x09_08),
2916             u16::to_le(0x0b_0a),
2917             u16::to_le(0x0d_0c),
2918             u16::to_le(0x0f_0e),
2919         ]
2920     );
2921     let list = instance
2922         .get_typed_func::<(), (WasmList<i16>,)>(&mut store, "list-i16")?
2923         .call_and_post_return(&mut store, ())?
2924         .0;
2925     assert_eq!(
2926         list.as_le_slice(&store),
2927         [
2928             i16::to_le(0x01_00),
2929             i16::to_le(0x03_02),
2930             i16::to_le(0x05_04),
2931             i16::to_le(0x07_06),
2932             i16::to_le(0x09_08),
2933             i16::to_le(0x0b_0a),
2934             i16::to_le(0x0d_0c),
2935             i16::to_le(0x0f_0e),
2936         ]
2937     );
2938     let list = instance
2939         .get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32")?
2940         .call_and_post_return(&mut store, ())?
2941         .0;
2942     assert_eq!(
2943         list.as_le_slice(&store),
2944         [
2945             u32::to_le(0x03_02_01_00),
2946             u32::to_le(0x07_06_05_04),
2947             u32::to_le(0x0b_0a_09_08),
2948             u32::to_le(0x0f_0e_0d_0c),
2949         ]
2950     );
2951     let list = instance
2952         .get_typed_func::<(), (WasmList<i32>,)>(&mut store, "list-i32")?
2953         .call_and_post_return(&mut store, ())?
2954         .0;
2955     assert_eq!(
2956         list.as_le_slice(&store),
2957         [
2958             i32::to_le(0x03_02_01_00),
2959             i32::to_le(0x07_06_05_04),
2960             i32::to_le(0x0b_0a_09_08),
2961             i32::to_le(0x0f_0e_0d_0c),
2962         ]
2963     );
2964     let list = instance
2965         .get_typed_func::<(), (WasmList<u64>,)>(&mut store, "list-u64")?
2966         .call_and_post_return(&mut store, ())?
2967         .0;
2968     assert_eq!(
2969         list.as_le_slice(&store),
2970         [
2971             u64::to_le(0x07_06_05_04_03_02_01_00),
2972             u64::to_le(0x0f_0e_0d_0c_0b_0a_09_08),
2973         ]
2974     );
2975     let list = instance
2976         .get_typed_func::<(), (WasmList<i64>,)>(&mut store, "list-i64")?
2977         .call_and_post_return(&mut store, ())?
2978         .0;
2979     assert_eq!(
2980         list.as_le_slice(&store),
2981         [
2982             i64::to_le(0x07_06_05_04_03_02_01_00),
2983             i64::to_le(0x0f_0e_0d_0c_0b_0a_09_08),
2984         ]
2985     );
2986 
2987     Ok(())
2988 }
2989 
2990 #[test]
2991 fn lower_then_lift() -> Result<()> {
2992     // First test simple integers when the import/export ABI happen to line up
2993     let component = r#"
2994 (component $c
2995   (import "f" (func $f (result u32)))
2996 
2997   (core func $f_lower
2998     (canon lower (func $f))
2999   )
3000   (func $f2 (result s32)
3001     (canon lift (core func $f_lower))
3002   )
3003   (export "f2" (func $f2))
3004 )
3005     "#;
3006 
3007     let engine = super::engine();
3008     let component = Component::new(&engine, component)?;
3009     let mut store = Store::new(&engine, ());
3010     let mut linker = Linker::new(&engine);
3011     linker.root().func_wrap("f", |_, _: ()| Ok((2u32,)))?;
3012     let instance = linker.instantiate(&mut store, &component)?;
3013 
3014     let f = instance.get_typed_func::<(), (i32,)>(&mut store, "f2")?;
3015     assert_eq!(f.call(&mut store, ())?, (2,));
3016 
3017     // First test strings when the import/export ABI happen to line up
3018     let component = format!(
3019         r#"
3020 (component $c
3021   (import "s" (func $f (param "a" string)))
3022 
3023   (core module $libc
3024     (memory (export "memory") 1)
3025     {REALLOC_AND_FREE}
3026   )
3027   (core instance $libc (instantiate $libc))
3028 
3029   (core func $f_lower
3030     (canon lower (func $f) (memory $libc "memory"))
3031   )
3032   (func $f2 (param "a" string)
3033     (canon lift (core func $f_lower)
3034         (memory $libc "memory")
3035         (realloc (func $libc "realloc"))
3036     )
3037   )
3038   (export "f" (func $f2))
3039 )
3040     "#
3041     );
3042 
3043     let component = Component::new(&engine, component)?;
3044     let mut store = Store::new(&engine, ());
3045     linker
3046         .root()
3047         .func_wrap("s", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| {
3048             assert_eq!(x.to_str(&store)?, "hello");
3049             Ok(())
3050         })?;
3051     let instance = linker.instantiate(&mut store, &component)?;
3052 
3053     let f = instance.get_typed_func::<(&str,), ()>(&mut store, "f")?;
3054     f.call(&mut store, ("hello",))?;
3055 
3056     // Next test "type punning" where return values are reinterpreted just
3057     // because the return ABI happens to line up.
3058     let component = format!(
3059         r#"
3060 (component $c
3061   (import "s2" (func $f (param "a" string) (result u32)))
3062 
3063   (core module $libc
3064     (memory (export "memory") 1)
3065     {REALLOC_AND_FREE}
3066   )
3067   (core instance $libc (instantiate $libc))
3068 
3069   (core func $f_lower
3070     (canon lower (func $f) (memory $libc "memory"))
3071   )
3072   (func $f2 (param "a" string) (result string)
3073     (canon lift (core func $f_lower)
3074         (memory $libc "memory")
3075         (realloc (func $libc "realloc"))
3076     )
3077   )
3078   (export "f" (func $f2))
3079 )
3080     "#
3081     );
3082 
3083     let component = Component::new(&engine, component)?;
3084     let mut store = Store::new(&engine, ());
3085     linker
3086         .root()
3087         .func_wrap("s2", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| {
3088             assert_eq!(x.to_str(&store)?, "hello");
3089             Ok((u32::MAX,))
3090         })?;
3091     let instance = linker.instantiate(&mut store, &component)?;
3092 
3093     let f = instance.get_typed_func::<(&str,), (WasmStr,)>(&mut store, "f")?;
3094     let err = f.call(&mut store, ("hello",)).err().unwrap();
3095     assert!(
3096         err.to_string().contains("return pointer not aligned"),
3097         "{}",
3098         err
3099     );
3100 
3101     Ok(())
3102 }
3103 
3104 #[test]
3105 fn errors_that_poison_instance() -> Result<()> {
3106     let component = format!(
3107         r#"
3108 (component $c
3109   (core module $m1
3110     (func (export "f1") unreachable)
3111     (func (export "f2"))
3112   )
3113   (core instance $m1 (instantiate $m1))
3114   (func (export "f1") (canon lift (core func $m1 "f1")))
3115   (func (export "f2") (canon lift (core func $m1 "f2")))
3116 
3117   (core module $m2
3118     (func (export "f") (param i32 i32))
3119     (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable)
3120     (memory (export "m") 1)
3121   )
3122   (core instance $m2 (instantiate $m2))
3123   (func (export "f3") (param "a" string)
3124     (canon lift (core func $m2 "f") (realloc (func $m2 "r")) (memory $m2 "m"))
3125   )
3126 
3127   (core module $m3
3128     (func (export "f") (result i32) i32.const 1)
3129     (memory (export "m") 1)
3130   )
3131   (core instance $m3 (instantiate $m3))
3132   (func (export "f4") (result string)
3133     (canon lift (core func $m3 "f") (memory $m3 "m"))
3134   )
3135 )
3136     "#
3137     );
3138 
3139     let engine = super::engine();
3140     let component = Component::new(&engine, component)?;
3141     let mut store = Store::new(&engine, ());
3142     let linker = Linker::new(&engine);
3143     let instance = linker.instantiate(&mut store, &component)?;
3144     let f1 = instance.get_typed_func::<(), ()>(&mut store, "f1")?;
3145     let f2 = instance.get_typed_func::<(), ()>(&mut store, "f2")?;
3146     assert_unreachable(f1.call(&mut store, ()));
3147     assert_poisoned(f1.call(&mut store, ()));
3148     assert_poisoned(f2.call(&mut store, ()));
3149 
3150     let instance = linker.instantiate(&mut store, &component)?;
3151     let f3 = instance.get_typed_func::<(&str,), ()>(&mut store, "f3")?;
3152     assert_unreachable(f3.call(&mut store, ("x",)));
3153     assert_poisoned(f3.call(&mut store, ("x",)));
3154 
3155     let instance = linker.instantiate(&mut store, &component)?;
3156     let f4 = instance.get_typed_func::<(), (WasmStr,)>(&mut store, "f4")?;
3157     assert!(f4.call(&mut store, ()).is_err());
3158     assert_poisoned(f4.call(&mut store, ()));
3159 
3160     return Ok(());
3161 
3162     #[track_caller]
3163     fn assert_unreachable<T>(err: Result<T>) {
3164         let err = match err {
3165             Ok(_) => panic!("expected an error"),
3166             Err(e) => e,
3167         };
3168         assert_eq!(
3169             err.downcast::<Trap>().unwrap(),
3170             Trap::UnreachableCodeReached
3171         );
3172     }
3173 
3174     #[track_caller]
3175     fn assert_poisoned<T>(err: Result<T>) {
3176         let err = match err {
3177             Ok(_) => panic!("expected an error"),
3178             Err(e) => e,
3179         };
3180         assert_eq!(
3181             err.downcast_ref::<Trap>(),
3182             Some(&Trap::CannotEnterComponent),
3183             "{err}",
3184         );
3185     }
3186 }
3187 
3188 #[test]
3189 fn run_export_with_internal_adapter() -> Result<()> {
3190     let component = r#"
3191 (component
3192   (type $t (func (param "a" u32) (result u32)))
3193   (component $a
3194     (core module $m
3195       (func (export "add-five") (param i32) (result i32)
3196         local.get 0
3197         i32.const 5
3198         i32.add)
3199     )
3200     (core instance $m (instantiate $m))
3201     (func (export "add-five") (type $t) (canon lift (core func $m "add-five")))
3202   )
3203   (component $b
3204     (import "interface-v1" (instance $i
3205       (export "add-five" (func (type $t)))))
3206     (core module $m
3207       (func $add-five (import "interface-0.1.0" "add-five") (param i32) (result i32))
3208       (func) ;; causes index out of bounds
3209       (func (export "run") (result i32) i32.const 0 call $add-five)
3210     )
3211     (core func $add-five (canon lower (func $i "add-five")))
3212     (core instance $i (instantiate 0
3213       (with "interface-0.1.0" (instance
3214         (export "add-five" (func $add-five))
3215       ))
3216     ))
3217     (func (result u32) (canon lift (core func $i "run")))
3218     (export "run" (func 1))
3219   )
3220   (instance $a (instantiate $a))
3221   (instance $b (instantiate $b (with "interface-v1" (instance $a))))
3222   (export "run" (func $b "run"))
3223 )
3224 "#;
3225     let engine = super::engine();
3226     let component = Component::new(&engine, component)?;
3227     let mut store = Store::new(&engine, ());
3228     let linker = Linker::new(&engine);
3229     let instance = linker.instantiate(&mut store, &component)?;
3230     let run = instance.get_typed_func::<(), (u32,)>(&mut store, "run")?;
3231     assert_eq!(run.call(&mut store, ())?, (5,));
3232     Ok(())
3233 }
3234