diff --git a/src/validation/func.rs b/src/validation/func.rs index 85c5b1d..63fc01e 100644 --- a/src/validation/func.rs +++ b/src/validation/func.rs @@ -21,7 +21,7 @@ const DEFAULT_VALUE_STACK_LIMIT: usize = 16384; const DEFAULT_FRAME_STACK_LIMIT: usize = 1024; /// Function validation context. -pub struct FunctionValidationContext<'a> { +struct FunctionValidationContext<'a> { /// Wasm module module: &'a ModuleContext, /// Current instruction position. @@ -40,7 +40,7 @@ pub struct FunctionValidationContext<'a> { /// Value type on the stack. #[derive(Debug, Clone, Copy)] -pub enum StackValueType { +enum StackValueType { /// Any value type. Any, /// Any number of any values of any type. @@ -54,7 +54,7 @@ pub struct Validator; /// Instruction outcome. #[derive(Debug, Clone)] -pub enum InstructionOutcome { +enum InstructionOutcome { /// Continue with next instruction. ValidateNextInstruction, /// Unreachable instruction reached. @@ -590,7 +590,7 @@ impl Validator { } impl<'a> FunctionValidationContext<'a> { - pub fn new( + fn new( module: &'a ModuleContext, locals: &'a [ValueType], value_stack_limit: usize, @@ -608,11 +608,11 @@ impl<'a> FunctionValidationContext<'a> { } } - pub fn push_value(&mut self, value_type: StackValueType) -> Result<(), Error> { + fn push_value(&mut self, value_type: StackValueType) -> Result<(), Error> { Ok(self.value_stack.push(value_type.into())?) } - pub fn pop_value(&mut self, value_type: StackValueType) -> Result<(), Error> { + fn pop_value(&mut self, value_type: StackValueType) -> Result<(), Error> { self.check_stack_access()?; match self.value_stack.pop()? { StackValueType::Specific(stack_value_type) if stack_value_type == value_type => Ok(()), @@ -625,7 +625,7 @@ impl<'a> FunctionValidationContext<'a> { } } - pub fn tee_value(&mut self, value_type: StackValueType) -> Result<(), Error> { + fn tee_value(&mut self, value_type: StackValueType) -> Result<(), Error> { self.check_stack_access()?; match *self.value_stack.top()? { StackValueType::Specific(stack_value_type) if stack_value_type == value_type => Ok(()), @@ -634,7 +634,7 @@ impl<'a> FunctionValidationContext<'a> { } } - pub fn pop_any_value(&mut self) -> Result { + fn pop_any_value(&mut self) -> Result { self.check_stack_access()?; match self.value_stack.pop()? { StackValueType::Specific(stack_value_type) => Ok(StackValueType::Specific(stack_value_type)), @@ -646,20 +646,20 @@ impl<'a> FunctionValidationContext<'a> { } } - pub fn tee_any_value(&mut self) -> Result { + fn tee_any_value(&mut self) -> Result { self.check_stack_access()?; Ok(self.value_stack.top().map(Clone::clone)?) } - pub fn unreachable(&mut self) -> Result<(), Error> { + fn unreachable(&mut self) -> Result<(), Error> { Ok(self.value_stack.push(StackValueType::AnyUnlimited)?) } - pub fn top_label(&self) -> Result<&BlockFrame, Error> { + fn top_label(&self) -> Result<&BlockFrame, Error> { Ok(self.frame_stack.top()?) } - pub fn push_label(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { + fn push_label(&mut self, frame_type: BlockFrameType, block_type: BlockType) -> Result<(), Error> { Ok(self.frame_stack.push(BlockFrame { frame_type: frame_type, block_type: block_type, @@ -670,7 +670,7 @@ impl<'a> FunctionValidationContext<'a> { })?) } - pub fn pop_label(&mut self) -> Result { + fn pop_label(&mut self) -> Result { let frame = self.frame_stack.pop()?; let actual_value_type = if self.value_stack.len() > frame.value_stack_len { Some(self.value_stack.pop()?) @@ -694,22 +694,22 @@ impl<'a> FunctionValidationContext<'a> { Ok(InstructionOutcome::ValidateNextInstruction) } - pub fn require_label(&self, idx: u32) -> Result<&BlockFrame, Error> { + fn require_label(&self, idx: u32) -> Result<&BlockFrame, Error> { Ok(self.frame_stack.get(idx as usize)?) } - pub fn return_type(&self) -> Result { + fn return_type(&self) -> Result { self.return_type.ok_or(Error("Trying to return from expression".into())) } - pub fn require_local(&self, idx: u32) -> Result { + fn require_local(&self, idx: u32) -> Result { self.locals.get(idx as usize) .cloned() .map(Into::into) .ok_or(Error(format!("Trying to access local with index {} when there are only {} locals", idx, self.locals.len()))) } - pub fn function_labels(self) -> HashMap { + fn function_labels(self) -> HashMap { self.labels } @@ -724,21 +724,21 @@ impl<'a> FunctionValidationContext<'a> { } impl StackValueType { - pub fn is_any(&self) -> bool { + fn is_any(&self) -> bool { match self { &StackValueType::Any => true, _ => false, } } - pub fn is_any_unlimited(&self) -> bool { + fn is_any_unlimited(&self) -> bool { match self { &StackValueType::AnyUnlimited => true, _ => false, } } - pub fn value_type(&self) -> ValueType { + fn value_type(&self) -> ValueType { match self { &StackValueType::Any | &StackValueType::AnyUnlimited => unreachable!("must be checked by caller"), &StackValueType::Specific(value_type) => value_type, diff --git a/src/validation/mod.rs b/src/validation/mod.rs index f5eb686..c490417 100644 --- a/src/validation/mod.rs +++ b/src/validation/mod.rs @@ -6,7 +6,7 @@ use elements::{BlockType, External, FunctionType, GlobalEntry, GlobalType, Inter Module, Opcode, ResizableLimits, TableType, Type, ValueType}; use common::stack; use self::context::ModuleContext; -use self::func::{FunctionValidationContext, Validator}; +use self::func::Validator; pub use self::module::ValidatedModule; diff --git a/src/validation/tests.rs b/src/validation/tests.rs index cd4f0b7..5df2778 100644 --- a/src/validation/tests.rs +++ b/src/validation/tests.rs @@ -175,27 +175,61 @@ fn global_init_misc() { // empty init expr let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Opcode::End]) - ) + .with_global( + GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Opcode::End]) ) + ) .build(); assert!(validate_module(&m).is_err()); // not an constant opcode used let m = module() - .with_global( - GlobalEntry::new( - GlobalType::new(ValueType::I32, true), - InitExpr::new(vec![Opcode::Unreachable, Opcode::End]) - ) + .with_global( + GlobalEntry::new( + GlobalType::new(ValueType::I32, true), + InitExpr::new(vec![Opcode::Unreachable, Opcode::End]) ) + ) .build(); assert!(validate_module(&m).is_err()); } +#[test] +fn module_limits_validity() { + // module cannot contain more than 1 memory atm. + let m = module() + .with_import( + ImportEntry::new( + "core".into(), + "memory".into(), + External::Memory(MemoryType::new(10, None)) + ) + ) + .memory() + .with_min(10) + .build() + .build(); + assert!(validate_module(&m).is_err()); + + // module cannot contain more than 1 table atm. + let m = module() + .with_import( + ImportEntry::new( + "core".into(), + "table".into(), + External::Table(TableType::new(10, None)) + ) + ) + .table() + .with_min(10) + .build() + .build(); + assert!(validate_module(&m).is_err()); +} + +// TODO: pepyakin // #[test] // fn if_else_with_return_type_validation() { // let module_instance = ModuleInstance::new(Weak::default(), "test".into(), module().build()).unwrap();