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