zingen/validator.rs
1//! Pre-visitor for parsing WASM.
2
3use crate::{Function, Result};
4use wasmparser::{Operator, VisitOperator};
5
6/// A pre-visitor that validates the WASM and then visits it.
7pub struct ValidateThenVisit<'a, T>(pub T, pub &'a mut Function);
8
9macro_rules! validate_then_visit {
10 ($( @$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident)*) => {
11 $(
12 fn $visit(&mut self $($(,$arg: $argty)*)?) -> Self::Output {
13 self.0.$visit($($($arg.clone()),*)?)?;
14 // Only visit operators if the compiler is in a reachable code state. If
15 // the compiler is in an unreachable code state, most of the operators are
16 // ignored except for If, Block, Loop, Else and End. These operators need
17 // to be observed in order to keep the control stack frames balanced and to
18 // determine if reachability should be restored.
19 let visit_when_unreachable = visit_op_when_unreachable(Operator::$op $({ $($arg: $arg.clone()),* })?);
20 if true || visit_when_unreachable {
21 Ok(self.1.$visit($($($arg),*)?))
22 } else {
23 Ok(Ok(()))
24 }
25 }
26 )*
27 };
28}
29
30fn visit_op_when_unreachable(op: Operator) -> bool {
31 use Operator::*;
32 matches!(op, If { .. } | Block { .. } | Loop { .. } | Else | End)
33}
34
35// /// Trait to handle reachability state.
36// trait ReachableState {
37// /// Returns true if the current state of the program is reachable.
38// fn is_reachable(&self) -> bool;
39// }
40//
41// impl ReachableState for Function {
42// fn is_reachable(&self) -> bool {
43// true
44// }
45// }
46
47impl<'a, T> VisitOperator<'a> for ValidateThenVisit<'_, T>
48where
49 T: VisitOperator<'a, Output = wasmparser::Result<()>>,
50{
51 type Output = Result<Result<()>>;
52
53 wasmparser::for_each_operator!(validate_then_visit);
54}