impl InvariantChecker {
fn new() -> Self {
Self {
invariants: vec![
SafetyInvariant::MemoryBounds,
SafetyInvariant::StackBalance,
SafetyInvariant::TypeSafety,
SafetyInvariant::NoIntegerOverflow,
],
}
}
#[allow(dead_code)]
fn check_all(&self, _module: &[u8]) -> Vec<InvariantViolation> {
Vec::new()
}
}
impl StackAnalyzer {
fn new() -> Self {
Self {
type_stack: Vec::new(),
}
}
fn update_stack(&self, stack: &mut Vec<ValType>, op: &Operator) -> Result<()> {
match op {
Operator::I32Const { .. } => stack.push(ValType::I32),
Operator::I64Const { .. } => stack.push(ValType::I64),
Operator::F32Const { .. } => stack.push(ValType::F32),
Operator::F64Const { .. } => stack.push(ValType::F64),
Operator::I32Add
| Operator::I32Sub
| Operator::I32Mul
| Operator::I32DivS
| Operator::I32DivU => {
pop_binary_i32(stack)?;
}
Operator::I64Add
| Operator::I64Sub
| Operator::I64Mul
| Operator::I64DivS
| Operator::I64DivU => {
pop_binary_i64(stack)?;
}
Operator::I32Eqz => {
if stack.pop() != Some(ValType::I32) {
return Err(anyhow!("Type error: expected i32"));
}
stack.push(ValType::I32);
}
Operator::I32Eq
| Operator::I32Ne
| Operator::I32LtS
| Operator::I32LtU
| Operator::I32GtS
| Operator::I32GtU => {
pop_comparison_i32(stack)?;
}
Operator::LocalGet { local_index: _ } => {
stack.push(ValType::I32); }
Operator::LocalSet { local_index: _ } => {
if stack.is_empty() {
return Err(anyhow!("Stack underflow"));
}
stack.pop();
}
Operator::Drop => {
if stack.is_empty() {
return Err(anyhow!("Stack underflow"));
}
stack.pop();
}
_ => {} }
Ok(())
}
}
fn pop_binary_i32(stack: &mut Vec<ValType>) -> Result<()> {
if stack.len() < 2 {
return Err(anyhow!("Stack underflow"));
}
stack.pop();
stack.pop();
stack.push(ValType::I32);
Ok(())
}
fn pop_binary_i64(stack: &mut Vec<ValType>) -> Result<()> {
if stack.len() < 2 {
return Err(anyhow!("Stack underflow"));
}
stack.pop();
stack.pop();
stack.push(ValType::I64);
Ok(())
}
fn pop_comparison_i32(stack: &mut Vec<ValType>) -> Result<()> {
if stack.len() < 2 {
return Err(anyhow!("Stack underflow"));
}
if stack.pop() != Some(ValType::I32) || stack.pop() != Some(ValType::I32) {
return Err(anyhow!("Type error: expected i32"));
}
stack.push(ValType::I32);
Ok(())
}