fuzzbug fix on br_table fallthrough types
This commit is contained in:
parent
87c416cadf
commit
e368f38716
|
@ -9,6 +9,9 @@ fuzz_target!(|module: wasm_smith::Module| {
|
|||
let orig_bytes = module.to_bytes();
|
||||
let parsed_module = Module::from_wasm_bytes(&orig_bytes[..]).unwrap();
|
||||
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.to_wasm_bytes();
|
||||
});
|
||||
|
|
|
@ -26,6 +26,21 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> {
|
|||
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) {
|
||||
log::trace!("translate: {:?}", op);
|
||||
match op {
|
||||
|
@ -69,9 +84,13 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> {
|
|||
ref if_true,
|
||||
ref if_false,
|
||||
} => {
|
||||
self.wasm.operators.push(wasm_encoder::Instruction::If(
|
||||
wasm_encoder::BlockType::Empty,
|
||||
));
|
||||
let fallthrough_ty =
|
||||
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.wasm.operators.push(wasm_encoder::Instruction::Else);
|
||||
self.translate_target(1, if_false, locations);
|
||||
|
@ -81,10 +100,17 @@ impl<'a, FT: FuncTypeSink> WasmContext<'a, FT> {
|
|||
ref targets,
|
||||
ref default,
|
||||
} => {
|
||||
let ty = self.create_type(vec![Type::I32], vec![]);
|
||||
for _ in 0..(targets.len() + 2) {
|
||||
let fallthrough_ty = self.find_fallthrough_ty(
|
||||
&[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(
|
||||
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);
|
||||
match target {
|
||||
&SerializedBlockTarget::Fallthrough(ref ops) => {
|
||||
&SerializedBlockTarget::Fallthrough(_, ref ops) => {
|
||||
for op in ops {
|
||||
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 {
|
||||
self.translate(op, locations);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use crate::{
|
|||
ValueDef,
|
||||
};
|
||||
use fxhash::FxHashSet;
|
||||
use wasmparser::Type;
|
||||
|
||||
/// A Wasm function body with a serialized sequence of operators that
|
||||
/// mirror Wasm opcodes in every way *except* for locals corresponding
|
||||
|
@ -24,21 +25,21 @@ pub struct SerializedBody {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum SerializedBlockTarget {
|
||||
Fallthrough(Vec<SerializedOperator>),
|
||||
Branch(usize, Vec<SerializedOperator>),
|
||||
Fallthrough(Vec<Type>, Vec<SerializedOperator>),
|
||||
Branch(usize, Vec<Type>, Vec<SerializedOperator>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum SerializedOperator {
|
||||
StartBlock {
|
||||
header: BlockId,
|
||||
params: Vec<(wasmparser::Type, Value)>,
|
||||
results: Vec<wasmparser::Type>,
|
||||
params: Vec<(Type, Value)>,
|
||||
results: Vec<Type>,
|
||||
},
|
||||
StartLoop {
|
||||
header: BlockId,
|
||||
params: Vec<(wasmparser::Type, Value)>,
|
||||
results: Vec<wasmparser::Type>,
|
||||
params: Vec<(Type, Value)>,
|
||||
results: Vec<Type>,
|
||||
},
|
||||
Br(SerializedBlockTarget),
|
||||
BrIf {
|
||||
|
@ -119,8 +120,8 @@ impl SerializedBlockTarget {
|
|||
w: &mut W,
|
||||
) {
|
||||
match self {
|
||||
&SerializedBlockTarget::Branch(_, ref ops)
|
||||
| &SerializedBlockTarget::Fallthrough(ref ops) => {
|
||||
&SerializedBlockTarget::Branch(_, _, ref ops)
|
||||
| &SerializedBlockTarget::Fallthrough(_, ref ops) => {
|
||||
for op in ops {
|
||||
op.visit_value_locals(r, w);
|
||||
}
|
||||
|
@ -246,10 +247,15 @@ impl<'a> SerializedBodyContext<'a> {
|
|||
self.push_value(value, &mut rev_ops);
|
||||
}
|
||||
rev_ops.reverse();
|
||||
let tys: Vec<Type> = self.f.blocks[target.target]
|
||||
.params
|
||||
.iter()
|
||||
.map(|&(ty, _)| ty)
|
||||
.collect();
|
||||
log::trace!(" -> ops: {:?}", rev_ops);
|
||||
match target.relative_branch {
|
||||
Some(branch) => SerializedBlockTarget::Branch(branch, rev_ops),
|
||||
None => SerializedBlockTarget::Fallthrough(rev_ops),
|
||||
Some(branch) => SerializedBlockTarget::Branch(branch, tys, rev_ops),
|
||||
None => SerializedBlockTarget::Fallthrough(tys, rev_ops),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -283,8 +289,6 @@ impl<'a> SerializedBodyContext<'a> {
|
|||
self.operators.extend(rev_ops);
|
||||
self.operators
|
||||
.push(SerializedOperator::BrTable { targets, default });
|
||||
self.operators
|
||||
.push(SerializedOperator::Operator(Operator::Unreachable));
|
||||
}
|
||||
&Terminator::Return { ref values, .. } => {
|
||||
let mut rev_ops = vec![];
|
||||
|
|
Loading…
Reference in a new issue