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)));
}
// use data section to initialize linear memory regions
if let Some(data_section) = self.module.data_section() {
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::{FunctionType, Type};
use common::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX};
use validation::module::ModuleContext;
use validation::context::ModuleContext;
use validation::Error;

View File

@ -1,18 +1,20 @@
#![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 func;
#[cfg(test)]
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);
impl fmt::Display for Error {
@ -34,10 +36,7 @@ pub fn validate_module(module: &Module) -> Result<(), Error> {
.function_section()
.map(|s| s.entries().len())
.unwrap_or(0);
let code_section_len = module
.code_section()
.map(|s| s.bodies().len())
.unwrap_or(0);
let code_section_len = module.code_section().map(|s| s.bodies().len()).unwrap_or(0);
if function_section_len != code_section_len {
return Err(Error(format!(
"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
if function_section_len != 0 { // tests use invalid code
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");
if function_section_len != 0 {
// tests use invalid code
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
for (index, function) in function_section.entries().iter().enumerate() {
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| {
let Error(ref msg) = e;
Error(format!("Function #{} validation error: {}", index, msg))
})?;
// TODO: pepyakin
// context.function_labels()
};
// TODO: pepyakin
// self.functions_labels.insert(index as u32, function_labels);
}
}
@ -113,44 +124,7 @@ fn prepare_context(module: &Module) -> Result<ModuleContext, Error> {
}
if let Some(global_section) = module.global_section() {
for global_entry in global_section.entries() {
let init = global_entry.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.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")));
}
global_entry.validate(&globals)?;
globals.push(global_entry.global_type().clone());
}
}
@ -190,3 +164,45 @@ impl TableType {
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))
}
}