From 9c156890e4632014104928545001a8657a040f4c Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Wed, 31 Jan 2018 18:32:06 +0300 Subject: [PATCH] Traps in execution --- examples/tictactoe.rs | 4 +- src/func.rs | 8 +- src/host.rs | 6 +- src/lib.rs | 1 + src/module.rs | 5 +- src/runner.rs | 308 ++++++++++++++++++++++-------------------- src/tests/host.rs | 10 +- 7 files changed, 182 insertions(+), 160 deletions(-) diff --git a/examples/tictactoe.rs b/examples/tictactoe.rs index 138de9c..be0f225 100644 --- a/examples/tictactoe.rs +++ b/examples/tictactoe.rs @@ -8,7 +8,7 @@ use wasmi::{ Error as InterpreterError, ModuleInstance, ModuleRef, Externals, RuntimeValue, FuncRef, ModuleImportResolver, FuncInstance, HostError, ImportsBuilder, Signature, ValueType, - RuntimeArgs, + RuntimeArgs, Trap, }; #[derive(Debug)] @@ -149,7 +149,7 @@ impl<'a> Externals for Runtime<'a> { &mut self, index: usize, args: RuntimeArgs, - ) -> Result, InterpreterError> { + ) -> Result, Trap> { match index { SET_FUNC_INDEX => { let idx: i32 = args.nth(0)?; diff --git a/src/func.rs b/src/func.rs index f04be05..7662e85 100644 --- a/src/func.rs +++ b/src/func.rs @@ -2,7 +2,7 @@ use std::rc::{Rc, Weak}; use std::fmt; use std::collections::HashMap; use parity_wasm::elements::{Local, Opcodes}; -use {Error, Signature}; +use {Trap, Signature}; use host::Externals; use runner::{check_function_args, Interpreter}; use value::RuntimeValue; @@ -132,10 +132,10 @@ impl FuncInstance { func: &FuncRef, args: &[RuntimeValue], externals: &mut E, - ) -> Result, Error> { + ) -> Result, Trap> { + debug_assert!(check_function_args(func.signature(), &args).is_ok()); match *func.as_internal() { - FuncInstanceInternal::Internal { ref signature, .. } => { - check_function_args(signature, &args)?; + FuncInstanceInternal::Internal { .. } => { let mut interpreter = Interpreter::new(externals); interpreter.start_execution(func, args) } diff --git a/src/host.rs b/src/host.rs index 3bdbf5d..71b3cc0 100644 --- a/src/host.rs +++ b/src/host.rs @@ -173,7 +173,7 @@ pub trait Externals { &mut self, index: usize, args: RuntimeArgs, - ) -> Result, Error>; + ) -> Result, Trap>; } /// Implementation of [`Externals`] that just traps on [`invoke_index`]. @@ -187,8 +187,8 @@ impl Externals for NopExternals { &mut self, _index: usize, _args: RuntimeArgs, - ) -> Result, Error> { - Err(Error::Trap(Trap::Unreachable)) + ) -> Result, Trap> { + Err(Trap::Unreachable) } } diff --git a/src/lib.rs b/src/lib.rs index 8e3377c..5d4e249 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,6 +115,7 @@ pub enum Trap { ElemSignatureMismatch, DivisionByZero, InvalidConversionToInt, + StackOverflow, } /// Internal interpreter error. diff --git a/src/module.rs b/src/module.rs index 0d10d25..cb1bcd6 100644 --- a/src/module.rs +++ b/src/module.rs @@ -1,3 +1,4 @@ +use Trap; use std::rc::Rc; use std::cell::RefCell; use std::fmt; @@ -575,7 +576,7 @@ impl ModuleInstance { } }; - FuncInstance::invoke(&func_instance, args, externals) + FuncInstance::invoke(&func_instance, args, externals).map_err(|t| Error::Trap(t)) } /// Find export by a name. @@ -608,7 +609,7 @@ impl<'a> NotStartedModuleRef<'a> { &self.instance } - pub fn run_start(self, state: &mut E) -> Result { + pub fn run_start(self, state: &mut E) -> Result { if let Some(start_fn_idx) = self.loaded_module.module().start_section() { let start_func = self.instance.func_by_index(start_fn_idx).expect( "Due to validation start function should exists", diff --git a/src/runner.rs b/src/runner.rs index df66c26..18cb17e 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -51,7 +51,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } } - pub fn start_execution(&mut self, func: &FuncRef, args: &[RuntimeValue]) -> Result, Error> { + pub fn start_execution(&mut self, func: &FuncRef, args: &[RuntimeValue]) -> Result, Trap> { let context = FunctionContext::new( func.clone(), DEFAULT_VALUE_STACK_LIMIT, @@ -59,13 +59,14 @@ impl<'a, E: Externals> Interpreter<'a, E> { func.signature(), args.into_iter().cloned().collect(), ); - self.run_function(context) + + let mut function_stack = VecDeque::new(); + function_stack.push_back(context); + + self.run_interpreter_loop(&mut function_stack) } - fn run_function(&mut self, function_context: FunctionContext) -> Result, Error> { - let mut function_stack = VecDeque::new(); - function_stack.push_back(function_context); - + fn run_interpreter_loop(&mut self, function_stack: &mut VecDeque) -> Result, Trap> { loop { let mut function_context = function_stack.pop_back().expect("on loop entry - not empty; on loop continue - checking for emptiness; qed"); let function_ref = function_context.function.clone(); @@ -99,7 +100,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { function_stack.push_back(nested_context); }, FuncInstanceInternal::Host { ref signature, .. } => { - let args = prepare_function_args(signature, &mut function_context.value_stack)?; + let args = prepare_function_args(signature, &mut function_context.value_stack); let return_val = FuncInstance::invoke(&nested_func, &args, self.externals)?; if let Some(return_val) = return_val { function_context.value_stack_mut().push(return_val)?; @@ -112,7 +113,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } } - fn do_run_function(&mut self, function_context: &mut FunctionContext, function_body: &[Opcode], function_labels: &HashMap) -> Result { + fn do_run_function(&mut self, function_context: &mut FunctionContext, function_body: &[Opcode], function_labels: &HashMap) -> Result { loop { let instruction = &function_body[function_context.position]; @@ -121,7 +122,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { InstructionOutcome::Branch(mut index) => { // discard index - 1 blocks while index >= 1 { - function_context.discard_frame()?; + function_context.discard_frame(); index -= 1; } @@ -144,12 +145,18 @@ impl<'a, E: Externals> Interpreter<'a, E> { } Ok(RunResult::Return(match function_context.return_type { - BlockType::Value(_) => Some(function_context.value_stack_mut().pop()?), + BlockType::Value(_) => { + let result = function_context + .value_stack_mut() + .pop() + .expect("Due to validation stack shouldn't be empty"); + Some(result) + }, BlockType::NoResult => None, })) } - fn run_instruction(&mut self, context: &mut FunctionContext, labels: &HashMap, opcode: &Opcode) -> Result { + fn run_instruction(&mut self, context: &mut FunctionContext, labels: &HashMap, opcode: &Opcode) -> Result { match opcode { &Opcode::Unreachable => self.run_unreachable(context), &Opcode::Nop => self.run_nop(context), @@ -343,25 +350,25 @@ impl<'a, E: Externals> Interpreter<'a, E> { } } - fn run_unreachable(&mut self, _context: &mut FunctionContext) -> Result { - Err(Error::Trap(Trap::Unreachable)) + fn run_unreachable(&mut self, _context: &mut FunctionContext) -> Result { + Err(Trap::Unreachable) } - fn run_nop(&mut self, _context: &mut FunctionContext) -> Result { + fn run_nop(&mut self, _context: &mut FunctionContext) -> Result { Ok(InstructionOutcome::RunNextInstruction) } - fn run_block(&mut self, context: &mut FunctionContext, labels: &HashMap, block_type: BlockType) -> Result { + fn run_block(&mut self, context: &mut FunctionContext, labels: &HashMap, block_type: BlockType) -> Result { context.push_frame(labels, BlockFrameType::Block, block_type)?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_loop(&mut self, context: &mut FunctionContext, labels: &HashMap, block_type: BlockType) -> Result { + fn run_loop(&mut self, context: &mut FunctionContext, labels: &HashMap, block_type: BlockType) -> Result { context.push_frame(labels, BlockFrameType::Loop, block_type)?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_if(&mut self, context: &mut FunctionContext, labels: &HashMap, block_type: BlockType) -> Result { + fn run_if(&mut self, context: &mut FunctionContext, labels: &HashMap, block_type: BlockType) -> Result { let condition: bool = context .value_stack_mut() .pop_as() @@ -376,39 +383,46 @@ impl<'a, E: Externals> Interpreter<'a, E> { context.position = else_pos; BlockFrameType::IfFalse }; - context.push_frame(labels, block_frame_type, block_type).map(|_| InstructionOutcome::RunNextInstruction) + context.push_frame(labels, block_frame_type, block_type)?; + + Ok(InstructionOutcome::RunNextInstruction) } - fn run_else(&mut self, context: &mut FunctionContext, labels: &HashMap) -> Result { + fn run_else(&mut self, context: &mut FunctionContext, labels: &HashMap) -> Result { let end_pos = labels[&context.position]; context.pop_frame(false)?; context.position = end_pos; Ok(InstructionOutcome::RunNextInstruction) } - fn run_end(&mut self, context: &mut FunctionContext) -> Result { + fn run_end(&mut self, context: &mut FunctionContext) -> Result { context.pop_frame(false)?; Ok(InstructionOutcome::End) } - fn run_br(&mut self, _context: &mut FunctionContext, label_idx: u32) -> Result { + fn run_br(&mut self, _context: &mut FunctionContext, label_idx: u32) -> Result { Ok(InstructionOutcome::Branch(label_idx as usize)) } - fn run_br_if(&mut self, context: &mut FunctionContext, label_idx: u32) -> Result { - if context.value_stack_mut().pop_as()? { + fn run_br_if(&mut self, context: &mut FunctionContext, label_idx: u32) -> Result { + let condition = context.value_stack_mut() + .pop_as() + .expect("Due to validation stack should contain value"); + if condition { Ok(InstructionOutcome::Branch(label_idx as usize)) } else { Ok(InstructionOutcome::RunNextInstruction) } } - fn run_br_table(&mut self, context: &mut FunctionContext, table: &[u32], default: u32) -> Result { - let index: u32 = context.value_stack_mut().pop_as()?; + fn run_br_table(&mut self, context: &mut FunctionContext, table: &[u32], default: u32) -> Result { + let index: u32 = context.value_stack_mut() + .pop_as() + .expect("Due to validation stack should contain value"); Ok(InstructionOutcome::Branch(table.get(index as usize).cloned().unwrap_or(default) as usize)) } - fn run_return(&mut self, _context: &mut FunctionContext) -> Result { + fn run_return(&mut self, _context: &mut FunctionContext) -> Result { Ok(InstructionOutcome::Return) } @@ -416,7 +430,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { &mut self, context: &mut FunctionContext, func_idx: u32, - ) -> Result { + ) -> Result { let func = context .module() .func_by_index(func_idx) @@ -428,7 +442,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { &mut self, context: &mut FunctionContext, signature_idx: u32, - ) -> Result { + ) -> Result { let table_func_idx: u32 = context .value_stack_mut() .pop_as() @@ -438,8 +452,8 @@ impl<'a, E: Externals> Interpreter<'a, E> { .table_by_index(DEFAULT_TABLE_INDEX) .expect("Due to validation table should exists"); let func_ref = table.get(table_func_idx) - .map_err(|_| Error::Trap(Trap::TableAccessOutOfBounds))? - .ok_or_else(|| Error::Trap(Trap::ElemUninitialized))?; + .map_err(|_| Trap::TableAccessOutOfBounds)? + .ok_or_else(|| Trap::ElemUninitialized)?; { let actual_function_type = func_ref.signature(); @@ -449,43 +463,41 @@ impl<'a, E: Externals> Interpreter<'a, E> { .expect("Due to validation type should exists"); if &*required_function_type != actual_function_type { - return Err(Error::Trap(Trap::ElemSignatureMismatch)); + return Err(Trap::ElemSignatureMismatch); } } Ok(InstructionOutcome::ExecuteCall(func_ref)) } - fn run_drop(&mut self, context: &mut FunctionContext) -> Result { - context + fn run_drop(&mut self, context: &mut FunctionContext) -> Result { + let _ = context .value_stack_mut() - .pop() - .map_err(Into::into) - .map(|_| InstructionOutcome::RunNextInstruction) - } - - fn run_select(&mut self, context: &mut FunctionContext) -> Result { - context - .value_stack_mut() - .pop_triple() - .and_then(|(left, mid, right)| { - let condition = right - .try_into() - .expect("Due to validation stack top should be I32"); - Ok((left, mid, condition)) - }) - .map(|(left, mid, condition)| if condition { left } else { mid }) - .map(|val| context.value_stack_mut().push(val)) - .map(|_| InstructionOutcome::RunNextInstruction) - } - - fn run_get_local(&mut self, context: &mut FunctionContext, index: u32) -> Result { - let value = context.get_local(index as usize); - context.value_stack_mut().push(value)?; + .pop(); Ok(InstructionOutcome::RunNextInstruction) } - fn run_set_local(&mut self, context: &mut FunctionContext, index: u32) -> Result { + fn run_select(&mut self, context: &mut FunctionContext) -> Result { + let (left, mid, right) = context + .value_stack_mut() + .pop_triple() + .expect("Due to validation there should be 3 values on stack"); + + let condition = right + .try_into() + .expect("Due to validation stack top should be I32"); + let val = if condition { left } else { mid }; + context.value_stack_mut().push(val)?; + Ok(InstructionOutcome::RunNextInstruction) + } + + fn run_get_local(&mut self, context: &mut FunctionContext, index: u32) -> Result { + let val = context.get_local(index as usize); + context.value_stack_mut().push(val)?; + Ok(InstructionOutcome::RunNextInstruction) + } + + fn run_set_local(&mut self, context: &mut FunctionContext, index: u32) -> Result { let arg = context .value_stack_mut() .pop() @@ -494,7 +506,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_tee_local(&mut self, context: &mut FunctionContext, index: u32) -> Result { + fn run_tee_local(&mut self, context: &mut FunctionContext, index: u32) -> Result { let arg = context .value_stack() .top() @@ -508,7 +520,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { &mut self, context: &mut FunctionContext, index: u32, - ) -> Result { + ) -> Result { let global = context .module() .global_by_index(index) @@ -522,7 +534,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { &mut self, context: &mut FunctionContext, index: u32, - ) -> Result { + ) -> Result { let val = context .value_stack_mut() .pop() @@ -535,7 +547,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_load(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_load(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result where RuntimeValue: From, T: LittleEndianConvert { let raw_address = context .value_stack_mut() @@ -545,20 +557,19 @@ impl<'a, E: Externals> Interpreter<'a, E> { effective_address( offset, raw_address, - ) - .map_err(Error::Trap)?; + )?; let m = context.module() .memory_by_index(DEFAULT_MEMORY_INDEX) .expect("Due to validation memory should exists"); let b = m.get(address, mem::size_of::()) - .map_err(|_| Error::Trap(Trap::MemoryAccessOutOfBounds))?; + .map_err(|_| Trap::MemoryAccessOutOfBounds)?; let n = T::from_little_endian(&b) .expect("Can't fail since buffer length should be size_of::"); context.value_stack_mut().push(n.into())?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_load_extend(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_load_extend(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result where T: ExtendInto, RuntimeValue: From, T: LittleEndianConvert { let raw_address = context .value_stack_mut() @@ -568,13 +579,12 @@ impl<'a, E: Externals> Interpreter<'a, E> { effective_address( offset, raw_address, - ) - .map_err(Error::Trap)?; + )?; let m = context.module() .memory_by_index(DEFAULT_MEMORY_INDEX) .expect("Due to validation memory should exists"); let b = m.get(address, mem::size_of::()) - .map_err(|_| Error::Trap(Trap::MemoryAccessOutOfBounds))?; + .map_err(|_| Trap::MemoryAccessOutOfBounds)?; let v = T::from_little_endian(&b) .expect("Can't fail since buffer length should be size_of::"); let stack_value: U = v.extend_into(); @@ -585,25 +595,28 @@ impl<'a, E: Externals> Interpreter<'a, E> { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_store(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result + fn run_store(&mut self, context: &mut FunctionContext, _align: u32, offset: u32) -> Result where RuntimeValue: TryInto, T: LittleEndianConvert { let stack_value = context .value_stack_mut() .pop_as::() .expect("Due to vaidation stack should contain value") .into_little_endian(); + let raw_address = context + .value_stack_mut() + .pop_as::() + .expect("Due to validation stack should contain value"); let address = effective_address( offset, - context.value_stack_mut().pop_as::()? - ) - .map_err(Error::Trap)?; + raw_address, + )?; let m = context.module() .memory_by_index(DEFAULT_MEMORY_INDEX) .expect("Due to validation memory should exists"); m.set(address, &stack_value) - .map_err(|_| Error::Trap(Trap::MemoryAccessOutOfBounds))?; + .map_err(|_| Trap::MemoryAccessOutOfBounds)?; Ok(InstructionOutcome::RunNextInstruction) } @@ -612,7 +625,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { context: &mut FunctionContext, _align: u32, offset: u32, - ) -> Result + ) -> Result where RuntimeValue: TryInto, T: WrapInto, @@ -633,17 +646,16 @@ impl<'a, E: Externals> Interpreter<'a, E> { effective_address( offset, raw_address, - ) - .map_err(Error::Trap)?; + )?; let m = context.module() .memory_by_index(DEFAULT_MEMORY_INDEX) .expect("Due to validation memory should exists"); m.set(address, &stack_value) - .map_err(|_| Error::Trap(Trap::MemoryAccessOutOfBounds))?; + .map_err(|_| Trap::MemoryAccessOutOfBounds)?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_current_memory(&mut self, context: &mut FunctionContext) -> Result { + fn run_current_memory(&mut self, context: &mut FunctionContext) -> Result { let m = context.module() .memory_by_index(DEFAULT_MEMORY_INDEX) .expect("Due to validation memory should exists"); @@ -654,8 +666,11 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_grow_memory(&mut self, context: &mut FunctionContext) -> Result { - let pages: u32 = context.value_stack_mut().pop_as()?; + fn run_grow_memory(&mut self, context: &mut FunctionContext) -> Result { + let pages: u32 = context + .value_stack_mut() + .pop_as() + .expect("Due to validation stack should contain value"); let m = context.module() .memory_by_index(DEFAULT_MEMORY_INDEX) .expect("Due to validation memory should exists"); @@ -668,7 +683,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_const(&mut self, context: &mut FunctionContext, val: RuntimeValue) -> Result { + fn run_const(&mut self, context: &mut FunctionContext, val: RuntimeValue) -> Result { context .value_stack_mut() .push(val) @@ -676,7 +691,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_relop(&mut self, context: &mut FunctionContext, f: F) -> Result + fn run_relop(&mut self, context: &mut FunctionContext, f: F) -> Result where RuntimeValue: TryInto, F: FnOnce(T, T) -> bool, @@ -690,53 +705,53 @@ impl<'a, E: Externals> Interpreter<'a, E> { } else { RuntimeValue::I32(0) }; - context.value_stack_mut().push(v).map_err(|e| Error::Stack(e.to_string()))?; + context.value_stack_mut().push(v)?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_eqz(&mut self, context: &mut FunctionContext) -> Result + fn run_eqz(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialEq + Default { let v = context .value_stack_mut() .pop_as::() .expect("Due to vaidation stack should contain value"); let v = RuntimeValue::I32(if v == Default::default() { 1 } else { 0 }); - context.value_stack_mut().push(v).map_err(|e| Error::Stack(e.to_string()))?; + context.value_stack_mut().push(v)?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_eq(&mut self, context: &mut FunctionContext) -> Result + fn run_eq(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialEq { self.run_relop(context, |left, right| left == right) } - fn run_ne(&mut self, context: &mut FunctionContext) -> Result + fn run_ne(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialEq { self.run_relop(context, |left, right| left != right) } - fn run_lt(&mut self, context: &mut FunctionContext) -> Result + fn run_lt(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialOrd + Display { self.run_relop(context, |left, right| left < right) } - fn run_gt(&mut self, context: &mut FunctionContext) -> Result + fn run_gt(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialOrd { self.run_relop(context, |left, right| left > right) } - fn run_lte(&mut self, context: &mut FunctionContext) -> Result + fn run_lte(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialOrd { self.run_relop(context, |left, right| left <= right) } - fn run_gte(&mut self, context: &mut FunctionContext) -> Result + fn run_gte(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: TryInto, T: PartialOrd { self.run_relop(context, |left, right| left >= right) } - fn run_unop(&mut self, context: &mut FunctionContext, f: F) -> Result + fn run_unop(&mut self, context: &mut FunctionContext, f: F) -> Result where F: FnOnce(T) -> U, RuntimeValue: From + TryInto @@ -750,22 +765,22 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_clz(&mut self, context: &mut FunctionContext) -> Result + fn run_clz(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Integer { self.run_unop(context, |v| v.leading_zeros()) } - fn run_ctz(&mut self, context: &mut FunctionContext) -> Result + fn run_ctz(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Integer { self.run_unop(context, |v| v.trailing_zeros()) } - fn run_popcnt(&mut self, context: &mut FunctionContext) -> Result + fn run_popcnt(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Integer { self.run_unop(context, |v| v.count_ones()) } - fn run_add(&mut self, context: &mut FunctionContext) -> Result + fn run_add(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: ArithmeticOps { let (left, right) = context .value_stack_mut() @@ -776,7 +791,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_sub(&mut self, context: &mut FunctionContext) -> Result + fn run_sub(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: ArithmeticOps { let (left, right) = context .value_stack_mut() @@ -787,7 +802,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_mul(&mut self, context: &mut FunctionContext) -> Result + fn run_mul(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: ArithmeticOps { let (left, right) = context .value_stack_mut() @@ -798,33 +813,33 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_div(&mut self, context: &mut FunctionContext) -> Result + fn run_div(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: TransmuteInto + Display, U: ArithmeticOps + TransmuteInto { let (left, right) = context .value_stack_mut() .pop_pair_as::() .expect("Due to validation stack should contain pair of values"); let (left, right) = (left.transmute_into(), right.transmute_into()); - let v = left.div(right).map_err(Error::Trap)?; + let v = left.div(right)?; let v = v.transmute_into(); context.value_stack_mut().push(v.into())?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_rem(&mut self, context: &mut FunctionContext) -> Result + fn run_rem(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: TransmuteInto, U: Integer + TransmuteInto { let (left, right) = context .value_stack_mut() .pop_pair_as::() .expect("Due to validation stack should contain pair of values"); let (left, right) = (left.transmute_into(), right.transmute_into()); - let v = left.rem(right).map_err(Error::Trap)?; + let v = left.rem(right)?; let v = v.transmute_into(); context.value_stack_mut().push(v.into())?; Ok(InstructionOutcome::RunNextInstruction) } - fn run_and(&mut self, context: &mut FunctionContext) -> Result + fn run_and(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From<::Output> + TryInto, T: ops::BitAnd { let (left, right) = context .value_stack_mut() @@ -835,7 +850,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_or(&mut self, context: &mut FunctionContext) -> Result + fn run_or(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From<::Output> + TryInto, T: ops::BitOr { let (left, right) = context .value_stack_mut() @@ -846,7 +861,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_xor(&mut self, context: &mut FunctionContext) -> Result + fn run_xor(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From<::Output> + TryInto, T: ops::BitXor { let (left, right) = context .value_stack_mut() @@ -857,7 +872,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_shl(&mut self, context: &mut FunctionContext, mask: T) -> Result + fn run_shl(&mut self, context: &mut FunctionContext, mask: T) -> Result where RuntimeValue: From<>::Output> + TryInto, T: ops::Shl + ops::BitAnd { let (left, right) = context .value_stack_mut() @@ -868,7 +883,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_shr(&mut self, context: &mut FunctionContext, mask: U) -> Result + fn run_shr(&mut self, context: &mut FunctionContext, mask: U) -> Result where RuntimeValue: From + TryInto, T: TransmuteInto, U: ops::Shr + ops::BitAnd, >::Output: TransmuteInto { let (left, right) = context .value_stack_mut() @@ -881,7 +896,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_rotl(&mut self, context: &mut FunctionContext) -> Result + fn run_rotl(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Integer { let (left, right) = context .value_stack_mut() @@ -892,7 +907,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_rotr(&mut self, context: &mut FunctionContext) -> Result + fn run_rotr(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Integer { let (left, right) = context @@ -904,13 +919,13 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_abs(&mut self, context: &mut FunctionContext) -> Result + fn run_abs(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { self.run_unop(context, |v| v.abs()) } - fn run_neg(&mut self, context: &mut FunctionContext) -> Result + fn run_neg(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From<::Output> + TryInto, T: ops::Neg @@ -918,37 +933,37 @@ impl<'a, E: Externals> Interpreter<'a, E> { self.run_unop(context, |v| v.neg()) } - fn run_ceil(&mut self, context: &mut FunctionContext) -> Result + fn run_ceil(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { self.run_unop(context, |v| v.ceil()) } - fn run_floor(&mut self, context: &mut FunctionContext) -> Result + fn run_floor(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { self.run_unop(context, |v| v.floor()) } - fn run_trunc(&mut self, context: &mut FunctionContext) -> Result + fn run_trunc(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { self.run_unop(context, |v| v.trunc()) } - fn run_nearest(&mut self, context: &mut FunctionContext) -> Result + fn run_nearest(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { self.run_unop(context, |v| v.nearest()) } - fn run_sqrt(&mut self, context: &mut FunctionContext) -> Result + fn run_sqrt(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { self.run_unop(context, |v| v.sqrt()) } - fn run_min(&mut self, context: &mut FunctionContext) -> Result + fn run_min(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { let (left, right) = context @@ -960,7 +975,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_max(&mut self, context: &mut FunctionContext) -> Result + fn run_max(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { let (left, right) = context .value_stack_mut() @@ -971,7 +986,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_copysign(&mut self, context: &mut FunctionContext) -> Result + fn run_copysign(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: Float { let (left, right) = context .value_stack_mut() @@ -982,25 +997,25 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_wrap(&mut self, context: &mut FunctionContext) -> Result + fn run_wrap(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: WrapInto { self.run_unop(context, |v| v.wrap_into()) } - fn run_trunc_to_int(&mut self, context: &mut FunctionContext) -> Result + fn run_trunc_to_int(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: TryTruncateInto, U: TransmuteInto, { let v = context .value_stack_mut() .pop_as::() .expect("Due to vaidation stack should contain value"); - v.try_truncate_into().map_err(Error::Trap) + v.try_truncate_into() .map(|v| v.transmute_into()) .map(|v| context.value_stack_mut().push(v.into())) .map(|_| InstructionOutcome::RunNextInstruction) } - fn run_extend(&mut self, context: &mut FunctionContext) -> Result + fn run_extend(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From + TryInto, T: ExtendInto, U: TransmuteInto { @@ -1015,7 +1030,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { Ok(InstructionOutcome::RunNextInstruction) } - fn run_reinterpret(&mut self, context: &mut FunctionContext) -> Result + fn run_reinterpret(&mut self, context: &mut FunctionContext) -> Result where RuntimeValue: From, RuntimeValue: TryInto, T: TransmuteInto { @@ -1068,7 +1083,7 @@ impl FunctionContext { } } - pub fn nested(&mut self, function: FuncRef) -> Result { + pub fn nested(&mut self, function: FuncRef) -> Result { let (function_locals, module, function_return_type) = { let module = match *function.as_internal() { FuncInstanceInternal::Internal { ref module, .. } => module.upgrade().expect("module deallocated"), @@ -1076,7 +1091,7 @@ impl FunctionContext { }; let function_type = function.signature(); let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt.into_elements())).unwrap_or(BlockType::NoResult); - let function_locals = prepare_function_args(function_type, &mut self.value_stack)?; + let function_locals = prepare_function_args(function_type, &mut self.value_stack); (function_locals, module, function_return_type) }; @@ -1134,7 +1149,7 @@ impl FunctionContext { &self.frame_stack } - pub fn push_frame(&mut self, labels: &HashMap, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { + pub fn push_frame(&mut self, labels: &HashMap, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Trap> { let begin_position = self.position; let branch_position = match frame_type { BlockFrameType::Function => usize::MAX, @@ -1152,28 +1167,32 @@ impl FunctionContext { BlockFrameType::Function => usize::MAX, _ => labels[&begin_position] + 1, }; - Ok(self.frame_stack.push(BlockFrame { + + self.frame_stack.push(BlockFrame { frame_type: frame_type, block_type: block_type, begin_position: begin_position, branch_position: branch_position, end_position: end_position, value_stack_len: self.value_stack.len(), - })?) + }).map_err(|_| Trap::StackOverflow)?; + + Ok(()) } - pub fn discard_frame(&mut self) -> Result<(), Error> { - Ok(self.frame_stack.pop().map(|_| ())?) + pub fn discard_frame(&mut self) { + let _ = self.frame_stack.pop().expect("Due to validation frame stack shouldn't be empty"); } - pub fn pop_frame(&mut self, is_branch: bool) -> Result<(), Error> { - let frame = self.frame_stack.pop()?; - if frame.value_stack_len > self.value_stack.len() { - return Err(Error::Stack("invalid stack len".into())); - } + pub fn pop_frame(&mut self, is_branch: bool) -> Result<(), Trap> { + let frame = self.frame_stack + .pop() + .expect("Due to validation frame stack shouldn't be empty"); + assert!(frame.value_stack_len <= self.value_stack.len(), "invalid stack len"); let frame_value = match frame.block_type { - BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch => Some(self.value_stack.pop()?), + BlockType::Value(_) if frame.frame_type != BlockFrameType::Loop || !is_branch => + Some(self.value_stack.pop().expect("Due to validation, stack shouldn't be empty")), _ => None, }; self.value_stack.resize(frame.value_stack_len); @@ -1199,13 +1218,13 @@ fn effective_address(address: u32, offset: u32) -> Result { } } -fn prepare_function_args(signature: &Signature, caller_stack: &mut ValueStack) -> Result, Error> { +fn prepare_function_args(signature: &Signature, caller_stack: &mut ValueStack) -> Vec { let mut args = signature.params().iter().cloned().rev().map(|_| { - caller_stack.pop() - }).collect::, _>>()?; + caller_stack.pop().expect("Due to validation stack shouldn't be empty") + }).collect::>(); args.reverse(); - check_function_args(signature, &args)?; - Ok(args) + check_function_args(signature, &args).expect("Due to validation arguments should match"); + args } pub fn check_function_args(signature: &Signature, args: &[RuntimeValue]) -> Result<(), Error> { @@ -1271,8 +1290,9 @@ impl ValueStack { self.stack_with_limit.pop().map_err(|e| Error::Stack(e.to_string())) } - fn push(&mut self, value: RuntimeValue) -> Result<(), Error> { - self.stack_with_limit.push(value).map_err(|e| Error::Stack(e.to_string())) + fn push(&mut self, value: RuntimeValue) -> Result<(), Trap> { + self.stack_with_limit.push(value) + .map_err(|_| Trap::StackOverflow) } fn resize(&mut self, new_len: usize) { diff --git a/src/tests/host.rs b/src/tests/host.rs index 27f7a72..eaeb987 100644 --- a/src/tests/host.rs +++ b/src/tests/host.rs @@ -1,7 +1,7 @@ use { Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef, - RuntimeValue, RuntimeArgs, Module, TableDescriptor, MemoryDescriptor, + RuntimeValue, RuntimeArgs, Module, TableDescriptor, MemoryDescriptor, Trap, }; use types::ValueType; use wabt::wat2wasm; @@ -79,7 +79,7 @@ impl Externals for TestHost { &mut self, index: usize, args: RuntimeArgs, - ) -> Result, Error> { + ) -> Result, Trap> { match index { SUB_FUNC_INDEX => { let a: i32 = args.nth(0)?; @@ -464,7 +464,7 @@ fn defer_providing_externals() { &mut self, index: usize, args: RuntimeArgs, - ) -> Result, Error> { + ) -> Result, Trap> { match index { INC_FUNC_INDEX => { let a = args.nth::(0)?; @@ -528,7 +528,7 @@ fn two_envs_one_externals() { &mut self, index: usize, _args: RuntimeArgs, - ) -> Result, Error> { + ) -> Result, Trap> { match index { PRIVILEGED_FUNC_INDEX => { println!("privileged!"); @@ -648,7 +648,7 @@ fn dynamically_add_host_func() { &mut self, index: usize, _args: RuntimeArgs, - ) -> Result, Error> { + ) -> Result, Trap> { match index { ADD_FUNC_FUNC_INDEX => { // Allocate indicies for the new function.