Path: blob/main/tests/all/component_model/func.rs
1692 views
#![cfg(not(miri))]12use super::{REALLOC_AND_FREE, TypedFuncExt};3use anyhow::Result;4use std::sync::Arc;5use wasmtime::component::*;6use wasmtime::{Config, Engine, Store, StoreContextMut, Trap};78const CANON_32BIT_NAN: u32 = 0b01111111110000000000000000000000;9const CANON_64BIT_NAN: u64 = 0b0111111111111000000000000000000000000000000000000000000000000000;1011#[test]12fn thunks() -> Result<()> {13let component = r#"14(component15(core module $m16(func (export "thunk"))17(func (export "thunk-trap") unreachable)18)19(core instance $i (instantiate $m))20(func (export "thunk")21(canon lift (core func $i "thunk"))22)23(func (export "thunk-trap")24(canon lift (core func $i "thunk-trap"))25)26)27"#;2829let engine = super::engine();30let component = Component::new(&engine, component)?;31let mut store = Store::new(&engine, ());32let instance = Linker::new(&engine).instantiate(&mut store, &component)?;33instance34.get_typed_func::<(), ()>(&mut store, "thunk")?35.call_and_post_return(&mut store, ())?;36let err = instance37.get_typed_func::<(), ()>(&mut store, "thunk-trap")?38.call(&mut store, ())39.unwrap_err();40assert_eq!(err.downcast::<Trap>()?, Trap::UnreachableCodeReached);4142Ok(())43}4445#[test]46fn typecheck() -> Result<()> {47let component = r#"48(component49(core module $m50(func (export "thunk"))51(func (export "take-string") (param i32 i32))52(func (export "two-args") (param i32 i32 i32))53(func (export "ret-one") (result i32) unreachable)5455(memory (export "memory") 1)56(func (export "realloc") (param i32 i32 i32 i32) (result i32)57unreachable)58)59(core instance $i (instantiate (module $m)))60(func (export "thunk")61(canon lift (core func $i "thunk"))62)63(func (export "take-string") (param "a" string)64(canon lift (core func $i "take-string") (memory $i "memory") (realloc (func $i "realloc")))65)66(func (export "take-two-args") (param "a" s32) (param "b" (list u8))67(canon lift (core func $i "two-args") (memory $i "memory") (realloc (func $i "realloc")))68)69(func (export "ret-tuple") (result (tuple u8 s8))70(canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))71)72(func (export "ret-tuple1") (result (tuple u32))73(canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))74)75(func (export "ret-string") (result string)76(canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))77)78(func (export "ret-list-u8") (result (list u8))79(canon lift (core func $i "ret-one") (memory $i "memory") (realloc (func $i "realloc")))80)81)82"#;8384let engine = Engine::default();85let component = Component::new(&engine, component)?;86let mut store = Store::new(&engine, ());87let instance = Linker::new(&engine).instantiate(&mut store, &component)?;88let thunk = instance.get_func(&mut store, "thunk").unwrap();89let take_string = instance.get_func(&mut store, "take-string").unwrap();90let take_two_args = instance.get_func(&mut store, "take-two-args").unwrap();91let ret_tuple = instance.get_func(&mut store, "ret-tuple").unwrap();92let ret_tuple1 = instance.get_func(&mut store, "ret-tuple1").unwrap();93let ret_string = instance.get_func(&mut store, "ret-string").unwrap();94let ret_list_u8 = instance.get_func(&mut store, "ret-list-u8").unwrap();95assert!(thunk.typed::<(), (u32,)>(&store).is_err());96assert!(thunk.typed::<(u32,), ()>(&store).is_err());97assert!(thunk.typed::<(), ()>(&store).is_ok());98assert!(take_string.typed::<(), ()>(&store).is_err());99assert!(take_string.typed::<(String,), ()>(&store).is_ok());100assert!(take_string.typed::<(&str,), ()>(&store).is_ok());101assert!(take_string.typed::<(&[u8],), ()>(&store).is_err());102assert!(take_two_args.typed::<(), ()>(&store).is_err());103assert!(take_two_args.typed::<(i32, &[u8]), (u32,)>(&store).is_err());104assert!(take_two_args.typed::<(u32, &[u8]), ()>(&store).is_err());105assert!(take_two_args.typed::<(i32, &[u8]), ()>(&store).is_ok());106assert!(ret_tuple.typed::<(), ()>(&store).is_err());107assert!(ret_tuple.typed::<(), (u8,)>(&store).is_err());108assert!(ret_tuple.typed::<(), ((u8, i8),)>(&store).is_ok());109assert!(ret_tuple1.typed::<(), ((u32,),)>(&store).is_ok());110assert!(ret_tuple1.typed::<(), (u32,)>(&store).is_err());111assert!(ret_string.typed::<(), ()>(&store).is_err());112assert!(ret_string.typed::<(), (WasmStr,)>(&store).is_ok());113assert!(ret_list_u8.typed::<(), (WasmList<u16>,)>(&store).is_err());114assert!(ret_list_u8.typed::<(), (WasmList<i8>,)>(&store).is_err());115assert!(ret_list_u8.typed::<(), (WasmList<u8>,)>(&store).is_ok());116117Ok(())118}119120#[test]121fn integers() -> Result<()> {122let component = r#"123(component124(core module $m125(func (export "take-i32-100") (param i32)126local.get 0127i32.const 100128i32.eq129br_if 0130unreachable131)132(func (export "take-i64-100") (param i64)133local.get 0134i64.const 100135i64.eq136br_if 0137unreachable138)139(func (export "ret-i32-0") (result i32) i32.const 0)140(func (export "ret-i64-0") (result i64) i64.const 0)141(func (export "ret-i32-minus-1") (result i32) i32.const -1)142(func (export "ret-i64-minus-1") (result i64) i64.const -1)143(func (export "ret-i32-100000") (result i32) i32.const 100000)144)145(core instance $i (instantiate (module $m)))146(func (export "take-u8") (param "a" u8) (canon lift (core func $i "take-i32-100")))147(func (export "take-s8") (param "a" s8) (canon lift (core func $i "take-i32-100")))148(func (export "take-u16") (param "a" u16) (canon lift (core func $i "take-i32-100")))149(func (export "take-s16") (param "a" s16) (canon lift (core func $i "take-i32-100")))150(func (export "take-u32") (param "a" u32) (canon lift (core func $i "take-i32-100")))151(func (export "take-s32") (param "a" s32) (canon lift (core func $i "take-i32-100")))152(func (export "take-u64") (param "a" u64) (canon lift (core func $i "take-i64-100")))153(func (export "take-s64") (param "a" s64) (canon lift (core func $i "take-i64-100")))154155(func (export "ret-u8") (result u8) (canon lift (core func $i "ret-i32-0")))156(func (export "ret-s8") (result s8) (canon lift (core func $i "ret-i32-0")))157(func (export "ret-u16") (result u16) (canon lift (core func $i "ret-i32-0")))158(func (export "ret-s16") (result s16) (canon lift (core func $i "ret-i32-0")))159(func (export "ret-u32") (result u32) (canon lift (core func $i "ret-i32-0")))160(func (export "ret-s32") (result s32) (canon lift (core func $i "ret-i32-0")))161(func (export "ret-u64") (result u64) (canon lift (core func $i "ret-i64-0")))162(func (export "ret-s64") (result s64) (canon lift (core func $i "ret-i64-0")))163164(func (export "retm1-u8") (result u8) (canon lift (core func $i "ret-i32-minus-1")))165(func (export "retm1-s8") (result s8) (canon lift (core func $i "ret-i32-minus-1")))166(func (export "retm1-u16") (result u16) (canon lift (core func $i "ret-i32-minus-1")))167(func (export "retm1-s16") (result s16) (canon lift (core func $i "ret-i32-minus-1")))168(func (export "retm1-u32") (result u32) (canon lift (core func $i "ret-i32-minus-1")))169(func (export "retm1-s32") (result s32) (canon lift (core func $i "ret-i32-minus-1")))170(func (export "retm1-u64") (result u64) (canon lift (core func $i "ret-i64-minus-1")))171(func (export "retm1-s64") (result s64) (canon lift (core func $i "ret-i64-minus-1")))172173(func (export "retbig-u8") (result u8) (canon lift (core func $i "ret-i32-100000")))174(func (export "retbig-s8") (result s8) (canon lift (core func $i "ret-i32-100000")))175(func (export "retbig-u16") (result u16) (canon lift (core func $i "ret-i32-100000")))176(func (export "retbig-s16") (result s16) (canon lift (core func $i "ret-i32-100000")))177(func (export "retbig-u32") (result u32) (canon lift (core func $i "ret-i32-100000")))178(func (export "retbig-s32") (result s32) (canon lift (core func $i "ret-i32-100000")))179)180"#;181182let engine = super::engine();183let component = Component::new(&engine, component)?;184let mut store = Store::new(&engine, ());185let new_instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component);186let instance = new_instance(&mut store)?;187188// Passing in 100 is valid for all primitives189instance190.get_typed_func::<(u8,), ()>(&mut store, "take-u8")?191.call_and_post_return(&mut store, (100,))?;192instance193.get_typed_func::<(i8,), ()>(&mut store, "take-s8")?194.call_and_post_return(&mut store, (100,))?;195instance196.get_typed_func::<(u16,), ()>(&mut store, "take-u16")?197.call_and_post_return(&mut store, (100,))?;198instance199.get_typed_func::<(i16,), ()>(&mut store, "take-s16")?200.call_and_post_return(&mut store, (100,))?;201instance202.get_typed_func::<(u32,), ()>(&mut store, "take-u32")?203.call_and_post_return(&mut store, (100,))?;204instance205.get_typed_func::<(i32,), ()>(&mut store, "take-s32")?206.call_and_post_return(&mut store, (100,))?;207instance208.get_typed_func::<(u64,), ()>(&mut store, "take-u64")?209.call_and_post_return(&mut store, (100,))?;210instance211.get_typed_func::<(i64,), ()>(&mut store, "take-s64")?212.call_and_post_return(&mut store, (100,))?;213214// This specific wasm instance traps if any value other than 100 is passed215new_instance(&mut store)?216.get_typed_func::<(u8,), ()>(&mut store, "take-u8")?217.call(&mut store, (101,))218.unwrap_err()219.downcast::<Trap>()?;220new_instance(&mut store)?221.get_typed_func::<(i8,), ()>(&mut store, "take-s8")?222.call(&mut store, (101,))223.unwrap_err()224.downcast::<Trap>()?;225new_instance(&mut store)?226.get_typed_func::<(u16,), ()>(&mut store, "take-u16")?227.call(&mut store, (101,))228.unwrap_err()229.downcast::<Trap>()?;230new_instance(&mut store)?231.get_typed_func::<(i16,), ()>(&mut store, "take-s16")?232.call(&mut store, (101,))233.unwrap_err()234.downcast::<Trap>()?;235new_instance(&mut store)?236.get_typed_func::<(u32,), ()>(&mut store, "take-u32")?237.call(&mut store, (101,))238.unwrap_err()239.downcast::<Trap>()?;240new_instance(&mut store)?241.get_typed_func::<(i32,), ()>(&mut store, "take-s32")?242.call(&mut store, (101,))243.unwrap_err()244.downcast::<Trap>()?;245new_instance(&mut store)?246.get_typed_func::<(u64,), ()>(&mut store, "take-u64")?247.call(&mut store, (101,))248.unwrap_err()249.downcast::<Trap>()?;250new_instance(&mut store)?251.get_typed_func::<(i64,), ()>(&mut store, "take-s64")?252.call(&mut store, (101,))253.unwrap_err()254.downcast::<Trap>()?;255256// Zero can be returned as any integer257assert_eq!(258instance259.get_typed_func::<(), (u8,)>(&mut store, "ret-u8")?260.call_and_post_return(&mut store, ())?,261(0,)262);263assert_eq!(264instance265.get_typed_func::<(), (i8,)>(&mut store, "ret-s8")?266.call_and_post_return(&mut store, ())?,267(0,)268);269assert_eq!(270instance271.get_typed_func::<(), (u16,)>(&mut store, "ret-u16")?272.call_and_post_return(&mut store, ())?,273(0,)274);275assert_eq!(276instance277.get_typed_func::<(), (i16,)>(&mut store, "ret-s16")?278.call_and_post_return(&mut store, ())?,279(0,)280);281assert_eq!(282instance283.get_typed_func::<(), (u32,)>(&mut store, "ret-u32")?284.call_and_post_return(&mut store, ())?,285(0,)286);287assert_eq!(288instance289.get_typed_func::<(), (i32,)>(&mut store, "ret-s32")?290.call_and_post_return(&mut store, ())?,291(0,)292);293assert_eq!(294instance295.get_typed_func::<(), (u64,)>(&mut store, "ret-u64")?296.call_and_post_return(&mut store, ())?,297(0,)298);299assert_eq!(300instance301.get_typed_func::<(), (i64,)>(&mut store, "ret-s64")?302.call_and_post_return(&mut store, ())?,303(0,)304);305306// Returning -1 should reinterpret the bytes as defined by each type.307assert_eq!(308instance309.get_typed_func::<(), (u8,)>(&mut store, "retm1-u8")?310.call_and_post_return(&mut store, ())?,311(0xff,)312);313assert_eq!(314instance315.get_typed_func::<(), (i8,)>(&mut store, "retm1-s8")?316.call_and_post_return(&mut store, ())?,317(-1,)318);319assert_eq!(320instance321.get_typed_func::<(), (u16,)>(&mut store, "retm1-u16")?322.call_and_post_return(&mut store, ())?,323(0xffff,)324);325assert_eq!(326instance327.get_typed_func::<(), (i16,)>(&mut store, "retm1-s16")?328.call_and_post_return(&mut store, ())?,329(-1,)330);331assert_eq!(332instance333.get_typed_func::<(), (u32,)>(&mut store, "retm1-u32")?334.call_and_post_return(&mut store, ())?,335(0xffffffff,)336);337assert_eq!(338instance339.get_typed_func::<(), (i32,)>(&mut store, "retm1-s32")?340.call_and_post_return(&mut store, ())?,341(-1,)342);343assert_eq!(344instance345.get_typed_func::<(), (u64,)>(&mut store, "retm1-u64")?346.call_and_post_return(&mut store, ())?,347(0xffffffff_ffffffff,)348);349assert_eq!(350instance351.get_typed_func::<(), (i64,)>(&mut store, "retm1-s64")?352.call_and_post_return(&mut store, ())?,353(-1,)354);355356// Returning 100000 should chop off bytes as necessary357let ret: u32 = 100000;358assert_eq!(359instance360.get_typed_func::<(), (u8,)>(&mut store, "retbig-u8")?361.call_and_post_return(&mut store, ())?,362(ret as u8,),363);364assert_eq!(365instance366.get_typed_func::<(), (i8,)>(&mut store, "retbig-s8")?367.call_and_post_return(&mut store, ())?,368(ret as i8,),369);370assert_eq!(371instance372.get_typed_func::<(), (u16,)>(&mut store, "retbig-u16")?373.call_and_post_return(&mut store, ())?,374(ret as u16,),375);376assert_eq!(377instance378.get_typed_func::<(), (i16,)>(&mut store, "retbig-s16")?379.call_and_post_return(&mut store, ())?,380(ret as i16,),381);382assert_eq!(383instance384.get_typed_func::<(), (u32,)>(&mut store, "retbig-u32")?385.call_and_post_return(&mut store, ())?,386(ret,),387);388assert_eq!(389instance390.get_typed_func::<(), (i32,)>(&mut store, "retbig-s32")?391.call_and_post_return(&mut store, ())?,392(ret as i32,),393);394395Ok(())396}397398#[test]399fn type_layers() -> Result<()> {400let component = r#"401(component402(core module $m403(func (export "take-i32-100") (param i32)404local.get 0405i32.const 2406i32.eq407br_if 0408unreachable409)410)411(core instance $i (instantiate $m))412(func (export "take-u32") (param "a" u32) (canon lift (core func $i "take-i32-100")))413)414"#;415416let engine = super::engine();417let component = Component::new(&engine, component)?;418let mut store = Store::new(&engine, ());419let instance = Linker::new(&engine).instantiate(&mut store, &component)?;420421instance422.get_typed_func::<(Box<u32>,), ()>(&mut store, "take-u32")?423.call_and_post_return(&mut store, (Box::new(2),))?;424instance425.get_typed_func::<(&u32,), ()>(&mut store, "take-u32")?426.call_and_post_return(&mut store, (&2,))?;427instance428.get_typed_func::<(Arc<u32>,), ()>(&mut store, "take-u32")?429.call_and_post_return(&mut store, (Arc::new(2),))?;430instance431.get_typed_func::<(&Box<Arc<Box<u32>>>,), ()>(&mut store, "take-u32")?432.call_and_post_return(&mut store, (&Box::new(Arc::new(Box::new(2))),))?;433434Ok(())435}436437#[test]438fn floats() -> Result<()> {439let component = r#"440(component441(core module $m442(func (export "i32.reinterpret_f32") (param f32) (result i32)443local.get 0444i32.reinterpret_f32445)446(func (export "i64.reinterpret_f64") (param f64) (result i64)447local.get 0448i64.reinterpret_f64449)450(func (export "f32.reinterpret_i32") (param i32) (result f32)451local.get 0452f32.reinterpret_i32453)454(func (export "f64.reinterpret_i64") (param i64) (result f64)455local.get 0456f64.reinterpret_i64457)458)459(core instance $i (instantiate $m))460461(func (export "f32-to-u32") (param "a" float32) (result u32)462(canon lift (core func $i "i32.reinterpret_f32"))463)464(func (export "f64-to-u64") (param "a" float64) (result u64)465(canon lift (core func $i "i64.reinterpret_f64"))466)467(func (export "u32-to-f32") (param "a" u32) (result float32)468(canon lift (core func $i "f32.reinterpret_i32"))469)470(func (export "u64-to-f64") (param "a" u64) (result float64)471(canon lift (core func $i "f64.reinterpret_i64"))472)473)474"#;475476let engine = super::engine();477let component = Component::new(&engine, component)?;478let mut store = Store::new(&engine, ());479let instance = Linker::new(&engine).instantiate(&mut store, &component)?;480let f32_to_u32 = instance.get_typed_func::<(f32,), (u32,)>(&mut store, "f32-to-u32")?;481let f64_to_u64 = instance.get_typed_func::<(f64,), (u64,)>(&mut store, "f64-to-u64")?;482let u32_to_f32 = instance.get_typed_func::<(u32,), (f32,)>(&mut store, "u32-to-f32")?;483let u64_to_f64 = instance.get_typed_func::<(u64,), (f64,)>(&mut store, "u64-to-f64")?;484485assert_eq!(f32_to_u32.call(&mut store, (1.0,))?, (1.0f32.to_bits(),));486f32_to_u32.post_return(&mut store)?;487assert_eq!(f64_to_u64.call(&mut store, (2.0,))?, (2.0f64.to_bits(),));488f64_to_u64.post_return(&mut store)?;489assert_eq!(u32_to_f32.call(&mut store, (3.0f32.to_bits(),))?, (3.0,));490u32_to_f32.post_return(&mut store)?;491assert_eq!(u64_to_f64.call(&mut store, (4.0f64.to_bits(),))?, (4.0,));492u64_to_f64.post_return(&mut store)?;493494assert_eq!(495u32_to_f32496.call(&mut store, (CANON_32BIT_NAN | 1,))?497.0498.to_bits(),499CANON_32BIT_NAN | 1500);501u32_to_f32.post_return(&mut store)?;502assert_eq!(503u64_to_f64504.call(&mut store, (CANON_64BIT_NAN | 1,))?505.0506.to_bits(),507CANON_64BIT_NAN | 1,508);509u64_to_f64.post_return(&mut store)?;510511assert_eq!(512f32_to_u32.call(&mut store, (f32::from_bits(CANON_32BIT_NAN | 1),))?,513(CANON_32BIT_NAN | 1,)514);515f32_to_u32.post_return(&mut store)?;516assert_eq!(517f64_to_u64.call(&mut store, (f64::from_bits(CANON_64BIT_NAN | 1),))?,518(CANON_64BIT_NAN | 1,)519);520f64_to_u64.post_return(&mut store)?;521522Ok(())523}524525#[test]526fn bools() -> Result<()> {527let component = r#"528(component529(core module $m530(func (export "pass") (param i32) (result i32) local.get 0)531)532(core instance $i (instantiate $m))533534(func (export "u32-to-bool") (param "a" u32) (result bool)535(canon lift (core func $i "pass"))536)537(func (export "bool-to-u32") (param "a" bool) (result u32)538(canon lift (core func $i "pass"))539)540)541"#;542543let engine = super::engine();544let component = Component::new(&engine, component)?;545let mut store = Store::new(&engine, ());546let instance = Linker::new(&engine).instantiate(&mut store, &component)?;547let u32_to_bool = instance.get_typed_func::<(u32,), (bool,)>(&mut store, "u32-to-bool")?;548let bool_to_u32 = instance.get_typed_func::<(bool,), (u32,)>(&mut store, "bool-to-u32")?;549550assert_eq!(bool_to_u32.call(&mut store, (false,))?, (0,));551bool_to_u32.post_return(&mut store)?;552assert_eq!(bool_to_u32.call(&mut store, (true,))?, (1,));553bool_to_u32.post_return(&mut store)?;554assert_eq!(u32_to_bool.call(&mut store, (0,))?, (false,));555u32_to_bool.post_return(&mut store)?;556assert_eq!(u32_to_bool.call(&mut store, (1,))?, (true,));557u32_to_bool.post_return(&mut store)?;558assert_eq!(u32_to_bool.call(&mut store, (2,))?, (true,));559u32_to_bool.post_return(&mut store)?;560561Ok(())562}563564#[test]565fn chars() -> Result<()> {566let component = r#"567(component568(core module $m569(func (export "pass") (param i32) (result i32) local.get 0)570)571(core instance $i (instantiate $m))572573(func (export "u32-to-char") (param "a" u32) (result char)574(canon lift (core func $i "pass"))575)576(func (export "char-to-u32") (param "a" char) (result u32)577(canon lift (core func $i "pass"))578)579)580"#;581582let engine = super::engine();583let component = Component::new(&engine, component)?;584let mut store = Store::new(&engine, ());585let instance = Linker::new(&engine).instantiate(&mut store, &component)?;586let u32_to_char = instance.get_typed_func::<(u32,), (char,)>(&mut store, "u32-to-char")?;587let char_to_u32 = instance.get_typed_func::<(char,), (u32,)>(&mut store, "char-to-u32")?;588589let mut roundtrip = |x: char| -> Result<()> {590assert_eq!(char_to_u32.call(&mut store, (x,))?, (x as u32,));591char_to_u32.post_return(&mut store)?;592assert_eq!(u32_to_char.call(&mut store, (x as u32,))?, (x,));593u32_to_char.post_return(&mut store)?;594Ok(())595};596597roundtrip('x')?;598roundtrip('a')?;599roundtrip('\0')?;600roundtrip('\n')?;601roundtrip('��')?;602603let u32_to_char = |store: &mut Store<()>| {604Linker::new(&engine)605.instantiate(&mut *store, &component)?606.get_typed_func::<(u32,), (char,)>(&mut *store, "u32-to-char")607};608let err = u32_to_char(&mut store)?609.call(&mut store, (0xd800,))610.unwrap_err();611assert!(err.to_string().contains("integer out of range"), "{}", err);612let err = u32_to_char(&mut store)?613.call(&mut store, (0xdfff,))614.unwrap_err();615assert!(err.to_string().contains("integer out of range"), "{}", err);616let err = u32_to_char(&mut store)?617.call(&mut store, (0x110000,))618.unwrap_err();619assert!(err.to_string().contains("integer out of range"), "{}", err);620let err = u32_to_char(&mut store)?621.call(&mut store, (u32::MAX,))622.unwrap_err();623assert!(err.to_string().contains("integer out of range"), "{}", err);624625Ok(())626}627628#[test]629fn tuple_result() -> Result<()> {630let component = r#"631(component632(core module $m633(memory (export "memory") 1)634(func (export "foo") (param i32 i32 f32 f64) (result i32)635(local $base i32)636(local.set $base (i32.const 8))637(i32.store8 offset=0 (local.get $base) (local.get 0))638(i32.store16 offset=2 (local.get $base) (local.get 1))639(f32.store offset=4 (local.get $base) (local.get 2))640(f64.store offset=8 (local.get $base) (local.get 3))641local.get $base642)643644(func (export "invalid") (result i32)645i32.const -8646)647)648(core instance $i (instantiate $m))649650(type $result (tuple s8 u16 float32 float64))651(func (export "tuple")652(param "a" s8) (param "b" u16) (param "c" float32) (param "d" float64) (result $result)653(canon lift (core func $i "foo") (memory $i "memory"))654)655(func (export "invalid") (result $result)656(canon lift (core func $i "invalid") (memory $i "memory"))657)658)659"#;660661let engine = super::engine();662let component = Component::new(&engine, component)?;663let mut store = Store::new(&engine, ());664let instance = Linker::new(&engine).instantiate(&mut store, &component)?;665666let input = (-1, 100, 3.0, 100.0);667let output = instance668.get_typed_func::<(i8, u16, f32, f64), ((i8, u16, f32, f64),)>(&mut store, "tuple")?669.call_and_post_return(&mut store, input)?;670assert_eq!((input,), output);671672let invalid_func =673instance.get_typed_func::<(), ((i8, u16, f32, f64),)>(&mut store, "invalid")?;674let err = invalid_func.call(&mut store, ()).err().unwrap();675assert!(676err.to_string().contains("pointer out of bounds of memory"),677"{}",678err679);680681Ok(())682}683684#[test]685fn strings() -> Result<()> {686let component = format!(687r#"(component688(core module $m689(memory (export "memory") 1)690(func (export "roundtrip") (param i32 i32) (result i32)691(local $base i32)692(local.set $base693(call $realloc694(i32.const 0)695(i32.const 0)696(i32.const 4)697(i32.const 8)))698(i32.store offset=0699(local.get $base)700(local.get 0))701(i32.store offset=4702(local.get $base)703(local.get 1))704(local.get $base)705)706707{REALLOC_AND_FREE}708)709(core instance $i (instantiate $m))710711(func (export "list8-to-str") (param "a" (list u8)) (result string)712(canon lift713(core func $i "roundtrip")714(memory $i "memory")715(realloc (func $i "realloc"))716)717)718(func (export "str-to-list8") (param "a" string) (result (list u8))719(canon lift720(core func $i "roundtrip")721(memory $i "memory")722(realloc (func $i "realloc"))723)724)725(func (export "list16-to-str") (param "a" (list u16)) (result string)726(canon lift727(core func $i "roundtrip")728string-encoding=utf16729(memory $i "memory")730(realloc (func $i "realloc"))731)732)733(func (export "str-to-list16") (param "a" string) (result (list u16))734(canon lift735(core func $i "roundtrip")736string-encoding=utf16737(memory $i "memory")738(realloc (func $i "realloc"))739)740)741)"#742);743744let engine = super::engine();745let component = Component::new(&engine, component)?;746let mut store = Store::new(&engine, ());747let instance = Linker::new(&engine).instantiate(&mut store, &component)?;748let list8_to_str =749instance.get_typed_func::<(&[u8],), (WasmStr,)>(&mut store, "list8-to-str")?;750let str_to_list8 =751instance.get_typed_func::<(&str,), (WasmList<u8>,)>(&mut store, "str-to-list8")?;752let list16_to_str =753instance.get_typed_func::<(&[u16],), (WasmStr,)>(&mut store, "list16-to-str")?;754let str_to_list16 =755instance.get_typed_func::<(&str,), (WasmList<u16>,)>(&mut store, "str-to-list16")?;756757let mut roundtrip = |x: &str| -> Result<()> {758let ret = list8_to_str.call(&mut store, (x.as_bytes(),))?.0;759assert_eq!(ret.to_str(&store)?, x);760list8_to_str.post_return(&mut store)?;761762let utf16 = x.encode_utf16().collect::<Vec<_>>();763let ret = list16_to_str.call(&mut store, (&utf16[..],))?.0;764assert_eq!(ret.to_str(&store)?, x);765list16_to_str.post_return(&mut store)?;766767let ret = str_to_list8.call(&mut store, (x,))?.0;768assert_eq!(769ret.iter(&mut store).collect::<Result<Vec<_>>>()?,770x.as_bytes()771);772str_to_list8.post_return(&mut store)?;773774let ret = str_to_list16.call(&mut store, (x,))?.0;775assert_eq!(ret.iter(&mut store).collect::<Result<Vec<_>>>()?, utf16,);776str_to_list16.post_return(&mut store)?;777778Ok(())779};780781roundtrip("")?;782roundtrip("foo")?;783roundtrip("hello there")?;784roundtrip("💝")?;785roundtrip("Löwe 老虎 Léopard")?;786787let ret = list8_to_str.call(&mut store, (b"\xff",))?.0;788let err = ret.to_str(&store).unwrap_err();789assert!(err.to_string().contains("invalid utf-8"), "{}", err);790list8_to_str.post_return(&mut store)?;791792let ret = list8_to_str793.call(&mut store, (b"hello there \xff invalid",))?794.0;795let err = ret.to_str(&store).unwrap_err();796assert!(err.to_string().contains("invalid utf-8"), "{}", err);797list8_to_str.post_return(&mut store)?;798799let ret = list16_to_str.call(&mut store, (&[0xd800],))?.0;800let err = ret.to_str(&store).unwrap_err();801assert!(err.to_string().contains("unpaired surrogate"), "{}", err);802list16_to_str.post_return(&mut store)?;803804let ret = list16_to_str.call(&mut store, (&[0xdfff],))?.0;805let err = ret.to_str(&store).unwrap_err();806assert!(err.to_string().contains("unpaired surrogate"), "{}", err);807list16_to_str.post_return(&mut store)?;808809let ret = list16_to_str.call(&mut store, (&[0xd800, 0xff00],))?.0;810let err = ret.to_str(&store).unwrap_err();811assert!(err.to_string().contains("unpaired surrogate"), "{}", err);812list16_to_str.post_return(&mut store)?;813814Ok(())815}816817#[tokio::test]818async fn async_reentrance() -> Result<()> {819_ = env_logger::try_init();820821let component = r#"822(component823(core module $shim824(import "" "task.return" (func $task-return (param i32)))825(table (export "funcs") 1 1 funcref)826(func (export "export") (param i32) (result i32)827(call_indirect (i32.const 0) (local.get 0))828)829(func (export "callback") (param i32 i32 i32) (result i32) unreachable)830)831(core func $task-return (canon task.return (result u32)))832(core instance $shim (instantiate $shim833(with "" (instance (export "task.return" (func $task-return))))834))835(func $shim-export (param "p1" u32) (result u32)836(canon lift (core func $shim "export") async (callback (func $shim "callback")))837)838839(component $inner840(import "import" (func $import (param "p1" u32) (result u32)))841(core module $libc (memory (export "memory") 1))842(core instance $libc (instantiate $libc))843(core func $import (canon lower (func $import) async (memory $libc "memory")))844845(core module $m846(import "libc" "memory" (memory 1))847(import "" "import" (func $import (param i32 i32) (result i32)))848(import "" "task.return" (func $task-return (param i32)))849(func (export "export") (param i32) (result i32)850(i32.store offset=0 (i32.const 1200) (local.get 0))851(call $import (i32.const 1200) (i32.const 1204))852drop853(call $task-return (i32.load offset=0 (i32.const 1204)))854i32.const 0855)856(func (export "callback") (param i32 i32 i32) (result i32) unreachable)857)858(core type $task-return-type (func (param i32)))859(core func $task-return (canon task.return (result u32)))860(core instance $i (instantiate $m861(with "" (instance862(export "task.return" (func $task-return))863(export "import" (func $import))864))865(with "libc" (instance $libc))866))867(func (export "export") (param "p1" u32) (result u32)868(canon lift (core func $i "export") async (callback (func $i "callback")))869)870)871(instance $inner (instantiate $inner (with "import" (func $shim-export))))872873(core module $libc (memory (export "memory") 1))874(core instance $libc (instantiate $libc))875(core func $inner-export (canon lower (func $inner "export") async (memory $libc "memory")))876877(core module $donut878(import "" "funcs" (table 1 1 funcref))879(import "libc" "memory" (memory 1))880(import "" "import" (func $import (param i32 i32) (result i32)))881(import "" "task.return" (func $task-return (param i32)))882(func $host-export (export "export") (param i32) (result i32)883(i32.store offset=0 (i32.const 1200) (local.get 0))884(call $import (i32.const 1200) (i32.const 1204))885drop886(call $task-return (i32.load offset=0 (i32.const 1204)))887i32.const 0888)889(func $guest-export (export "guest-export") (param i32) (result i32) unreachable)890(func (export "callback") (param i32 i32 i32) (result i32) unreachable)891(func $start892(table.set (i32.const 0) (ref.func $guest-export))893)894(start $start)895)896897(core instance $donut (instantiate $donut898(with "" (instance899(export "task.return" (func $task-return))900(export "import" (func $inner-export))901(export "funcs" (table $shim "funcs"))902))903(with "libc" (instance $libc))904))905(func (export "export") (param "p1" u32) (result u32)906(canon lift (core func $donut "export") async (callback (func $donut "callback")))907)908)"#;909910let mut config = Config::new();911config.wasm_component_model_async(true);912config.async_support(true);913let engine = &Engine::new(&config)?;914let component = Component::new(&engine, component)?;915let mut store = Store::new(&engine, ());916917let instance = Linker::new(&engine)918.instantiate_async(&mut store, &component)919.await?;920let func = instance.get_typed_func::<(u32,), (u32,)>(&mut store, "export")?;921let message = "cannot enter component instance";922match instance923.run_concurrent(&mut store, async move |accessor| {924func.call_concurrent(accessor, (42,)).await925})926.await927{928Ok(_) => panic!(),929Err(e) => assert!(930format!("{e:?}").contains(message),931"expected `{message}`; got `{e:?}`"932),933}934935Ok(())936}937938#[tokio::test]939async fn missing_task_return_call_stackless() -> Result<()> {940task_return_trap(941r#"(component942(core module $m943(import "" "task.return" (func $task-return))944(func (export "foo") (result i32)945i32.const 0946)947(func (export "callback") (param i32 i32 i32) (result i32) unreachable)948)949(core func $task-return (canon task.return))950(core instance $i (instantiate $m951(with "" (instance (export "task.return" (func $task-return))))952))953(func (export "foo") (canon lift (core func $i "foo") async (callback (func $i "callback"))))954)"#,955"wasm trap: async-lifted export failed to produce a result",956)957.await958}959960#[tokio::test]961async fn missing_task_return_call_stackful() -> Result<()> {962task_return_trap(963r#"(component964(core module $m965(import "" "task.return" (func $task-return))966(func (export "foo"))967)968(core func $task-return (canon task.return))969(core instance $i (instantiate $m970(with "" (instance (export "task.return" (func $task-return))))971))972(func (export "foo") (canon lift (core func $i "foo") async))973)"#,974"wasm trap: async-lifted export failed to produce a result",975)976.await977}978979#[tokio::test]980async fn task_return_type_mismatch() -> Result<()> {981task_return_trap(982r#"(component983(core module $m984(import "" "task.return" (func $task-return (param i32)))985(func (export "foo") (call $task-return (i32.const 42)))986)987(core func $task-return (canon task.return (result u32)))988(core instance $i (instantiate $m989(with "" (instance (export "task.return" (func $task-return))))990))991(func (export "foo") (canon lift (core func $i "foo") async))992)"#,993"invalid `task.return` signature and/or options for current task",994)995.await996}997998#[tokio::test]999async fn task_return_memory_mismatch() -> Result<()> {1000task_return_trap(1001r#"(component1002(core module $libc (memory (export "memory") 1))1003(core instance $libc (instantiate $libc))1004(core module $m1005(import "" "task.return" (func $task-return))1006(func (export "foo") (call $task-return))1007)1008(core func $task-return (canon task.return (memory $libc "memory")))1009(core instance $i (instantiate $m1010(with "" (instance (export "task.return" (func $task-return))))1011))1012(func (export "foo") (canon lift (core func $i "foo") async))1013)"#,1014"invalid `task.return` signature and/or options for current task",1015)1016.await1017}10181019#[tokio::test]1020async fn task_return_string_encoding_mismatch() -> Result<()> {1021task_return_trap(1022r#"(component1023(core module $m1024(import "" "task.return" (func $task-return))1025(func (export "foo") (call $task-return))1026)1027(core func $task-return (canon task.return string-encoding=utf16))1028(core instance $i (instantiate $m1029(with "" (instance (export "task.return" (func $task-return))))1030))1031(func (export "foo") (canon lift (core func $i "foo") async))1032)"#,1033"invalid `task.return` signature and/or options for current task",1034)1035.await1036}10371038async fn task_return_trap(component: &str, substring: &str) -> Result<()> {1039let mut config = Config::new();1040config.wasm_component_model_async(true);1041config.wasm_component_model_async_stackful(true);1042config.async_support(true);1043let engine = &Engine::new(&config)?;1044let component = Component::new(&engine, component)?;1045let mut store = Store::new(&engine, ());10461047let instance = Linker::new(&engine)1048.instantiate_async(&mut store, &component)1049.await?;10501051let func = instance.get_typed_func::<(), ()>(&mut store, "foo")?;1052match instance1053.run_concurrent(&mut store, async move |accessor| {1054func.call_concurrent(accessor, ()).await1055})1056.await1057{1058Ok(_) => panic!(),1059Err(e) => {1060assert!(1061format!("{e:?}").contains(substring),1062"could not find `{substring}` in `{e:?}`"1063)1064}1065}10661067Ok(())1068}10691070#[tokio::test]1071async fn many_parameters() -> Result<()> {1072test_many_parameters(false, false).await1073}10741075#[tokio::test]1076async fn many_parameters_concurrent() -> Result<()> {1077test_many_parameters(false, true).await1078}10791080#[tokio::test]1081async fn many_parameters_dynamic() -> Result<()> {1082test_many_parameters(true, false).await1083}10841085#[tokio::test]1086async fn many_parameters_dynamic_concurrent() -> Result<()> {1087test_many_parameters(true, true).await1088}10891090async fn test_many_parameters(dynamic: bool, concurrent: bool) -> Result<()> {1091let (body, async_opts) = if concurrent {1092(1093r#"1094(call $task-return1095(i32.const 0)1096(i32.mul1097(memory.size)1098(i32.const 65536)1099)1100(local.get 0)1101)11021103(i32.const 0)1104"#,1105r#"async (callback (func $i "callback"))"#,1106)1107} else {1108(1109r#"1110(local $base i32)11111112;; Allocate space for the return1113(local.set $base1114(call $realloc1115(i32.const 0)1116(i32.const 0)1117(i32.const 4)1118(i32.const 12)))11191120;; Store the pointer/length of the entire linear memory1121;; so we have access to everything.1122(i32.store offset=01123(local.get $base)1124(i32.const 0))1125(i32.store offset=41126(local.get $base)1127(i32.mul1128(memory.size)1129(i32.const 65536)))11301131;; And also store our pointer parameter1132(i32.store offset=81133(local.get $base)1134(local.get 0))11351136(local.get $base)1137"#,1138"",1139)1140};11411142let component = format!(1143r#"(component1144(core module $libc1145(memory (export "memory") 1)11461147{REALLOC_AND_FREE}1148)1149(core instance $libc (instantiate $libc))1150(core module $m1151(import "libc" "memory" (memory 1))1152(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))1153(import "" "task.return" (func $task-return (param i32 i32 i32)))1154(func (export "foo") (param i32) (result i32)1155{body}1156)1157(func (export "callback") (param i32 i32 i32) (result i32) unreachable)1158)1159(type $tuple (tuple (list u8) u32))1160(core func $task-return (canon task.return1161(result $tuple)1162(memory $libc "memory")1163))1164(core instance $i (instantiate $m1165(with "" (instance (export "task.return" (func $task-return))))1166(with "libc" (instance $libc))1167))11681169(type $t (func1170(param "p1" s8) ;; offset 0, size 11171(param "p2" u64) ;; offset 8, size 81172(param "p3" float32) ;; offset 16, size 41173(param "p4" u8) ;; offset 20, size 11174(param "p5" s16) ;; offset 22, size 21175(param "p6" string) ;; offset 24, size 81176(param "p7" (list u32)) ;; offset 32, size 81177(param "p8" bool) ;; offset 40, size 11178(param "p9" bool) ;; offset 41, size 11179(param "p0" char) ;; offset 44, size 41180(param "pa" (list bool)) ;; offset 48, size 81181(param "pb" (list char)) ;; offset 56, size 81182(param "pc" (list string)) ;; offset 64, size 811831184(result $tuple)1185))1186(func (export "many-param") (type $t)1187(canon lift1188(core func $i "foo")1189(memory $libc "memory")1190(realloc (func $libc "realloc"))1191{async_opts}1192)1193)1194)"#1195);11961197let mut config = Config::new();1198config.wasm_component_model_async(true);1199config.async_support(true);1200let engine = &Engine::new(&config)?;1201let component = Component::new(&engine, component)?;1202let mut store = Store::new(&engine, ());12031204let instance = Linker::new(&engine)1205.instantiate_async(&mut store, &component)1206.await?;12071208let input = (1209-100,1210u64::MAX / 2,1211f32::from_bits(CANON_32BIT_NAN | 1),121238,121318831,1214"this is the first string",1215[1, 2, 3, 4, 5, 6, 7, 8].as_slice(),1216true,1217false,1218'��',1219[false, true, false, true, true].as_slice(),1220['��', '��', '��', '��', '��'].as_slice(),1221[1222"the quick",1223"brown fox",1224"was too lazy",1225"to jump over the dog",1226"what a demanding dog",1227]1228.as_slice(),1229);12301231let (memory, pointer) = if dynamic {1232let input = vec![1233Val::S8(input.0),1234Val::U64(input.1),1235Val::Float32(input.2),1236Val::U8(input.3),1237Val::S16(input.4),1238Val::String(input.5.into()),1239Val::List(input.6.iter().copied().map(Val::U32).collect()),1240Val::Bool(input.7),1241Val::Bool(input.8),1242Val::Char(input.9),1243Val::List(input.10.iter().copied().map(Val::Bool).collect()),1244Val::List(input.11.iter().copied().map(Val::Char).collect()),1245Val::List(input.12.iter().map(|&s| Val::String(s.into())).collect()),1246];1247let func = instance.get_func(&mut store, "many-param").unwrap();12481249let mut results = vec![Val::Bool(false)];1250if concurrent {1251instance1252.run_concurrent(&mut store, async |store| {1253func.call_concurrent(store, &input, &mut results).await1254})1255.await??;1256} else {1257func.call_async(&mut store, &input, &mut results).await?;1258};1259let mut results = results.into_iter();1260let Some(Val::Tuple(results)) = results.next() else {1261panic!()1262};1263let mut results = results.into_iter();1264let Some(Val::List(memory)) = results.next() else {1265panic!()1266};1267let Some(Val::U32(pointer)) = results.next() else {1268panic!()1269};1270(1271memory1272.into_iter()1273.map(|v| if let Val::U8(v) = v { v } else { panic!() })1274.collect(),1275pointer,1276)1277} else {1278let func = instance.get_typed_func::<(1279i8,1280u64,1281f32,1282u8,1283i16,1284&str,1285&[u32],1286bool,1287bool,1288char,1289&[bool],1290&[char],1291&[&str],1292), ((Vec<u8>, u32),)>(&mut store, "many-param")?;12931294if concurrent {1295instance1296.run_concurrent(&mut store, async move |accessor| {1297func.call_concurrent(accessor, input).await1298})1299.await??1300.01301} else {1302func.call_async(&mut store, input).await?.01303}1304};1305let memory = &memory[..];13061307let mut actual = &memory[pointer as usize..][..72];1308assert_eq!(i8::from_le_bytes(*actual.take_n::<1>()), input.0);1309actual.skip::<7>();1310assert_eq!(u64::from_le_bytes(*actual.take_n::<8>()), input.1);1311assert_eq!(1312u32::from_le_bytes(*actual.take_n::<4>()),1313CANON_32BIT_NAN | 11314);1315assert_eq!(u8::from_le_bytes(*actual.take_n::<1>()), input.3);1316actual.skip::<1>();1317assert_eq!(i16::from_le_bytes(*actual.take_n::<2>()), input.4);1318assert_eq!(actual.ptr_len(memory, 1), input.5.as_bytes());1319let mut mem = actual.ptr_len(memory, 4);1320for expected in input.6.iter() {1321assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected);1322}1323assert!(mem.is_empty());1324assert_eq!(actual.take_n::<1>(), &[input.7 as u8]);1325assert_eq!(actual.take_n::<1>(), &[input.8 as u8]);1326actual.skip::<2>();1327assert_eq!(u32::from_le_bytes(*actual.take_n::<4>()), input.9 as u32);13281329// (list bool)1330mem = actual.ptr_len(memory, 1);1331for expected in input.10.iter() {1332assert_eq!(mem.take_n::<1>(), &[*expected as u8]);1333}1334assert!(mem.is_empty());13351336// (list char)1337mem = actual.ptr_len(memory, 4);1338for expected in input.11.iter() {1339assert_eq!(u32::from_le_bytes(*mem.take_n::<4>()), *expected as u32);1340}1341assert!(mem.is_empty());13421343// (list string)1344mem = actual.ptr_len(memory, 8);1345for expected in input.12.iter() {1346let actual = mem.ptr_len(memory, 1);1347assert_eq!(actual, expected.as_bytes());1348}1349assert!(mem.is_empty());1350assert!(actual.is_empty());13511352Ok(())1353}13541355#[tokio::test]1356async fn many_results() -> Result<()> {1357test_many_results(false, false).await1358}13591360#[tokio::test]1361async fn many_results_concurrent() -> Result<()> {1362test_many_results(false, true).await1363}13641365#[tokio::test]1366async fn many_results_dynamic() -> Result<()> {1367test_many_results(true, false).await1368}13691370#[tokio::test]1371async fn many_results_dynamic_concurrent() -> Result<()> {1372test_many_results(true, true).await1373}13741375async fn test_many_results(dynamic: bool, concurrent: bool) -> Result<()> {1376let (ret, async_opts) = if concurrent {1377(1378r#"1379call $task-return1380i32.const 01381"#,1382r#"async (callback (func $i "callback"))"#,1383)1384} else {1385("", "")1386};13871388let my_nan = CANON_32BIT_NAN | 1;13891390let component = format!(1391r#"(component1392(core module $libc1393(memory (export "memory") 1)13941395{REALLOC_AND_FREE}1396)1397(core instance $libc (instantiate $libc))1398(core module $m1399(import "libc" "memory" (memory 1))1400(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))1401(import "" "task.return" (func $task-return (param i32)))1402(func (export "foo") (result i32)1403(local $base i32)1404(local $string i32)1405(local $list i32)14061407(local.set $base1408(call $realloc1409(i32.const 0)1410(i32.const 0)1411(i32.const 8)1412(i32.const 72)))14131414(i32.store8 offset=01415(local.get $base)1416(i32.const -100))14171418(i64.store offset=81419(local.get $base)1420(i64.const 9223372036854775807))14211422(f32.store offset=161423(local.get $base)1424(f32.reinterpret_i32 (i32.const {my_nan})))14251426(i32.store8 offset=201427(local.get $base)1428(i32.const 38))14291430(i32.store16 offset=221431(local.get $base)1432(i32.const 18831))14331434(local.set $string1435(call $realloc1436(i32.const 0)1437(i32.const 0)1438(i32.const 1)1439(i32.const 6)))14401441(i32.store8 offset=01442(local.get $string)1443(i32.const 97)) ;; 'a'1444(i32.store8 offset=11445(local.get $string)1446(i32.const 98)) ;; 'b'1447(i32.store8 offset=21448(local.get $string)1449(i32.const 99)) ;; 'c'1450(i32.store8 offset=31451(local.get $string)1452(i32.const 100)) ;; 'd'1453(i32.store8 offset=41454(local.get $string)1455(i32.const 101)) ;; 'e'1456(i32.store8 offset=51457(local.get $string)1458(i32.const 102)) ;; 'f'14591460(i32.store offset=241461(local.get $base)1462(local.get $string))14631464(i32.store offset=281465(local.get $base)1466(i32.const 2))14671468(local.set $list1469(call $realloc1470(i32.const 0)1471(i32.const 0)1472(i32.const 4)1473(i32.const 32)))14741475(i32.store offset=01476(local.get $list)1477(i32.const 1))1478(i32.store offset=41479(local.get $list)1480(i32.const 2))1481(i32.store offset=81482(local.get $list)1483(i32.const 3))1484(i32.store offset=121485(local.get $list)1486(i32.const 4))1487(i32.store offset=161488(local.get $list)1489(i32.const 5))1490(i32.store offset=201491(local.get $list)1492(i32.const 6))1493(i32.store offset=241494(local.get $list)1495(i32.const 7))1496(i32.store offset=281497(local.get $list)1498(i32.const 8))14991500(i32.store offset=321501(local.get $base)1502(local.get $list))15031504(i32.store offset=361505(local.get $base)1506(i32.const 8))15071508(i32.store8 offset=401509(local.get $base)1510(i32.const 1))15111512(i32.store8 offset=411513(local.get $base)1514(i32.const 0))15151516(i32.store offset=441517(local.get $base)1518(i32.const 128681)) ;; '🚩'15191520(local.set $list1521(call $realloc1522(i32.const 0)1523(i32.const 0)1524(i32.const 1)1525(i32.const 5)))15261527(i32.store8 offset=01528(local.get $list)1529(i32.const 0))1530(i32.store8 offset=11531(local.get $list)1532(i32.const 1))1533(i32.store8 offset=21534(local.get $list)1535(i32.const 0))1536(i32.store8 offset=31537(local.get $list)1538(i32.const 1))1539(i32.store8 offset=41540(local.get $list)1541(i32.const 1))15421543(i32.store offset=481544(local.get $base)1545(local.get $list))15461547(i32.store offset=521548(local.get $base)1549(i32.const 5))15501551(local.set $list1552(call $realloc1553(i32.const 0)1554(i32.const 0)1555(i32.const 4)1556(i32.const 20)))15571558(i32.store offset=01559(local.get $list)1560(i32.const 127820)) ;; '🍌'1561(i32.store offset=41562(local.get $list)1563(i32.const 129360)) ;; '🥐'1564(i32.store offset=81565(local.get $list)1566(i32.const 127831)) ;; '🍗'1567(i32.store offset=121568(local.get $list)1569(i32.const 127833)) ;; '🍙'1570(i32.store offset=161571(local.get $list)1572(i32.const 127841)) ;; '🍡'15731574(i32.store offset=561575(local.get $base)1576(local.get $list))15771578(i32.store offset=601579(local.get $base)1580(i32.const 5))15811582(local.set $list1583(call $realloc1584(i32.const 0)1585(i32.const 0)1586(i32.const 4)1587(i32.const 16)))15881589(i32.store offset=01590(local.get $list)1591(i32.add (local.get $string) (i32.const 2)))1592(i32.store offset=41593(local.get $list)1594(i32.const 2))1595(i32.store offset=81596(local.get $list)1597(i32.add (local.get $string) (i32.const 4)))1598(i32.store offset=121599(local.get $list)1600(i32.const 2))16011602(i32.store offset=641603(local.get $base)1604(local.get $list))16051606(i32.store offset=681607(local.get $base)1608(i32.const 2))16091610local.get $base16111612{ret}1613)1614(func (export "callback") (param i32 i32 i32) (result i32) unreachable)1615)1616(type $tuple (tuple1617s81618u641619float321620u81621s161622string1623(list u32)1624bool1625bool1626char1627(list bool)1628(list char)1629(list string)1630))1631(core func $task-return (canon task.return1632(result $tuple)1633(memory $libc "memory")1634))1635(core instance $i (instantiate $m1636(with "" (instance (export "task.return" (func $task-return))))1637(with "libc" (instance $libc))1638))16391640(type $t (func (result $tuple)))1641(func (export "many-results") (type $t)1642(canon lift1643(core func $i "foo")1644(memory $libc "memory")1645(realloc (func $libc "realloc"))1646{async_opts}1647)1648)1649)"#1650);16511652let mut config = Config::new();1653config.wasm_component_model_async(true);1654config.async_support(true);1655let engine = &Engine::new(&config)?;1656let component = Component::new(&engine, component)?;1657let mut store = Store::new(&engine, ());16581659let instance = Linker::new(&engine)1660.instantiate_async(&mut store, &component)1661.await?;16621663let expected = (1664-100i8,1665u64::MAX / 2,1666f32::from_bits(CANON_32BIT_NAN | 1),166738u8,166818831i16,1669"ab".to_string(),1670vec![1u32, 2, 3, 4, 5, 6, 7, 8],1671true,1672false,1673'��',1674vec![false, true, false, true, true],1675vec!['��', '��', '��', '��', '��'],1676vec!["cd".to_string(), "ef".to_string()],1677);16781679let actual = if dynamic {1680let func = instance.get_func(&mut store, "many-results").unwrap();16811682let mut results = vec![Val::Bool(false)];1683if concurrent {1684instance1685.run_concurrent(&mut store, async |store| {1686func.call_concurrent(store, &[], &mut results).await1687})1688.await??;1689} else {1690func.call_async(&mut store, &[], &mut results).await?;1691};1692let mut results = results.into_iter();16931694let Some(Val::Tuple(results)) = results.next() else {1695panic!()1696};1697let mut results = results.into_iter();1698let Some(Val::S8(p1)) = results.next() else {1699panic!()1700};1701let Some(Val::U64(p2)) = results.next() else {1702panic!()1703};1704let Some(Val::Float32(p3)) = results.next() else {1705panic!()1706};1707let Some(Val::U8(p4)) = results.next() else {1708panic!()1709};1710let Some(Val::S16(p5)) = results.next() else {1711panic!()1712};1713let Some(Val::String(p6)) = results.next() else {1714panic!()1715};1716let Some(Val::List(p7)) = results.next() else {1717panic!()1718};1719let p7 = p71720.into_iter()1721.map(|v| if let Val::U32(v) = v { v } else { panic!() })1722.collect();1723let Some(Val::Bool(p8)) = results.next() else {1724panic!()1725};1726let Some(Val::Bool(p9)) = results.next() else {1727panic!()1728};1729let Some(Val::Char(p0)) = results.next() else {1730panic!()1731};1732let Some(Val::List(pa)) = results.next() else {1733panic!()1734};1735let pa = pa1736.into_iter()1737.map(|v| if let Val::Bool(v) = v { v } else { panic!() })1738.collect();1739let Some(Val::List(pb)) = results.next() else {1740panic!()1741};1742let pb = pb1743.into_iter()1744.map(|v| if let Val::Char(v) = v { v } else { panic!() })1745.collect();1746let Some(Val::List(pc)) = results.next() else {1747panic!()1748};1749let pc = pc1750.into_iter()1751.map(|v| if let Val::String(v) = v { v } else { panic!() })1752.collect();17531754(p1, p2, p3, p4, p5, p6, p7, p8, p9, p0, pa, pb, pc)1755} else {1756let func = instance.get_typed_func::<(), ((1757i8,1758u64,1759f32,1760u8,1761i16,1762String,1763Vec<u32>,1764bool,1765bool,1766char,1767Vec<bool>,1768Vec<char>,1769Vec<String>,1770),)>(&mut store, "many-results")?;17711772if concurrent {1773instance1774.run_concurrent(&mut store, async move |accessor| {1775func.call_concurrent(accessor, ()).await1776})1777.await??1778.01779} else {1780func.call_async(&mut store, ()).await?.01781}1782};17831784assert_eq!(expected.0, actual.0);1785assert_eq!(expected.1, actual.1);1786assert!(expected.2.is_nan());1787assert!(actual.2.is_nan());1788assert_eq!(expected.3, actual.3);1789assert_eq!(expected.4, actual.4);1790assert_eq!(expected.5, actual.5);1791assert_eq!(expected.6, actual.6);1792assert_eq!(expected.7, actual.7);1793assert_eq!(expected.8, actual.8);1794assert_eq!(expected.9, actual.9);1795assert_eq!(expected.10, actual.10);1796assert_eq!(expected.11, actual.11);1797assert_eq!(expected.12, actual.12);17981799Ok(())1800}18011802#[test]1803fn some_traps() -> Result<()> {1804let middle_of_memory = (i32::MAX / 2) & (!0xff);1805let component = format!(1806r#"(component1807(core module $m1808(memory (export "memory") 1)1809(func (export "take-many") (param i32))1810(func (export "take-list") (param i32 i32))18111812(func (export "realloc") (param i32 i32 i32 i32) (result i32)1813unreachable)1814)1815(core instance $i (instantiate $m))18161817(func (export "take-list-unreachable") (param "a" (list u8))1818(canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc")))1819)1820(func (export "take-string-unreachable") (param "a" string)1821(canon lift (core func $i "take-list") (memory $i "memory") (realloc (func $i "realloc")))1822)18231824(type $t (func1825(param "s1" string)1826(param "s2" string)1827(param "s3" string)1828(param "s4" string)1829(param "s5" string)1830(param "s6" string)1831(param "s7" string)1832(param "s8" string)1833(param "s9" string)1834(param "s10" string)1835))1836(func (export "take-many-unreachable") (type $t)1837(canon lift (core func $i "take-many") (memory $i "memory") (realloc (func $i "realloc")))1838)18391840(core module $m21841(memory (export "memory") 1)1842(func (export "take-many") (param i32))1843(func (export "take-list") (param i32 i32))18441845(func (export "realloc") (param i32 i32 i32 i32) (result i32)1846i32.const {middle_of_memory})1847)1848(core instance $i2 (instantiate $m2))18491850(func (export "take-list-base-oob") (param "a" (list u8))1851(canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc")))1852)1853(func (export "take-string-base-oob") (param "a" string)1854(canon lift (core func $i2 "take-list") (memory $i2 "memory") (realloc (func $i2 "realloc")))1855)1856(func (export "take-many-base-oob") (type $t)1857(canon lift (core func $i2 "take-many") (memory $i2 "memory") (realloc (func $i2 "realloc")))1858)18591860(core module $m31861(memory (export "memory") 1)1862(func (export "take-many") (param i32))1863(func (export "take-list") (param i32 i32))18641865(func (export "realloc") (param i32 i32 i32 i32) (result i32)1866i32.const 65532)1867)1868(core instance $i3 (instantiate $m3))18691870(func (export "take-list-end-oob") (param "a" (list u8))1871(canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc")))1872)1873(func (export "take-string-end-oob") (param "a" string)1874(canon lift (core func $i3 "take-list") (memory $i3 "memory") (realloc (func $i3 "realloc")))1875)1876(func (export "take-many-end-oob") (type $t)1877(canon lift (core func $i3 "take-many") (memory $i3 "memory") (realloc (func $i3 "realloc")))1878)18791880(core module $m41881(memory (export "memory") 1)1882(func (export "take-many") (param i32))18831884(global $cnt (mut i32) (i32.const 0))1885(func (export "realloc") (param i32 i32 i32 i32) (result i32)1886global.get $cnt1887if (result i32)1888i32.const 1000001889else1890i32.const 11891global.set $cnt1892i32.const 01893end1894)1895)1896(core instance $i4 (instantiate $m4))18971898(func (export "take-many-second-oob") (type $t)1899(canon lift (core func $i4 "take-many") (memory $i4 "memory") (realloc (func $i4 "realloc")))1900)1901)"#1902);19031904let engine = super::engine();1905let component = Component::new(&engine, component)?;1906let mut store = Store::new(&engine, ());1907let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component);19081909// This should fail when calling the allocator function for the argument1910let err = instance(&mut store)?1911.get_typed_func::<(&[u8],), ()>(&mut store, "take-list-unreachable")?1912.call(&mut store, (&[],))1913.unwrap_err()1914.downcast::<Trap>()?;1915assert_eq!(err, Trap::UnreachableCodeReached);19161917// This should fail when calling the allocator function for the argument1918let err = instance(&mut store)?1919.get_typed_func::<(&str,), ()>(&mut store, "take-string-unreachable")?1920.call(&mut store, ("",))1921.unwrap_err()1922.downcast::<Trap>()?;1923assert_eq!(err, Trap::UnreachableCodeReached);19241925// This should fail when calling the allocator function for the space1926// to store the arguments (before arguments are even lowered)1927let err = instance(&mut store)?1928.get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(1929&mut store,1930"take-many-unreachable",1931)?1932.call(&mut store, ("", "", "", "", "", "", "", "", "", ""))1933.unwrap_err()1934.downcast::<Trap>()?;1935assert_eq!(err, Trap::UnreachableCodeReached);19361937// Assert that when the base pointer returned by malloc is out of bounds1938// that errors are reported as such. Both empty and lists with contents1939// should all be invalid here.1940//1941// FIXME(WebAssembly/component-model#32) confirm the semantics here are1942// what's desired.1943#[track_caller]1944fn assert_oob(err: &anyhow::Error) {1945assert!(1946err.to_string()1947.contains("realloc return: beyond end of memory"),1948"{err:?}",1949);1950}1951let err = instance(&mut store)?1952.get_typed_func::<(&[u8],), ()>(&mut store, "take-list-base-oob")?1953.call(&mut store, (&[],))1954.unwrap_err();1955assert_oob(&err);1956let err = instance(&mut store)?1957.get_typed_func::<(&[u8],), ()>(&mut store, "take-list-base-oob")?1958.call(&mut store, (&[1],))1959.unwrap_err();1960assert_oob(&err);1961let err = instance(&mut store)?1962.get_typed_func::<(&str,), ()>(&mut store, "take-string-base-oob")?1963.call(&mut store, ("",))1964.unwrap_err();1965assert_oob(&err);1966let err = instance(&mut store)?1967.get_typed_func::<(&str,), ()>(&mut store, "take-string-base-oob")?1968.call(&mut store, ("x",))1969.unwrap_err();1970assert_oob(&err);1971let err = instance(&mut store)?1972.get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(1973&mut store,1974"take-many-base-oob",1975)?1976.call(&mut store, ("", "", "", "", "", "", "", "", "", ""))1977.unwrap_err();1978assert_oob(&err);19791980// Test here that when the returned pointer from malloc is one byte from the1981// end of memory that empty things are fine, but larger things are not.19821983instance(&mut store)?1984.get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")?1985.call_and_post_return(&mut store, (&[],))?;1986instance(&mut store)?1987.get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")?1988.call_and_post_return(&mut store, (&[1, 2, 3, 4],))?;1989let err = instance(&mut store)?1990.get_typed_func::<(&[u8],), ()>(&mut store, "take-list-end-oob")?1991.call(&mut store, (&[1, 2, 3, 4, 5],))1992.unwrap_err();1993assert_oob(&err);1994instance(&mut store)?1995.get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")?1996.call_and_post_return(&mut store, ("",))?;1997instance(&mut store)?1998.get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")?1999.call_and_post_return(&mut store, ("abcd",))?;2000let err = instance(&mut store)?2001.get_typed_func::<(&str,), ()>(&mut store, "take-string-end-oob")?2002.call(&mut store, ("abcde",))2003.unwrap_err();2004assert_oob(&err);2005let err = instance(&mut store)?2006.get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(2007&mut store,2008"take-many-end-oob",2009)?2010.call(&mut store, ("", "", "", "", "", "", "", "", "", ""))2011.unwrap_err();2012assert_oob(&err);20132014// For this function the first allocation, the space to store all the2015// arguments, is in-bounds but then all further allocations, such as for2016// each individual string, are all out of bounds.2017let err = instance(&mut store)?2018.get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(2019&mut store,2020"take-many-second-oob",2021)?2022.call(&mut store, ("", "", "", "", "", "", "", "", "", ""))2023.unwrap_err();2024assert_oob(&err);2025let err = instance(&mut store)?2026.get_typed_func::<(&str, &str, &str, &str, &str, &str, &str, &str, &str, &str), ()>(2027&mut store,2028"take-many-second-oob",2029)?2030.call(&mut store, ("", "", "", "", "", "", "", "", "", "x"))2031.unwrap_err();2032assert_oob(&err);2033Ok(())2034}20352036#[test]2037fn char_bool_memory() -> Result<()> {2038let component = format!(2039r#"(component2040(core module $m2041(memory (export "memory") 1)2042(func (export "ret-tuple") (param i32 i32) (result i32)2043(local $base i32)20442045;; Allocate space for the return2046(local.set $base2047(call $realloc2048(i32.const 0)2049(i32.const 0)2050(i32.const 4)2051(i32.const 8)))20522053;; store the boolean2054(i32.store offset=02055(local.get $base)2056(local.get 0))20572058;; store the char2059(i32.store offset=42060(local.get $base)2061(local.get 1))20622063(local.get $base)2064)20652066{REALLOC_AND_FREE}2067)2068(core instance $i (instantiate $m))20692070(func (export "ret-tuple") (param "a" u32) (param "b" u32) (result (tuple bool char))2071(canon lift (core func $i "ret-tuple")2072(memory $i "memory")2073(realloc (func $i "realloc")))2074)2075)"#2076);20772078let engine = super::engine();2079let component = Component::new(&engine, component)?;2080let mut store = Store::new(&engine, ());2081let instance = Linker::new(&engine).instantiate(&mut store, &component)?;2082let func = instance.get_typed_func::<(u32, u32), ((bool, char),)>(&mut store, "ret-tuple")?;20832084let (ret,) = func.call(&mut store, (0, 'a' as u32))?;2085assert_eq!(ret, (false, 'a'));2086func.post_return(&mut store)?;20872088let (ret,) = func.call(&mut store, (1, '��' as u32))?;2089assert_eq!(ret, (true, '��'));2090func.post_return(&mut store)?;20912092let (ret,) = func.call(&mut store, (2, 'a' as u32))?;2093assert_eq!(ret, (true, 'a'));2094func.post_return(&mut store)?;20952096assert!(func.call(&mut store, (0, 0xd800)).is_err());20972098Ok(())2099}21002101#[test]2102fn string_list_oob() -> Result<()> {2103let component = format!(2104r#"(component2105(core module $m2106(memory (export "memory") 1)2107(func (export "ret-list") (result i32)2108(local $base i32)21092110;; Allocate space for the return2111(local.set $base2112(call $realloc2113(i32.const 0)2114(i32.const 0)2115(i32.const 4)2116(i32.const 8)))21172118(i32.store offset=02119(local.get $base)2120(i32.const 100000))2121(i32.store offset=42122(local.get $base)2123(i32.const 1))21242125(local.get $base)2126)21272128{REALLOC_AND_FREE}2129)2130(core instance $i (instantiate $m))21312132(func (export "ret-list-u8") (result (list u8))2133(canon lift (core func $i "ret-list")2134(memory $i "memory")2135(realloc (func $i "realloc"))2136)2137)2138(func (export "ret-string") (result string)2139(canon lift (core func $i "ret-list")2140(memory $i "memory")2141(realloc (func $i "realloc"))2142)2143)2144)"#2145);21462147let engine = super::engine();2148let component = Component::new(&engine, component)?;2149let mut store = Store::new(&engine, ());2150let ret_list_u8 = Linker::new(&engine)2151.instantiate(&mut store, &component)?2152.get_typed_func::<(), (WasmList<u8>,)>(&mut store, "ret-list-u8")?;2153let ret_string = Linker::new(&engine)2154.instantiate(&mut store, &component)?2155.get_typed_func::<(), (WasmStr,)>(&mut store, "ret-string")?;21562157let err = ret_list_u8.call(&mut store, ()).err().unwrap();2158assert!(err.to_string().contains("out of bounds"), "{}", err);21592160let err = ret_string.call(&mut store, ()).err().unwrap();2161assert!(err.to_string().contains("out of bounds"), "{}", err);21622163Ok(())2164}21652166#[test]2167fn tuples() -> Result<()> {2168let component = format!(2169r#"(component2170(core module $m2171(memory (export "memory") 1)2172(func (export "foo")2173(param i32 f64 i32)2174(result i32)21752176local.get 02177i32.const 02178i32.ne2179if unreachable end21802181local.get 12182f64.const 12183f64.ne2184if unreachable end21852186local.get 22187i32.const 22188i32.ne2189if unreachable end21902191i32.const 32192)2193)2194(core instance $i (instantiate $m))21952196(func (export "foo")2197(param "a" (tuple s32 float64))2198(param "b" (tuple s8))2199(result (tuple u16))2200(canon lift (core func $i "foo"))2201)2202)"#2203);22042205let engine = super::engine();2206let component = Component::new(&engine, component)?;2207let mut store = Store::new(&engine, ());2208let instance = Linker::new(&engine).instantiate(&mut store, &component)?;2209let foo = instance.get_typed_func::<((i32, f64), (i8,)), ((u16,),)>(&mut store, "foo")?;2210assert_eq!(foo.call(&mut store, ((0, 1.0), (2,)))?, ((3,),));22112212Ok(())2213}22142215#[test]2216fn option() -> Result<()> {2217let component = format!(2218r#"(component2219(core module $m2220(memory (export "memory") 1)2221(func (export "pass1") (param i32 i32) (result i32)2222(local $base i32)2223(local.set $base2224(call $realloc2225(i32.const 0)2226(i32.const 0)2227(i32.const 4)2228(i32.const 8)))22292230(i32.store offset=02231(local.get $base)2232(local.get 0))2233(i32.store offset=42234(local.get $base)2235(local.get 1))22362237(local.get $base)2238)2239(func (export "pass2") (param i32 i32 i32) (result i32)2240(local $base i32)2241(local.set $base2242(call $realloc2243(i32.const 0)2244(i32.const 0)2245(i32.const 4)2246(i32.const 12)))22472248(i32.store offset=02249(local.get $base)2250(local.get 0))2251(i32.store offset=42252(local.get $base)2253(local.get 1))2254(i32.store offset=82255(local.get $base)2256(local.get 2))22572258(local.get $base)2259)22602261{REALLOC_AND_FREE}2262)2263(core instance $i (instantiate $m))22642265(func (export "option-u8-to-tuple") (param "a" (option u8)) (result (tuple u32 u32))2266(canon lift (core func $i "pass1") (memory $i "memory"))2267)2268(func (export "option-u32-to-tuple") (param "a" (option u32)) (result (tuple u32 u32))2269(canon lift (core func $i "pass1") (memory $i "memory"))2270)2271(func (export "option-string-to-tuple") (param "a" (option string)) (result (tuple u32 string))2272(canon lift2273(core func $i "pass2")2274(memory $i "memory")2275(realloc (func $i "realloc"))2276)2277)2278(func (export "to-option-u8") (param "a" u32) (param "b" u32) (result (option u8))2279(canon lift (core func $i "pass1") (memory $i "memory"))2280)2281(func (export "to-option-u32") (param "a" u32) (param "b" u32) (result (option u32))2282(canon lift2283(core func $i "pass1")2284(memory $i "memory")2285)2286)2287(func (export "to-option-string") (param "a" u32) (param "b" string) (result (option string))2288(canon lift2289(core func $i "pass2")2290(memory $i "memory")2291(realloc (func $i "realloc"))2292)2293)2294)"#2295);22962297let engine = super::engine();2298let component = Component::new(&engine, component)?;2299let mut store = Store::new(&engine, ());2300let linker = Linker::new(&engine);2301let instance = linker.instantiate(&mut store, &component)?;23022303let option_u8_to_tuple = instance2304.get_typed_func::<(Option<u8>,), ((u32, u32),)>(&mut store, "option-u8-to-tuple")?;2305assert_eq!(option_u8_to_tuple.call(&mut store, (None,))?, ((0, 0),));2306option_u8_to_tuple.post_return(&mut store)?;2307assert_eq!(option_u8_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),));2308option_u8_to_tuple.post_return(&mut store)?;2309assert_eq!(2310option_u8_to_tuple.call(&mut store, (Some(100),))?,2311((1, 100),)2312);2313option_u8_to_tuple.post_return(&mut store)?;23142315let option_u32_to_tuple = instance2316.get_typed_func::<(Option<u32>,), ((u32, u32),)>(&mut store, "option-u32-to-tuple")?;2317assert_eq!(option_u32_to_tuple.call(&mut store, (None,))?, ((0, 0),));2318option_u32_to_tuple.post_return(&mut store)?;2319assert_eq!(option_u32_to_tuple.call(&mut store, (Some(0),))?, ((1, 0),));2320option_u32_to_tuple.post_return(&mut store)?;2321assert_eq!(2322option_u32_to_tuple.call(&mut store, (Some(100),))?,2323((1, 100),)2324);2325option_u32_to_tuple.post_return(&mut store)?;23262327let option_string_to_tuple = instance.get_typed_func::<(Option<&str>,), ((u32, WasmStr),)>(2328&mut store,2329"option-string-to-tuple",2330)?;2331let ((a, b),) = option_string_to_tuple.call(&mut store, (None,))?;2332assert_eq!(a, 0);2333assert_eq!(b.to_str(&store)?, "");2334option_string_to_tuple.post_return(&mut store)?;2335let ((a, b),) = option_string_to_tuple.call(&mut store, (Some(""),))?;2336assert_eq!(a, 1);2337assert_eq!(b.to_str(&store)?, "");2338option_string_to_tuple.post_return(&mut store)?;2339let ((a, b),) = option_string_to_tuple.call(&mut store, (Some("hello"),))?;2340assert_eq!(a, 1);2341assert_eq!(b.to_str(&store)?, "hello");2342option_string_to_tuple.post_return(&mut store)?;23432344let instance = linker.instantiate(&mut store, &component)?;2345let to_option_u8 =2346instance.get_typed_func::<(u32, u32), (Option<u8>,)>(&mut store, "to-option-u8")?;2347assert_eq!(to_option_u8.call(&mut store, (0x00_00, 0))?, (None,));2348to_option_u8.post_return(&mut store)?;2349assert_eq!(to_option_u8.call(&mut store, (0x00_01, 0))?, (Some(0),));2350to_option_u8.post_return(&mut store)?;2351assert_eq!(to_option_u8.call(&mut store, (0xfd_01, 0))?, (Some(0xfd),));2352to_option_u8.post_return(&mut store)?;2353assert!(to_option_u8.call(&mut store, (0x00_02, 0)).is_err());23542355let instance = linker.instantiate(&mut store, &component)?;2356let to_option_u32 =2357instance.get_typed_func::<(u32, u32), (Option<u32>,)>(&mut store, "to-option-u32")?;2358assert_eq!(to_option_u32.call(&mut store, (0, 0))?, (None,));2359to_option_u32.post_return(&mut store)?;2360assert_eq!(to_option_u32.call(&mut store, (1, 0))?, (Some(0),));2361to_option_u32.post_return(&mut store)?;2362assert_eq!(2363to_option_u32.call(&mut store, (1, 0x1234fead))?,2364(Some(0x1234fead),)2365);2366to_option_u32.post_return(&mut store)?;2367assert!(to_option_u32.call(&mut store, (2, 0)).is_err());23682369let instance = linker.instantiate(&mut store, &component)?;2370let to_option_string = instance2371.get_typed_func::<(u32, &str), (Option<WasmStr>,)>(&mut store, "to-option-string")?;2372let ret = to_option_string.call(&mut store, (0, ""))?.0;2373assert!(ret.is_none());2374to_option_string.post_return(&mut store)?;2375let ret = to_option_string.call(&mut store, (1, ""))?.0;2376assert_eq!(ret.unwrap().to_str(&store)?, "");2377to_option_string.post_return(&mut store)?;2378let ret = to_option_string.call(&mut store, (1, "cheesecake"))?.0;2379assert_eq!(ret.unwrap().to_str(&store)?, "cheesecake");2380to_option_string.post_return(&mut store)?;2381assert!(to_option_string.call(&mut store, (2, "")).is_err());23822383Ok(())2384}23852386#[test]2387fn expected() -> Result<()> {2388let component = format!(2389r#"(component2390(core module $m2391(memory (export "memory") 1)2392(func (export "pass0") (param i32) (result i32)2393local.get 02394)2395(func (export "pass1") (param i32 i32) (result i32)2396(local $base i32)2397(local.set $base2398(call $realloc2399(i32.const 0)2400(i32.const 0)2401(i32.const 4)2402(i32.const 8)))24032404(i32.store offset=02405(local.get $base)2406(local.get 0))2407(i32.store offset=42408(local.get $base)2409(local.get 1))24102411(local.get $base)2412)2413(func (export "pass2") (param i32 i32 i32) (result i32)2414(local $base i32)2415(local.set $base2416(call $realloc2417(i32.const 0)2418(i32.const 0)2419(i32.const 4)2420(i32.const 12)))24212422(i32.store offset=02423(local.get $base)2424(local.get 0))2425(i32.store offset=42426(local.get $base)2427(local.get 1))2428(i32.store offset=82429(local.get $base)2430(local.get 2))24312432(local.get $base)2433)24342435{REALLOC_AND_FREE}2436)2437(core instance $i (instantiate $m))24382439(func (export "take-expected-unit") (param "a" (result)) (result u32)2440(canon lift (core func $i "pass0"))2441)2442(func (export "take-expected-u8-f32") (param "a" (result u8 (error float32))) (result (tuple u32 u32))2443(canon lift (core func $i "pass1") (memory $i "memory"))2444)2445(type $list (list u8))2446(func (export "take-expected-string") (param "a" (result string (error $list))) (result (tuple u32 string))2447(canon lift2448(core func $i "pass2")2449(memory $i "memory")2450(realloc (func $i "realloc"))2451)2452)2453(func (export "to-expected-unit") (param "a" u32) (result (result))2454(canon lift (core func $i "pass0"))2455)2456(func (export "to-expected-s16-f32") (param "a" u32) (param "b" u32) (result (result s16 (error float32)))2457(canon lift2458(core func $i "pass1")2459(memory $i "memory")2460(realloc (func $i "realloc"))2461)2462)2463)"#2464);24652466let engine = super::engine();2467let component = Component::new(&engine, component)?;2468let mut store = Store::new(&engine, ());2469let linker = Linker::new(&engine);2470let instance = linker.instantiate(&mut store, &component)?;2471let take_expected_unit =2472instance.get_typed_func::<(Result<(), ()>,), (u32,)>(&mut store, "take-expected-unit")?;2473assert_eq!(take_expected_unit.call(&mut store, (Ok(()),))?, (0,));2474take_expected_unit.post_return(&mut store)?;2475assert_eq!(take_expected_unit.call(&mut store, (Err(()),))?, (1,));2476take_expected_unit.post_return(&mut store)?;24772478let take_expected_u8_f32 = instance2479.get_typed_func::<(Result<u8, f32>,), ((u32, u32),)>(&mut store, "take-expected-u8-f32")?;2480assert_eq!(take_expected_u8_f32.call(&mut store, (Ok(1),))?, ((0, 1),));2481take_expected_u8_f32.post_return(&mut store)?;2482assert_eq!(2483take_expected_u8_f32.call(&mut store, (Err(2.0),))?,2484((1, 2.0f32.to_bits()),)2485);2486take_expected_u8_f32.post_return(&mut store)?;24872488let take_expected_string = instance2489.get_typed_func::<(Result<&str, &[u8]>,), ((u32, WasmStr),)>(2490&mut store,2491"take-expected-string",2492)?;2493let ((a, b),) = take_expected_string.call(&mut store, (Ok("hello"),))?;2494assert_eq!(a, 0);2495assert_eq!(b.to_str(&store)?, "hello");2496take_expected_string.post_return(&mut store)?;2497let ((a, b),) = take_expected_string.call(&mut store, (Err(b"goodbye"),))?;2498assert_eq!(a, 1);2499assert_eq!(b.to_str(&store)?, "goodbye");2500take_expected_string.post_return(&mut store)?;25012502let instance = linker.instantiate(&mut store, &component)?;2503let to_expected_unit =2504instance.get_typed_func::<(u32,), (Result<(), ()>,)>(&mut store, "to-expected-unit")?;2505assert_eq!(to_expected_unit.call(&mut store, (0,))?, (Ok(()),));2506to_expected_unit.post_return(&mut store)?;2507assert_eq!(to_expected_unit.call(&mut store, (1,))?, (Err(()),));2508to_expected_unit.post_return(&mut store)?;2509let err = to_expected_unit.call(&mut store, (2,)).unwrap_err();2510assert!(err.to_string().contains("invalid expected"), "{}", err);25112512let instance = linker.instantiate(&mut store, &component)?;2513let to_expected_s16_f32 = instance2514.get_typed_func::<(u32, u32), (Result<i16, f32>,)>(&mut store, "to-expected-s16-f32")?;2515assert_eq!(to_expected_s16_f32.call(&mut store, (0, 0))?, (Ok(0),));2516to_expected_s16_f32.post_return(&mut store)?;2517assert_eq!(to_expected_s16_f32.call(&mut store, (0, 100))?, (Ok(100),));2518to_expected_s16_f32.post_return(&mut store)?;2519assert_eq!(2520to_expected_s16_f32.call(&mut store, (1, 1.0f32.to_bits()))?,2521(Err(1.0),)2522);2523to_expected_s16_f32.post_return(&mut store)?;2524let ret = to_expected_s16_f322525.call(&mut store, (1, CANON_32BIT_NAN | 1))?2526.0;2527assert_eq!(ret.unwrap_err().to_bits(), CANON_32BIT_NAN | 1);2528to_expected_s16_f32.post_return(&mut store)?;2529assert!(to_expected_s16_f32.call(&mut store, (2, 0)).is_err());25302531Ok(())2532}25332534#[test]2535fn fancy_list() -> Result<()> {2536let component = format!(2537r#"(component2538(core module $m2539(memory (export "memory") 1)2540(func (export "take") (param i32 i32) (result i32)2541(local $base i32)2542(local.set $base2543(call $realloc2544(i32.const 0)2545(i32.const 0)2546(i32.const 4)2547(i32.const 16)))25482549(i32.store offset=02550(local.get $base)2551(local.get 0))2552(i32.store offset=42553(local.get $base)2554(local.get 1))2555(i32.store offset=82556(local.get $base)2557(i32.const 0))2558(i32.store offset=122559(local.get $base)2560(i32.mul2561(memory.size)2562(i32.const 65536)))25632564(local.get $base)2565)25662567{REALLOC_AND_FREE}2568)2569(core instance $i (instantiate $m))25702571(type $a (option u8))2572(type $b (result (error string)))2573(type $input (list (tuple $a $b)))2574(func (export "take")2575(param "a" $input)2576(result (tuple u32 u32 (list u8)))2577(canon lift2578(core func $i "take")2579(memory $i "memory")2580(realloc (func $i "realloc"))2581)2582)2583)"#2584);25852586let engine = super::engine();2587let component = Component::new(&engine, component)?;2588let mut store = Store::new(&engine, ());2589let instance = Linker::new(&engine).instantiate(&mut store, &component)?;25902591let func = instance2592.get_typed_func::<(&[(Option<u8>, Result<(), &str>)],), ((u32, u32, WasmList<u8>),)>(2593&mut store, "take",2594)?;25952596let input = [2597(None, Ok(())),2598(Some(2), Err("hello there")),2599(Some(200), Err("general kenobi")),2600];2601let ((ptr, len, list),) = func.call(&mut store, (&input,))?;2602let memory = list.as_le_slice(&store);2603let ptr = usize::try_from(ptr).unwrap();2604let len = usize::try_from(len).unwrap();2605let mut array = &memory[ptr..][..len * 16];26062607for (a, b) in input.iter() {2608match a {2609Some(val) => {2610assert_eq!(*array.take_n::<2>(), [1, *val]);2611}2612None => {2613assert_eq!(*array.take_n::<1>(), [0]);2614array.skip::<1>();2615}2616}2617array.skip::<2>();2618match b {2619Ok(()) => {2620assert_eq!(*array.take_n::<1>(), [0]);2621array.skip::<11>();2622}2623Err(s) => {2624assert_eq!(*array.take_n::<1>(), [1]);2625array.skip::<3>();2626assert_eq!(array.ptr_len(memory, 1), s.as_bytes());2627}2628}2629}2630assert!(array.is_empty());26312632Ok(())2633}26342635trait SliceExt<'a> {2636fn take_n<const N: usize>(&mut self) -> &'a [u8; N];26372638fn skip<const N: usize>(&mut self) {2639self.take_n::<N>();2640}26412642fn ptr_len<'b>(&mut self, all_memory: &'b [u8], size: usize) -> &'b [u8] {2643let ptr = u32::from_le_bytes(*self.take_n::<4>());2644let len = u32::from_le_bytes(*self.take_n::<4>());2645let ptr = usize::try_from(ptr).unwrap();2646let len = usize::try_from(len).unwrap();2647&all_memory[ptr..][..len * size]2648}2649}26502651impl<'a> SliceExt<'a> for &'a [u8] {2652fn take_n<const N: usize>(&mut self) -> &'a [u8; N] {2653let (a, b) = self.split_at(N);2654*self = b;2655a.try_into().unwrap()2656}2657}26582659#[test]2660fn invalid_alignment() -> Result<()> {2661let component = format!(2662r#"(component2663(core module $m2664(memory (export "memory") 1)2665(func (export "realloc") (param i32 i32 i32 i32) (result i32)2666i32.const 1)26672668(func (export "take-i32") (param i32))2669(func (export "ret-1") (result i32) i32.const 1)2670(func (export "ret-unaligned-list") (result i32)2671(i32.store offset=0 (i32.const 8) (i32.const 1))2672(i32.store offset=4 (i32.const 8) (i32.const 1))2673i32.const 8)2674)2675(core instance $i (instantiate $m))26762677(func (export "many-params")2678(param "s1" string) (param "s2" string) (param "s3" string) (param "s4" string)2679(param "s5" string) (param "s6" string) (param "s7" string) (param "s8" string)2680(param "s9" string) (param "s10" string) (param "s11" string) (param "s12" string)2681(canon lift2682(core func $i "take-i32")2683(memory $i "memory")2684(realloc (func $i "realloc"))2685)2686)2687(func (export "string-ret") (result string)2688(canon lift2689(core func $i "ret-1")2690(memory $i "memory")2691(realloc (func $i "realloc"))2692)2693)2694(func (export "list-u32-ret") (result (list u32))2695(canon lift2696(core func $i "ret-unaligned-list")2697(memory $i "memory")2698(realloc (func $i "realloc"))2699)2700)2701)"#2702);27032704let engine = super::engine();2705let component = Component::new(&engine, component)?;2706let mut store = Store::new(&engine, ());2707let instance = |store: &mut Store<()>| Linker::new(&engine).instantiate(store, &component);27082709let err = instance(&mut store)?2710.get_typed_func::<(2711&str,2712&str,2713&str,2714&str,2715&str,2716&str,2717&str,2718&str,2719&str,2720&str,2721&str,2722&str,2723), ()>(&mut store, "many-params")?2724.call(&mut store, ("", "", "", "", "", "", "", "", "", "", "", ""))2725.unwrap_err();2726assert!(2727err.to_string()2728.contains("realloc return: result not aligned"),2729"{}",2730err2731);27322733let err = instance(&mut store)?2734.get_typed_func::<(), (WasmStr,)>(&mut store, "string-ret")?2735.call(&mut store, ())2736.err()2737.unwrap();2738assert!(2739err.to_string().contains("return pointer not aligned"),2740"{}",2741err2742);27432744let err = instance(&mut store)?2745.get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32-ret")?2746.call(&mut store, ())2747.err()2748.unwrap();2749assert!(2750err.to_string().contains("list pointer is not aligned"),2751"{}",2752err2753);27542755Ok(())2756}27572758#[test]2759fn drop_component_still_works() -> Result<()> {2760let component = r#"2761(component2762(import "f" (func $f))27632764(core func $f_lower2765(canon lower (func $f))2766)2767(core module $m2768(import "" "" (func $f))27692770(func $f22771call $f2772call $f2773)27742775(export "f" (func $f2))2776)2777(core instance $i (instantiate $m2778(with "" (instance2779(export "" (func $f_lower))2780))2781))2782(func (export "g")2783(canon lift2784(core func $i "f")2785)2786)2787)2788"#;27892790let (mut store, instance) = {2791let engine = super::engine();2792let component = Component::new(&engine, component)?;2793let mut store = Store::new(&engine, 0);2794let mut linker = Linker::new(&engine);2795linker.root().func_wrap(2796"f",2797|mut store: StoreContextMut<'_, u32>, _: ()| -> Result<()> {2798*store.data_mut() += 1;2799Ok(())2800},2801)?;2802let instance = linker.instantiate(&mut store, &component)?;2803(store, instance)2804};28052806let f = instance.get_typed_func::<(), ()>(&mut store, "g")?;2807assert_eq!(*store.data(), 0);2808f.call(&mut store, ())?;2809assert_eq!(*store.data(), 2);28102811Ok(())2812}28132814#[test]2815fn raw_slice_of_various_types() -> Result<()> {2816let component = r#"2817(component2818(core module $m2819(memory (export "memory") 1)28202821(func (export "list8") (result i32)2822(call $setup_list (i32.const 16))2823)2824(func (export "list16") (result i32)2825(call $setup_list (i32.const 8))2826)2827(func (export "list32") (result i32)2828(call $setup_list (i32.const 4))2829)2830(func (export "list64") (result i32)2831(call $setup_list (i32.const 2))2832)28332834(func $setup_list (param i32) (result i32)2835(i32.store offset=0 (i32.const 100) (i32.const 8))2836(i32.store offset=4 (i32.const 100) (local.get 0))2837i32.const 1002838)28392840(data (i32.const 8) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f")2841)2842(core instance $i (instantiate $m))2843(func (export "list-u8") (result (list u8))2844(canon lift (core func $i "list8") (memory $i "memory"))2845)2846(func (export "list-i8") (result (list s8))2847(canon lift (core func $i "list8") (memory $i "memory"))2848)2849(func (export "list-u16") (result (list u16))2850(canon lift (core func $i "list16") (memory $i "memory"))2851)2852(func (export "list-i16") (result (list s16))2853(canon lift (core func $i "list16") (memory $i "memory"))2854)2855(func (export "list-u32") (result (list u32))2856(canon lift (core func $i "list32") (memory $i "memory"))2857)2858(func (export "list-i32") (result (list s32))2859(canon lift (core func $i "list32") (memory $i "memory"))2860)2861(func (export "list-u64") (result (list u64))2862(canon lift (core func $i "list64") (memory $i "memory"))2863)2864(func (export "list-i64") (result (list s64))2865(canon lift (core func $i "list64") (memory $i "memory"))2866)2867)2868"#;28692870let (mut store, instance) = {2871let engine = super::engine();2872let component = Component::new(&engine, component)?;2873let mut store = Store::new(&engine, ());2874let instance = Linker::new(&engine).instantiate(&mut store, &component)?;2875(store, instance)2876};28772878let list = instance2879.get_typed_func::<(), (WasmList<u8>,)>(&mut store, "list-u8")?2880.call_and_post_return(&mut store, ())?2881.0;2882assert_eq!(2883list.as_le_slice(&store),2884[28850x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,28860x0e, 0x0f,2887]2888);2889let list = instance2890.get_typed_func::<(), (WasmList<i8>,)>(&mut store, "list-i8")?2891.call_and_post_return(&mut store, ())?2892.0;2893assert_eq!(2894list.as_le_slice(&store),2895[28960x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,28970x0e, 0x0f,2898]2899);29002901let list = instance2902.get_typed_func::<(), (WasmList<u16>,)>(&mut store, "list-u16")?2903.call_and_post_return(&mut store, ())?2904.0;2905assert_eq!(2906list.as_le_slice(&store),2907[2908u16::to_le(0x01_00),2909u16::to_le(0x03_02),2910u16::to_le(0x05_04),2911u16::to_le(0x07_06),2912u16::to_le(0x09_08),2913u16::to_le(0x0b_0a),2914u16::to_le(0x0d_0c),2915u16::to_le(0x0f_0e),2916]2917);2918let list = instance2919.get_typed_func::<(), (WasmList<i16>,)>(&mut store, "list-i16")?2920.call_and_post_return(&mut store, ())?2921.0;2922assert_eq!(2923list.as_le_slice(&store),2924[2925i16::to_le(0x01_00),2926i16::to_le(0x03_02),2927i16::to_le(0x05_04),2928i16::to_le(0x07_06),2929i16::to_le(0x09_08),2930i16::to_le(0x0b_0a),2931i16::to_le(0x0d_0c),2932i16::to_le(0x0f_0e),2933]2934);2935let list = instance2936.get_typed_func::<(), (WasmList<u32>,)>(&mut store, "list-u32")?2937.call_and_post_return(&mut store, ())?2938.0;2939assert_eq!(2940list.as_le_slice(&store),2941[2942u32::to_le(0x03_02_01_00),2943u32::to_le(0x07_06_05_04),2944u32::to_le(0x0b_0a_09_08),2945u32::to_le(0x0f_0e_0d_0c),2946]2947);2948let list = instance2949.get_typed_func::<(), (WasmList<i32>,)>(&mut store, "list-i32")?2950.call_and_post_return(&mut store, ())?2951.0;2952assert_eq!(2953list.as_le_slice(&store),2954[2955i32::to_le(0x03_02_01_00),2956i32::to_le(0x07_06_05_04),2957i32::to_le(0x0b_0a_09_08),2958i32::to_le(0x0f_0e_0d_0c),2959]2960);2961let list = instance2962.get_typed_func::<(), (WasmList<u64>,)>(&mut store, "list-u64")?2963.call_and_post_return(&mut store, ())?2964.0;2965assert_eq!(2966list.as_le_slice(&store),2967[2968u64::to_le(0x07_06_05_04_03_02_01_00),2969u64::to_le(0x0f_0e_0d_0c_0b_0a_09_08),2970]2971);2972let list = instance2973.get_typed_func::<(), (WasmList<i64>,)>(&mut store, "list-i64")?2974.call_and_post_return(&mut store, ())?2975.0;2976assert_eq!(2977list.as_le_slice(&store),2978[2979i64::to_le(0x07_06_05_04_03_02_01_00),2980i64::to_le(0x0f_0e_0d_0c_0b_0a_09_08),2981]2982);29832984Ok(())2985}29862987#[test]2988fn lower_then_lift() -> Result<()> {2989// First test simple integers when the import/export ABI happen to line up2990let component = r#"2991(component $c2992(import "f" (func $f (result u32)))29932994(core func $f_lower2995(canon lower (func $f))2996)2997(func $f2 (result s32)2998(canon lift (core func $f_lower))2999)3000(export "f2" (func $f2))3001)3002"#;30033004let engine = super::engine();3005let component = Component::new(&engine, component)?;3006let mut store = Store::new(&engine, ());3007let mut linker = Linker::new(&engine);3008linker.root().func_wrap("f", |_, _: ()| Ok((2u32,)))?;3009let instance = linker.instantiate(&mut store, &component)?;30103011let f = instance.get_typed_func::<(), (i32,)>(&mut store, "f2")?;3012assert_eq!(f.call(&mut store, ())?, (2,));30133014// First test strings when the import/export ABI happen to line up3015let component = format!(3016r#"3017(component $c3018(import "s" (func $f (param "a" string)))30193020(core module $libc3021(memory (export "memory") 1)3022{REALLOC_AND_FREE}3023)3024(core instance $libc (instantiate $libc))30253026(core func $f_lower3027(canon lower (func $f) (memory $libc "memory"))3028)3029(func $f2 (param "a" string)3030(canon lift (core func $f_lower)3031(memory $libc "memory")3032(realloc (func $libc "realloc"))3033)3034)3035(export "f" (func $f2))3036)3037"#3038);30393040let component = Component::new(&engine, component)?;3041let mut store = Store::new(&engine, ());3042linker3043.root()3044.func_wrap("s", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| {3045assert_eq!(x.to_str(&store)?, "hello");3046Ok(())3047})?;3048let instance = linker.instantiate(&mut store, &component)?;30493050let f = instance.get_typed_func::<(&str,), ()>(&mut store, "f")?;3051f.call(&mut store, ("hello",))?;30523053// Next test "type punning" where return values are reinterpreted just3054// because the return ABI happens to line up.3055let component = format!(3056r#"3057(component $c3058(import "s2" (func $f (param "a" string) (result u32)))30593060(core module $libc3061(memory (export "memory") 1)3062{REALLOC_AND_FREE}3063)3064(core instance $libc (instantiate $libc))30653066(core func $f_lower3067(canon lower (func $f) (memory $libc "memory"))3068)3069(func $f2 (param "a" string) (result string)3070(canon lift (core func $f_lower)3071(memory $libc "memory")3072(realloc (func $libc "realloc"))3073)3074)3075(export "f" (func $f2))3076)3077"#3078);30793080let component = Component::new(&engine, component)?;3081let mut store = Store::new(&engine, ());3082linker3083.root()3084.func_wrap("s2", |store: StoreContextMut<'_, ()>, (x,): (WasmStr,)| {3085assert_eq!(x.to_str(&store)?, "hello");3086Ok((u32::MAX,))3087})?;3088let instance = linker.instantiate(&mut store, &component)?;30893090let f = instance.get_typed_func::<(&str,), (WasmStr,)>(&mut store, "f")?;3091let err = f.call(&mut store, ("hello",)).err().unwrap();3092assert!(3093err.to_string().contains("return pointer not aligned"),3094"{}",3095err3096);30973098Ok(())3099}31003101#[test]3102fn errors_that_poison_instance() -> Result<()> {3103let component = format!(3104r#"3105(component $c3106(core module $m13107(func (export "f1") unreachable)3108(func (export "f2"))3109)3110(core instance $m1 (instantiate $m1))3111(func (export "f1") (canon lift (core func $m1 "f1")))3112(func (export "f2") (canon lift (core func $m1 "f2")))31133114(core module $m23115(func (export "f") (param i32 i32))3116(func (export "r") (param i32 i32 i32 i32) (result i32) unreachable)3117(memory (export "m") 1)3118)3119(core instance $m2 (instantiate $m2))3120(func (export "f3") (param "a" string)3121(canon lift (core func $m2 "f") (realloc (func $m2 "r")) (memory $m2 "m"))3122)31233124(core module $m33125(func (export "f") (result i32) i32.const 1)3126(memory (export "m") 1)3127)3128(core instance $m3 (instantiate $m3))3129(func (export "f4") (result string)3130(canon lift (core func $m3 "f") (memory $m3 "m"))3131)3132)3133"#3134);31353136let engine = super::engine();3137let component = Component::new(&engine, component)?;3138let mut store = Store::new(&engine, ());3139let linker = Linker::new(&engine);3140let instance = linker.instantiate(&mut store, &component)?;3141let f1 = instance.get_typed_func::<(), ()>(&mut store, "f1")?;3142let f2 = instance.get_typed_func::<(), ()>(&mut store, "f2")?;3143assert_unreachable(f1.call(&mut store, ()));3144assert_poisoned(f1.call(&mut store, ()));3145assert_poisoned(f2.call(&mut store, ()));31463147let instance = linker.instantiate(&mut store, &component)?;3148let f3 = instance.get_typed_func::<(&str,), ()>(&mut store, "f3")?;3149assert_unreachable(f3.call(&mut store, ("x",)));3150assert_poisoned(f3.call(&mut store, ("x",)));31513152let instance = linker.instantiate(&mut store, &component)?;3153let f4 = instance.get_typed_func::<(), (WasmStr,)>(&mut store, "f4")?;3154assert!(f4.call(&mut store, ()).is_err());3155assert_poisoned(f4.call(&mut store, ()));31563157return Ok(());31583159#[track_caller]3160fn assert_unreachable<T>(err: Result<T>) {3161let err = match err {3162Ok(_) => panic!("expected an error"),3163Err(e) => e,3164};3165assert_eq!(3166err.downcast::<Trap>().unwrap(),3167Trap::UnreachableCodeReached3168);3169}31703171#[track_caller]3172fn assert_poisoned<T>(err: Result<T>) {3173let err = match err {3174Ok(_) => panic!("expected an error"),3175Err(e) => e,3176};3177assert_eq!(3178err.downcast_ref::<Trap>(),3179Some(&Trap::CannotEnterComponent),3180"{err}",3181);3182}3183}31843185#[test]3186fn run_export_with_internal_adapter() -> Result<()> {3187let component = r#"3188(component3189(type $t (func (param "a" u32) (result u32)))3190(component $a3191(core module $m3192(func (export "add-five") (param i32) (result i32)3193local.get 03194i32.const 53195i32.add)3196)3197(core instance $m (instantiate $m))3198(func (export "add-five") (type $t) (canon lift (core func $m "add-five")))3199)3200(component $b3201(import "interface-v1" (instance $i3202(export "add-five" (func (type $t)))))3203(core module $m3204(func $add-five (import "interface-0.1.0" "add-five") (param i32) (result i32))3205(func) ;; causes index out of bounds3206(func (export "run") (result i32) i32.const 0 call $add-five)3207)3208(core func $add-five (canon lower (func $i "add-five")))3209(core instance $i (instantiate 03210(with "interface-0.1.0" (instance3211(export "add-five" (func $add-five))3212))3213))3214(func (result u32) (canon lift (core func $i "run")))3215(export "run" (func 1))3216)3217(instance $a (instantiate $a))3218(instance $b (instantiate $b (with "interface-v1" (instance $a))))3219(export "run" (func $b "run"))3220)3221"#;3222let engine = super::engine();3223let component = Component::new(&engine, component)?;3224let mut store = Store::new(&engine, ());3225let linker = Linker::new(&engine);3226let instance = linker.instantiate(&mut store, &component)?;3227let run = instance.get_typed_func::<(), (u32,)>(&mut store, "run")?;3228assert_eq!(run.call(&mut store, ())?, (5,));3229Ok(())3230}323132323233