xref: /wasmtime-44.0.1/tests/all/exceptions.rs (revision cc8d04f4)
1 use wasmtime::*;
2 use wasmtime_test_macros::wasmtime_test;
3 
4 #[wasmtime_test(wasm_features(exceptions))]
5 #[cfg_attr(miri, ignore)]
basic_throw(config: &mut Config) -> Result<()>6 fn basic_throw(config: &mut Config) -> Result<()> {
7     let engine = Engine::new(config)?;
8     let mut store = Store::new(&engine, ());
9 
10     let module = Module::new(
11         &engine,
12         r#"
13         (module
14           (tag $e0 (param i32 i64))
15 
16           (func $throw (param i32 i64)
17                 (throw $e0 (local.get 0) (local.get 1)))
18 
19           (func $catch (export "catch") (param i32 i64) (result i32 i64)
20 
21                 (block $b (result i32 i64)
22                        (try_table (result i32 i64)
23                                   (catch $e0 $b)
24                                   (call $throw (local.get 0) (local.get 1))
25                                   (i32.const 42)
26                                   (i64.const 100)))))
27           "#,
28     )?;
29 
30     let instance = Instance::new(&mut store, &module, &[])?;
31     let func = instance.get_func(&mut store, "catch").unwrap();
32     let mut results = [Val::I32(0), Val::I64(0)];
33     func.call(&mut store, &[Val::I32(1), Val::I64(2)], &mut results[..])?;
34     assert!(matches!(results[0], Val::I32(1)));
35     assert!(matches!(results[1], Val::I64(2)));
36 
37     Ok(())
38 }
39 
40 #[wasmtime_test(wasm_features(exceptions))]
41 #[cfg_attr(miri, ignore)]
dynamic_tags(config: &mut Config) -> Result<()>42 fn dynamic_tags(config: &mut Config) -> Result<()> {
43     let engine = Engine::new(config)?;
44     let mut store = Store::new(&engine, ());
45 
46     let module = Module::new(
47         &engine,
48         r#"
49         (module
50           (import "test" "e0" (tag $e0 (param i32 i64)))
51           (import "test" "e1" (tag $e1 (param i32 i64)))
52 
53           (func $throw_e1 (param i32 i64)
54                 (throw $e1 (local.get 0) (local.get 1)))
55 
56           (func $catch (export "catch") (param i32 i64) (result i32 i64 i32)
57                 (block $b1 (result i32 i64)
58                  (block $b0 (result i32 i64)
59                         (try_table (result i32 i64)
60                                    (catch $e0 $b0)
61                                    (catch $e1 $b1)
62                                    (call $throw_e1 (local.get 0) (local.get 1))
63                                    (unreachable)))
64                  (i32.const 0)
65                  (return))
66                 (i32.const 1)
67                 (return)))
68           "#,
69     )?;
70 
71     let functy = FuncType::new(&engine, [ValType::I32, ValType::I64], []);
72     let tagty = TagType::new(functy);
73     let tag0 = Tag::new(&mut store, &tagty)?;
74     let tag1 = Tag::new(&mut store, &tagty)?;
75 
76     // Instantiate with two different tags -- second catch-clause
77     // should match (on $e1).
78     let instance1 = Instance::new(&mut store, &module, &[Extern::Tag(tag0), Extern::Tag(tag1)])?;
79     let func1 = instance1.get_func(&mut store, "catch").unwrap();
80     let mut results = [Val::I32(0), Val::I64(0), Val::I32(0)];
81     func1.call(&mut store, &[Val::I32(1), Val::I64(2)], &mut results[..])?;
82     assert!(matches!(results[0], Val::I32(1)));
83     assert!(matches!(results[1], Val::I64(2)));
84     assert!(matches!(results[2], Val::I32(1)));
85 
86     // Instantiate with two imports of the same tag -- now first
87     // catch-clause should match (on $e0, since $e0 is an alias to
88     // $e1).
89     let instance2 = Instance::new(&mut store, &module, &[Extern::Tag(tag0), Extern::Tag(tag0)])?;
90     let func2 = instance2.get_func(&mut store, "catch").unwrap();
91     let mut results = [Val::I32(0), Val::I64(0), Val::I32(0)];
92     func2.call(&mut store, &[Val::I32(1), Val::I64(2)], &mut results[..])?;
93     assert!(matches!(results[0], Val::I32(1)));
94     assert!(matches!(results[1], Val::I64(2)));
95     assert!(matches!(results[2], Val::I32(0)));
96 
97     Ok(())
98 }
99 
100 #[wasmtime_test(wasm_features(exceptions))]
101 #[cfg_attr(miri, ignore)]
exception_escape_to_host(config: &mut Config) -> Result<()>102 fn exception_escape_to_host(config: &mut Config) -> Result<()> {
103     let engine = Engine::new(config)?;
104     let mut store = Store::new(&engine, ());
105 
106     let module = Module::new(
107         &engine,
108         r#"
109         (module
110           (import "test" "e0" (tag $e0 (param i32)))
111 
112           (func $throw (export "throw")
113                 (throw $e0 (i32.const 42))))
114           "#,
115     )?;
116 
117     let functy = FuncType::new(&engine, [ValType::I32], []);
118     let tagty = TagType::new(functy);
119     let tag = Tag::new(&mut store, &tagty)?;
120     let instance = Instance::new(&mut store, &module, &[Extern::Tag(tag)])?;
121     let func = instance.get_func(&mut store, "throw").unwrap();
122     let mut results = [];
123     let result = func.call(&mut store, &[], &mut results[..]);
124     assert!(result.is_err());
125     assert!(result.unwrap_err().is::<ThrownException>());
126     let exn = store.take_pending_exception().unwrap();
127     let exntag = exn.tag(&mut store)?;
128     assert!(Tag::eq(&exntag, &tag, &store));
129 
130     Ok(())
131 }
132 
133 #[wasmtime_test(wasm_features(exceptions))]
134 #[cfg_attr(miri, ignore)]
exception_from_host(config: &mut Config) -> Result<()>135 fn exception_from_host(config: &mut Config) -> Result<()> {
136     let engine = Engine::new(config)?;
137     let mut store = Store::new(&engine, ());
138 
139     let module = Module::new(
140         &engine,
141         r#"
142         (module
143           (import "test" "e0" (tag $e0 (param i32)))
144           (import "test" "f" (func $f (param i32)))
145 
146           (func $catch (export "catch") (result i32)
147                 (block $b (result i32)
148                   (try_table (result i32) (catch $e0 $b)
149                    i32.const 42
150                    call $f
151                    i32.const 0))))
152           "#,
153     )?;
154 
155     let functy = FuncType::new(&engine, [ValType::I32], []);
156     let tagty = TagType::new(functy.clone());
157     let exnty = ExnType::from_tag_type(&tagty).unwrap();
158     let exnpre = ExnRefPre::new(&mut store, exnty);
159     let tag = Tag::new(&mut store, &tagty)?;
160     let extfunc = Func::new(&mut store, functy, move |mut caller, args, _rets| {
161         let exn = ExnRef::new(
162             &mut caller,
163             &exnpre,
164             &tag,
165             &[Val::I32(args[0].unwrap_i32())],
166         )
167         .unwrap();
168         caller.as_context_mut().throw(exn)?;
169         Ok(())
170     });
171     let instance = Instance::new(
172         &mut store,
173         &module,
174         &[Extern::Tag(tag), Extern::Func(extfunc)],
175     )?;
176     let func = instance.get_func(&mut store, "catch").unwrap();
177     let mut results = [Val::null_any_ref()];
178     func.call(&mut store, &[], &mut results[..])?;
179     assert_eq!(results[0].unwrap_i32(), 42);
180 
181     Ok(())
182 }
183 
184 #[wasmtime_test(wasm_features(exceptions))]
exception_across_no_wasm(config: &mut Config) -> Result<()>185 fn exception_across_no_wasm(config: &mut Config) -> Result<()> {
186     let engine = Engine::new(config)?;
187     let mut store = Store::new(&engine, ());
188 
189     let functy = FuncType::new(&engine, [ValType::I32], []);
190     let tagty = TagType::new(functy.clone());
191     let exnty = ExnType::from_tag_type(&tagty).unwrap();
192     let exnpre = ExnRefPre::new(&mut store, exnty);
193     let tag = Tag::new(&mut store, &tagty)?;
194     let extfunc = Func::new(&mut store, functy, move |mut caller, args, _rets| {
195         let exn = ExnRef::new(
196             &mut caller,
197             &exnpre,
198             &tag,
199             &[Val::I32(args[0].unwrap_i32())],
200         )
201         .unwrap();
202         caller.as_context_mut().throw(exn)?;
203         Ok(())
204     });
205     let mut results = [];
206     let result = extfunc.call(&mut store, &[Val::I32(42)], &mut results[..]);
207     assert!(result.is_err() && result.unwrap_err().downcast::<ThrownException>().is_ok());
208     let exn = store.take_pending_exception().unwrap();
209     let exntag = exn.tag(&mut store)?;
210     assert!(Tag::eq(&exntag, &tag, &store));
211     assert_eq!(exn.field(&mut store, 0)?.unwrap_i32(), 42);
212 
213     Ok(())
214 }
215 
216 #[wasmtime_test(wasm_features(gc, exceptions))]
gc_with_exnref_global(config: &mut Config) -> Result<()>217 fn gc_with_exnref_global(config: &mut Config) -> Result<()> {
218     let engine = Engine::new(config)?;
219     let mut store = Store::new(&engine, ());
220 
221     let module = Module::new(
222         &engine,
223         r#"
224         (module
225           (global (export "g") (mut exnref) (ref.null exn)))
226           "#,
227     )?;
228 
229     let instance = Instance::new(&mut store, &module, &[])?;
230 
231     let functy = FuncType::new(&engine, [], []);
232     let tagty = TagType::new(functy.clone());
233     let exnty = ExnType::from_tag_type(&tagty).unwrap();
234     let exnpre = ExnRefPre::new(&mut store, exnty);
235     let tag = Tag::new(&mut store, &tagty)?;
236     let exn = ExnRef::new(&mut store, &exnpre, &tag, &[])?;
237 
238     let global = instance.get_global(&mut store, "g").unwrap();
239     global.set(&mut store, Val::ExnRef(Some(exn)))?;
240 
241     store.gc(None)?;
242 
243     Ok(())
244 }
245