Skip to content

Commit

Permalink
Merge pull request #173 from alexcrichton/wasmparser-validator
Browse files Browse the repository at this point in the history
Rely on wasmparser for validation
  • Loading branch information
fitzgen committed Jul 14, 2020
2 parents 56f78ff + fd94d9f commit e8ef427
Show file tree
Hide file tree
Showing 3 changed files with 562 additions and 975 deletions.
138 changes: 3 additions & 135 deletions src/module/functions/local_function/context.rs
Expand Up @@ -17,10 +17,6 @@ pub(crate) struct ControlFrame {
/// The result type of the block (used to check its result).
pub end_types: Box<[ValType]>,

/// The height of the operand stack at the start of the block (used to check
/// that operands do not underflow the current block).
pub height: usize,

/// If `true`, then this frame is unreachable. This is used to handle
/// stack-polymorphic typing after unconditional branches.
pub unreachable: bool,
Expand All @@ -32,25 +28,6 @@ pub(crate) struct ControlFrame {
pub kind: BlockKind,
}

impl ControlFrame {
/// Get the expected types on the stack for branches to this block.
pub fn label_types(&self) -> &[ValType] {
if let BlockKind::Loop = self.kind {
&self.start_types
} else {
&self.end_types
}
}
}

/// The operand stack.
///
/// `None` is used for `Unknown` stack-polymophic values.
///
/// We also keep track of the instruction that created the value at each stack
/// slot.
pub(crate) type OperandStack = Vec<Option<ValType>>;

/// The control frame stack.
pub(crate) type ControlStack = Vec<ControlFrame>;

Expand All @@ -68,9 +45,6 @@ pub(crate) struct ValidationContext<'a> {
/// The function being validated/constructed.
pub func: &'a mut LocalFunction,

/// The operands stack.
pub operands: &'a mut OperandStack,

/// The control frames stack.
pub controls: &'a mut ControlStack,

Expand All @@ -91,40 +65,18 @@ impl<'a> ValidationContext<'a> {
indices: &'a IndicesToIds,
func_id: FunctionId,
func: &'a mut LocalFunction,
operands: &'a mut OperandStack,
controls: &'a mut ControlStack,
) -> ValidationContext<'a> {
ValidationContext {
module,
indices,
func_id,
func,
operands,
controls,
if_else: Vec::new(),
}
}

pub fn push_operand(&mut self, op: Option<ValType>) {
impl_push_operand(&mut self.operands, op);
}

pub fn pop_operand(&mut self) -> Result<Option<ValType>> {
impl_pop_operand(&mut self.operands, &mut self.controls)
}

pub fn pop_operand_expected(&mut self, expected: Option<ValType>) -> Result<Option<ValType>> {
impl_pop_operand_expected(&mut self.operands, &mut self.controls, expected)
}

pub fn push_operands(&mut self, types: &[ValType]) {
impl_push_operands(&mut self.operands, types);
}

pub fn pop_operands(&mut self, expected: &[ValType]) -> Result<()> {
impl_pop_operands(&mut self.operands, &self.controls, expected)
}

pub fn push_control(
&mut self,
kind: BlockKind,
Expand All @@ -136,7 +88,6 @@ impl<'a> ValidationContext<'a> {
kind,
self.func,
self.controls,
self.operands,
start_types,
end_types,
)
Expand All @@ -151,24 +102,21 @@ impl<'a> ValidationContext<'a> {
kind,
self.func,
self.controls,
self.operands,
ty.into(),
start_types,
end_types,
)
}

pub fn pop_control(&mut self) -> Result<(ControlFrame, InstrSeqId)> {
let frame = impl_pop_control(&mut self.controls, &mut self.operands)?;
let frame = impl_pop_control(&mut self.controls)?;
let block = frame.block;
Ok((frame, block))
}

pub fn unreachable(&mut self) {
let frame = self.controls.last_mut().unwrap();
frame.unreachable = true;
let height = frame.height;
self.operands.truncate(height);
}

