Better error handling in fuzzing; skip on unsupported features

This commit is contained in:
Chris Fallin 2022-11-29 10:05:43 -08:00
parent 88bcc3d906
commit 26e7c7a3af
No known key found for this signature in database
GPG key ID: 31649E4FE65EB465
4 changed files with 57 additions and 9 deletions

View file

@ -1,12 +1,28 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use waffle::Module;
use waffle::{FrontendError, Module};
fuzz_target!(|module: wasm_smith::Module| {
let _ = env_logger::try_init();
log::debug!("original module: {:?}", module);
let orig_bytes = module.to_bytes();
let parsed_module = Module::from_wasm_bytes(&orig_bytes[..]).unwrap();
let parsed_module = match Module::from_wasm_bytes(&orig_bytes[..]) {
Ok(m) => m,
Err(e) => {
match e.downcast::<FrontendError>() {
Ok(FrontendError::UnsupportedFeature(_)) => {
// Just skip this case.
return;
}
Ok(e) => {
panic!("Frontend error: {:?}", e);
}
Err(e) => {
panic!("Other error when parsing module: {:?}", e);
}
}
}
};
let _ = parsed_module.to_wasm_bytes();
});

15
src/errors.rs Normal file
View file

@ -0,0 +1,15 @@
//! Error types.
#[derive(Clone, Debug)]
pub enum FrontendError {
UnsupportedFeature(String),
Internal(String),
}
impl std::fmt::Display for FrontendError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
}
}
impl std::error::Error for FrontendError {}

View file

@ -3,6 +3,7 @@
#![allow(dead_code)]
use crate::entity::EntityRef;
use crate::errors::FrontendError;
use crate::ir::*;
use crate::op_traits::{op_inputs, op_outputs};
use crate::ops::Operator;
@ -33,17 +34,20 @@ fn parse_init_expr<'a>(init_expr: &wasmparser::ConstExpr<'a>) -> Result<Option<u
return Ok(None);
}
if operators.len() != 2 || !matches!(&operators[1], &wasmparser::Operator::End) {
anyhow::bail!(
bail!(FrontendError::UnsupportedFeature(format!(
"Unsupported operator seq in base-address expr: {:?}",
operators
);
)));
}
Ok(match &operators[0] {
&wasmparser::Operator::I32Const { value } => Some(value as u64),
&wasmparser::Operator::I64Const { value } => Some(value as u64),
&wasmparser::Operator::F32Const { value } => Some(value.bits() as u64),
&wasmparser::Operator::F64Const { value } => Some(value.bits()),
op => anyhow::bail!("Unsupported data segment base-address operator: {:?}", op),
op => anyhow::bail!(FrontendError::UnsupportedFeature(format!(
"Unsupported data segment base-address operator: {:?}",
op
))),
})
}
@ -186,7 +190,10 @@ fn handle_payload<'a>(
for element in reader {
let element = element?;
if element.ty != wasmparser::ValType::FuncRef {
anyhow::bail!("Unsupported table type: {:?}", element.ty);
bail!(FrontendError::UnsupportedFeature(format!(
"Unsupported table type: {:?}",
element.ty
)));
}
match &element.kind {
wasmparser::ElementKind::Passive => {}
@ -206,7 +213,10 @@ fn handle_payload<'a>(
for item in items {
let func = match item {
wasmparser::ElementItem::Func(func_idx) => Func::from(func_idx),
_ => anyhow::bail!("Unsupported element item: {:?}", item),
_ => bail!(FrontendError::UnsupportedFeature(format!(
"Unsupported element item: {:?}",
item
))),
};
funcs.push(func);
}
@ -1099,7 +1109,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
self.cur_block = Some(el);
self.locals.start_block(el);
} else {
bail!("Else without If on top of frame stack");
bail!(FrontendError::Internal(format!(
"Else without If on top of frame stack"
)));
}
}
@ -1163,7 +1175,10 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
self.emit_ret(&retvals[..]);
}
_ => bail!("Unsupported operator: {:?}", op),
_ => bail!(FrontendError::UnsupportedFeature(format!(
"Unsupported operator: {:?}",
op
))),
}
Ok(())

View file

@ -14,6 +14,8 @@ mod op_traits;
mod ops;
pub mod passes;
mod scoped_map;
mod errors;
pub use ir::*;
pub use ops::{Ieee32, Ieee64, Operator};
pub use errors::*;