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