pub fn control(&self, n: usize) -> Result<&ControlFrame> {
Expand Down Expand Up @@ -208,73 +156,11 @@ impl<'a> ValidationContext<'a> {
}
}

fn impl_push_operand(operands: &mut OperandStack, op: Option<ValType>) {
log::trace!("push operand: {:?}", op);
operands.push(op);
}

fn impl_pop_operand(
operands: &mut OperandStack,
controls: &ControlStack,
) -> Result<Option<ValType>> {
if let Some(f) = controls.last() {
if operands.len() == f.height {
if f.unreachable {
log::trace!("pop operand: None");
return Ok(None);
}
return Err(ErrorKind::InvalidWasm)
.context("popped operand past control frame height in non-unreachable code");
}
}
let op = operands.pop().unwrap();
log::trace!("pop operand: {:?}", op);
Ok(op)
}

fn impl_pop_operand_expected(
operands: &mut OperandStack,
controls: &ControlStack,
expected: Option<ValType>,
) -> Result<Option<ValType>> {
match (impl_pop_operand(operands, controls)?, expected) {
(None, expected) => Ok(expected),
(actual, None) => Ok(actual),
(Some(actual), Some(expected)) => {
if actual != expected {
Err(ErrorKind::InvalidWasm)
.context(format!("expected type {}", expected))
.context(format!("found type {}", actual))
} else {
Ok(Some(expected))
}
}
}
}

fn impl_push_operands(operands: &mut OperandStack, types: &[ValType]) {
for ty in types {
impl_push_operand(operands, Some(*ty));
}
}

fn impl_pop_operands(
operands: &mut OperandStack,
controls: &ControlStack,
expected: &[ValType],
) -> Result<()> {
for ty in expected.iter().cloned().rev() {
impl_pop_operand_expected(operands, controls, Some(ty))?;
}
Ok(())
}

fn impl_push_control(
types: &ModuleTypes,
kind: BlockKind,
func: &mut LocalFunction,
controls: &mut ControlStack,
operands: &mut OperandStack,
start_types: Box<[ValType]>,
end_types: Box<[ValType]>,
) -> Result<InstrSeqId> {
Expand All @@ -291,7 +177,6 @@ fn impl_push_control(
kind,
func,
controls,
operands,
ty,
start_types,
end_types,
Expand All @@ -303,7 +188,6 @@ fn impl_push_control_with_ty(
kind: BlockKind,
func: &mut LocalFunction,
controls: &mut ControlStack,
operands: &mut OperandStack,
ty: InstrSeqType,
start_types: Box<[ValType]>,
end_types: Box<[ValType]>,
Expand All @@ -313,15 +197,11 @@ fn impl_push_control_with_ty(
debug_assert_eq!(types.results(ty), &end_types[..]);
}

let height = operands.len();
impl_push_operands(operands, &start_types);

let block = func.add_block(|id| InstrSeq::new(id, ty));

controls.push(ControlFrame {
start_types,
end_types,
height,
unreachable: false,
block,
kind,
Expand All @@ -330,23 +210,11 @@ fn impl_push_control_with_ty(
block
}

fn impl_pop_control(
controls: &mut ControlStack,
operands: &mut OperandStack,
) -> Result<ControlFrame> {
let frame = controls
fn impl_pop_control(controls: &mut ControlStack) -> Result<ControlFrame> {
controls
.last()
.ok_or_else(|| ErrorKind::InvalidWasm)
.context("attempted to pop a frame from an empty control stack")?;
impl_pop_operands(operands, controls, &frame.end_types)?;
if operands.len() != frame.height {
return Err(ErrorKind::InvalidWasm).context(format!(
"incorrect number of operands on the stack at the end of a control frame; \
found {}, expected {}",
operands.len(),
frame.height
));
}
let frame = controls.pop().unwrap();
Ok(frame)
}

0 comments on commit e8ef427

Please sign in to comment.