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