Allow wasm embedders to reject wasm modules with unsupported features. (#345)
Define `WasmError` (and an accompanying `WasmResult`) to represent errors translating WebAssembly functions. Make `translate_call` and related functions return `WasmResult`s so that embedders have the flexibility to reject features they don't support. Move `InvalidInput` out of `CtonError` and into `WasmError`, where it's now named `InvalidWebAssembly`, as it's a WebAssembly-specific error condition. Also extend it to preserve the original error message and bytecode offset.
This commit is contained in:
@@ -105,7 +105,9 @@ fn handle_module(
|
||||
}
|
||||
|
||||
let mut dummy_environ = DummyEnvironment::with_flags(fisa.flags.clone());
|
||||
translate_module(&data, &mut dummy_environ)?;
|
||||
translate_module(&data, &mut dummy_environ).map_err(
|
||||
|e| e.to_string(),
|
||||
)?;
|
||||
|
||||
terminal.fg(term::color::GREEN).unwrap();
|
||||
vprintln!(flag_verbose, "ok");
|
||||
|
||||
@@ -7,13 +7,6 @@ use verifier;
|
||||
/// When Cretonne fails to compile a function, it will return one of these error codes.
|
||||
#[derive(Fail, Debug, PartialEq, Eq)]
|
||||
pub enum CtonError {
|
||||
/// The input is invalid.
|
||||
///
|
||||
/// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly
|
||||
/// code. This should never happen for validated WebAssembly code.
|
||||
#[fail(display = "Invalid input code")]
|
||||
InvalidInput,
|
||||
|
||||
/// An IR verifier error.
|
||||
///
|
||||
/// This always represents a bug, either in the code that generated IR for Cretonne, or a bug
|
||||
|
||||
@@ -13,6 +13,8 @@ wasmparser = { version = "0.16.1", default-features = false }
|
||||
cretonne-codegen = { path = "../codegen", version = "0.8.0", default-features = false }
|
||||
cretonne-frontend = { path = "../frontend", version = "0.8.0", default-features = false }
|
||||
hashmap_core = { version = "0.1.4", optional = true }
|
||||
failure = { version = "0.1.1", default-features = false, features = ["derive"] }
|
||||
failure_derive = { version = "0.1.1", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3.5"
|
||||
|
||||
@@ -27,7 +27,7 @@ use cretonne_codegen::ir::types::*;
|
||||
use cretonne_codegen::ir::{self, InstBuilder, JumpTableData, MemFlags};
|
||||
use cretonne_codegen::packed_option::ReservedValue;
|
||||
use cretonne_frontend::{FunctionBuilder, Variable};
|
||||
use environ::{FuncEnvironment, GlobalValue};
|
||||
use environ::{FuncEnvironment, GlobalValue, WasmResult};
|
||||
use state::{ControlStackFrame, TranslationState};
|
||||
use std::collections::{hash_map, HashMap};
|
||||
use std::vec::Vec;
|
||||
@@ -45,13 +45,13 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
builder: &mut FunctionBuilder<Variable>,
|
||||
state: &mut TranslationState,
|
||||
environ: &mut FE,
|
||||
) {
|
||||
) -> WasmResult<()> {
|
||||
if !state.reachable {
|
||||
return translate_unreachable_operator(&op, builder, state);
|
||||
return Ok(translate_unreachable_operator(&op, builder, state));
|
||||
}
|
||||
|
||||
// This big match treats all Wasm code operators.
|
||||
match op {
|
||||
Ok(match op {
|
||||
/********************************** Locals ****************************************
|
||||
* `get_local` and `set_local` are treated as non-SSA variables and will completely
|
||||
* disappear in the Cretonne Code
|
||||
@@ -362,7 +362,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
function_index as FunctionIndex,
|
||||
fref,
|
||||
state.peekn(num_args),
|
||||
);
|
||||
)?;
|
||||
state.popn(num_args);
|
||||
state.pushn(builder.inst_results(call));
|
||||
}
|
||||
@@ -378,7 +378,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
sigref,
|
||||
callee,
|
||||
state.peekn(num_args),
|
||||
);
|
||||
)?;
|
||||
state.popn(num_args);
|
||||
state.pushn(builder.inst_results(call));
|
||||
}
|
||||
@@ -397,7 +397,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
heap_index,
|
||||
heap,
|
||||
val,
|
||||
))
|
||||
)?)
|
||||
}
|
||||
Operator::CurrentMemory { reserved } => {
|
||||
let heap_index = reserved as MemoryIndex;
|
||||
@@ -406,7 +406,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
builder.cursor(),
|
||||
heap_index,
|
||||
heap,
|
||||
));
|
||||
)?);
|
||||
}
|
||||
/******************************* Load instructions ***********************************
|
||||
* Wasm specifies an integer alignment flag but we drop it in Cretonne.
|
||||
@@ -857,7 +857,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
Operator::I64AtomicRmw32UCmpxchg { .. } => {
|
||||
panic!("proposed thread operators not yet supported");
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Clippy warns us of some fields we are deliberately ignoring
|
||||
|
||||
@@ -4,7 +4,7 @@ use cretonne_codegen::cursor::FuncCursor;
|
||||
use cretonne_codegen::ir::types::*;
|
||||
use cretonne_codegen::ir::{self, InstBuilder};
|
||||
use cretonne_codegen::settings;
|
||||
use environ::{FuncEnvironment, GlobalValue, ModuleEnvironment};
|
||||
use environ::{FuncEnvironment, GlobalValue, ModuleEnvironment, WasmResult};
|
||||
use func_translator::FuncTranslator;
|
||||
use std::string::String;
|
||||
use std::vec::Vec;
|
||||
@@ -196,7 +196,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
||||
sig_ref: ir::SigRef,
|
||||
callee: ir::Value,
|
||||
call_args: &[ir::Value],
|
||||
) -> ir::Inst {
|
||||
) -> WasmResult<ir::Inst> {
|
||||
// Pass the current function's vmctx parameter on to the callee.
|
||||
let vmctx = pos.func
|
||||
.special_param(ir::ArgumentPurpose::VMContext)
|
||||
@@ -224,9 +224,11 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
||||
args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
|
||||
args.push(vmctx, &mut pos.func.dfg.value_lists);
|
||||
|
||||
pos.ins()
|
||||
.CallIndirect(ir::Opcode::CallIndirect, VOID, sig_ref, args)
|
||||
.0
|
||||
Ok(
|
||||
pos.ins()
|
||||
.CallIndirect(ir::Opcode::CallIndirect, VOID, sig_ref, args)
|
||||
.0,
|
||||
)
|
||||
}
|
||||
|
||||
fn translate_call(
|
||||
@@ -235,7 +237,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
||||
_callee_index: FunctionIndex,
|
||||
callee: ir::FuncRef,
|
||||
call_args: &[ir::Value],
|
||||
) -> ir::Inst {
|
||||
) -> WasmResult<ir::Inst> {
|
||||
// Pass the current function's vmctx parameter on to the callee.
|
||||
let vmctx = pos.func
|
||||
.special_param(ir::ArgumentPurpose::VMContext)
|
||||
@@ -247,7 +249,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
||||
args.extend(call_args.iter().cloned(), &mut pos.func.dfg.value_lists);
|
||||
args.push(vmctx, &mut pos.func.dfg.value_lists);
|
||||
|
||||
pos.ins().Call(ir::Opcode::Call, VOID, callee, args).0
|
||||
Ok(pos.ins().Call(ir::Opcode::Call, VOID, callee, args).0)
|
||||
}
|
||||
|
||||
fn translate_grow_memory(
|
||||
@@ -256,8 +258,8 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
||||
_index: MemoryIndex,
|
||||
_heap: ir::Heap,
|
||||
_val: ir::Value,
|
||||
) -> ir::Value {
|
||||
pos.ins().iconst(I32, -1)
|
||||
) -> WasmResult<ir::Value> {
|
||||
Ok(pos.ins().iconst(I32, -1))
|
||||
}
|
||||
|
||||
fn translate_current_memory(
|
||||
@@ -265,8 +267,8 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
|
||||
mut pos: FuncCursor,
|
||||
_index: MemoryIndex,
|
||||
_heap: ir::Heap,
|
||||
) -> ir::Value {
|
||||
pos.ins().iconst(I32, -1)
|
||||
) -> WasmResult<ir::Value> {
|
||||
Ok(pos.ins().iconst(I32, -1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,7 +387,7 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
||||
self.info.start_func = Some(func_index);
|
||||
}
|
||||
|
||||
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> Result<(), String> {
|
||||
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> WasmResult<()> {
|
||||
let func = {
|
||||
let mut func_environ = DummyFuncEnvironment::new(&self.info);
|
||||
let function_index = self.get_num_func_imports() + self.info.function_bodies.len();
|
||||
@@ -393,9 +395,11 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
||||
let sig = func_environ.vmctx_sig(self.get_func_type(function_index));
|
||||
let mut func = ir::Function::with_name_signature(name, sig);
|
||||
let reader = wasmparser::BinaryReader::new(body_bytes);
|
||||
self.trans
|
||||
.translate_from_reader(reader, &mut func, &mut func_environ)
|
||||
.map_err(|e| format!("{}", e))?;
|
||||
self.trans.translate_from_reader(
|
||||
reader,
|
||||
&mut func,
|
||||
&mut func_environ,
|
||||
)?;
|
||||
func
|
||||
};
|
||||
self.func_bytecode_sizes.push(body_bytes.len());
|
||||
|
||||
@@ -4,4 +4,4 @@ mod dummy;
|
||||
mod spec;
|
||||
|
||||
pub use environ::dummy::DummyEnvironment;
|
||||
pub use environ::spec::{FuncEnvironment, GlobalValue, ModuleEnvironment};
|
||||
pub use environ::spec::{FuncEnvironment, GlobalValue, ModuleEnvironment, WasmError, WasmResult};
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
use cretonne_codegen::cursor::FuncCursor;
|
||||
use cretonne_codegen::ir::{self, InstBuilder};
|
||||
use cretonne_codegen::settings::Flags;
|
||||
use std::string::String;
|
||||
use std::vec::Vec;
|
||||
use translation_utils::{FunctionIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex,
|
||||
Table, TableIndex};
|
||||
use wasmparser::BinaryReaderError;
|
||||
|
||||
/// The value of a WebAssembly global variable.
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -23,6 +23,49 @@ pub enum GlobalValue {
|
||||
},
|
||||
}
|
||||
|
||||
/// A WebAssembly translation error.
|
||||
///
|
||||
/// When a WebAssembly function can't be translated, one of these error codes will be returned
|
||||
/// to describe the failure.
|
||||
#[derive(Fail, Debug, PartialEq, Eq)]
|
||||
pub enum WasmError {
|
||||
/// The input WebAssembly code is invalid.
|
||||
///
|
||||
/// This error code is used by a WebAssembly translator when it encounters invalid WebAssembly
|
||||
/// code. This should never happen for validated WebAssembly code.
|
||||
#[fail(display = "Invalid input WebAssembly code at offset {}: {}", _1, _0)]
|
||||
InvalidWebAssembly {
|
||||
message: &'static str,
|
||||
offset: usize,
|
||||
},
|
||||
|
||||
/// A feature used by the WebAssembly code is not supported by the embedding environment.
|
||||
///
|
||||
/// Embedding environments may have their own limitations and feature restrictions.
|
||||
#[fail(display = "Unsupported feature: {}", _0)]
|
||||
Unsupported(&'static str),
|
||||
|
||||
/// An implementation limit was exceeded.
|
||||
///
|
||||
/// Cretonne can compile very large and complicated functions, but the [implementation has
|
||||
/// limits][limits] that cause compilation to fail when they are exceeded.
|
||||
///
|
||||
/// [limits]: https://cretonne.readthedocs.io/en/latest/langref.html#implementation-limits
|
||||
#[fail(display = "Implementation limit exceeded")]
|
||||
ImplLimitExceeded,
|
||||
}
|
||||
|
||||
impl WasmError {
|
||||
/// Convert from a `BinaryReaderError` to a `WasmError`.
|
||||
pub fn from_binary_reader_error(e: BinaryReaderError) -> Self {
|
||||
let BinaryReaderError { message, offset } = e;
|
||||
WasmError::InvalidWebAssembly { message, offset }
|
||||
}
|
||||
}
|
||||
|
||||
/// A convenient alias for a `Result` that uses `WasmError` as the error type.
|
||||
pub type WasmResult<T> = Result<T, WasmError>;
|
||||
|
||||
/// Environment affecting the translation of a single WebAssembly function.
|
||||
///
|
||||
/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cretonne
|
||||
@@ -99,7 +142,7 @@ pub trait FuncEnvironment {
|
||||
sig_ref: ir::SigRef,
|
||||
callee: ir::Value,
|
||||
call_args: &[ir::Value],
|
||||
) -> ir::Inst;
|
||||
) -> WasmResult<ir::Inst>;
|
||||
|
||||
/// Translate a `call` WebAssembly instruction at `pos`.
|
||||
///
|
||||
@@ -114,8 +157,8 @@ pub trait FuncEnvironment {
|
||||
_callee_index: FunctionIndex,
|
||||
callee: ir::FuncRef,
|
||||
call_args: &[ir::Value],
|
||||
) -> ir::Inst {
|
||||
pos.ins().call(callee, call_args)
|
||||
) -> WasmResult<ir::Inst> {
|
||||
Ok(pos.ins().call(callee, call_args))
|
||||
}
|
||||
|
||||
/// Translate a `grow_memory` WebAssembly instruction.
|
||||
@@ -132,7 +175,7 @@ pub trait FuncEnvironment {
|
||||
index: MemoryIndex,
|
||||
heap: ir::Heap,
|
||||
val: ir::Value,
|
||||
) -> ir::Value;
|
||||
) -> WasmResult<ir::Value>;
|
||||
|
||||
/// Translates a `current_memory` WebAssembly instruction.
|
||||
///
|
||||
@@ -145,7 +188,7 @@ pub trait FuncEnvironment {
|
||||
pos: FuncCursor,
|
||||
index: MemoryIndex,
|
||||
heap: ir::Heap,
|
||||
) -> ir::Value;
|
||||
) -> WasmResult<ir::Value>;
|
||||
|
||||
/// Emit code at the beginning of every wasm loop.
|
||||
///
|
||||
@@ -229,5 +272,5 @@ pub trait ModuleEnvironment<'data> {
|
||||
fn declare_start_func(&mut self, index: FunctionIndex);
|
||||
|
||||
/// Provides the contents of a function body.
|
||||
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> Result<(), String>;
|
||||
fn define_function_body(&mut self, body_bytes: &'data [u8]) -> WasmResult<()>;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,9 @@
|
||||
use code_translator::translate_operator;
|
||||
use cretonne_codegen::entity::EntityRef;
|
||||
use cretonne_codegen::ir::{self, Ebb, InstBuilder};
|
||||
use cretonne_codegen::result::{CtonError, CtonResult};
|
||||
use cretonne_codegen::timing;
|
||||
use cretonne_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
|
||||
use environ::FuncEnvironment;
|
||||
use environ::{FuncEnvironment, WasmError, WasmResult};
|
||||
use state::TranslationState;
|
||||
use wasmparser::{self, BinaryReader};
|
||||
|
||||
@@ -56,7 +55,7 @@ impl FuncTranslator {
|
||||
code: &[u8],
|
||||
func: &mut ir::Function,
|
||||
environ: &mut FE,
|
||||
) -> CtonResult {
|
||||
) -> WasmResult<()> {
|
||||
self.translate_from_reader(BinaryReader::new(code), func, environ)
|
||||
}
|
||||
|
||||
@@ -66,7 +65,7 @@ impl FuncTranslator {
|
||||
mut reader: BinaryReader,
|
||||
func: &mut ir::Function,
|
||||
environ: &mut FE,
|
||||
) -> CtonResult {
|
||||
) -> WasmResult<()> {
|
||||
let _tt = timing::wasm_translate_function();
|
||||
dbg!(
|
||||
"translate({} bytes, {}{})",
|
||||
@@ -134,17 +133,17 @@ fn parse_local_decls(
|
||||
reader: &mut BinaryReader,
|
||||
builder: &mut FunctionBuilder<Variable>,
|
||||
num_params: usize,
|
||||
) -> CtonResult {
|
||||
) -> WasmResult<()> {
|
||||
let mut next_local = num_params;
|
||||
let local_count = reader.read_local_count().map_err(
|
||||
|_| CtonError::InvalidInput,
|
||||
)?;
|
||||
let local_count = reader.read_local_count().map_err(|e| {
|
||||
WasmError::from_binary_reader_error(e)
|
||||
})?;
|
||||
|
||||
let mut locals_total = 0;
|
||||
for _ in 0..local_count {
|
||||
builder.set_srcloc(cur_srcloc(reader));
|
||||
let (count, ty) = reader.read_local_decl(&mut locals_total).map_err(|_| {
|
||||
CtonError::InvalidInput
|
||||
let (count, ty) = reader.read_local_decl(&mut locals_total).map_err(|e| {
|
||||
WasmError::from_binary_reader_error(e)
|
||||
})?;
|
||||
declare_locals(builder, count, ty, &mut next_local);
|
||||
}
|
||||
@@ -189,15 +188,17 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
|
||||
builder: &mut FunctionBuilder<Variable>,
|
||||
state: &mut TranslationState,
|
||||
environ: &mut FE,
|
||||
) -> CtonResult {
|
||||
) -> WasmResult<()> {
|
||||
// The control stack is initialized with a single block representing the whole function.
|
||||
debug_assert_eq!(state.control_stack.len(), 1, "State not initialized");
|
||||
|
||||
// Keep going until the final `End` operator which pops the outermost block.
|
||||
while !state.control_stack.is_empty() {
|
||||
builder.set_srcloc(cur_srcloc(&reader));
|
||||
let op = reader.read_operator().map_err(|_| CtonError::InvalidInput)?;
|
||||
translate_operator(op, builder, state, environ);
|
||||
let op = reader.read_operator().map_err(|e| {
|
||||
WasmError::from_binary_reader_error(e)
|
||||
})?;
|
||||
translate_operator(op, builder, state, environ)?;
|
||||
}
|
||||
|
||||
// The final `End` operator left us in the exit block where we need to manually add a return
|
||||
|
||||
@@ -42,6 +42,10 @@ extern crate cretonne_codegen;
|
||||
extern crate cretonne_frontend;
|
||||
extern crate wasmparser;
|
||||
|
||||
extern crate failure;
|
||||
#[macro_use]
|
||||
extern crate failure_derive;
|
||||
|
||||
mod code_translator;
|
||||
mod environ;
|
||||
mod func_translator;
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
//! Translation skeleton that traverses the whole WebAssembly module and call helper functions
|
||||
//! to deal with each part of it.
|
||||
use cretonne_codegen::timing;
|
||||
use environ::ModuleEnvironment;
|
||||
use environ::{ModuleEnvironment, WasmError, WasmResult};
|
||||
use sections_translator::{parse_data_section, parse_elements_section, parse_export_section,
|
||||
parse_function_section, parse_function_signatures, parse_global_section,
|
||||
parse_import_section, parse_memory_section, parse_start_section,
|
||||
parse_table_section, SectionParsingError};
|
||||
use wasmparser::{BinaryReaderError, Parser, ParserInput, ParserState, SectionCode, WasmDecoder};
|
||||
|
||||
use std::string::String;
|
||||
parse_table_section};
|
||||
use wasmparser::{Parser, ParserInput, ParserState, SectionCode, WasmDecoder};
|
||||
|
||||
/// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cretonne IR
|
||||
/// [`Function`](../codegen/ir/function/struct.Function.html).
|
||||
@@ -17,13 +15,13 @@ use std::string::String;
|
||||
pub fn translate_module<'data>(
|
||||
data: &'data [u8],
|
||||
environ: &mut ModuleEnvironment<'data>,
|
||||
) -> Result<(), String> {
|
||||
) -> WasmResult<()> {
|
||||
let _tt = timing::wasm_translate_module();
|
||||
let mut parser = Parser::new(data);
|
||||
match *parser.read() {
|
||||
ParserState::BeginWasm { .. } => {}
|
||||
ParserState::Error(BinaryReaderError { message, offset }) => {
|
||||
return Err(format!("at offset {}: {}", offset, message));
|
||||
ParserState::Error(e) => {
|
||||
return Err(WasmError::from_binary_reader_error(e));
|
||||
}
|
||||
ref s => panic!("modules should begin properly: {:?}", s),
|
||||
}
|
||||
@@ -31,83 +29,38 @@ pub fn translate_module<'data>(
|
||||
loop {
|
||||
match *parser.read_with_input(next_input) {
|
||||
ParserState::BeginSection { code: SectionCode::Type, .. } => {
|
||||
match parse_function_signatures(&mut parser, environ) {
|
||||
Ok(()) => (),
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the type section: {}", s))
|
||||
}
|
||||
};
|
||||
parse_function_signatures(&mut parser, environ)?;
|
||||
next_input = ParserInput::Default;
|
||||
}
|
||||
ParserState::BeginSection { code: SectionCode::Import, .. } => {
|
||||
match parse_import_section(&mut parser, environ) {
|
||||
Ok(()) => {}
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the import section: {}", s))
|
||||
}
|
||||
}
|
||||
parse_import_section(&mut parser, environ)?;
|
||||
next_input = ParserInput::Default;
|
||||
}
|
||||
ParserState::BeginSection { code: SectionCode::Function, .. } => {
|
||||
match parse_function_section(&mut parser, environ) {
|
||||
Ok(()) => {}
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the function section: {}", s))
|
||||
}
|
||||
}
|
||||
parse_function_section(&mut parser, environ)?;
|
||||
next_input = ParserInput::Default;
|
||||
}
|
||||
ParserState::BeginSection { code: SectionCode::Table, .. } => {
|
||||
match parse_table_section(&mut parser, environ) {
|
||||
Ok(()) => (),
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the table section: {}", s))
|
||||
}
|
||||
}
|
||||
parse_table_section(&mut parser, environ)?;
|
||||
}
|
||||
ParserState::BeginSection { code: SectionCode::Memory, .. } => {
|
||||
match parse_memory_section(&mut parser, environ) {
|
||||
Ok(()) => {}
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the memory section: {}", s))
|
||||
}
|
||||
}
|
||||
parse_memory_section(&mut parser, environ)?;
|
||||
next_input = ParserInput::Default;
|
||||
}
|
||||
ParserState::BeginSection { code: SectionCode::Global, .. } => {
|
||||
match parse_global_section(&mut parser, environ) {
|
||||
Ok(()) => {}
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the global section: {}", s))
|
||||
}
|
||||
}
|
||||
parse_global_section(&mut parser, environ)?;
|
||||
next_input = ParserInput::Default;
|
||||
}
|
||||
ParserState::BeginSection { code: SectionCode::Export, .. } => {
|
||||
match parse_export_section(&mut parser, environ) {
|
||||
Ok(()) => {}
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the export section: {}", s))
|
||||
}
|
||||
}
|
||||
parse_export_section(&mut parser, environ)?;
|
||||
next_input = ParserInput::Default;
|
||||
}
|
||||
ParserState::BeginSection { code: SectionCode::Start, .. } => {
|
||||
match parse_start_section(&mut parser, environ) {
|
||||
Ok(()) => (),
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the start section: {}", s))
|
||||
}
|
||||
}
|
||||
parse_start_section(&mut parser, environ)?;
|
||||
next_input = ParserInput::Default;
|
||||
}
|
||||
ParserState::BeginSection { code: SectionCode::Element, .. } => {
|
||||
match parse_elements_section(&mut parser, environ) {
|
||||
Ok(()) => (),
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the element section: {}", s))
|
||||
}
|
||||
}
|
||||
parse_elements_section(&mut parser, environ)?;
|
||||
next_input = ParserInput::Default;
|
||||
}
|
||||
ParserState::BeginSection { code: SectionCode::Code, .. } => {
|
||||
@@ -119,18 +72,14 @@ pub fn translate_module<'data>(
|
||||
}
|
||||
ParserState::EndWasm => return Ok(()),
|
||||
ParserState::BeginSection { code: SectionCode::Data, .. } => {
|
||||
match parse_data_section(&mut parser, environ) {
|
||||
Ok(()) => (),
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the data section: {}", s))
|
||||
}
|
||||
}
|
||||
parse_data_section(&mut parser, environ)?;
|
||||
}
|
||||
ParserState::BeginSection { code: SectionCode::Custom { .. }, .. } => {
|
||||
// Ignore unknown custom sections.
|
||||
next_input = ParserInput::SkipSection;
|
||||
}
|
||||
_ => return Err(String::from("wrong content in the preamble")),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
_ => panic!("wrong content in the preamble"),
|
||||
};
|
||||
}
|
||||
// At this point we've entered the code section
|
||||
@@ -138,25 +87,21 @@ pub fn translate_module<'data>(
|
||||
match *parser.read() {
|
||||
ParserState::BeginFunctionBody { .. } => {}
|
||||
ParserState::EndSection => break,
|
||||
_ => return Err(String::from("wrong content in code section")),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("wrong content in code section: {:?}", s),
|
||||
}
|
||||
let mut reader = parser.create_binary_reader();
|
||||
let size = reader.bytes_remaining();
|
||||
environ.define_function_body(
|
||||
reader.read_bytes(size).map_err(|e| {
|
||||
format!("at offset {}: {}", e.offset, e.message)
|
||||
WasmError::from_binary_reader_error(e)
|
||||
})?,
|
||||
)?;
|
||||
}
|
||||
loop {
|
||||
match *parser.read() {
|
||||
ParserState::BeginSection { code: SectionCode::Data, .. } => {
|
||||
match parse_data_section(&mut parser, environ) {
|
||||
Ok(()) => (),
|
||||
Err(SectionParsingError::WrongSectionContent(s)) => {
|
||||
return Err(format!("wrong content in the data section: {}", s))
|
||||
}
|
||||
}
|
||||
parse_data_section(&mut parser, environ)?;
|
||||
}
|
||||
ParserState::EndWasm => break,
|
||||
_ => (),
|
||||
|
||||
@@ -8,9 +8,8 @@
|
||||
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
|
||||
//! interpreted on the fly.
|
||||
use cretonne_codegen::ir::{self, AbiParam, Signature};
|
||||
use environ::ModuleEnvironment;
|
||||
use environ::{ModuleEnvironment, WasmError, WasmResult};
|
||||
use std::str::from_utf8;
|
||||
use std::string::String;
|
||||
use std::vec::Vec;
|
||||
use translation_utils::{type_to_type, FunctionIndex, Global, GlobalIndex, GlobalInit, Memory,
|
||||
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex};
|
||||
@@ -18,15 +17,11 @@ use wasmparser;
|
||||
use wasmparser::{ExternalKind, FuncType, ImportSectionEntryType, MemoryType, Operator, Parser,
|
||||
ParserState, WasmDecoder};
|
||||
|
||||
pub enum SectionParsingError {
|
||||
WrongSectionContent(String),
|
||||
}
|
||||
|
||||
/// Reads the Type Section of the wasm module and returns the corresponding function signatures.
|
||||
pub fn parse_function_signatures(
|
||||
parser: &mut Parser,
|
||||
environ: &mut ModuleEnvironment,
|
||||
) -> Result<(), SectionParsingError> {
|
||||
) -> WasmResult<()> {
|
||||
loop {
|
||||
match *parser.read() {
|
||||
ParserState::EndSection => break,
|
||||
@@ -50,7 +45,8 @@ pub fn parse_function_signatures(
|
||||
}));
|
||||
environ.declare_signature(&sig);
|
||||
}
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -60,7 +56,7 @@ pub fn parse_function_signatures(
|
||||
pub fn parse_import_section<'data>(
|
||||
parser: &mut Parser<'data>,
|
||||
environ: &mut ModuleEnvironment<'data>,
|
||||
) -> Result<(), SectionParsingError> {
|
||||
) -> WasmResult<()> {
|
||||
loop {
|
||||
match *parser.read() {
|
||||
ParserState::ImportSectionEntry {
|
||||
@@ -110,7 +106,8 @@ pub fn parse_import_section<'data>(
|
||||
})
|
||||
}
|
||||
ParserState::EndSection => break,
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
@@ -120,14 +117,15 @@ pub fn parse_import_section<'data>(
|
||||
pub fn parse_function_section(
|
||||
parser: &mut Parser,
|
||||
environ: &mut ModuleEnvironment,
|
||||
) -> Result<(), SectionParsingError> {
|
||||
) -> WasmResult<()> {
|
||||
loop {
|
||||
match *parser.read() {
|
||||
ParserState::FunctionSectionEntry(sigindex) => {
|
||||
environ.declare_func_type(sigindex as SignatureIndex);
|
||||
}
|
||||
ParserState::EndSection => break,
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
@@ -137,7 +135,7 @@ pub fn parse_function_section(
|
||||
pub fn parse_export_section<'data>(
|
||||
parser: &mut Parser<'data>,
|
||||
environ: &mut ModuleEnvironment<'data>,
|
||||
) -> Result<(), SectionParsingError> {
|
||||
) -> WasmResult<()> {
|
||||
loop {
|
||||
match *parser.read() {
|
||||
ParserState::ExportSectionEntry {
|
||||
@@ -158,24 +156,23 @@ pub fn parse_export_section<'data>(
|
||||
}
|
||||
}
|
||||
ParserState::EndSection => break,
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieves the start function index from the start section
|
||||
pub fn parse_start_section(
|
||||
parser: &mut Parser,
|
||||
environ: &mut ModuleEnvironment,
|
||||
) -> Result<(), SectionParsingError> {
|
||||
pub fn parse_start_section(parser: &mut Parser, environ: &mut ModuleEnvironment) -> WasmResult<()> {
|
||||
loop {
|
||||
match *parser.read() {
|
||||
ParserState::StartSectionEntry(index) => {
|
||||
environ.declare_start_func(index as FunctionIndex);
|
||||
}
|
||||
ParserState::EndSection => break,
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
@@ -185,7 +182,7 @@ pub fn parse_start_section(
|
||||
pub fn parse_memory_section(
|
||||
parser: &mut Parser,
|
||||
environ: &mut ModuleEnvironment,
|
||||
) -> Result<(), SectionParsingError> {
|
||||
) -> WasmResult<()> {
|
||||
loop {
|
||||
match *parser.read() {
|
||||
ParserState::MemorySectionEntry(ref ty) => {
|
||||
@@ -196,7 +193,8 @@ pub fn parse_memory_section(
|
||||
});
|
||||
}
|
||||
ParserState::EndSection => break,
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
@@ -206,16 +204,18 @@ pub fn parse_memory_section(
|
||||
pub fn parse_global_section(
|
||||
parser: &mut Parser,
|
||||
environ: &mut ModuleEnvironment,
|
||||
) -> Result<(), SectionParsingError> {
|
||||
) -> WasmResult<()> {
|
||||
loop {
|
||||
let (content_type, mutability) = match *parser.read() {
|
||||
ParserState::BeginGlobalSectionEntry(ref ty) => (ty.content_type, ty.mutable),
|
||||
ParserState::EndSection => break,
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
match *parser.read() {
|
||||
ParserState::BeginInitExpressionBody => (),
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
}
|
||||
let initializer = match *parser.read() {
|
||||
ParserState::InitExpressionOperator(Operator::I32Const { value }) => {
|
||||
@@ -233,11 +233,13 @@ pub fn parse_global_section(
|
||||
ParserState::InitExpressionOperator(Operator::GetGlobal { global_index }) => {
|
||||
GlobalInit::GlobalRef(global_index as GlobalIndex)
|
||||
}
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
match *parser.read() {
|
||||
ParserState::EndInitExpressionBody => (),
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
}
|
||||
let global = Global {
|
||||
ty: type_to_type(&content_type).unwrap(),
|
||||
@@ -247,7 +249,8 @@ pub fn parse_global_section(
|
||||
environ.declare_global(global);
|
||||
match *parser.read() {
|
||||
ParserState::EndGlobalSectionEntry => (),
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -256,16 +259,18 @@ pub fn parse_global_section(
|
||||
pub fn parse_data_section<'data>(
|
||||
parser: &mut Parser<'data>,
|
||||
environ: &mut ModuleEnvironment<'data>,
|
||||
) -> Result<(), SectionParsingError> {
|
||||
) -> WasmResult<()> {
|
||||
loop {
|
||||
let memory_index = match *parser.read() {
|
||||
ParserState::BeginDataSectionEntry(memory_index) => memory_index,
|
||||
ParserState::EndSection => break,
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
match *parser.read() {
|
||||
ParserState::BeginInitExpressionBody => (),
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
let (base, offset) = match *parser.read() {
|
||||
ParserState::InitExpressionOperator(Operator::I32Const { value }) => {
|
||||
@@ -278,22 +283,26 @@ pub fn parse_data_section<'data>(
|
||||
_ => panic!("should not happen"),
|
||||
}
|
||||
}
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
match *parser.read() {
|
||||
ParserState::EndInitExpressionBody => (),
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
match *parser.read() {
|
||||
ParserState::BeginDataSectionEntryBody(_) => (),
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
let mut running_offset = offset;
|
||||
loop {
|
||||
let data = match *parser.read() {
|
||||
ParserState::DataSectionEntryBodyChunk(data) => data,
|
||||
ParserState::EndDataSectionEntryBody => break,
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
environ.declare_data_initialization(
|
||||
memory_index as MemoryIndex,
|
||||
@@ -305,17 +314,15 @@ pub fn parse_data_section<'data>(
|
||||
}
|
||||
match *parser.read() {
|
||||
ParserState::EndDataSectionEntry => (),
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieves the tables from the table section
|
||||
pub fn parse_table_section(
|
||||
parser: &mut Parser,
|
||||
environ: &mut ModuleEnvironment,
|
||||
) -> Result<(), SectionParsingError> {
|
||||
pub fn parse_table_section(parser: &mut Parser, environ: &mut ModuleEnvironment) -> WasmResult<()> {
|
||||
loop {
|
||||
match *parser.read() {
|
||||
ParserState::TableSectionEntry(ref table) => {
|
||||
@@ -329,7 +336,8 @@ pub fn parse_table_section(
|
||||
})
|
||||
}
|
||||
ParserState::EndSection => break,
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
@@ -339,16 +347,18 @@ pub fn parse_table_section(
|
||||
pub fn parse_elements_section(
|
||||
parser: &mut Parser,
|
||||
environ: &mut ModuleEnvironment,
|
||||
) -> Result<(), SectionParsingError> {
|
||||
) -> WasmResult<()> {
|
||||
loop {
|
||||
let table_index = match *parser.read() {
|
||||
ParserState::BeginElementSectionEntry(table_index) => table_index as TableIndex,
|
||||
ParserState::EndSection => break,
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
match *parser.read() {
|
||||
ParserState::BeginInitExpressionBody => (),
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
let (base, offset) = match *parser.read() {
|
||||
ParserState::InitExpressionOperator(Operator::I32Const { value }) => {
|
||||
@@ -361,11 +371,13 @@ pub fn parse_elements_section(
|
||||
_ => panic!("should not happen"),
|
||||
}
|
||||
}
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
match *parser.read() {
|
||||
ParserState::EndInitExpressionBody => (),
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
match *parser.read() {
|
||||
ParserState::ElementSectionEntryBody(ref elements) => {
|
||||
@@ -373,11 +385,13 @@ pub fn parse_elements_section(
|
||||
elements.iter().map(|&x| x as FunctionIndex).collect();
|
||||
environ.declare_table_elements(table_index, base, offset, elems)
|
||||
}
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
match *parser.read() {
|
||||
ParserState::EndElementSectionEntry => (),
|
||||
ref s => return Err(SectionParsingError::WrongSectionContent(format!("{:?}", s))),
|
||||
ParserState::Error(e) => return Err(WasmError::from_binary_reader_error(e)),
|
||||
ref s => panic!("unexpected section content: {:?}", s),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user