1 #![cfg(not(miri))]
2
3 use super::ApiStyle;
4 use wasmtime::component::*;
5 use wasmtime::{Engine, Result};
6 use wasmtime::{Store, StoreContextMut, Trap};
7
8 #[tokio::test]
invoke_post_return_sync() -> Result<()>9 async fn invoke_post_return_sync() -> Result<()> {
10 invoke_post_return(ApiStyle::Sync, true).await
11 }
12
13 #[tokio::test]
invoke_post_return_async() -> Result<()>14 async fn invoke_post_return_async() -> Result<()> {
15 invoke_post_return(ApiStyle::Async, true).await
16 }
17
18 #[tokio::test]
invoke_post_return_async_not_concurrent() -> Result<()>19 async fn invoke_post_return_async_not_concurrent() -> Result<()> {
20 invoke_post_return(ApiStyle::AsyncNotConcurrent, true).await
21 }
22
23 #[tokio::test]
invoke_post_return_async_not_concurrent_dynamic() -> Result<()>24 async fn invoke_post_return_async_not_concurrent_dynamic() -> Result<()> {
25 invoke_post_return(ApiStyle::AsyncNotConcurrent, false).await
26 }
27
28 #[tokio::test]
invoke_post_return_concurrent() -> Result<()>29 async fn invoke_post_return_concurrent() -> Result<()> {
30 invoke_post_return(ApiStyle::Concurrent, true).await
31 }
32
invoke_post_return(style: ApiStyle, typed: bool) -> Result<()>33 async fn invoke_post_return(style: ApiStyle, typed: bool) -> Result<()> {
34 let component = r#"
35 (component
36 (import "f" (func $f))
37
38 (core func $f_lower
39 (canon lower (func $f))
40 )
41 (core module $m
42 (import "" "" (func $f))
43
44 (func (export "thunk"))
45
46 (func $post_return
47 call $f)
48 (export "post-return" (func $post_return))
49 )
50 (core instance $i (instantiate $m
51 (with "" (instance
52 (export "" (func $f_lower))
53 ))
54 ))
55 (func (export "thunk")
56 (canon lift
57 (core func $i "thunk")
58 (post-return (func $i "post-return"))
59 )
60 )
61 )
62 "#;
63
64 let engine = Engine::new(&style.config())?;
65 let component = Component::new(&engine, component)?;
66 let mut store = Store::new(&engine, ());
67 let mut linker = Linker::new(&engine);
68 linker
69 .root()
70 .func_wrap("f", |_: StoreContextMut<'_, ()>, _: ()| -> Result<()> {
71 unreachable!()
72 })?;
73
74 let instance = style.instantiate(&mut store, &linker, &component).await?;
75 let thunk = instance.get_typed_func::<(), ()>(&mut store, "thunk")?;
76
77 let result = if typed {
78 style.call(&mut store, thunk, ()).await
79 } else {
80 assert!(matches!(style, ApiStyle::AsyncNotConcurrent));
81 thunk.func().call_async(&mut store, &[], &mut []).await
82 };
83 assert!(matches!(
84 result.unwrap_err().downcast::<Trap>(),
85 Ok(Trap::CannotLeaveComponent)
86 ));
87
88 Ok(())
89 }
90
91 #[test]
post_return_all_types() -> Result<()>92 fn post_return_all_types() -> Result<()> {
93 let component = r#"
94 (component
95 (core module $m
96 (func (export "i32") (result i32)
97 i32.const 1)
98 (func (export "i64") (result i64)
99 i64.const 2)
100 (func (export "f32") (result f32)
101 f32.const 3)
102 (func (export "f64") (result f64)
103 f64.const 4)
104
105 (func (export "post-i32") (param i32)
106 local.get 0
107 i32.const 1
108 i32.ne
109 if unreachable end)
110 (func (export "post-i64") (param i64)
111 local.get 0
112 i64.const 2
113 i64.ne
114 if unreachable end)
115 (func (export "post-f32") (param f32)
116 local.get 0
117 f32.const 3
118 f32.ne
119 if unreachable end)
120 (func (export "post-f64") (param f64)
121 local.get 0
122 f64.const 4
123 f64.ne
124 if unreachable end)
125 )
126 (core instance $i (instantiate $m))
127 (func (export "i32") (result u32)
128 (canon lift (core func $i "i32") (post-return (func $i "post-i32")))
129 )
130 (func (export "i64") (result u64)
131 (canon lift (core func $i "i64") (post-return (func $i "post-i64")))
132 )
133 (func (export "f32") (result float32)
134 (canon lift (core func $i "f32") (post-return (func $i "post-f32")))
135 )
136 (func (export "f64") (result float64)
137 (canon lift (core func $i "f64") (post-return (func $i "post-f64")))
138 )
139 )
140 "#;
141
142 let engine = super::engine();
143 let component = Component::new(&engine, component)?;
144 let mut store = Store::new(&engine, false);
145 let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
146 let i32 = instance.get_typed_func::<(), (u32,)>(&mut store, "i32")?;
147 let i64 = instance.get_typed_func::<(), (u64,)>(&mut store, "i64")?;
148 let f32 = instance.get_typed_func::<(), (f32,)>(&mut store, "f32")?;
149 let f64 = instance.get_typed_func::<(), (f64,)>(&mut store, "f64")?;
150
151 assert_eq!(i32.call(&mut store, ())?, (1,));
152
153 assert_eq!(i64.call(&mut store, ())?, (2,));
154
155 assert_eq!(f32.call(&mut store, ())?, (3.,));
156
157 assert_eq!(f64.call(&mut store, ())?, (4.,));
158
159 Ok(())
160 }
161
162 #[test]
post_return_string() -> Result<()>163 fn post_return_string() -> Result<()> {
164 let component = r#"
165 (component
166 (core module $m
167 (memory (export "memory") 1)
168 (func (export "get") (result i32)
169 (i32.store offset=0 (i32.const 8) (i32.const 100))
170 (i32.store offset=4 (i32.const 8) (i32.const 11))
171 i32.const 8
172 )
173
174 (func (export "post") (param i32)
175 local.get 0
176 i32.const 8
177 i32.ne
178 if unreachable end)
179
180 (data (i32.const 100) "hello world")
181 )
182 (core instance $i (instantiate $m))
183 (func (export "get") (result string)
184 (canon lift
185 (core func $i "get")
186 (post-return (func $i "post"))
187 (memory $i "memory")
188 )
189 )
190 )
191 "#;
192
193 let engine = super::engine();
194 let component = Component::new(&engine, component)?;
195 let mut store = Store::new(&engine, false);
196 let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
197 let get = instance.get_typed_func::<(), (WasmStr,)>(&mut store, "get")?;
198 let s = get.call(&mut store, ())?.0;
199 assert_eq!(s.to_str(&store)?, "hello world");
200
201 Ok(())
202 }
203
204 #[test]
trap_in_post_return_poisons_instance() -> Result<()>205 fn trap_in_post_return_poisons_instance() -> Result<()> {
206 let component = r#"
207 (component
208 (core module $m
209 (func (export "f"))
210 (func (export "post") unreachable)
211 )
212 (core instance $i (instantiate $m))
213 (func (export "f")
214 (canon lift
215 (core func $i "f")
216 (post-return (func $i "post"))
217 )
218 )
219 )
220 "#;
221
222 let engine = super::engine();
223 let component = Component::new(&engine, component)?;
224 let mut store = Store::new(&engine, ());
225 let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
226 let f = instance.get_typed_func::<(), ()>(&mut store, "f")?;
227 let trap = f.call(&mut store, ()).unwrap_err().downcast::<Trap>()?;
228 assert_eq!(trap, Trap::UnreachableCodeReached);
229 let err = f.call(&mut store, ()).unwrap_err();
230 assert_eq!(
231 err.downcast_ref(),
232 Some(&Trap::CannotEnterComponent),
233 "{err}",
234 );
235
236 Ok(())
237 }
238