fuzzbug fixes
This commit is contained in:
parent
7e161064bf
commit
83c4777895
158
src/frontend.rs
158
src/frontend.rs
|
@ -221,11 +221,6 @@ impl LocalTracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, local: LocalId, value: Value) {
|
pub fn set(&mut self, local: LocalId, value: Value) {
|
||||||
if self.cur_block.is_none() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assert_ne!(value, Value::undef());
|
|
||||||
|
|
||||||
log::trace!("set: local {} value {:?}", local, value);
|
log::trace!("set: local {} value {:?}", local, value);
|
||||||
self.in_cur_block.insert(local, value);
|
self.in_cur_block.insert(local, value);
|
||||||
}
|
}
|
||||||
|
@ -288,13 +283,12 @@ impl LocalTracker {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&mut self, body: &mut FunctionBody, local: LocalId) -> Value {
|
pub fn get(&mut self, body: &mut FunctionBody, local: LocalId) -> Value {
|
||||||
if self.cur_block.is_none() {
|
if let Some(block) = self.cur_block {
|
||||||
return Value::undef();
|
assert!((local as usize) < body.locals.len());
|
||||||
|
self.get_in_block(body, block, local)
|
||||||
|
} else {
|
||||||
|
Value::undef()
|
||||||
}
|
}
|
||||||
|
|
||||||
let block = self.cur_block.unwrap();
|
|
||||||
assert!((local as usize) < body.locals.len());
|
|
||||||
self.get_in_block(body, block, local)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_default_value(&mut self, body: &mut FunctionBody, ty: Type) -> Value {
|
fn create_default_value(&mut self, body: &mut FunctionBody, ty: Type) -> Value {
|
||||||
|
@ -544,6 +538,14 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
self.op_stack.pop().unwrap().1
|
self.op_stack.pop().unwrap().1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn block_results(&mut self, n: usize, start_depth: usize) -> Vec<Value> {
|
||||||
|
if self.op_stack.len() < start_depth + n {
|
||||||
|
vec![Value::undef(); n]
|
||||||
|
} else {
|
||||||
|
self.pop_n(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_op(&mut self, op: wasmparser::Operator<'a>) -> Result<()> {
|
fn handle_op(&mut self, op: wasmparser::Operator<'a>) -> Result<()> {
|
||||||
trace!("handle_op: {:?}", op);
|
trace!("handle_op: {:?}", op);
|
||||||
trace!("op_stack = {:?}", self.op_stack);
|
trace!("op_stack = {:?}", self.op_stack);
|
||||||
|
@ -560,24 +562,20 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
|
|
||||||
wasmparser::Operator::LocalGet { local_index } => {
|
wasmparser::Operator::LocalGet { local_index } => {
|
||||||
let ty = self.body.locals[*local_index as usize];
|
let ty = self.body.locals[*local_index as usize];
|
||||||
if self.cur_block.is_some() {
|
let value = self.locals.get(&mut self.body, *local_index);
|
||||||
let value = self.locals.get(&mut self.body, *local_index);
|
self.op_stack.push((ty, value));
|
||||||
self.op_stack.push((ty, value));
|
|
||||||
} else {
|
|
||||||
self.op_stack.push((ty, Value::undef()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmparser::Operator::LocalSet { local_index } => {
|
wasmparser::Operator::LocalSet { local_index } => {
|
||||||
let (_, value) = self.op_stack.pop().unwrap();
|
let (_, value) = self.op_stack.pop().unwrap();
|
||||||
if self.cur_block.is_some() {
|
if value != Value::undef() {
|
||||||
self.locals.set(*local_index, value);
|
self.locals.set(*local_index, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmparser::Operator::LocalTee { local_index } => {
|
wasmparser::Operator::LocalTee { local_index } => {
|
||||||
let (_ty, value) = *self.op_stack.last().unwrap();
|
let (_ty, value) = *self.op_stack.last().unwrap();
|
||||||
if self.cur_block.is_some() {
|
if value != Value::undef() {
|
||||||
self.locals.set(*local_index, value);
|
self.locals.set(*local_index, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -766,23 +764,6 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
let _ = self.pop_1();
|
let _ = self.pop_1();
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmparser::Operator::End if self.cur_block.is_none() => {
|
|
||||||
let frame = self.ctrl_stack.pop().unwrap();
|
|
||||||
self.op_stack.truncate(frame.start_depth());
|
|
||||||
match frame {
|
|
||||||
Frame::Block { out, .. } | Frame::If { out, .. } | Frame::Else { out, .. } => {
|
|
||||||
self.locals.seal_block_preds(out, &mut self.body);
|
|
||||||
}
|
|
||||||
Frame::Loop { out, header, .. } => {
|
|
||||||
self.locals.seal_block_preds(out, &mut self.body);
|
|
||||||
self.locals.seal_block_preds(header, &mut self.body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.cur_block = Some(frame.out());
|
|
||||||
self.push_block_params(frame.results().len());
|
|
||||||
self.locals.start_block(frame.out());
|
|
||||||
}
|
|
||||||
|
|
||||||
wasmparser::Operator::End => {
|
wasmparser::Operator::End => {
|
||||||
let frame = self.ctrl_stack.pop();
|
let frame = self.ctrl_stack.pop();
|
||||||
match &frame {
|
match &frame {
|
||||||
|
@ -803,12 +784,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
}) => {
|
}) => {
|
||||||
// Generate a branch to the out-block with
|
// Generate a branch to the out-block with
|
||||||
// blockparams for the results.
|
// blockparams for the results.
|
||||||
if self.cur_block.is_some() {
|
let result_values = self.block_results(results.len(), *start_depth);
|
||||||
let result_values = self.pop_n(results.len());
|
self.emit_branch(*out, &result_values[..]);
|
||||||
self.emit_branch(*out, &result_values[..]);
|
|
||||||
}
|
|
||||||
self.op_stack.truncate(*start_depth);
|
self.op_stack.truncate(*start_depth);
|
||||||
self.locals.finish_block();
|
|
||||||
// Seal the out-block: no more edges will be
|
// Seal the out-block: no more edges will be
|
||||||
// added to it. Also, if we're ending a loop,
|
// added to it. Also, if we're ending a loop,
|
||||||
// seal thea header: no more back-edges will
|
// seal thea header: no more back-edges will
|
||||||
|
@ -831,9 +809,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
}) => {
|
}) => {
|
||||||
// Generate a branch to the out-block with
|
// Generate a branch to the out-block with
|
||||||
// blockparams for the results.
|
// blockparams for the results.
|
||||||
let result_values = self.pop_n(results.len());
|
let result_values = self.block_results(results.len(), *start_depth);
|
||||||
self.emit_branch(*out, &result_values[..]);
|
self.emit_branch(*out, &result_values[..]);
|
||||||
self.locals.finish_block();
|
|
||||||
self.op_stack.truncate(*start_depth);
|
self.op_stack.truncate(*start_depth);
|
||||||
// No `else`, so we need to generate a trivial
|
// No `else`, so we need to generate a trivial
|
||||||
// branch in the else-block. If the if-block-type
|
// branch in the else-block. If the if-block-type
|
||||||
|
@ -847,7 +824,6 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
self.locals.start_block(*el);
|
self.locals.start_block(*el);
|
||||||
self.cur_block = Some(*el);
|
self.cur_block = Some(*el);
|
||||||
self.emit_branch(*out, &else_result_values[..]);
|
self.emit_branch(*out, &else_result_values[..]);
|
||||||
self.locals.finish_block();
|
|
||||||
assert_eq!(self.op_stack.len(), *start_depth);
|
assert_eq!(self.op_stack.len(), *start_depth);
|
||||||
self.cur_block = Some(*out);
|
self.cur_block = Some(*out);
|
||||||
self.locals.seal_block_preds(*out, &mut self.body);
|
self.locals.seal_block_preds(*out, &mut self.body);
|
||||||
|
@ -862,9 +838,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
}) => {
|
}) => {
|
||||||
// Generate a branch to the out-block with
|
// Generate a branch to the out-block with
|
||||||
// blockparams for the results.
|
// blockparams for the results.
|
||||||
let result_values = self.pop_n(results.len());
|
let result_values = self.block_results(results.len(), *start_depth);
|
||||||
self.emit_branch(*out, &result_values[..]);
|
self.emit_branch(*out, &result_values[..]);
|
||||||
self.locals.finish_block();
|
|
||||||
self.op_stack.truncate(*start_depth);
|
self.op_stack.truncate(*start_depth);
|
||||||
self.cur_block = Some(*out);
|
self.cur_block = Some(*out);
|
||||||
self.locals.seal_block_preds(*out, &mut self.body);
|
self.locals.seal_block_preds(*out, &mut self.body);
|
||||||
|
@ -942,10 +917,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
results,
|
results,
|
||||||
} = self.ctrl_stack.pop().unwrap()
|
} = self.ctrl_stack.pop().unwrap()
|
||||||
{
|
{
|
||||||
if self.cur_block.is_some() {
|
let if_results = self.pop_n(results.len());
|
||||||
let if_results = self.pop_n(results.len());
|
self.emit_branch(out, &if_results[..]);
|
||||||
self.emit_branch(out, &if_results[..]);
|
|
||||||
}
|
|
||||||
self.op_stack.truncate(start_depth);
|
self.op_stack.truncate(start_depth);
|
||||||
self.op_stack.extend(param_values);
|
self.op_stack.extend(param_values);
|
||||||
self.ctrl_stack.push(Frame::Else {
|
self.ctrl_stack.push(Frame::Else {
|
||||||
|
@ -976,8 +949,6 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
// Get the args off the stack unconditionally.
|
// Get the args off the stack unconditionally.
|
||||||
let args = self.pop_n(frame.br_args().len());
|
let args = self.pop_n(frame.br_args().len());
|
||||||
self.emit_branch(frame.br_target(), &args[..]);
|
self.emit_branch(frame.br_target(), &args[..]);
|
||||||
self.locals.finish_block();
|
|
||||||
self.cur_block = None;
|
|
||||||
}
|
}
|
||||||
Some(cond) => {
|
Some(cond) => {
|
||||||
let cont = self.body.add_block();
|
let cont = self.body.add_block();
|
||||||
|
@ -988,10 +959,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
self.emit_cond_branch(cond, frame.br_target(), &args[..], cont, &[]);
|
self.emit_cond_branch(cond, frame.br_target(), &args[..], cont, &[]);
|
||||||
self.locals.seal_block_preds(cont, &mut self.body);
|
self.locals.seal_block_preds(cont, &mut self.body);
|
||||||
if self.cur_block.is_some() {
|
self.cur_block = Some(cont);
|
||||||
self.cur_block = Some(cont);
|
self.locals.start_block(cont);
|
||||||
self.locals.start_block(cont);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1017,15 +986,11 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
term_targets.push(block);
|
term_targets.push(block);
|
||||||
}
|
}
|
||||||
self.emit_br_table(index, default_term_target, &term_targets[..], &args[..]);
|
self.emit_br_table(index, default_term_target, &term_targets[..], &args[..]);
|
||||||
self.locals.finish_block();
|
|
||||||
self.cur_block = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wasmparser::Operator::Return => {
|
wasmparser::Operator::Return => {
|
||||||
let retvals = self.pop_n(self.module.signatures[self.my_sig].returns.len());
|
let retvals = self.pop_n(self.module.signatures[self.my_sig].returns.len());
|
||||||
self.emit_ret(&retvals[..]);
|
self.emit_ret(&retvals[..]);
|
||||||
self.locals.finish_block();
|
|
||||||
self.cur_block = None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => bail!("Unsupported operator: {:?}", op),
|
_ => bail!("Unsupported operator: {:?}", op),
|
||||||
|
@ -1074,6 +1039,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
args,
|
args,
|
||||||
};
|
};
|
||||||
self.body.blocks[block].terminator = Terminator::Br { target };
|
self.body.blocks[block].terminator = Terminator::Br { target };
|
||||||
|
self.cur_block = None;
|
||||||
|
self.locals.finish_block();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1109,6 +1076,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
};
|
};
|
||||||
self.body.add_edge(block, if_true);
|
self.body.add_edge(block, if_true);
|
||||||
self.body.add_edge(block, if_false);
|
self.body.add_edge(block, if_false);
|
||||||
|
self.cur_block = None;
|
||||||
|
self.locals.finish_block();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1153,6 +1122,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
targets,
|
targets,
|
||||||
default,
|
default,
|
||||||
};
|
};
|
||||||
|
self.cur_block = None;
|
||||||
|
self.locals.finish_block();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1197,48 +1168,43 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
inputs
|
inputs
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let n_outputs = outputs.len();
|
||||||
|
|
||||||
|
let mut input_operands = vec![];
|
||||||
|
for input in inputs.into_iter().rev() {
|
||||||
|
let (stack_top_ty, stack_top) = self.op_stack.pop().unwrap();
|
||||||
|
assert_eq!(stack_top_ty, input);
|
||||||
|
input_operands.push(stack_top);
|
||||||
|
}
|
||||||
|
input_operands.reverse();
|
||||||
|
log::trace!(" -> operands: {:?}", input_operands);
|
||||||
|
|
||||||
|
let ty = if n_outputs == 1 {
|
||||||
|
Some(outputs[0])
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let value = self
|
||||||
|
.body
|
||||||
|
.add_value(ValueDef::Operator(op, input_operands), ty);
|
||||||
|
log::trace!(" -> value: {:?} ty {:?}", value, ty);
|
||||||
|
|
||||||
if let Some(block) = self.cur_block {
|
if let Some(block) = self.cur_block {
|
||||||
let n_outputs = outputs.len();
|
|
||||||
|
|
||||||
let mut input_operands = vec![];
|
|
||||||
for input in inputs.into_iter().rev() {
|
|
||||||
let (stack_top_ty, stack_top) = self.op_stack.pop().unwrap();
|
|
||||||
assert_eq!(stack_top_ty, input);
|
|
||||||
input_operands.push(stack_top);
|
|
||||||
}
|
|
||||||
input_operands.reverse();
|
|
||||||
log::trace!(" -> operands: {:?}", input_operands);
|
|
||||||
|
|
||||||
let ty = if n_outputs == 1 {
|
|
||||||
Some(outputs[0])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let value = self
|
|
||||||
.body
|
|
||||||
.add_value(ValueDef::Operator(op, input_operands), ty);
|
|
||||||
log::trace!(" -> value: {:?} ty {:?}", value, ty);
|
|
||||||
|
|
||||||
if !op_effects(&op).unwrap().is_empty() {
|
if !op_effects(&op).unwrap().is_empty() {
|
||||||
self.body.blocks[block].insts.push(value);
|
self.body.blocks[block].insts.push(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if n_outputs == 1 {
|
if n_outputs == 1 {
|
||||||
let output_ty = outputs[0];
|
let output_ty = outputs[0];
|
||||||
self.op_stack.push((output_ty, value));
|
self.op_stack.push((output_ty, value));
|
||||||
} else {
|
|
||||||
for (i, output_ty) in outputs.into_iter().enumerate() {
|
|
||||||
let pick = self
|
|
||||||
.body
|
|
||||||
.add_value(ValueDef::PickOutput(value, i), Some(output_ty));
|
|
||||||
self.op_stack.push((output_ty, pick));
|
|
||||||
log::trace!(" -> pick {}: {:?} ty {:?}", i, pick, output_ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
let _ = self.pop_n(inputs.len());
|
for (i, output_ty) in outputs.into_iter().enumerate() {
|
||||||
for ty in outputs {
|
let pick = self
|
||||||
self.op_stack.push((ty, Value::undef()));
|
.body
|
||||||
|
.add_value(ValueDef::PickOutput(value, i), Some(output_ty));
|
||||||
|
self.op_stack.push((output_ty, pick));
|
||||||
|
log::trace!(" -> pick {}: {:?} ty {:?}", i, pick, output_ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue