This commit is contained in:
Sergey Pepyakin
2017-12-01 19:42:34 +03:00
parent 907b914fba
commit 0feed2fa21
5 changed files with 161 additions and 147 deletions

View File

@ -366,8 +366,6 @@ impl ModuleInstance {
return Err(Error::Validation(format!("length of function section is {}, while len of code section is {}", function_section_len, code_section_len))); return Err(Error::Validation(format!("length of function section is {}, while len of code section is {}", function_section_len, code_section_len)));
} }
// use data section to initialize linear memory regions // use data section to initialize linear memory regions
if let Some(data_section) = self.module.data_section() { if let Some(data_section) = self.module.data_section() {
for (data_segment_index, data_segment) in data_section.entries().iter().enumerate() { for (data_segment_index, data_segment) in data_section.entries().iter().enumerate() {

89
src/validation/context.rs Normal file
View File

@ -0,0 +1,89 @@
use elements::{MemoryType, TableType, GlobalType, Type};
use elements::{Opcode, BlockType, ValueType, TableElementType};
use validation::Error;
pub struct ModuleContext {
pub memories: Vec<MemoryType>,
pub tables: Vec<TableType>,
pub globals: Vec<GlobalType>,
pub types: Vec<Type>,
pub func_type_indexes: Vec<u32>,
}
impl ModuleContext {
pub fn memories(&self) -> &[MemoryType] {
&self.memories
}
pub fn tables(&self) -> &[TableType] {
&self.tables
}
pub fn globals(&self) -> &[GlobalType] {
&self.globals
}
pub fn types(&self) -> &[Type] {
&self.types
}
pub fn func_type_indexes(&self) -> &[u32] {
&self.func_type_indexes
}
pub fn require_memory(&self, idx: u32) -> Result<(), Error> {
if self.memories().get(idx as usize).is_none() {
return Err(Error(format!("Memory at index {} doesn't exists", idx)));
}
Ok(())
}
pub fn require_table(&self, idx: u32, expected_type: TableElementType) -> Result<(), Error> {
let table = match self.tables().get(idx as usize) {
Some(table) => table,
None => {
return Err(Error(format!("Table at index {} doesn't exists", idx)));
}
};
if table.elem_type() != expected_type {
return Err(Error(format!(
"Table {} has element type {:?} while {:?} expected",
idx,
table.elem_type(),
expected_type
)));
}
Ok(())
}
pub fn require_function(&self, idx: u32) -> Result<(Vec<ValueType>, BlockType), Error> {
let ty_idx = match self.func_type_indexes().get(idx as usize) {
Some(ty_idx) => *ty_idx,
None => {
return Err(Error(
format!("Function at index {} doesn't exists", idx),
));
}
};
self.require_function_type(ty_idx)
}
pub fn require_function_type(&self, idx: u32) -> Result<(Vec<ValueType>, BlockType), Error> {
let ty = match self.types().get(idx as usize) {
Some(&Type::Function(ref func_ty)) => func_ty,
None => {
return Err(Error(
format!("Type at index {} doesn't exists", idx),
));
}
};
let params = ty.params().to_vec();
let return_ty = ty.return_type()
.map(BlockType::Value)
.unwrap_or(BlockType::NoResult);
Ok((params, return_ty))
}
}

View File

@ -5,7 +5,7 @@ use std::collections::HashMap;
use elements::{Opcode, BlockType, ValueType, TableElementType, Func, FuncBody}; use elements::{Opcode, BlockType, ValueType, TableElementType, Func, FuncBody};
use elements::{FunctionType, Type}; use elements::{FunctionType, Type};
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}; use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
use validation::module::ModuleContext; use validation::context::ModuleContext;
use validation::Error; use validation::Error;

View File

@ -1,18 +1,20 @@
#![allow(unused, missing_docs)] #![allow(unused, missing_docs)]
use std::fmt;
use std::iter::repeat;
use elements::{BlockType, External, FunctionType, GlobalEntry, GlobalType, MemoryType, Module,
Opcode, ResizableLimits, TableType, Type, ValueType};
use common::stack;
use self::context::ModuleContext;
use self::func::{FunctionValidationContext, Validator};
mod context;
mod module; mod module;
mod func; mod func;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use std::fmt;
use std::iter::repeat;
use elements::{Module, ResizableLimits, MemoryType, TableType, GlobalType, FunctionType, External, Opcode, ValueType, BlockType, Type};
use common::stack;
use self::module::ModuleContext;
use self::func::{Validator, FunctionValidationContext};
pub struct Error(String); pub struct Error(String);
impl fmt::Display for Error { impl fmt::Display for Error {
@ -34,10 +36,7 @@ pub fn validate_module(module: &Module) -> Result<(), Error> {
.function_section() .function_section()
.map(|s| s.entries().len()) .map(|s| s.entries().len())
.unwrap_or(0); .unwrap_or(0);
let code_section_len = module let code_section_len = module.code_section().map(|s| s.bodies().len()).unwrap_or(0);
.code_section()
.map(|s| s.bodies().len())
.unwrap_or(0);
if function_section_len != code_section_len { if function_section_len != code_section_len {
return Err(Error(format!( return Err(Error(format!(
"length of function section is {}, while len of code section is {}", "length of function section is {}, while len of code section is {}",
@ -47,19 +46,31 @@ pub fn validate_module(module: &Module) -> Result<(), Error> {
} }
// validate every function body in user modules // validate every function body in user modules
if function_section_len != 0 { // tests use invalid code if function_section_len != 0 {
let function_section = module.function_section().expect("function_section_len != 0; qed"); // tests use invalid code
let code_section = module.code_section().expect("function_section_len != 0; function_section_len == code_section_len; qed"); let function_section = module
.function_section()
.expect("function_section_len != 0; qed");
let code_section = module
.code_section()
.expect("function_section_len != 0; function_section_len == code_section_len; qed");
// check every function body // check every function body
for (index, function) in function_section.entries().iter().enumerate() { for (index, function) in function_section.entries().iter().enumerate() {
let function_labels = { let function_labels = {
let function_body = code_section.bodies().get(index as usize).ok_or(Error(format!("Missing body for function {}", index)))?; let function_body = code_section
.bodies()
.get(index as usize)
.ok_or(Error(format!("Missing body for function {}", index)))?;
Validator::validate_function(&context, function, function_body).map_err(|e| { Validator::validate_function(&context, function, function_body).map_err(|e| {
let Error(ref msg) = e; let Error(ref msg) = e;
Error(format!("Function #{} validation error: {}", index, msg)) Error(format!("Function #{} validation error: {}", index, msg))
})?; })?;
// TODO: pepyakin
// context.function_labels() // context.function_labels()
}; };
// TODO: pepyakin
// self.functions_labels.insert(index as u32, function_labels); // self.functions_labels.insert(index as u32, function_labels);
} }
} }
@ -68,8 +79,8 @@ pub fn validate_module(module: &Module) -> Result<(), Error> {
fn prepare_context(module: &Module) -> Result<ModuleContext, Error> { fn prepare_context(module: &Module) -> Result<ModuleContext, Error> {
// TODO: Validate start // TODO: Validate start
// TODO: Validate imports // TODO: Validate imports
// TODO: Validate exports // TODO: Validate exports
// Copy types from module as is. // Copy types from module as is.
let types = module let types = module
@ -113,44 +124,7 @@ fn prepare_context(module: &Module) -> Result<ModuleContext, Error> {
} }
if let Some(global_section) = module.global_section() { if let Some(global_section) = module.global_section() {
for global_entry in global_section.entries() { for global_entry in global_section.entries() {
let init = global_entry.init_expr().code(); global_entry.validate(&globals)?;
if init.len() != 2 {
return Err(Error(format!("Init expression should always be with length 2")));
}
let init_expr_ty: ValueType = match init[0] {
Opcode::I32Const(_) => ValueType::I32,
Opcode::I64Const(_) => ValueType::I64,
Opcode::F32Const(_) => ValueType::F32,
Opcode::F64Const(_) => ValueType::F64,
Opcode::GetGlobal(idx) => {
match globals.get(idx as usize) {
Some(target_global) => {
if target_global.is_mutable() {
return Err(Error(
format!("Global {} is mutable", idx)
));
}
target_global.content_type()
},
None => return Err(Error(
format!("Global {} doesn't exists", idx)
)),
}
},
_ => return Err(Error(format!("Non constant opcode in init expr"))),
};
if init_expr_ty != global_entry.global_type().content_type() {
return Err(Error(
format!(
"Trying to initialize variable of type {:?} with value of type {:?}",
global_entry.global_type().content_type(),
init_expr_ty
)
));
}
if init[1] != Opcode::End {
return Err(Error(format!("Expression doesn't ends with `end` opcode")));
}
globals.push(global_entry.global_type().clone()); globals.push(global_entry.global_type().clone());
} }
} }
@ -190,3 +164,45 @@ impl TableType {
self.limits().validate() self.limits().validate()
} }
} }
impl GlobalEntry {
fn validate(&self, globals_sofar: &[GlobalType]) -> Result<(), Error> {
let init = self.init_expr().code();
if init.len() != 2 {
return Err(Error(
format!("Init expression should always be with length 2"),
));
}
let init_expr_ty: ValueType = match init[0] {
Opcode::I32Const(_) => ValueType::I32,
Opcode::I64Const(_) => ValueType::I64,
Opcode::F32Const(_) => ValueType::F32,
Opcode::F64Const(_) => ValueType::F64,
Opcode::GetGlobal(idx) => match globals_sofar.get(idx as usize) {
Some(target_global) => {
if target_global.is_mutable() {
return Err(Error(format!("Global {} is mutable", idx)));
}
target_global.content_type()
}
None => {
return Err(Error(
format!("Global {} doesn't exists or not yet defined", idx),
))
}
},
_ => return Err(Error(format!("Non constant opcode in init expr"))),
};
if init_expr_ty != self.global_type().content_type() {
return Err(Error(format!(
"Trying to initialize variable of type {:?} with value of type {:?}",
self.global_type().content_type(),
init_expr_ty
)));
}
if init[1] != Opcode::End {
return Err(Error(format!("Expression doesn't ends with `end` opcode")));
}
Ok(())
}
}

View File

@ -1,89 +0,0 @@
use elements::{MemoryType, TableType, GlobalType, Type};
use elements::{Opcode, BlockType, ValueType, TableElementType};
use validation::Error;
pub struct ModuleContext {
pub memories: Vec<MemoryType>,
pub tables: Vec<TableType>,
pub globals: Vec<GlobalType>,
pub types: Vec<Type>,
pub func_type_indexes: Vec<u32>,
}
impl ModuleContext {
pub fn memories(&self) -> &[MemoryType] {
&self.memories
}
pub fn tables(&self) -> &[TableType] {
&self.tables
}
pub fn globals(&self) -> &[GlobalType] {
&self.globals
}
pub fn types(&self) -> &[Type] {
&self.types
}
pub fn func_type_indexes(&self) -> &[u32] {
&self.func_type_indexes
}
pub fn require_memory(&self, idx: u32) -> Result<(), Error> {
if self.memories().get(idx as usize).is_none() {
return Err(Error(format!("Memory at index {} doesn't exists", idx)));
}
Ok(())
}
pub fn require_table(&self, idx: u32, expected_type: TableElementType) -> Result<(), Error> {
let table = match self.tables().get(idx as usize) {
Some(table) => table,
None => {
return Err(Error(format!("Table at index {} doesn't exists", idx)));
}
};
if table.elem_type() != expected_type {
return Err(Error(format!(
"Table {} has element type {:?} while {:?} expected",
idx,
table.elem_type(),
expected_type
)));
}
Ok(())
}
pub fn require_function(&self, idx: u32) -> Result<(Vec<ValueType>, BlockType), Error> {
let ty_idx = match self.func_type_indexes().get(idx as usize) {
Some(ty_idx) => *ty_idx,
None => {
return Err(Error(
format!("Function at index {} doesn't exists", idx),
));
}
};
self.require_function_type(ty_idx)
}
pub fn require_function_type(&self, idx: u32) -> Result<(Vec<ValueType>, BlockType), Error> {
let ty = match self.types().get(idx as usize) {
Some(&Type::Function(ref func_ty)) => func_ty,
None => {
return Err(Error(
format!("Type at index {} doesn't exists", idx),
));
}
};
let params = ty.params().to_vec();
let return_ty = ty.return_type()
.map(BlockType::Value)
.unwrap_or(BlockType::NoResult);
Ok((params, return_ty))
}
}