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