Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/tests/all/exceptions.rs
1691 views
1
use wasmtime::*;
2
use wasmtime_test_macros::wasmtime_test;
3
4
#[wasmtime_test(wasm_features(exceptions))]
5
#[cfg_attr(miri, ignore)]
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)]
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)]
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)]
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))]
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))]
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
246