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