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