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.wasm_component_model_async_stackful(true);
914     config.wasm_component_model_threading(true);
915     config.async_support(true);
916     let engine = &Engine::new(&config)?;
917     let component = Component::new(&engine, component)?;
918     let mut store = Store::new(&engine, ());
919 
920     let instance = Linker::new(&engine)
921         .instantiate_async(&mut store, &component)
922         .await?;
923     let func = instance.get_typed_func::<(u32,), (u32,)>(&mut store, "export")?;
924     let message = "cannot enter component instance";
925     match store
926         .run_concurrent(async move |accessor| {
927             anyhow::Ok(func.call_concurrent(accessor, (42,)).await?.0)
928         })
929         .await
930     {
931         Ok(_) => panic!(),
932         Err(e) => assert!(
933             format!("{e:?}").contains(message),
934             "expected `{message}`; got `{e:?}`"
935         ),
936     }
937 
938     Ok(())
939 }
940 
941 #[tokio::test]
942 async fn missing_task_return_call_stackless() -> Result<()> {
943     task_return_trap(
944         r#"(component
945             (core module $m
946                 (import "" "task.return" (func $task-return))
947                 (func (export "foo") (result i32)
948                     i32.const 0
949                 )
950                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
951             )
952             (core func $task-return (canon task.return))
953             (core instance $i (instantiate $m
954                 (with "" (instance (export "task.return" (func $task-return))))
955             ))
956             (func (export "foo") (canon lift (core func $i "foo") async (callback (func $i "callback"))))
957         )"#,
958         "wasm trap: async-lifted export failed to produce a result",
959     )
960     .await
961 }
962 
963 #[tokio::test]
964 async fn missing_task_return_call_stackless_explicit_thread() -> Result<()> {
965     task_return_trap(
966         r#"(component
967             (core module $libc
968                 (table (export "__indirect_function_table") 1 funcref))
969             (core module $m
970                 (import "" "task.return" (func $task-return))
971                 (import "" "thread.new-indirect" (func $thread-new-indirect (param i32 i32) (result i32)))
972                 (import "" "thread.resume-later" (func $thread-resume-later (param i32)))
973                 (import "libc" "__indirect_function_table" (table $indirect-function-table 1 funcref))
974                 (func $thread-start (param i32) (; empty ;))
975                 (elem (table $indirect-function-table) (i32.const 0) func $thread-start)
976                 (func (export "foo") (result i32)
977                     (call $thread-resume-later
978                         (call $thread-new-indirect (i32.const 0) (i32.const 0)))
979                     i32.const 0
980                 )
981                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
982             )
983             (core instance $libc (instantiate $libc))
984             (core type $start-func-ty (func (param i32)))
985             (alias core export $libc "__indirect_function_table" (core table $indirect-function-table))
986             (core func $thread-new-indirect
987                 (canon thread.new-indirect $start-func-ty (table $indirect-function-table)))
988             (core func $thread-resume-later (canon thread.resume-later))
989             (core func $task-return (canon task.return))
990             (core instance $i (instantiate $m
991                 (with "" (instance
992                     (export "thread.new-indirect" (func $thread-new-indirect))
993                     (export "thread.resume-later" (func $thread-resume-later))
994                     (export "task.return" (func $task-return))
995                 ))
996                 (with "libc" (instance $libc))
997             ))
998             (func (export "foo") (canon lift (core func $i "foo") async (callback (func $i "callback"))))
999         )"#,
1000         "wasm trap: async-lifted export failed to produce a result",
1001     )
1002     .await
1003 }
1004 
1005 #[tokio::test]
1006 async fn missing_task_return_call_stackful_explicit_thread() -> Result<()> {
1007     task_return_trap(
1008         r#"(component
1009             (core module $libc
1010                 (table (export "__indirect_function_table") 1 funcref))
1011             (core module $m
1012                 (import "" "task.return" (func $task-return))
1013                 (import "" "thread.new-indirect" (func $thread-new-indirect (param i32 i32) (result i32)))
1014                 (import "" "thread.resume-later" (func $thread-resume-later (param i32)))
1015                 (import "libc" "__indirect_function_table" (table $indirect-function-table 1 funcref))
1016                 (func $thread-start (param i32) (; empty ;))
1017                 (elem (table $indirect-function-table) (i32.const 0) func $thread-start)
1018                 (func (export "foo")
1019                     (call $thread-resume-later
1020                         (call $thread-new-indirect (i32.const 0) (i32.const 0)))
1021                 )
1022             )
1023             (core instance $libc (instantiate $libc))
1024             (core type $start-func-ty (func (param i32)))
1025             (alias core export $libc "__indirect_function_table" (core table $indirect-function-table))
1026             (core func $thread-new-indirect
1027                 (canon thread.new-indirect $start-func-ty (table $indirect-function-table)))
1028             (core func $thread-resume-later (canon thread.resume-later))
1029             (core func $task-return (canon task.return))
1030             (core instance $i (instantiate $m
1031                 (with "" (instance
1032                     (export "thread.new-indirect" (func $thread-new-indirect))
1033                     (export "thread.resume-later" (func $thread-resume-later))
1034                     (export "task.return" (func $task-return))
1035                 ))
1036                 (with "libc" (instance $libc))
1037             ))
1038             (func (export "foo") (canon lift (core func $i "foo") async))
1039         )"#,
1040         "wasm trap: async-lifted export failed to produce a result",
1041     )
1042     .await
1043 }
1044 
1045 #[tokio::test]
1046 async fn missing_task_return_call_stackful() -> Result<()> {
1047     task_return_trap(
1048         r#"(component
1049             (core module $m
1050                 (import "" "task.return" (func $task-return))
1051                 (func (export "foo"))
1052             )
1053             (core func $task-return (canon task.return))
1054             (core instance $i (instantiate $m
1055                 (with "" (instance (export "task.return" (func $task-return))))
1056             ))
1057             (func (export "foo") (canon lift (core func $i "foo") async))
1058         )"#,
1059         "wasm trap: async-lifted export failed to produce a result",
1060     )
1061     .await
1062 }
1063 
1064 #[tokio::test]
1065 async fn task_return_type_mismatch() -> Result<()> {
1066     task_return_trap(
1067         r#"(component
1068             (core module $m
1069                 (import "" "task.return" (func $task-return (param i32)))
1070                 (func (export "foo") (call $task-return (i32.const 42)))
1071             )
1072             (core func $task-return (canon task.return (result u32)))
1073             (core instance $i (instantiate $m
1074                 (with "" (instance (export "task.return" (func $task-return))))
1075             ))
1076             (func (export "foo") (canon lift (core func $i "foo") async))
1077         )"#,
1078         "invalid `task.return` signature and/or options for current task",
1079     )
1080     .await
1081 }
1082 
1083 #[tokio::test]
1084 async fn task_return_memory_mismatch() -> Result<()> {
1085     task_return_trap(
1086         r#"(component
1087             (core module $libc (memory (export "memory") 1))
1088             (core instance $libc (instantiate $libc))
1089             (core module $m
1090                 (import "" "task.return" (func $task-return))
1091                 (func (export "foo") (call $task-return))
1092             )
1093             (core func $task-return (canon task.return (memory $libc "memory")))
1094             (core instance $i (instantiate $m
1095                 (with "" (instance (export "task.return" (func $task-return))))
1096             ))
1097             (func (export "foo") (canon lift (core func $i "foo") async))
1098         )"#,
1099         "invalid `task.return` signature and/or options for current task",
1100     )
1101     .await
1102 }
1103 
1104 #[tokio::test]
1105 async fn task_return_string_encoding_mismatch() -> Result<()> {
1106     task_return_trap(
1107         r#"(component
1108             (core module $m
1109                 (import "" "task.return" (func $task-return))
1110                 (func (export "foo") (call $task-return))
1111             )
1112             (core func $task-return (canon task.return string-encoding=utf16))
1113             (core instance $i (instantiate $m
1114                 (with "" (instance (export "task.return" (func $task-return))))
1115             ))
1116             (func (export "foo") (canon lift (core func $i "foo") async))
1117         )"#,
1118         "invalid `task.return` signature and/or options for current task",
1119     )
1120     .await
1121 }
1122 
1123 async fn task_return_trap(component: &str, substring: &str) -> Result<()> {
1124     let mut config = Config::new();
1125     config.wasm_component_model_async(true);
1126     config.wasm_component_model_async_stackful(true);
1127     config.wasm_component_model_threading(true);
1128     config.async_support(true);
1129     let engine = &Engine::new(&config)?;
1130     let component = Component::new(&engine, component)?;
1131     let mut store = Store::new(&engine, ());
1132 
1133     let instance = Linker::new(&engine)
1134         .instantiate_async(&mut store, &component)
1135         .await?;
1136 
1137     let func = instance.get_typed_func::<(), ()>(&mut store, "foo")?;
1138     match store
1139         .run_concurrent(async move |accessor| {
1140             anyhow::Ok(func.call_concurrent(accessor, ()).await?.0)
1141         })
1142         .await
1143     {
1144         Ok(_) => panic!(),
1145         Err(e) => {
1146             assert!(
1147                 format!("{e:?}").contains(substring),
1148                 "could not find `{substring}` in `{e:?}`"
1149             )
1150         }
1151     }
1152 
1153     Ok(())
1154 }
1155 
1156 #[tokio::test]
1157 async fn many_parameters() -> Result<()> {
1158     test_many_parameters(false, false).await
1159 }
1160 
1161 #[tokio::test]
1162 async fn many_parameters_concurrent() -> Result<()> {
1163     test_many_parameters(false, true).await
1164 }
1165 
1166 #[tokio::test]
1167 async fn many_parameters_dynamic() -> Result<()> {
1168     test_many_parameters(true, false).await
1169 }
1170 
1171 #[tokio::test]
1172 async fn many_parameters_dynamic_concurrent() -> Result<()> {
1173     test_many_parameters(true, true).await
1174 }
1175 
1176 async fn test_many_parameters(dynamic: bool, concurrent: bool) -> Result<()> {
1177     let (body, async_opts) = if concurrent {
1178         (
1179             r#"
1180                     (call $task-return
1181                         (i32.const 0)
1182                         (i32.mul
1183                             (memory.size)
1184                             (i32.const 65536)
1185                         )
1186                         (local.get 0)
1187                     )
1188 
1189                     (i32.const 0)
1190             "#,
1191             r#"async (callback (func $i "callback"))"#,
1192         )
1193     } else {
1194         (
1195             r#"
1196                     (local $base i32)
1197 
1198                     ;; Allocate space for the return
1199                     (local.set $base
1200                         (call $realloc
1201                             (i32.const 0)
1202                             (i32.const 0)
1203                             (i32.const 4)
1204                             (i32.const 12)))
1205 
1206                     ;; Store the pointer/length of the entire linear memory
1207                     ;; so we have access to everything.
1208                     (i32.store offset=0
1209                         (local.get $base)
1210                         (i32.const 0))
1211                     (i32.store offset=4
1212                         (local.get $base)
1213                         (i32.mul
1214                             (memory.size)
1215                             (i32.const 65536)))
1216 
1217                     ;; And also store our pointer parameter
1218                     (i32.store offset=8
1219                         (local.get $base)
1220                         (local.get 0))
1221 
1222                     (local.get $base)
1223             "#,
1224             "",
1225         )
1226     };
1227 
1228     let component = format!(
1229         r#"(component
1230             (core module $libc
1231                 (memory (export "memory") 1)
1232 
1233                 {REALLOC_AND_FREE}
1234             )
1235             (core instance $libc (instantiate $libc))
1236             (core module $m
1237                 (import "libc" "memory" (memory 1))
1238                 (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
1239                 (import "" "task.return" (func $task-return (param i32 i32 i32)))
1240                 (func (export "foo") (param i32) (result i32)
1241                     {body}
1242                 )
1243                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
1244             )
1245             (type $tuple (tuple (list u8) u32))
1246             (core func $task-return (canon task.return
1247                 (result $tuple)
1248                 (memory $libc "memory")
1249             ))
1250             (core instance $i (instantiate $m
1251                 (with "" (instance (export "task.return" (func $task-return))))
1252                 (with "libc" (instance $libc))
1253             ))
1254 
1255             (type $t (func
1256                 (param "p1" s8)              ;; offset  0, size 1
1257                 (param "p2" u64)             ;; offset  8, size 8
1258                 (param "p3" float32)         ;; offset 16, size 4
1259                 (param "p4" u8)              ;; offset 20, size 1
1260                 (param "p5" s16)             ;; offset 22, size 2
1261                 (param "p6" string)          ;; offset 24, size 8
1262                 (param "p7" (list u32))      ;; offset 32, size 8
1263                 (param "p8" bool)            ;; offset 40, size 1
1264                 (param "p9" bool)            ;; offset 41, size 1
1265                 (param "p0" char)            ;; offset 44, size 4
1266                 (param "pa" (list bool))     ;; offset 48, size 8
1267                 (param "pb" (list char))     ;; offset 56, size 8
1268                 (param "pc" (list string))   ;; offset 64, size 8
1269 
1270                 (result $tuple)
1271             ))
1272             (func (export "many-param") (type $t)
1273                 (canon lift
1274                     (core func $i "foo")
1275                     (memory $libc "memory")
1276                     (realloc (func $libc "realloc"))
1277                     {async_opts}
1278                 )
1279             )
1280         )"#
1281     );
1282 
1283     let mut config = Config::new();
1284     config.wasm_component_model_async(true);
1285     config.async_support(true);
1286     let engine = &Engine::new(&config)?;
1287     let component = Component::new(&engine, component)?;
1288     let mut store = Store::new(&engine, ());
1289 
1290     let instance = Linker::new(&engine)
1291         .instantiate_async(&mut store, &component)
1292         .await?;
1293 
1294     let input = (
1295         -100,
1296         u64::MAX / 2,
1297         f32::from_bits(CANON_32BIT_NAN | 1),
1298         38,
1299         18831,
1300         "this is the first string",
1301         [1, 2, 3, 4, 5, 6, 7, 8].as_slice(),
1302         true,
1303         false,
1304         '��',
1305         [false, true, false, true, true].as_slice(),
1306         ['��', '��', '��', '��', '��'].as_slice(),
1307         [
1308             "the quick",
1309             "brown fox",
1310             "was too lazy",
1311             "to jump over the dog",
1312             "what a demanding dog",
1313         ]
1314         .as_slice(),
1315     );
1316 
1317     let (memory, pointer) = if dynamic {
1318         let input = vec![
1319             Val::S8(input.0),
1320             Val::U64(input.1),
1321             Val::Float32(input.2),
1322             Val::U8(input.3),
1323             Val::S16(input.4),
1324             Val::String(input.5.into()),
1325             Val::List(input.6.iter().copied().map(Val::U32).collect()),
1326             Val::Bool(input.7),
1327             Val::Bool(input.8),
1328             Val::Char(input.9),
1329             Val::List(input.10.iter().copied().map(Val::Bool).collect()),
1330             Val::List(input.11.iter().copied().map(Val::Char).collect()),
1331             Val::List(input.12.iter().map(|&s| Val::String(s.into())).collect()),
1332         ];
1333         let func = instance.get_func(&mut store, "many-param").unwrap();
1334 
1335         let mut results = vec![Val::Bool(false)];
1336         if concurrent {
1337             store
1338                 .run_concurrent(async |store| {
1339                     func.call_concurrent(store, &input, &mut results).await?;
1340                     anyhow::Ok(())
1341                 })
1342                 .await??;
1343         } else {
1344             func.call_async(&mut store, &input, &mut results).await?;
1345         };
1346         let mut results = results.into_iter();
1347         let Some(Val::Tuple(results)) = results.next() else {
1348             panic!()
1349         };
1350         let mut results = results.into_iter();
1351         let Some(Val::List(memory)) = results.next() else {
1352             panic!()
1353         };
1354         let Some(Val::U32(pointer)) = results.next() else {
1355             panic!()
1356         };
1357         (
1358             memory
1359                 .into_iter()
1360                 .map(|v| if let Val::U8(v) = v { v } else { panic!() })
1361                 .collect(),
1362             pointer,
1363         )
1364     } else {
1365         let func = instance.get_typed_func::<(
1366             i8,
1367             u64,
1368             f32,
1369             u8,
1370             i16,
1371             &str,
1372             &[u32],
1373             bool,
1374             bool,
1375             char,
1376             &[bool],
1377             &[char],
1378             &[&str],
1379         ), ((Vec<u8>, u32),)>(&mut store, "many-param")?;
1380 
1381         if concurrent {
1382             store
1383                 .run_concurrent(async move |accessor| {
1384                     anyhow::Ok(func.call_concurrent(accessor, input).await?.0)
1385                 })
1386                 .await??
1387                 .0
1388         } else {
1389             func.call_async(&mut store, input).await?.0
1390         }
1391     };
1392     let memory = &memory[..];
1393 
1394     let mut actual = &memory[pointer as usize..][..72];
1395     assert_eq!(i8::from_le_bytes(*actual.take_n::<1>()), input.0);
1396     actual.skip::<7>();
1397     assert_eq!(u64::from_le_bytes(*actual.take_n::<8>()), input.1);
1398     assert_eq!(
1399         u32::from_le_bytes(*actual.take_n::<4>()),
1400         CANON_32BIT_NAN | 1
1401     );
1402     assert_eq!(u8::from_le_bytes(*actual.take_n::<1>()), input.3);
1403     actual.skip::<1>();
1404     assert_eq!(i16::from_le_bytes(*actual.take_n::<2>()), input.4);
1405     assert_eq!(actual.ptr_len(memory, 1), input.5.as_bytes());
1406     let mut mem = actual.ptr_len(memory, 4);
1407     for expected in input.6.iter() {
1408         assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected);
1409     }
1410     assert!(mem.is_empty());
1411     assert_eq!(actual.take_n::<1>(), &[input.7 as u8]);
1412     assert_eq!(actual.take_n::<1>(), &[input.8 as u8]);
1413     actual.skip::<2>();
1414     assert_eq!(u32::from_le_bytes(*actual.take_n::<4>()), input.9 as u32);
1415 
1416     // (list bool)
1417     mem = actual.ptr_len(memory, 1);
1418     for expected in input.10.iter() {
1419         assert_eq!(mem.take_n::<1>(), &[*expected as u8]);
1420     }
1421     assert!(mem.is_empty());
1422 
1423     // (list char)
1424     mem = actual.ptr_len(memory, 4);
1425     for expected in input.11.iter() {
1426         assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected as u32);
1427     }
1428     assert!(mem.is_empty());
1429 
1430     // (list string)
1431     mem = actual.ptr_len(memory, 8);
1432     for expected in input.12.iter() {
1433         let actual = mem.ptr_len(memory, 1);
1434         assert_eq!(actual, expected.as_bytes());
1435     }
1436     assert!(mem.is_empty());
1437     assert!(actual.is_empty());
1438 
1439     Ok(())
1440 }
1441 
1442 #[tokio::test]
1443 async fn many_results() -> Result<()> {
1444     test_many_results(false, false).await
1445 }
1446 
1447 #[tokio::test]
1448 async fn many_results_concurrent() -> Result<()> {
1449     test_many_results(false, true).await
1450 }
1451 
1452 #[tokio::test]
1453 async fn many_results_dynamic() -> Result<()> {
1454     test_many_results(true, false).await
1455 }
1456 
1457 #[tokio::test]
1458 async fn many_results_dynamic_concurrent() -> Result<()> {
1459     test_many_results(true, true).await
1460 }
1461 
1462 async fn test_many_results(dynamic: bool, concurrent: bool) -> Result<()> {
1463     let (ret, async_opts) = if concurrent {
1464         (
1465             r#"
1466                    call $task-return
1467                    i32.const 0
1468             "#,
1469             r#"async (callback (func $i "callback"))"#,
1470         )
1471     } else {
1472         ("", "")
1473     };
1474 
1475     let my_nan = CANON_32BIT_NAN | 1;
1476 
1477     let component = format!(
1478         r#"(component
1479             (core module $libc
1480                 (memory (export "memory") 1)
1481 
1482                 {REALLOC_AND_FREE}
1483             )
1484             (core instance $libc (instantiate $libc))
1485             (core module $m
1486                 (import "libc" "memory" (memory 1))
1487                 (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
1488                 (import "" "task.return" (func $task-return (param i32)))
1489                 (func (export "foo") (result i32)
1490                     (local $base i32)
1491                     (local $string i32)
1492                     (local $list i32)
1493 
1494                     (local.set $base
1495                         (call $realloc
1496                             (i32.const 0)
1497                             (i32.const 0)
1498                             (i32.const 8)
1499                             (i32.const 72)))
1500 
1501                     (i32.store8 offset=0
1502                         (local.get $base)
1503                         (i32.const -100))
1504 
1505                     (i64.store offset=8
1506                         (local.get $base)
1507                         (i64.const 9223372036854775807))
1508 
1509                     (f32.store offset=16
1510                         (local.get $base)
1511                         (f32.reinterpret_i32 (i32.const {my_nan})))
1512 
1513                     (i32.store8 offset=20
1514                         (local.get $base)
1515                         (i32.const 38))
1516 
1517                     (i32.store16 offset=22
1518                         (local.get $base)
1519                         (i32.const 18831))
1520 
1521                     (local.set $string
1522                         (call $realloc
1523                             (i32.const 0)
1524                             (i32.const 0)
1525                             (i32.const 1)
1526                             (i32.const 6)))
1527 
1528                     (i32.store8 offset=0
1529                         (local.get $string)
1530                         (i32.const 97)) ;; 'a'
1531                     (i32.store8 offset=1
1532                         (local.get $string)
1533                         (i32.const 98)) ;; 'b'
1534                     (i32.store8 offset=2
1535                         (local.get $string)
1536                         (i32.const 99)) ;; 'c'
1537                     (i32.store8 offset=3
1538                         (local.get $string)
1539                         (i32.const 100)) ;; 'd'
1540                     (i32.store8 offset=4
1541                         (local.get $string)
1542                         (i32.const 101)) ;; 'e'
1543                     (i32.store8 offset=5
1544                         (local.get $string)
1545                         (i32.const 102)) ;; 'f'
1546 
1547                     (i32.store offset=24
1548                         (local.get $base)
1549                         (local.get $string))
1550 
1551                     (i32.store offset=28
1552                         (local.get $base)
1553                         (i32.const 2))
1554 
1555                     (local.set $list
1556                         (call $realloc
1557                             (i32.const 0)
1558                             (i32.const 0)
1559                             (i32.const 4)
1560                             (i32.const 32)))
1561 
1562                     (i32.store offset=0
1563                         (local.get $list)
1564                         (i32.const 1))
1565                     (i32.store offset=4
1566                         (local.get $list)
1567                         (i32.const 2))
1568                     (i32.store offset=8
1569                         (local.get $list)
1570                         (i32.const 3))
1571                     (i32.store offset=12
1572                         (local.get $list)
1573                         (i32.const 4))
1574                     (i32.store offset=16
1575                         (local.get $list)
1576                         (i32.const 5))
1577                     (i32.store offset=20
1578                         (local.get $list)
1579                         (i32.const 6))
1580                     (i32.store offset=24
1581                         (local.get $list)
1582                         (i32.const 7))
1583                     (i32.store offset=28
1584                         (local.get $list)
1585                         (i32.const 8))
1586 
1587                     (i32.store offset=32
1588                         (local.get $base)
1589                         (local.get $list))
1590 
1591                     (i32.store offset=36
1592                         (local.get $base)
1593                         (i32.const 8))
1594 
1595                     (i32.store8 offset=40
1596                         (local.get $base)
1597                         (i32.const 1))
1598 
1599                     (i32.store8 offset=41
1600                         (local.get $base)
1601                         (i32.const 0))
1602 
1603                     (i32.store offset=44
1604                         (local.get $base)
1605                         (i32.const 128681)) ;; '��'
1606 
1607                     (local.set $list
1608                         (call $realloc
1609                             (i32.const 0)
1610                             (i32.const 0)
1611                             (i32.const 1)
1612                             (i32.const 5)))
1613 
1614                     (i32.store8 offset=0
1615                         (local.get $list)
1616                         (i32.const 0))
1617                     (i32.store8 offset=1
1618                         (local.get $list)
1619                         (i32.const 1))
1620                     (i32.store8 offset=2
1621                         (local.get $list)
1622                         (i32.const 0))
1623                     (i32.store8 offset=3
1624                         (local.get $list)
1625                         (i32.const 1))
1626                     (i32.store8 offset=4
1627                         (local.get $list)
1628                         (i32.const 1))
1629 
1630                     (i32.store offset=48
1631                         (local.get $base)
1632                         (local.get $list))
1633 
1634                     (i32.store offset=52
1635                         (local.get $base)
1636                         (i32.const 5))
1637 
1638                     (local.set $list
1639                         (call $realloc
1640                             (i32.const 0)
1641                             (i32.const 0)
1642                             (i32.const 4)
1643                             (i32.const 20)))
1644 
1645                     (i32.store offset=0
1646                         (local.get $list)
1647                         (i32.const 127820)) ;; '��'
1648                     (i32.store offset=4
1649                         (local.get $list)
1650                         (i32.const 129360)) ;; '��'
1651                     (i32.store offset=8
1652                         (local.get $list)
1653                         (i32.const 127831)) ;; '��'
1654                     (i32.store offset=12
1655                         (local.get $list)
1656                         (i32.const 127833)) ;; '��'
1657                     (i32.store offset=16
1658                         (local.get $list)
1659                         (i32.const 127841)) ;; '��'
1660 
1661                     (i32.store offset=56
1662                         (local.get $base)
1663                         (local.get $list))
1664 
1665                     (i32.store offset=60
1666                         (local.get $base)
1667                         (i32.const 5))
1668 
1669                     (local.set $list
1670                         (call $realloc
1671                             (i32.const 0)
1672                             (i32.const 0)
1673                             (i32.const 4)
1674                             (i32.const 16)))
1675 
1676                     (i32.store offset=0
1677                         (local.get $list)
1678                         (i32.add (local.get $string) (i32.const 2)))
1679                     (i32.store offset=4
1680                         (local.get $list)
1681                         (i32.const 2))
1682                     (i32.store offset=8
1683                         (local.get $list)
1684                         (i32.add (local.get $string) (i32.const 4)))
1685                     (i32.store offset=12
1686                         (local.get $list)
1687                         (i32.const 2))
1688 
1689                     (i32.store offset=64
1690                         (local.get $base)
1691                         (local.get $list))
1692 
1693                     (i32.store offset=68
1694                         (local.get $base)
1695                         (i32.const 2))
1696 
1697                     local.get $base
1698 
1699                     {ret}
1700                 )
1701                 (func (export "callback") (param i32 i32 i32) (result i32) unreachable)
1702             )
1703             (type $tuple (tuple
1704                 s8
1705                 u64
1706                 float32
1707                 u8
1708                 s16
1709                 string
1710                 (list u32)
1711                 bool
1712                 bool
1713                 char
1714                 (list bool)
1715                 (list char)
1716                 (list string)
1717             ))
1718             (core func $task-return (canon task.return
1719                 (result $tuple)
1720                 (memory $libc "memory")
1721             ))
1722             (core instance $i (instantiate $m
1723                 (with "" (instance (export "task.return" (func $task-return))))
1724                 (with "libc" (instance $libc))
1725             ))
1726 
1727             (type $t (func (result $tuple)))
1728             (func (export "many-results") (type $t)
1729                 (canon lift
1730                     (core func $i "foo")
1731                     (memory $libc "memory")
1732                     (realloc (func $libc "realloc"))
1733                     {async_opts}
1734                 )
1735             )
1736         )"#
1737     );
1738 
1739     let mut config = Config::new();
1740     config.wasm_component_model_async(true);
1741     config.async_support(true);
1742     let engine = &Engine::new(&config)?;
1743     let component = Component::new(&engine, component)?;
1744     let mut store = Store::new(&engine, ());
1745 
1746     let instance = Linker::new(&engine)
1747         .instantiate_async(&mut store, &component)
1748         .await?;
1749 
1750     let expected = (
1751         -100i8,
1752         u64::MAX / 2,
1753         f32::from_bits(CANON_32BIT_NAN | 1),
1754         38u8,
1755         18831i16,
1756         "ab".to_string(),
1757         vec![1u32, 2, 3, 4, 5, 6, 7, 8],
1758         true,
1759         false,
1760         '��',
1761         vec![false, true, false, true, true],
1762         vec!['��', '��', '��', '��', '��'],
1763         vec!["cd".to_string(), "ef".to_string()],
1764     );
1765 
1766     let actual = if dynamic {
1767         let func = instance.get_func(&mut store, "many-results").unwrap();
1768 
1769         let mut results = vec![Val::Bool(false)];
1770         if concurrent {
1771             store
1772                 .run_concurrent(async |store| {
1773                     func.call_concurrent(store, &[], &mut results).await?;
1774                     anyhow::Ok(())
1775                 })
1776                 .await??;
1777         } else {
1778             func.call_async(&mut store, &[], &mut results).await?;
1779         };
1780         let mut results = results.into_iter();
1781 
1782         let Some(Val::Tuple(results)) = results.next() else {
1783             panic!()
1784         };
1785         let mut results = results.into_iter();
1786         let Some(Val::S8(p1)) = results.next() else {
1787             panic!()
1788         };
1789         let Some(Val::U64(p2)) = results.next() else {
1790             panic!()
1791         };
1792         let Some(Val::Float32(p3)) = results.next() else {
1793             panic!()
1794         };
1795         let Some(Val::U8(p4)) = results.next() else {
1796             panic!()
1797         };
1798         let Some(Val::S16(p5)) = results.next() else {
1799             panic!()
1800         };
1801         let Some(Val::String(p6)) = results.next() else {
1802             panic!()
1803         };
1804         let Some(Val::List(p7)) = results.next() else {
1805             panic!()
1806         };
1807         let p7 = p7
1808             .into_iter()
1809             .map(|v| if let Val::U32(v) = v { v } else { panic!() })
1810             .collect();
1811         let Some(Val::Bool(p8)) = results.next() else {
1812             panic!()
1813         };
1814         let Some(Val::Bool(p9)) = results.next() else {
1815             panic!()
1816         };
1817         let Some(Val::Char(p0)) = results.next() else {
1818             panic!()
1819         };
1820         let Some(Val::List(pa)) = results.next() else {
1821             panic!()
1822         };
1823         let pa = pa
1824             .into_iter()
1825             .map(|v| if let Val::Bool(v) = v { v } else { panic!() })
1826             .collect();
1827         let Some(Val::List(pb)) = results.next() else {
1828             panic!()
1829         };
1830         let pb = pb
1831             .into_iter()
1832             .map(|v| if let Val::Char(v) = v { v } else { panic!() })
1833             .collect();
1834         let Some(Val::List(pc)) = results.next() else {
1835             panic!()
1836         };
1837         let pc = pc
1838             .into_iter()
1839             .map(|v| if let Val::String(v) = v { v } else { panic!() })
1840             .collect();
1841 
1842         (p1, p2, p3, p4, p5, p6, p7, p8, p9, p0, pa, pb, pc)
1843     } else {
1844         let func = instance.get_typed_func::<(), ((
1845             i8,
1846             u64,
1847             f32,
1848             u8,
1849             i16,
1850             String,
1851             Vec<u32>,
1852             bool,
1853             bool,
1854             char,
1855             Vec<bool>,
1856             Vec<char>,
1857             Vec<String>,
1858         ),)>(&mut store, "many-results")?;
1859 
1860         if concurrent {
1861             store
1862                 .run_concurrent(async move |accessor| {
1863                     anyhow::Ok(func.call_concurrent(accessor, ()).await?.0)
1864                 })
1865                 .await??
1866                 .0
1867         } else {
1868             func.call_async(&mut store, ()).await?.0
1869         }
1870     };
1871 
1872     assert_eq!(expected.0, actual.0);
1873     assert_eq!(expected.1, actual.1);
1874     assert!(expected.2.is_nan());
1875     assert!(actual.2.is_nan());
1876     assert_eq!(expected.3, actual.3);
1877     assert_eq!(expected.4, actual.4);
1878     assert_eq!(expected.5, actual.5);
1879     assert_eq!(expected.6, actual.6);
1880     assert_eq!(expected.7, actual.7);
1881     assert_eq!(expected.8, actual.8);
1882     assert_eq!(expected.9, actual.9);
1883     assert_eq!(expected.10, actual.10);
1884     assert_eq!(expected.11, actual.11);
1885     assert_eq!(expected.12, actual.12);
1886 
1887     Ok(())
1888 }
1889 
1890 #[test]
1891 fn some_traps() -> Result<()> {
1892     let middle_of_memory = (i32::MAX / 2) & (!0xff);
1893     let component = format!(
1894         r#"(component
1895             (core module $m
1896                 (memory (export "memory") 1)
1897                 (func (export "take-many") (param i32))
1898                 (func (export "take-list") (param i32 i32))
1899 
1900                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1901                     unreachable)
1902             )
1903             (core instance $i (instantiate $m))
1904 
1905             (func (export "take-list-unreachable") (param "a" (list u8))
1906                 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc")))
1907             )
1908             (func (export "take-string-unreachable") (param "a" string)
1909                 (canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc")))
1910             )
1911 
1912             (type $t (func
1913                 (param "s1" string)
1914                 (param "s2" string)
1915                 (param "s3" string)
1916                 (param "s4" string)
1917                 (param "s5" string)
1918                 (param "s6" string)
1919                 (param "s7" string)
1920                 (param "s8" string)
1921                 (param "s9" string)
1922                 (param "s10" string)
1923             ))
1924             (func (export "take-many-unreachable") (type $t)
1925                 (canon lift (core func $i "take-many") (memory $i "memory") (realloc (func $i "realloc")))
1926             )
1927 
1928             (core module $m2
1929                 (memory (export "memory") 1)
1930                 (func (export "take-many") (param i32))
1931                 (func (export "take-list") (param i32 i32))
1932 
1933                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1934                     i32.const {middle_of_memory})
1935             )
1936             (core instance $i2 (instantiate $m2))
1937 
1938             (func (export "take-list-base-oob") (param "a" (list u8))
1939                 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1940             )
1941             (func (export "take-string-base-oob") (param "a" string)
1942                 (canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1943             )
1944             (func (export "take-many-base-oob") (type $t)
1945                 (canon lift (core func $i2 "take-many") (memory $i2 "memory") (realloc (func $i2 "realloc")))
1946             )
1947 
1948             (core module $m3
1949                 (memory (export "memory") 1)
1950                 (func (export "take-many") (param i32))
1951                 (func (export "take-list") (param i32 i32))
1952 
1953                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1954                     i32.const 65532)
1955             )
1956             (core instance $i3 (instantiate $m3))
1957 
1958             (func (export "take-list-end-oob") (param "a" (list u8))
1959                 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1960             )
1961             (func (export "take-string-end-oob") (param "a" string)
1962                 (canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1963             )
1964             (func (export "take-many-end-oob") (type $t)
1965                 (canon lift (core func $i3 "take-many") (memory $i3 "memory") (realloc (func $i3 "realloc")))
1966             )
1967 
1968             (core module $m4
1969                 (memory (export "memory") 1)
1970                 (func (export "take-many") (param i32))
1971 
1972                 (global $cnt (mut i32) (i32.const 0))
1973                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
1974                     global.get $cnt
1975                     if (result i32)
1976                         i32.const 100000
1977                     else
1978                         i32.const 1
1979                         global.set $cnt
1980                         i32.const 0
1981                     end
1982                 )
1983             )
1984             (core instance $i4 (instantiate $m4))
1985 
1986             (func (export "take-many-second-oob") (type $t)
1987                 (canon lift (core func $i4 "take-many") (memory $i4 "memory") (realloc (func $i4 "realloc")))
1988             )
1989         )"#
1990     );
1991 
1992     let engine = super::engine();
1993     let component = Component::new(&engine, component)?;
1994     let mut store = Store::new(&engine, ());
1995     let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component);
1996 
1997     // This should fail when calling the allocator function for the argument
1998     let err = instance(&mut store)?
1999         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-unreachable")?
2000         .call(&mut store, (&[],))
2001         .unwrap_err()
2002         .downcast::<Trap>()?;
2003     assert_eq!(err, Trap::UnreachableCodeReached);
2004 
2005     // This should fail when calling the allocator function for the argument
2006     let err = instance(&mut store)?
2007         .get_typed_func::<(&str,), ()>(&mut store, "take-string-unreachable")?
2008         .call(&mut store, ("",))
2009         .unwrap_err()
2010         .downcast::<Trap>()?;
2011     assert_eq!(err, Trap::UnreachableCodeReached);
2012 
2013     // This should fail when calling the allocator function for the space
2014     // to store the arguments (before arguments are even lowered)
2015     let err = instance(&mut store)?
2016         .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2017             &mut store,
2018             "take-many-unreachable",
2019         )?
2020         .call(&mut store, ("", "", "", "", "", "", "", "", "", ""))
2021         .unwrap_err()
2022         .downcast::<Trap>()?;
2023     assert_eq!(err, Trap::UnreachableCodeReached);
2024 
2025     // Assert that when the base pointer returned by malloc is out of bounds
2026     // that errors are reported as such. Both empty and lists with contents
2027     // should all be invalid here.
2028     //
2029     // FIXME(WebAssembly/component-model#32) confirm the semantics here are
2030     // what's desired.
2031     #[track_caller]
2032     fn assert_oob(err: &anyhow::Error) {
2033         assert!(
2034             err.to_string()
2035                 .contains("realloc return: beyond end of memory"),
2036             "{err:?}",
2037         );
2038     }
2039     let err = instance(&mut store)?
2040         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-base-oob")?
2041         .call(&mut store, (&[],))
2042         .unwrap_err();
2043     assert_oob(&err);
2044     let err = instance(&mut store)?
2045         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-base-oob")?
2046         .call(&mut store, (&[1],))
2047         .unwrap_err();
2048     assert_oob(&err);
2049     let err = instance(&mut store)?
2050         .get_typed_func::<(&str,), ()>(&mut store, "take-string-base-oob")?
2051         .call(&mut store, ("",))
2052         .unwrap_err();
2053     assert_oob(&err);
2054     let err = instance(&mut store)?
2055         .get_typed_func::<(&str,), ()>(&mut store, "take-string-base-oob")?
2056         .call(&mut store, ("x",))
2057         .unwrap_err();
2058     assert_oob(&err);
2059     let err = instance(&mut store)?
2060         .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2061             &mut store,
2062             "take-many-base-oob",
2063         )?
2064         .call(&mut store, ("", "", "", "", "", "", "", "", "", ""))
2065         .unwrap_err();
2066     assert_oob(&err);
2067 
2068     // Test here that when the returned pointer from malloc is one byte from the
2069     // end of memory that empty things are fine, but larger things are not.
2070 
2071     instance(&mut store)?
2072         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")?
2073         .call_and_post_return(&mut store, (&[],))?;
2074     instance(&mut store)?
2075         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")?
2076         .call_and_post_return(&mut store, (&[1, 2, 3, 4],))?;
2077     let err = instance(&mut store)?
2078         .get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")?
2079         .call(&mut store, (&[1, 2, 3, 4, 5],))
2080         .unwrap_err();
2081     assert_oob(&err);
2082     instance(&mut store)?
2083         .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")?
2084         .call_and_post_return(&mut store, ("",))?;
2085     instance(&mut store)?
2086         .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")?
2087         .call_and_post_return(&mut store, ("abcd",))?;
2088     let err = instance(&mut store)?
2089         .get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")?
2090         .call(&mut store, ("abcde",))
2091         .unwrap_err();
2092     assert_oob(&err);
2093     let err = instance(&mut store)?
2094         .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2095             &mut store,
2096             "take-many-end-oob",
2097         )?
2098         .call(&mut store, ("", "", "", "", "", "", "", "", "", ""))
2099         .unwrap_err();
2100     assert_oob(&err);
2101 
2102     // For this function the first allocation, the space to store all the
2103     // arguments, is in-bounds but then all further allocations, such as for
2104     // each individual string, are all out of bounds.
2105     let err = instance(&mut store)?
2106         .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2107             &mut store,
2108             "take-many-second-oob",
2109         )?
2110         .call(&mut store, ("", "", "", "", "", "", "", "", "", ""))
2111         .unwrap_err();
2112     assert_oob(&err);
2113     let err = instance(&mut store)?
2114         .get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(
2115             &mut store,
2116             "take-many-second-oob",
2117         )?
2118         .call(&mut store, ("", "", "", "", "", "", "", "", "", "x"))
2119         .unwrap_err();
2120     assert_oob(&err);
2121     Ok(())
2122 }
2123 
2124 #[test]
2125 fn char_bool_memory() -> Result<()> {
2126     let component = format!(
2127         r#"(component
2128             (core module $m
2129                 (memory (export "memory") 1)
2130                 (func (export "ret-tuple") (param i32 i32) (result i32)
2131                     (local $base i32)
2132 
2133                     ;; Allocate space for the return
2134                     (local.set $base
2135                         (call $realloc
2136                             (i32.const 0)
2137                             (i32.const 0)
2138                             (i32.const 4)
2139                             (i32.const 8)))
2140 
2141                     ;; store the boolean
2142                     (i32.store offset=0
2143                         (local.get $base)
2144                         (local.get 0))
2145 
2146                     ;; store the char
2147                     (i32.store offset=4
2148                         (local.get $base)
2149                         (local.get 1))
2150 
2151                     (local.get $base)
2152                 )
2153 
2154                 {REALLOC_AND_FREE}
2155             )
2156             (core instance $i (instantiate $m))
2157 
2158             (func (export "ret-tuple") (param "a" u32) (param "b" u32) (result (tuple bool char))
2159                 (canon lift (core func $i "ret-tuple")
2160                     (memory $i "memory")
2161                     (realloc (func $i "realloc")))
2162             )
2163         )"#
2164     );
2165 
2166     let engine = super::engine();
2167     let component = Component::new(&engine, component)?;
2168     let mut store = Store::new(&engine, ());
2169     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2170     let func = instance.get_typed_func::<(u32, u32), ((bool, char),)>(&mut store, "ret-tuple")?;
2171 
2172     let (ret,) = func.call(&mut store, (0, 'a' as u32))?;
2173     assert_eq!(ret, (false, 'a'));
2174     func.post_return(&mut store)?;
2175 
2176     let (ret,) = func.call(&mut store, (1, '��' as u32))?;
2177     assert_eq!(ret, (true, '��'));
2178     func.post_return(&mut store)?;
2179 
2180     let (ret,) = func.call(&mut store, (2, 'a' as u32))?;
2181     assert_eq!(ret, (true, 'a'));
2182     func.post_return(&mut store)?;
2183 
2184     assert!(func.call(&mut store, (0, 0xd800)).is_err());
2185 
2186     Ok(())
2187 }
2188 
2189 #[test]
2190 fn string_list_oob() -> Result<()> {
2191     let component = format!(
2192         r#"(component
2193             (core module $m
2194                 (memory (export "memory") 1)
2195                 (func (export "ret-list") (result i32)
2196                     (local $base i32)
2197 
2198                     ;; Allocate space for the return
2199                     (local.set $base
2200                         (call $realloc
2201                             (i32.const 0)
2202                             (i32.const 0)
2203                             (i32.const 4)
2204                             (i32.const 8)))
2205 
2206                     (i32.store offset=0
2207                         (local.get $base)
2208                         (i32.const 100000))
2209                     (i32.store offset=4
2210                         (local.get $base)
2211                         (i32.const 1))
2212 
2213                     (local.get $base)
2214                 )
2215 
2216                 {REALLOC_AND_FREE}
2217             )
2218             (core instance $i (instantiate $m))
2219 
2220             (func (export "ret-list-u8") (result (list u8))
2221                 (canon lift (core func $i "ret-list")
2222                     (memory $i "memory")
2223                     (realloc (func $i "realloc"))
2224                 )
2225             )
2226             (func (export "ret-string") (result string)
2227                 (canon lift (core func $i "ret-list")
2228                     (memory $i "memory")
2229                     (realloc (func $i "realloc"))
2230                 )
2231             )
2232         )"#
2233     );
2234 
2235     let engine = super::engine();
2236     let component = Component::new(&engine, component)?;
2237     let mut store = Store::new(&engine, ());
2238     let ret_list_u8 = Linker::new(&engine)
2239         .instantiate(&mut store, &component)?
2240         .get_typed_func::<(), (WasmList<u8>,)>(&mut store, "ret-list-u8")?;
2241     let ret_string = Linker::new(&engine)
2242         .instantiate(&mut store, &component)?
2243         .get_typed_func::<(), (WasmStr,)>(&mut store, "ret-string")?;
2244 
2245     let err = ret_list_u8.call(&mut store, ()).err().unwrap();
2246     assert!(err.to_string().contains("out of bounds"), "{}", err);
2247 
2248     let err = ret_string.call(&mut store, ()).err().unwrap();
2249     assert!(err.to_string().contains("out of bounds"), "{}", err);
2250 
2251     Ok(())
2252 }
2253 
2254 #[test]
2255 fn tuples() -> Result<()> {
2256     let component = format!(
2257         r#"(component
2258             (core module $m
2259                 (memory (export "memory") 1)
2260                 (func (export "foo")
2261                     (param i32 f64 i32)
2262                     (result i32)
2263 
2264                     local.get 0
2265                     i32.const 0
2266                     i32.ne
2267                     if unreachable end
2268 
2269                     local.get 1
2270                     f64.const 1
2271                     f64.ne
2272                     if unreachable end
2273 
2274                     local.get 2
2275                     i32.const 2
2276                     i32.ne
2277                     if unreachable end
2278 
2279                     i32.const 3
2280                 )
2281             )
2282             (core instance $i (instantiate $m))
2283 
2284             (func (export "foo")
2285                 (param "a" (tuple s32 float64))
2286                 (param "b" (tuple s8))
2287                 (result (tuple u16))
2288                 (canon lift (core func $i "foo"))
2289             )
2290         )"#
2291     );
2292 
2293     let engine = super::engine();
2294     let component = Component::new(&engine, component)?;
2295     let mut store = Store::new(&engine, ());
2296     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2297     let foo = instance.get_typed_func::<((i32, f64), (i8,)), ((u16,),)>(&mut store, "foo")?;
2298     assert_eq!(foo.call(&mut store, ((0, 1.0), (2,)))?, ((3,),));
2299 
2300     Ok(())
2301 }
2302 
2303 #[test]
2304 fn option() -> Result<()> {
2305     let component = format!(
2306         r#"(component
2307             (core module $m
2308                 (memory (export "memory") 1)
2309                 (func (export "pass1") (param i32 i32) (result i32)
2310                     (local $base i32)
2311                     (local.set $base
2312                         (call $realloc
2313                             (i32.const 0)
2314                             (i32.const 0)
2315                             (i32.const 4)
2316                             (i32.const 8)))
2317 
2318                     (i32.store offset=0
2319                         (local.get $base)
2320                         (local.get 0))
2321                     (i32.store offset=4
2322                         (local.get $base)
2323                         (local.get 1))
2324 
2325                     (local.get $base)
2326                 )
2327                 (func (export "pass2") (param i32 i32 i32) (result i32)
2328                     (local $base i32)
2329                     (local.set $base
2330                         (call $realloc
2331                             (i32.const 0)
2332                             (i32.const 0)
2333                             (i32.const 4)
2334                             (i32.const 12)))
2335 
2336                     (i32.store offset=0
2337                         (local.get $base)
2338                         (local.get 0))
2339                     (i32.store offset=4
2340                         (local.get $base)
2341                         (local.get 1))
2342                     (i32.store offset=8
2343                         (local.get $base)
2344                         (local.get 2))
2345 
2346                     (local.get $base)
2347                 )
2348 
2349                 {REALLOC_AND_FREE}
2350             )
2351             (core instance $i (instantiate $m))
2352 
2353             (func (export "option-u8-to-tuple") (param "a" (option u8)) (result (tuple u32 u32))
2354                 (canon lift (core func $i "pass1") (memory $i "memory"))
2355             )
2356             (func (export "option-u32-to-tuple") (param "a" (option u32)) (result (tuple u32 u32))
2357                 (canon lift (core func $i "pass1") (memory $i "memory"))
2358             )
2359             (func (export "option-string-to-tuple") (param "a" (option string)) (result (tuple u32 string))
2360                 (canon lift
2361                     (core func $i "pass2")
2362                     (memory $i "memory")
2363                     (realloc (func $i "realloc"))
2364                 )
2365             )
2366             (func (export "to-option-u8") (param "a" u32) (param "b" u32) (result (option u8))
2367                 (canon lift (core func $i "pass1") (memory $i "memory"))
2368             )
2369             (func (export "to-option-u32") (param "a" u32) (param "b" u32) (result (option u32))
2370                 (canon lift
2371                     (core func $i "pass1")
2372                     (memory $i "memory")
2373                 )
2374             )
2375             (func (export "to-option-string") (param "a" u32) (param "b" string) (result (option string))
2376                 (canon lift
2377                     (core func $i "pass2")
2378                     (memory $i "memory")
2379                     (realloc (func $i "realloc"))
2380                 )
2381             )
2382         )"#
2383     );
2384 
2385     let engine = super::engine();
2386     let component = Component::new(&engine, component)?;
2387     let mut store = Store::new(&engine, ());
2388     let linker = Linker::new(&engine);
2389     let instance = linker.instantiate(&mut store, &component)?;
2390 
2391     let option_u8_to_tuple = instance
2392         .get_typed_func::<(Option<u8>,), ((u32, u32),)>(&mut store, "option-u8-to-tuple")?;
2393     assert_eq!(option_u8_to_tuple.call(&mut store, (None,))?, ((0, 0),));
2394     option_u8_to_tuple.post_return(&mut store)?;
2395     assert_eq!(option_u8_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),));
2396     option_u8_to_tuple.post_return(&mut store)?;
2397     assert_eq!(
2398         option_u8_to_tuple.call(&mut store, (Some(100),))?,
2399         ((1, 100),)
2400     );
2401     option_u8_to_tuple.post_return(&mut store)?;
2402 
2403     let option_u32_to_tuple = instance
2404         .get_typed_func::<(Option<u32>,), ((u32, u32),)>(&mut store, "option-u32-to-tuple")?;
2405     assert_eq!(option_u32_to_tuple.call(&mut store, (None,))?, ((0, 0),));
2406     option_u32_to_tuple.post_return(&mut store)?;
2407     assert_eq!(option_u32_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),));
2408     option_u32_to_tuple.post_return(&mut store)?;
2409     assert_eq!(
2410         option_u32_to_tuple.call(&mut store, (Some(100),))?,
2411         ((1, 100),)
2412     );
2413     option_u32_to_tuple.post_return(&mut store)?;
2414 
2415     let option_string_to_tuple = instance.get_typed_func::<(Option<&str>,), ((u32, WasmStr),)>(
2416         &mut store,
2417         "option-string-to-tuple",
2418     )?;
2419     let ((a, b),) = option_string_to_tuple.call(&mut store, (None,))?;
2420     assert_eq!(a, 0);
2421     assert_eq!(b.to_str(&store)?, "");
2422     option_string_to_tuple.post_return(&mut store)?;
2423     let ((a, b),) = option_string_to_tuple.call(&mut store, (Some(""),))?;
2424     assert_eq!(a, 1);
2425     assert_eq!(b.to_str(&store)?, "");
2426     option_string_to_tuple.post_return(&mut store)?;
2427     let ((a, b),) = option_string_to_tuple.call(&mut store, (Some("hello"),))?;
2428     assert_eq!(a, 1);
2429     assert_eq!(b.to_str(&store)?, "hello");
2430     option_string_to_tuple.post_return(&mut store)?;
2431 
2432     let instance = linker.instantiate(&mut store, &component)?;
2433     let to_option_u8 =
2434         instance.get_typed_func::<(u32, u32), (Option<u8>,)>(&mut store, "to-option-u8")?;
2435     assert_eq!(to_option_u8.call(&mut store, (0x00_00, 0))?, (None,));
2436     to_option_u8.post_return(&mut store)?;
2437     assert_eq!(to_option_u8.call(&mut store, (0x00_01, 0))?, (Some(0),));
2438     to_option_u8.post_return(&mut store)?;
2439     assert_eq!(to_option_u8.call(&mut store, (0xfd_01, 0))?, (Some(0xfd),));
2440     to_option_u8.post_return(&mut store)?;
2441     assert!(to_option_u8.call(&mut store, (0x00_02, 0)).is_err());
2442 
2443     let instance = linker.instantiate(&mut store, &component)?;
2444     let to_option_u32 =
2445         instance.get_typed_func::<(u32, u32), (Option<u32>,)>(&mut store, "to-option-u32")?;
2446     assert_eq!(to_option_u32.call(&mut store, (0, 0))?, (None,));
2447     to_option_u32.post_return(&mut store)?;
2448     assert_eq!(to_option_u32.call(&mut store, (1, 0))?, (Some(0),));
2449     to_option_u32.post_return(&mut store)?;
2450     assert_eq!(
2451         to_option_u32.call(&mut store, (1, 0x1234fead))?,
2452         (Some(0x1234fead),)
2453     );
2454     to_option_u32.post_return(&mut store)?;
2455     assert!(to_option_u32.call(&mut store, (2, 0)).is_err());
2456 
2457     let instance = linker.instantiate(&mut store, &component)?;
2458     let to_option_string = instance
2459         .get_typed_func::<(u32, &str), (Option<WasmStr>,)>(&mut store, "to-option-string")?;
2460     let ret = to_option_string.call(&mut store, (0, ""))?.0;
2461     assert!(ret.is_none());
2462     to_option_string.post_return(&mut store)?;
2463     let ret = to_option_string.call(&mut store, (1, ""))?.0;
2464     assert_eq!(ret.unwrap().to_str(&store)?, "");
2465     to_option_string.post_return(&mut store)?;
2466     let ret = to_option_string.call(&mut store, (1, "cheesecake"))?.0;
2467     assert_eq!(ret.unwrap().to_str(&store)?, "cheesecake");
2468     to_option_string.post_return(&mut store)?;
2469     assert!(to_option_string.call(&mut store, (2, "")).is_err());
2470 
2471     Ok(())
2472 }
2473 
2474 #[test]
2475 fn expected() -> Result<()> {
2476     let component = format!(
2477         r#"(component
2478             (core module $m
2479                 (memory (export "memory") 1)
2480                 (func (export "pass0") (param i32) (result i32)
2481                     local.get 0
2482                 )
2483                 (func (export "pass1") (param i32 i32) (result i32)
2484                     (local $base i32)
2485                     (local.set $base
2486                         (call $realloc
2487                             (i32.const 0)
2488                             (i32.const 0)
2489                             (i32.const 4)
2490                             (i32.const 8)))
2491 
2492                     (i32.store offset=0
2493                         (local.get $base)
2494                         (local.get 0))
2495                     (i32.store offset=4
2496                         (local.get $base)
2497                         (local.get 1))
2498 
2499                     (local.get $base)
2500                 )
2501                 (func (export "pass2") (param i32 i32 i32) (result i32)
2502                     (local $base i32)
2503                     (local.set $base
2504                         (call $realloc
2505                             (i32.const 0)
2506                             (i32.const 0)
2507                             (i32.const 4)
2508                             (i32.const 12)))
2509 
2510                     (i32.store offset=0
2511                         (local.get $base)
2512                         (local.get 0))
2513                     (i32.store offset=4
2514                         (local.get $base)
2515                         (local.get 1))
2516                     (i32.store offset=8
2517                         (local.get $base)
2518                         (local.get 2))
2519 
2520                     (local.get $base)
2521                 )
2522 
2523                 {REALLOC_AND_FREE}
2524             )
2525             (core instance $i (instantiate $m))
2526 
2527             (func (export "take-expected-unit") (param "a" (result)) (result u32)
2528                 (canon lift (core func $i "pass0"))
2529             )
2530             (func (export "take-expected-u8-f32") (param "a" (result u8 (error float32))) (result (tuple u32 u32))
2531                 (canon lift (core func $i "pass1") (memory $i "memory"))
2532             )
2533             (type $list (list u8))
2534             (func (export "take-expected-string") (param "a" (result string (error $list))) (result (tuple u32 string))
2535                 (canon lift
2536                     (core func $i "pass2")
2537                     (memory $i "memory")
2538                     (realloc (func $i "realloc"))
2539                 )
2540             )
2541             (func (export "to-expected-unit") (param "a" u32) (result (result))
2542                 (canon lift (core func $i "pass0"))
2543             )
2544             (func (export "to-expected-s16-f32") (param "a" u32) (param "b" u32) (result (result s16 (error float32)))
2545                 (canon lift
2546                     (core func $i "pass1")
2547                     (memory $i "memory")
2548                     (realloc (func $i "realloc"))
2549                 )
2550             )
2551         )"#
2552     );
2553 
2554     let engine = super::engine();
2555     let component = Component::new(&engine, component)?;
2556     let mut store = Store::new(&engine, ());
2557     let linker = Linker::new(&engine);
2558     let instance = linker.instantiate(&mut store, &component)?;
2559     let take_expected_unit =
2560         instance.get_typed_func::<(Result<(), ()>,), (u32,)>(&mut store, "take-expected-unit")?;
2561     assert_eq!(take_expected_unit.call(&mut store, (Ok(()),))?, (0,));
2562     take_expected_unit.post_return(&mut store)?;
2563     assert_eq!(take_expected_unit.call(&mut store, (Err(()),))?, (1,));
2564     take_expected_unit.post_return(&mut store)?;
2565 
2566     let take_expected_u8_f32 = instance
2567         .get_typed_func::<(Result<u8, f32>,), ((u32, u32),)>(&mut store, "take-expected-u8-f32")?;
2568     assert_eq!(take_expected_u8_f32.call(&mut store, (Ok(1),))?, ((0, 1),));
2569     take_expected_u8_f32.post_return(&mut store)?;
2570     assert_eq!(
2571         take_expected_u8_f32.call(&mut store, (Err(2.0),))?,
2572         ((1, 2.0f32.to_bits()),)
2573     );
2574     take_expected_u8_f32.post_return(&mut store)?;
2575 
2576     let take_expected_string = instance
2577         .get_typed_func::<(Result<&str, &[u8]>,), ((u32, WasmStr),)>(
2578             &mut store,
2579             "take-expected-string",
2580         )?;
2581     let ((a, b),) = take_expected_string.call(&mut store, (Ok("hello"),))?;
2582     assert_eq!(a, 0);
2583     assert_eq!(b.to_str(&store)?, "hello");
2584     take_expected_string.post_return(&mut store)?;
2585     let ((a, b),) = take_expected_string.call(&mut store, (Err(b"goodbye"),))?;
2586     assert_eq!(a, 1);
2587     assert_eq!(b.to_str(&store)?, "goodbye");
2588     take_expected_string.post_return(&mut store)?;
2589 
2590     let instance = linker.instantiate(&mut store, &component)?;
2591     let to_expected_unit =
2592         instance.get_typed_func::<(u32,), (Result<(), ()>,)>(&mut store, "to-expected-unit")?;
2593     assert_eq!(to_expected_unit.call(&mut store, (0,))?, (Ok(()),));
2594     to_expected_unit.post_return(&mut store)?;
2595     assert_eq!(to_expected_unit.call(&mut store, (1,))?, (Err(()),));
2596     to_expected_unit.post_return(&mut store)?;
2597     let err = to_expected_unit.call(&mut store, (2,)).unwrap_err();
2598     assert!(err.to_string().contains("invalid expected"), "{}", err);
2599 
2600     let instance = linker.instantiate(&mut store, &component)?;
2601     let to_expected_s16_f32 = instance
2602         .get_typed_func::<(u32, u32), (Result<i16, f32>,)>(&mut store, "to-expected-s16-f32")?;
2603     assert_eq!(to_expected_s16_f32.call(&mut store, (0, 0))?, (Ok(0),));
2604     to_expected_s16_f32.post_return(&mut store)?;
2605     assert_eq!(to_expected_s16_f32.call(&mut store, (0, 100))?, (Ok(100),));
2606     to_expected_s16_f32.post_return(&mut store)?;
2607     assert_eq!(
2608         to_expected_s16_f32.call(&mut store, (1, 1.0f32.to_bits()))?,
2609         (Err(1.0),)
2610     );
2611     to_expected_s16_f32.post_return(&mut store)?;
2612     let ret = to_expected_s16_f32
2613         .call(&mut store, (1, CANON_32BIT_NAN | 1))?
2614         .0;
2615     assert_eq!(ret.unwrap_err().to_bits(), CANON_32BIT_NAN | 1);
2616     to_expected_s16_f32.post_return(&mut store)?;
2617     assert!(to_expected_s16_f32.call(&mut store, (2, 0)).is_err());
2618 
2619     Ok(())
2620 }
2621 
2622 #[test]
2623 fn fancy_list() -> Result<()> {
2624     let component = format!(
2625         r#"(component
2626             (core module $m
2627                 (memory (export "memory") 1)
2628                 (func (export "take") (param i32 i32) (result i32)
2629                     (local $base i32)
2630                     (local.set $base
2631                         (call $realloc
2632                             (i32.const 0)
2633                             (i32.const 0)
2634                             (i32.const 4)
2635                             (i32.const 16)))
2636 
2637                     (i32.store offset=0
2638                         (local.get $base)
2639                         (local.get 0))
2640                     (i32.store offset=4
2641                         (local.get $base)
2642                         (local.get 1))
2643                     (i32.store offset=8
2644                         (local.get $base)
2645                         (i32.const 0))
2646                     (i32.store offset=12
2647                         (local.get $base)
2648                         (i32.mul
2649                             (memory.size)
2650                             (i32.const 65536)))
2651 
2652                     (local.get $base)
2653                 )
2654 
2655                 {REALLOC_AND_FREE}
2656             )
2657             (core instance $i (instantiate $m))
2658 
2659             (type $a (option u8))
2660             (type $b (result (error string)))
2661             (type $input (list (tuple $a $b)))
2662             (func (export "take")
2663                 (param "a" $input)
2664                 (result (tuple u32 u32 (list u8)))
2665                 (canon lift
2666                     (core func $i "take")
2667                     (memory $i "memory")
2668                     (realloc (func $i "realloc"))
2669                 )
2670             )
2671         )"#
2672     );
2673 
2674     let engine = super::engine();
2675     let component = Component::new(&engine, component)?;
2676     let mut store = Store::new(&engine, ());
2677     let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2678 
2679     let func = instance
2680         .get_typed_func::<(&[(Option<u8>, Result<(), &str>)],), ((u32, u32, WasmList<u8>),)>(
2681             &mut store, "take",
2682         )?;
2683 
2684     let input = [
2685         (None, Ok(())),
2686         (Some(2), Err("hello there")),
2687         (Some(200), Err("general kenobi")),
2688     ];
2689     let ((ptr, len, list),) = func.call(&mut store, (&input,))?;
2690     let memory = list.as_le_slice(&store);
2691     let ptr = usize::try_from(ptr).unwrap();
2692     let len = usize::try_from(len).unwrap();
2693     let mut array = &memory[ptr..][..len * 16];
2694 
2695     for (a, b) in input.iter() {
2696         match a {
2697             Some(val) => {
2698                 assert_eq!(*array.take_n::<2>(), [1, *val]);
2699             }
2700             None => {
2701                 assert_eq!(*array.take_n::<1>(), [0]);
2702                 array.skip::<1>();
2703             }
2704         }
2705         array.skip::<2>();
2706         match b {
2707             Ok(()) => {
2708                 assert_eq!(*array.take_n::<1>(), [0]);
2709                 array.skip::<11>();
2710             }
2711             Err(s) => {
2712                 assert_eq!(*array.take_n::<1>(), [1]);
2713                 array.skip::<3>();
2714                 assert_eq!(array.ptr_len(memory, 1), s.as_bytes());
2715             }
2716         }
2717     }
2718     assert!(array.is_empty());
2719 
2720     Ok(())
2721 }
2722 
2723 trait SliceExt<'a> {
2724     fn take_n<const N: usize>(&mut self) -> &'a [u8; N];
2725 
2726     fn skip<const N: usize>(&mut self) {
2727         self.take_n::<N>();
2728     }
2729 
2730     fn ptr_len<'b>(&mut self, all_memory: &'b [u8], size: usize) -> &'b [u8] {
2731         let ptr = u32::from_le_bytes(*self.take_n::<4>());
2732         let len = u32::from_le_bytes(*self.take_n::<4>());
2733         let ptr = usize::try_from(ptr).unwrap();
2734         let len = usize::try_from(len).unwrap();
2735         &all_memory[ptr..][..len * size]
2736     }
2737 }
2738 
2739 impl<'a> SliceExt<'a> for &'a [u8] {
2740     fn take_n<const N: usize>(&mut self) -> &'a [u8; N] {
2741         let (a, b) = self.split_at(N);
2742         *self = b;
2743         a.try_into().unwrap()
2744     }
2745 }
2746 
2747 #[test]
2748 fn invalid_alignment() -> Result<()> {
2749     let component = format!(
2750         r#"(component
2751             (core module $m
2752                 (memory (export "memory") 1)
2753                 (func (export "realloc") (param i32 i32 i32 i32) (result i32)
2754                     i32.const 1)
2755 
2756                 (func (export "take-i32") (param i32))
2757                 (func (export "ret-1") (result i32) i32.const 1)
2758                 (func (export "ret-unaligned-list") (result i32)
2759                     (i32.store offset=0 (i32.const 8) (i32.const 1))
2760                     (i32.store offset=4 (i32.const 8) (i32.const 1))
2761                     i32.const 8)
2762             )
2763             (core instance $i (instantiate $m))
2764 
2765             (func (export "many-params")
2766                 (param "s1" string) (param "s2" string) (param "s3" string) (param "s4" string)
2767                 (param "s5" string) (param "s6" string) (param "s7" string) (param "s8" string)
2768                 (param "s9" string) (param "s10" string) (param "s11" string) (param "s12" string)
2769                 (canon lift
2770                     (core func $i "take-i32")
2771                     (memory $i "memory")
2772                     (realloc (func $i "realloc"))
2773                 )
2774             )
2775             (func (export "string-ret") (result string)
2776                 (canon lift
2777                     (core func $i "ret-1")
2778                     (memory $i "memory")
2779                     (realloc (func $i "realloc"))
2780                 )
2781             )
2782             (func (export "list-u32-ret") (result (list u32))
2783                 (canon lift
2784                     (core func $i "ret-unaligned-list")
2785                     (memory $i "memory")
2786                     (realloc (func $i "realloc"))
2787                 )
2788             )
2789         )"#
2790     );
2791 
2792     let engine = super::engine();
2793     let component = Component::new(&engine, component)?;
2794     let mut store = Store::new(&engine, ());
2795     let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component);
2796 
2797     let err = instance(&mut store)?
2798         .get_typed_func::<(
2799             &str,
2800             &str,
2801             &str,
2802             &str,
2803             &str,
2804             &str,
2805             &str,
2806             &str,
2807             &str,
2808             &str,
2809             &str,
2810             &str,
2811         ), ()>(&mut store, "many-params")?
2812         .call(&mut store, ("", "", "", "", "", "", "", "", "", "", "", ""))
2813         .unwrap_err();
2814     assert!(
2815         err.to_string()
2816             .contains("realloc return: result not aligned"),
2817         "{}",
2818         err
2819     );
2820 
2821     let err = instance(&mut store)?
2822         .get_typed_func::<(), (WasmStr,)>(&mut store, "string-ret")?
2823         .call(&mut store, ())
2824         .err()
2825         .unwrap();
2826     assert!(
2827         err.to_string().contains("return pointer not aligned"),
2828         "{}",
2829         err
2830     );
2831 
2832     let err = instance(&mut store)?
2833         .get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32-ret")?
2834         .call(&mut store, ())
2835         .err()
2836         .unwrap();
2837     assert!(
2838         err.to_string().contains("list pointer is not aligned"),
2839         "{}",
2840         err
2841     );
2842 
2843     Ok(())
2844 }
2845 
2846 #[test]
2847 fn drop_component_still_works() -> Result<()> {
2848     let component = r#"
2849         (component
2850             (import "f" (func $f))
2851 
2852             (core func $f_lower
2853                 (canon lower (func $f))
2854             )
2855             (core module $m
2856                 (import "" "" (func $f))
2857 
2858                 (func $f2
2859                     call $f
2860                     call $f
2861                 )
2862 
2863                 (export "f" (func $f2))
2864             )
2865             (core instance $i (instantiate $m
2866                 (with "" (instance
2867                     (export "" (func $f_lower))
2868                 ))
2869             ))
2870             (func (export "g")
2871                 (canon lift
2872                     (core func $i "f")
2873                 )
2874             )
2875         )
2876     "#;
2877 
2878     let (mut store, instance) = {
2879         let engine = super::engine();
2880         let component = Component::new(&engine, component)?;
2881         let mut store = Store::new(&engine, 0);
2882         let mut linker = Linker::new(&engine);
2883         linker.root().func_wrap(
2884             "f",
2885             |mut store: StoreContextMut<'_, u32>, _: ()| -> Result<()> {
2886                 *store.data_mut() += 1;
2887                 Ok(())
2888             },
2889         )?;
2890         let instance = linker.instantiate(&mut store, &component)?;
2891         (store, instance)
2892     };
2893 
2894     let f = instance.get_typed_func::<(), ()>(&mut store, "g")?;
2895     assert_eq!(*store.data(), 0);
2896     f.call(&mut store, ())?;
2897     assert_eq!(*store.data(), 2);
2898 
2899     Ok(())
2900 }
2901 
2902 #[test]
2903 fn raw_slice_of_various_types() -> Result<()> {
2904     let component = r#"
2905         (component
2906             (core module $m
2907                 (memory (export "memory") 1)
2908 
2909                 (func (export "list8") (result i32)
2910                     (call $setup_list (i32.const 16))
2911                 )
2912                 (func (export "list16") (result i32)
2913                     (call $setup_list (i32.const 8))
2914                 )
2915                 (func (export "list32") (result i32)
2916                     (call $setup_list (i32.const 4))
2917                 )
2918                 (func (export "list64") (result i32)
2919                     (call $setup_list (i32.const 2))
2920                 )
2921 
2922                 (func $setup_list (param i32) (result i32)
2923                     (i32.store offset=0 (i32.const 100) (i32.const 8))
2924                     (i32.store offset=4 (i32.const 100) (local.get 0))
2925                     i32.const 100
2926                 )
2927 
2928                 (data (i32.const 8) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f")
2929             )
2930             (core instance $i (instantiate $m))
2931             (func (export "list-u8") (result (list u8))
2932                 (canon lift (core func $i "list8") (memory $i "memory"))
2933             )
2934             (func (export "list-i8") (result (list s8))
2935                 (canon lift (core func $i "list8") (memory $i "memory"))
2936             )
2937             (func (export "list-u16") (result (list u16))
2938                 (canon lift (core func $i "list16") (memory $i "memory"))
2939             )
2940             (func (export "list-i16") (result (list s16))
2941                 (canon lift (core func $i "list16") (memory $i "memory"))
2942             )
2943             (func (export "list-u32") (result (list u32))
2944                 (canon lift (core func $i "list32") (memory $i "memory"))
2945             )
2946             (func (export "list-i32") (result (list s32))
2947                 (canon lift (core func $i "list32") (memory $i "memory"))
2948             )
2949             (func (export "list-u64") (result (list u64))
2950                 (canon lift (core func $i "list64") (memory $i "memory"))
2951             )
2952             (func (export "list-i64") (result (list s64))
2953                 (canon lift (core func $i "list64") (memory $i "memory"))
2954             )
2955         )
2956     "#;
2957 
2958     let (mut store, instance) = {
2959         let engine = super::engine();
2960         let component = Component::new(&engine, component)?;
2961         let mut store = Store::new(&engine, ());
2962         let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
2963         (store, instance)
2964     };
2965 
2966     let list = instance
2967         .get_typed_func::<(), (WasmList<u8>,)>(&mut store, "list-u8")?
2968         .call_and_post_return(&mut store, ())?
2969         .0;
2970     assert_eq!(
2971         list.as_le_slice(&store),
2972         [
2973             0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
2974             0x0e, 0x0f,
2975         ]
2976     );
2977     let list = instance
2978         .get_typed_func::<(), (WasmList<i8>,)>(&mut store, "list-i8")?
2979         .call_and_post_return(&mut store, ())?
2980         .0;
2981     assert_eq!(
2982         list.as_le_slice(&store),
2983         [
2984             0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
2985             0x0e, 0x0f,
2986         ]
2987     );
2988 
2989     let list = instance
2990         .get_typed_func::<(), (WasmList<u16>,)>(&mut store, "list-u16")?
2991         .call_and_post_return(&mut store, ())?
2992         .0;
2993     assert_eq!(
2994         list.as_le_slice(&store),
2995         [
2996             u16::to_le(0x01_00),
2997             u16::to_le(0x03_02),
2998             u16::to_le(0x05_04),
2999             u16::to_le(0x07_06),
3000             u16::to_le(0x09_08),
3001             u16::to_le(0x0b_0a),
3002             u16::to_le(0x0d_0c),
3003             u16::to_le(0x0f_0e),
3004         ]
3005     );
3006     let list = instance
3007         .get_typed_func::<(), (WasmList<i16>,)>(&mut store, "list-i16")?
3008         .call_and_post_return(&mut store, ())?
3009         .0;
3010     assert_eq!(
3011         list.as_le_slice(&store),
3012         [
3013             i16::to_le(0x01_00),
3014             i16::to_le(0x03_02),
3015             i16::to_le(0x05_04),
3016             i16::to_le(0x07_06),
3017             i16::to_le(0x09_08),
3018             i16::to_le(0x0b_0a),
3019             i16::to_le(0x0d_0c),
3020             i16::to_le(0x0f_0e),
3021         ]
3022     );
3023     let list = instance
3024         .get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32")?
3025         .call_and_post_return(&mut store, ())?
3026         .0;
3027     assert_eq!(
3028         list.as_le_slice(&store),
3029         [
3030             u32::to_le(0x03_02_01_00),
3031             u32::to_le(0x07_06_05_04),
3032             u32::to_le(0x0b_0a_09_08),
3033             u32::to_le(0x0f_0e_0d_0c),
3034         ]
3035     );
3036     let list = instance
3037         .get_typed_func::<(), (WasmList<i32>,)>(&mut store, "list-i32")?
3038         .call_and_post_return(&mut store, ())?
3039         .0;
3040     assert_eq!(
3041         list.as_le_slice(&store),
3042         [
3043             i32::to_le(0x03_02_01_00),
3044             i32::to_le(0x07_06_05_04),
3045             i32::to_le(0x0b_0a_09_08),
3046             i32::to_le(0x0f_0e_0d_0c),
3047         ]
3048     );
3049     let list = instance
3050         .get_typed_func::<(), (WasmList<u64>,)>(&mut store, "list-u64")?
3051         .call_and_post_return(&mut store, ())?
3052         .0;
3053     assert_eq!(
3054         list.as_le_slice(&store),
3055         [
3056             u64::to_le(0x07_06_05_04_03_02_01_00),
3057             u64::to_le(0x0f_0e_0d_0c_0b_0a_09_08),
3058         ]
3059     );
3060     let list = instance
3061         .get_typed_func::<(), (WasmList<i64>,)>(&mut store, "list-i64")?
3062         .call_and_post_return(&mut store, ())?
3063         .0;
3064     assert_eq!(
3065         list.as_le_slice(&store),
3066         [
3067             i64::to_le(0x07_06_05_04_03_02_01_00),
3068             i64::to_le(0x0f_0e_0d_0c_0b_0a_09_08),
3069         ]
3070     );
3071 
3072     Ok(())
3073 }
3074 
3075 #[test]
3076 fn lower_then_lift() -> Result<()> {
3077     // First test simple integers when the import/export ABI happen to line up
3078     let component = r#"
3079 (component $c
3080   (import "f" (func $f (result u32)))
3081 
3082   (core func $f_lower
3083     (canon lower (func $f))
3084   )
3085   (func $f2 (result s32)
3086     (canon lift (core func $f_lower))
3087   )
3088   (export "f2" (func $f2))
3089 )
3090     "#;
3091 
3092     let engine = super::engine();
3093     let component = Component::new(&engine, component)?;
3094     let mut store = Store::new(&engine, ());
3095     let mut linker = Linker::new(&engine);
3096     linker.root().func_wrap("f", |_, _: ()| Ok((2u32,)))?;
3097     let instance = linker.instantiate(&mut store, &component)?;
3098 
3099     let f = instance.get_typed_func::<(), (i32,)>(&mut store, "f2")?;
3100     assert_eq!(f.call(&mut store, ())?, (2,));
3101 
3102     // First test strings when the import/export ABI happen to line up
3103     let component = format!(
3104         r#"
3105 (component $c
3106   (import "s" (func $f (param "a" string)))
3107 
3108   (core module $libc
3109     (memory (export "memory") 1)
3110     {REALLOC_AND_FREE}
3111   )
3112   (core instance $libc (instantiate $libc))
3113 
3114   (core func $f_lower
3115     (canon lower (func $f) (memory $libc "memory"))
3116   )
3117   (func $f2 (param "a" string)
3118     (canon lift (core func $f_lower)
3119         (memory $libc "memory")
3120         (realloc (func $libc "realloc"))
3121     )
3122   )
3123   (export "f" (func $f2))
3124 )
3125     "#
3126     );
3127 
3128     let component = Component::new(&engine, component)?;
3129     let mut store = Store::new(&engine, ());
3130     linker
3131         .root()
3132         .func_wrap("s", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| {
3133             assert_eq!(x.to_str(&store)?, "hello");
3134             Ok(())
3135         })?;
3136     let instance = linker.instantiate(&mut store, &component)?;
3137 
3138     let f = instance.get_typed_func::<(&str,), ()>(&mut store, "f")?;
3139     f.call(&mut store, ("hello",))?;
3140 
3141     // Next test "type punning" where return values are reinterpreted just
3142     // because the return ABI happens to line up.
3143     let component = format!(
3144         r#"
3145 (component $c
3146   (import "s2" (func $f (param "a" string) (result u32)))
3147 
3148   (core module $libc
3149     (memory (export "memory") 1)
3150     {REALLOC_AND_FREE}
3151   )
3152   (core instance $libc (instantiate $libc))
3153 
3154   (core func $f_lower
3155     (canon lower (func $f) (memory $libc "memory"))
3156   )
3157   (func $f2 (param "a" string) (result string)
3158     (canon lift (core func $f_lower)
3159         (memory $libc "memory")
3160         (realloc (func $libc "realloc"))
3161     )
3162   )
3163   (export "f" (func $f2))
3164 )
3165     "#
3166     );
3167 
3168     let component = Component::new(&engine, component)?;
3169     let mut store = Store::new(&engine, ());
3170     linker
3171         .root()
3172         .func_wrap("s2", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| {
3173             assert_eq!(x.to_str(&store)?, "hello");
3174             Ok((u32::MAX,))
3175         })?;
3176     let instance = linker.instantiate(&mut store, &component)?;
3177 
3178     let f = instance.get_typed_func::<(&str,), (WasmStr,)>(&mut store, "f")?;
3179     let err = f.call(&mut store, ("hello",)).err().unwrap();
3180     assert!(
3181         err.to_string().contains("return pointer not aligned"),
3182         "{}",
3183         err
3184     );
3185 
3186     Ok(())
3187 }
3188 
3189 #[test]
3190 fn errors_that_poison_instance() -> Result<()> {
3191     let component = format!(
3192         r#"
3193 (component $c
3194   (core module $m1
3195     (func (export "f1") unreachable)
3196     (func (export "f2"))
3197   )
3198   (core instance $m1 (instantiate $m1))
3199   (func (export "f1") (canon lift (core func $m1 "f1")))
3200   (func (export "f2") (canon lift (core func $m1 "f2")))
3201 
3202   (core module $m2
3203     (func (export "f") (param i32 i32))
3204     (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable)
3205     (memory (export "m") 1)
3206   )
3207   (core instance $m2 (instantiate $m2))
3208   (func (export "f3") (param "a" string)
3209     (canon lift (core func $m2 "f") (realloc (func $m2 "r")) (memory $m2 "m"))
3210   )
3211 
3212   (core module $m3
3213     (func (export "f") (result i32) i32.const 1)
3214     (memory (export "m") 1)
3215   )
3216   (core instance $m3 (instantiate $m3))
3217   (func (export "f4") (result string)
3218     (canon lift (core func $m3 "f") (memory $m3 "m"))
3219   )
3220 )
3221     "#
3222     );
3223 
3224     let engine = super::engine();
3225     let component = Component::new(&engine, component)?;
3226     let mut store = Store::new(&engine, ());
3227     let linker = Linker::new(&engine);
3228     let instance = linker.instantiate(&mut store, &component)?;
3229     let f1 = instance.get_typed_func::<(), ()>(&mut store, "f1")?;
3230     let f2 = instance.get_typed_func::<(), ()>(&mut store, "f2")?;
3231     assert_unreachable(f1.call(&mut store, ()));
3232     assert_poisoned(f1.call(&mut store, ()));
3233     assert_poisoned(f2.call(&mut store, ()));
3234 
3235     let instance = linker.instantiate(&mut store, &component)?;
3236     let f3 = instance.get_typed_func::<(&str,), ()>(&mut store, "f3")?;
3237     assert_unreachable(f3.call(&mut store, ("x",)));
3238     assert_poisoned(f3.call(&mut store, ("x",)));
3239 
3240     let instance = linker.instantiate(&mut store, &component)?;
3241     let f4 = instance.get_typed_func::<(), (WasmStr,)>(&mut store, "f4")?;
3242     assert!(f4.call(&mut store, ()).is_err());
3243     assert_poisoned(f4.call(&mut store, ()));
3244 
3245     return Ok(());
3246 
3247     #[track_caller]
3248     fn assert_unreachable<T>(err: Result<T>) {
3249         let err = match err {
3250             Ok(_) => panic!("expected an error"),
3251             Err(e) => e,
3252         };
3253         assert_eq!(
3254             err.downcast::<Trap>().unwrap(),
3255             Trap::UnreachableCodeReached
3256         );
3257     }
3258 
3259     #[track_caller]
3260     fn assert_poisoned<T>(err: Result<T>) {
3261         let err = match err {
3262             Ok(_) => panic!("expected an error"),
3263             Err(e) => e,
3264         };
3265         assert_eq!(
3266             err.downcast_ref::<Trap>(),
3267             Some(&Trap::CannotEnterComponent),
3268             "{err}",
3269         );
3270     }
3271 }
3272 
3273 #[test]
3274 fn run_export_with_internal_adapter() -> Result<()> {
3275     let component = r#"
3276 (component
3277   (type $t (func (param "a" u32) (result u32)))
3278   (component $a
3279     (core module $m
3280       (func (export "add-five") (param i32) (result i32)
3281         local.get 0
3282         i32.const 5
3283         i32.add)
3284     )
3285     (core instance $m (instantiate $m))
3286     (func (export "add-five") (type $t) (canon lift (core func $m "add-five")))
3287   )
3288   (component $b
3289     (import "interface-v1" (instance $i
3290       (export "add-five" (func (type $t)))))
3291     (core module $m
3292       (func $add-five (import "interface-0.1.0" "add-five") (param i32) (result i32))
3293       (func) ;; causes index out of bounds
3294       (func (export "run") (result i32) i32.const 0 call $add-five)
3295     )
3296     (core func $add-five (canon lower (func $i "add-five")))
3297     (core instance $i (instantiate 0
3298       (with "interface-0.1.0" (instance
3299         (export "add-five" (func $add-five))
3300       ))
3301     ))
3302     (func (result u32) (canon lift (core func $i "run")))
3303     (export "run" (func 1))
3304   )
3305   (instance $a (instantiate $a))
3306   (instance $b (instantiate $b (with "interface-v1" (instance $a))))
3307   (export "run" (func $b "run"))
3308 )
3309 "#;
3310     let engine = super::engine();
3311     let component = Component::new(&engine, component)?;
3312     let mut store = Store::new(&engine, ());
3313     let linker = Linker::new(&engine);
3314     let instance = linker.instantiate(&mut store, &component)?;
3315     let run = instance.get_typed_func::<(), (u32,)>(&mut store, "run")?;
3316     assert_eq!(run.call(&mut store, ())?, (5,));
3317     Ok(())
3318 }
3319