Skip to content

Commit 645df68

Browse files
authored
Fail deterministically on invalid modules (#1969)
Inspired by bytecodealliance/wasmtime#9947 this helps keep the output of `wasm-tools validate` more deterministic by ensuring that the first error is reported instead of any error within a module.
1 parent 31c5811 commit 645df68

File tree

3 files changed

+133
-14
lines changed

3 files changed

+133
-14
lines changed

src/bin/wasm-tools/validate.rs

+24-14
Original file line numberDiff line numberDiff line change
@@ -144,21 +144,31 @@ impl Opts {
144144
}
145145
log::info!("module structure validated in {:?}", start.elapsed());
146146

147-
// After we've validate the entire wasm module we'll use `rayon` to iterate
148-
// over all functions in parallel and perform parallel validation of the
149-
// input wasm module.
147+
// After we've validate the entire wasm module we'll use `rayon` to
148+
// iterate over all functions in parallel and perform parallel
149+
// validation of the input wasm module.
150+
//
151+
// Note that validation results for each function are collected into a
152+
// vector to ensure that in the case of multiple errors the first is
153+
// always reported. Otherwise `rayon` does not guarantee the order that
154+
// failures show up in.
150155
let start = Instant::now();
151-
functions_to_validate.into_par_iter().try_for_each_init(
152-
FuncValidatorAllocations::default,
153-
|allocs, (to_validate, body)| -> Result<_> {
154-
let mut validator = to_validate.into_validator(mem::take(allocs));
155-
validator
156-
.validate(&body)
157-
.with_context(|| format!("func {} failed to validate", validator.index()))?;
158-
*allocs = validator.into_allocations();
159-
Ok(())
160-
},
161-
)?;
156+
functions_to_validate
157+
.into_par_iter()
158+
.map_init(
159+
FuncValidatorAllocations::default,
160+
|allocs, (to_validate, body)| -> Result<_> {
161+
let mut validator = to_validate.into_validator(mem::take(allocs));
162+
validator.validate(&body).with_context(|| {
163+
format!("func {} failed to validate", validator.index())
164+
})?;
165+
*allocs = validator.into_allocations();
166+
Ok(())
167+
},
168+
)
169+
.collect::<Vec<_>>()
170+
.into_iter()
171+
.collect::<Result<Vec<_>>>()?;
162172
log::info!("functions validated in {:?}", start.elapsed());
163173
Ok(())
164174
}

tests/cli/multiple-failures.wat

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
;; FAIL: validate %
2+
3+
(module
4+
(func (result i32))
5+
(func (result i32))
6+
(func (result i32))
7+
(func (result i32))
8+
(func (result i32))
9+
(func (result i32))
10+
(func (result i32))
11+
(func (result i32))
12+
(func (result i32))
13+
(func (result i32))
14+
(func (result i32))
15+
(func (result i32))
16+
(func (result i32))
17+
(func (result i32))
18+
(func (result i32))
19+
(func (result i32))
20+
(func (result i32))
21+
(func (result i32))
22+
(func (result i32))
23+
(func (result i32))
24+
(func (result i32))
25+
(func (result i32))
26+
(func (result i32))
27+
(func (result i32))
28+
(func (result i32))
29+
(func (result i32))
30+
(func (result i32))
31+
(func (result i32))
32+
(func (result i32))
33+
(func (result i32))
34+
(func (result i32))
35+
(func (result i32))
36+
(func (result i32))
37+
(func (result i32))
38+
(func (result i32))
39+
(func (result i32))
40+
(func (result i32))
41+
(func (result i32))
42+
(func (result i32))
43+
(func (result i32))
44+
(func (result i32))
45+
(func (result i32))
46+
(func (result i32))
47+
(func (result i32))
48+
(func (result i32))
49+
(func (result i32))
50+
(func (result i32))
51+
(func (result i32))
52+
(func (result i32))
53+
(func (result i32))
54+
(func (result i32))
55+
(func (result i32))
56+
(func (result i32))
57+
(func (result i32))
58+
(func (result i32))
59+
(func (result i32))
60+
(func (result i32))
61+
(func (result i32))
62+
(func (result i32))
63+
(func (result i32))
64+
(func (result i32))
65+
(func (result i32))
66+
(func (result i32))
67+
(func (result i32))
68+
(func (result i32))
69+
(func (result i32))
70+
(func (result i32))
71+
(func (result i32))
72+
(func (result i32))
73+
(func (result i32))
74+
(func (result i32))
75+
(func (result i32))
76+
(func (result i32))
77+
(func (result i32))
78+
(func (result i32))
79+
(func (result i32))
80+
(func (result i32))
81+
(func (result i32))
82+
(func (result i32))
83+
(func (result i32))
84+
(func (result i32))
85+
(func (result i32))
86+
(func (result i32))
87+
(func (result i32))
88+
(func (result i32))
89+
(func (result i32))
90+
(func (result i32))
91+
(func (result i32))
92+
(func (result i32))
93+
(func (result i32))
94+
(func (result i32))
95+
(func (result i32))
96+
(func (result i32))
97+
(func (result i32))
98+
(func (result i32))
99+
(func (result i32))
100+
(func (result i32))
101+
(func (result i32))
102+
(func (result i32))
103+
(func (result i32))
104+
(func (result i32))
105+
)
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
error: func 0 failed to validate
2+
3+
Caused by:
4+
0: type mismatch: expected i32 but nothing on stack (at offset 0x7d)

0 commit comments

Comments
 (0)