fuzzbug fix on br_table fallthrough types

This commit is contained in:
Chris Fallin 2021-12-24 16:10:53 -08:00
parent 87c416cadf
commit e368f38716
3 changed files with 58 additions and 20 deletions

View file

@ -9,6 +9,9 @@ fuzz_target!(|module: wasm_smith::Module| {
let orig_bytes = module.to_bytes(); let orig_bytes = module.to_bytes();
let parsed_module = Module::from_wasm_bytes(&orig_bytes[..]).unwrap(); let parsed_module = Module::from_wasm_bytes(&orig_bytes[..]).unwrap();
let roundtrip_bytes = parsed_module.to_wasm_bytes(); let roundtrip_bytes = parsed_module.to_wasm_bytes();
if let Ok(filename) = std::env::var("ROUNDTRIP_WASM_SAVE") {
std::fs::write(filename, &roundtrip_bytes[..]).unwrap();
}
let parsed_roundtrip_module = Module::from_wasm_bytes(&roundtrip_bytes[..]).unwrap(); let parsed_roundtrip_module = Module::from_wasm_bytes(&roundtrip_bytes[..]).unwrap();
let _ = parsed_roundtrip_module.to_wasm_bytes(); let _ = parsed_roundtrip_module.to_wasm_bytes();
}); });

View file

@ -26,6 +26,21 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> {
self.func_type_sink.add_signature(params, results) self.func_type_sink.add_signature(params, results)
} }
fn find_fallthrough_ty<'b>(
&mut self,
params: &[Type],
mut targets: impl Iterator<Item = &'b SerializedBlockTarget>,
) -> u32 {
let fallthrough_rets = targets
.find_map(|target| match target {
SerializedBlockTarget::Fallthrough(tys, ..) => Some(&tys[..]),
_ => None,
})
.unwrap_or(&[]);
self.create_type(params.to_vec(), fallthrough_rets.to_vec())
}
fn translate(&mut self, op: &SerializedOperator, locations: &Locations) { fn translate(&mut self, op: &SerializedOperator, locations: &Locations) {
log::trace!("translate: {:?}", op); log::trace!("translate: {:?}", op);
match op { match op {
@ -69,9 +84,13 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> {
ref if_true, ref if_true,
ref if_false, ref if_false,
} => { } => {
self.wasm.operators.push(wasm_encoder::Instruction::If( let fallthrough_ty =
wasm_encoder::BlockType::Empty, self.find_fallthrough_ty(&[], [if_true, if_false].iter().map(|&targ| targ));
)); self.wasm
.operators
.push(wasm_encoder::Instruction::If(BlockType::FunctionType(
fallthrough_ty,
)));
self.translate_target(1, if_true, locations); self.translate_target(1, if_true, locations);
self.wasm.operators.push(wasm_encoder::Instruction::Else); self.wasm.operators.push(wasm_encoder::Instruction::Else);
self.translate_target(1, if_false, locations); self.translate_target(1, if_false, locations);
@ -81,10 +100,17 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> {
ref targets, ref targets,
ref default, ref default,
} => { } => {
let ty = self.create_type(vec![Type::I32], vec![]); let fallthrough_ty = self.find_fallthrough_ty(
for _ in 0..(targets.len() + 2) { &[Type::I32],
targets.iter().chain(std::iter::once(default)),
);
self.wasm.operators.push(wasm_encoder::Instruction::Block(
wasm_encoder::BlockType::FunctionType(fallthrough_ty),
));
let index_ty = self.create_type(vec![Type::I32], vec![]);
for _ in 0..(targets.len() + 1) {
self.wasm.operators.push(wasm_encoder::Instruction::Block( self.wasm.operators.push(wasm_encoder::Instruction::Block(
wasm_encoder::BlockType::FunctionType(ty), wasm_encoder::BlockType::FunctionType(index_ty),
)); ));
} }
@ -132,12 +158,17 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> {
) { ) {
log::trace!("translate_target: {:?}", target); log::trace!("translate_target: {:?}", target);
match target { match target {
&SerializedBlockTarget::Fallthrough(ref ops) => { &SerializedBlockTarget::Fallthrough(_, ref ops) => {
for op in ops { for op in ops {
self.translate(op, locations); self.translate(op, locations);
} }
if extra_blocks > 0 {
self.wasm
.operators
.push(wasm_encoder::Instruction::Br((extra_blocks - 1) as u32));
}
} }
&SerializedBlockTarget::Branch(branch, ref ops) => { &SerializedBlockTarget::Branch(branch, _, ref ops) => {
for op in ops { for op in ops {
self.translate(op, locations); self.translate(op, locations);
} }

View file

@ -12,6 +12,7 @@ use crate::{
ValueDef, ValueDef,
}; };
use fxhash::FxHashSet; use fxhash::FxHashSet;
use wasmparser::Type;
/// A Wasm function body with a serialized sequence of operators that /// A Wasm function body with a serialized sequence of operators that
/// mirror Wasm opcodes in every way *except* for locals corresponding /// mirror Wasm opcodes in every way *except* for locals corresponding
@ -24,21 +25,21 @@ pub struct SerializedBody {
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum SerializedBlockTarget { pub enum SerializedBlockTarget {
Fallthrough(Vec<SerializedOperator>), Fallthrough(Vec<Type>, Vec<SerializedOperator>),
Branch(usize, Vec<SerializedOperator>), Branch(usize, Vec<Type>, Vec<SerializedOperator>),
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum SerializedOperator { pub enum SerializedOperator {
StartBlock { StartBlock {
header: BlockId, header: BlockId,
params: Vec<(wasmparser::Type, Value)>, params: Vec<(Type, Value)>,
results: Vec<wasmparser::Type>, results: Vec<Type>,
}, },
StartLoop { StartLoop {
header: BlockId, header: BlockId,
params: Vec<(wasmparser::Type, Value)>, params: Vec<(Type, Value)>,
results: Vec<wasmparser::Type>, results: Vec<Type>,
}, },
Br(SerializedBlockTarget), Br(SerializedBlockTarget),
BrIf { BrIf {
@ -119,8 +120,8 @@ impl SerializedBlockTarget {
w: &mut W, w: &mut W,
) { ) {
match self { match self {
&SerializedBlockTarget::Branch(_, ref ops) &SerializedBlockTarget::Branch(_, _, ref ops)
| &SerializedBlockTarget::Fallthrough(ref ops) => { | &SerializedBlockTarget::Fallthrough(_, ref ops) => {
for op in ops { for op in ops {
op.visit_value_locals(r, w); op.visit_value_locals(r, w);
} }
@ -246,10 +247,15 @@ impl<'a> SerializedBodyContext<'a> {
self.push_value(value, &mut rev_ops); self.push_value(value, &mut rev_ops);
} }
rev_ops.reverse(); rev_ops.reverse();
let tys: Vec<Type> = self.f.blocks[target.target]
.params
.iter()
.map(|&(ty, _)| ty)
.collect();
log::trace!(" -> ops: {:?}", rev_ops); log::trace!(" -> ops: {:?}", rev_ops);
match target.relative_branch { match target.relative_branch {
Some(branch) => SerializedBlockTarget::Branch(branch, rev_ops), Some(branch) => SerializedBlockTarget::Branch(branch, tys, rev_ops),
None => SerializedBlockTarget::Fallthrough(rev_ops), None => SerializedBlockTarget::Fallthrough(tys, rev_ops),
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -283,8 +289,6 @@ impl<'a> SerializedBodyContext<'a> {
self.operators.extend(rev_ops); self.operators.extend(rev_ops);
self.operators self.operators
.push(SerializedOperator::BrTable { targets, default }); .push(SerializedOperator::BrTable { targets, default });
self.operators
.push(SerializedOperator::Operator(Operator::Unreachable));
} }
&Terminator::Return { ref values, .. } => { &Terminator::Return { ref values, .. } => {
let mut rev_ops = vec![]; let mut rev_ops = vec![];