Merge branch 'master' into feature/emscripten-for-bundling

This commit is contained in:
Mackenzie Clark 2019-03-04 13:16:01 -08:00 committed by GitHub
commit 84c8be6b33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 70 additions and 112 deletions

View File

@ -2,7 +2,7 @@ use crate::relocation::{TrapData, TrapSink};
use crate::trampoline::Trampolines; use crate::trampoline::Trampolines;
use hashbrown::HashSet; use hashbrown::HashSet;
use libc::c_void; use libc::c_void;
use std::{cell::Cell, sync::Arc}; use std::{any::Any, cell::Cell, sync::Arc};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::{ProtectedCaller, Token, UserTrapper}, backend::{ProtectedCaller, Token, UserTrapper},
error::RuntimeResult, error::RuntimeResult,
@ -25,14 +25,14 @@ pub use self::unix::*;
pub use self::windows::*; pub use self::windows::*;
thread_local! { thread_local! {
pub static TRAP_EARLY_DATA: Cell<Option<String>> = Cell::new(None); pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any>>> = Cell::new(None);
} }
pub struct Trapper; pub struct Trapper;
impl UserTrapper for Trapper { impl UserTrapper for Trapper {
unsafe fn do_early_trap(&self, msg: String) -> ! { unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> ! {
TRAP_EARLY_DATA.with(|cell| cell.set(Some(msg))); TRAP_EARLY_DATA.with(|cell| cell.set(Some(data)));
trigger_trap() trigger_trap()
} }
} }

View File

@ -79,8 +79,8 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
if signum != 0 { if signum != 0 {
*jmp_buf = prev_jmp_buf; *jmp_buf = prev_jmp_buf;
if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) { if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
Err(RuntimeError::User { msg }) Err(RuntimeError::Panic { data })
} else { } else {
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get()); let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
@ -91,28 +91,28 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
{ {
Err(match Signal::from_c_int(signum) { Err(match Signal::from_c_int(signum) {
Ok(SIGILL) => match trapcode { Ok(SIGILL) => match trapcode {
TrapCode::BadSignature => RuntimeError::IndirectCallSignature { TrapCode::BadSignature => RuntimeError::Trap {
table: TableIndex::new(0), msg: "incorrect call_indirect signature".into(),
}, },
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull { TrapCode::IndirectCallToNull => RuntimeError::Trap {
table: TableIndex::new(0), msg: "indirect call to null".into(),
}, },
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess { TrapCode::HeapOutOfBounds => RuntimeError::Trap {
memory: MemoryIndex::new(0), msg: "memory out-of-bounds access".into(),
addr: None,
}, },
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds { TrapCode::TableOutOfBounds => RuntimeError::Trap {
table: TableIndex::new(0), msg: "table out-of-bounds access".into(),
}, },
_ => RuntimeError::Unknown { _ => RuntimeError::Trap {
msg: "unknown trap".to_string(), msg: "unknown trap".into(),
}, },
}, },
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::OutOfBoundsAccess { Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::Trap {
memory: MemoryIndex::new(0), msg: "memory out-of-bounds access".into(),
addr: None, },
Ok(SIGFPE) => RuntimeError::Trap {
msg: "illegal arithmetic operation".into(),
}, },
Ok(SIGFPE) => RuntimeError::IllegalArithmeticOperation,
_ => unimplemented!(), _ => unimplemented!(),
} }
.into()) .into())
@ -126,8 +126,8 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
_ => "unkown trapped signal", _ => "unkown trapped signal",
}; };
// When the trap-handler is fully implemented, this will return more information. // When the trap-handler is fully implemented, this will return more information.
Err(RuntimeError::Unknown { Err(RuntimeError::Trap {
msg: format!("trap at {:p} - {}", faulting_addr, signal), msg: format!("unknown trap at {:p} - {}", faulting_addr, signal).into(),
} }
.into()) .into())
} }

View File

@ -57,35 +57,34 @@ pub fn call_protected(
}) = handler_data.lookup(instruction_pointer as _) }) = handler_data.lookup(instruction_pointer as _)
{ {
Err(match signum as DWORD { Err(match signum as DWORD {
EXCEPTION_ACCESS_VIOLATION => RuntimeError::OutOfBoundsAccess { EXCEPTION_ACCESS_VIOLATION => RuntimeError::Trap {
memory: MemoryIndex::new(0), msg: "memory out-of-bounds access".into(),
addr: None,
}, },
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode { EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
TrapCode::BadSignature => RuntimeError::IndirectCallSignature { TrapCode::BadSignature => RuntimeError::Trap {
table: TableIndex::new(0), msg: "incorrect call_indirect signature".into(),
}, },
TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull { TrapCode::IndirectCallToNull => RuntimeError::Trap {
table: TableIndex::new(0), msg: "indirect call to null".into(),
}, },
TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess { TrapCode::HeapOutOfBounds => RuntimeError::Trap {
memory: MemoryIndex::new(0), msg: "memory out-of-bounds access".into(),
addr: None,
}, },
TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds { TrapCode::TableOutOfBounds => RuntimeError::Trap {
table: TableIndex::new(0), msg: "table out-of-bounds access".into(),
}, },
_ => RuntimeError::Unknown { _ => RuntimeError::Trap {
msg: "unknown trap".to_string(), msg: "unknown trap".into(),
}, },
}, },
EXCEPTION_STACK_OVERFLOW => RuntimeError::Unknown { EXCEPTION_STACK_OVERFLOW => RuntimeError::Trap {
msg: "unknown trap".to_string(), msg: "stack overflow trap".into(),
}, },
EXCEPTION_INT_DIVIDE_BY_ZERO => RuntimeError::IllegalArithmeticOperation, EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => RuntimeError::Trap {
EXCEPTION_INT_OVERFLOW => RuntimeError::IllegalArithmeticOperation, msg: "illegal arithmetic operation".into(),
_ => RuntimeError::Unknown { },
msg: "unknown trap".to_string(), _ => RuntimeError::Trap {
msg: "unknown trap".into(),
}, },
} }
.into()) .into())
@ -103,8 +102,8 @@ pub fn call_protected(
_ => "unkown trapped signal", _ => "unkown trapped signal",
}; };
Err(RuntimeError::Unknown { Err(RuntimeError::Trap {
msg: format!("trap at {} - {}", exception_address, signal), msg: format!("unknown trap at {} - {}", exception_address, signal).into(),
} }
.into()) .into())
} }

View File

@ -12,7 +12,7 @@ use crate::{
module::ModuleInfo, module::ModuleInfo,
sys::Memory, sys::Memory,
}; };
use std::ptr::NonNull; use std::{any::Any, ptr::NonNull};
pub mod sys { pub mod sys {
pub use crate::sys::*; pub use crate::sys::*;
@ -78,7 +78,7 @@ pub trait ProtectedCaller: Send + Sync {
} }
pub trait UserTrapper { pub trait UserTrapper {
unsafe fn do_early_trap(&self, msg: String) -> !; unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> !;
} }
pub trait FuncResolver: Send + Sync { pub trait FuncResolver: Send + Sync {

View File

@ -1,8 +1,9 @@
use crate::types::{ use crate::types::{
FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type, FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type,
Value,
}; };
use core::borrow::Borrow; use core::borrow::Borrow;
use std::sync::Arc; use std::{any::Any, sync::Arc};
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
pub type CompileResult<T> = std::result::Result<T, CompileError>; pub type CompileResult<T> = std::result::Result<T, CompileError>;
@ -120,28 +121,11 @@ impl std::error::Error for LinkError {}
/// The main way to do this is `Instance.call`. /// The main way to do this is `Instance.call`.
/// ///
/// Comparing two `RuntimeError`s always evaluates to false. /// Comparing two `RuntimeError`s always evaluates to false.
#[derive(Debug, Clone)] #[derive(Debug)]
pub enum RuntimeError { pub enum RuntimeError {
OutOfBoundsAccess { Trap { msg: Box<str> },
memory: MemoryIndex, Exception { data: Box<[Value]> },
addr: Option<u32>, Panic { data: Box<dyn Any> },
},
TableOutOfBounds {
table: TableIndex,
},
IndirectCallSignature {
table: TableIndex,
},
IndirectCallToNull {
table: TableIndex,
},
IllegalArithmeticOperation,
User {
msg: String,
},
Unknown {
msg: String,
},
} }
impl PartialEq for RuntimeError { impl PartialEq for RuntimeError {
@ -153,30 +137,13 @@ impl PartialEq for RuntimeError {
impl std::fmt::Display for RuntimeError { impl std::fmt::Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {
RuntimeError::IndirectCallSignature { table } => write!( RuntimeError::Trap { ref msg } => {
f, write!(f, "WebAssembly trap occured during runtime: {}", msg)
"Indirect call signature error with Table Index \"{:?}\"",
table
),
RuntimeError::IndirectCallToNull { table } => {
write!(f, "Indirect call to null with table index \"{:?}\"", table)
} }
RuntimeError::IllegalArithmeticOperation => write!(f, "Illegal arithmetic operation"), RuntimeError::Exception { ref data } => {
RuntimeError::OutOfBoundsAccess { memory, addr } => match addr { write!(f, "Uncaught WebAssembly exception: {:?}", data)
Some(addr) => write!(
f,
"Out-of-bounds access with memory index {:?} and address {}",
memory, addr
),
None => write!(f, "Out-of-bounds access with memory index {:?}", memory),
},
RuntimeError::TableOutOfBounds { table } => {
write!(f, "Table out of bounds with table index \"{:?}\"", table)
} }
RuntimeError::Unknown { msg } => { RuntimeError::Panic { data: _ } => write!(f, "User-defined \"panic\""),
write!(f, "Unknown runtime error with message: \"{}\"", msg)
}
RuntimeError::User { msg } => write!(f, "User runtime error with message: \"{}\"", msg),
} }
} }
} }
@ -239,7 +206,7 @@ impl std::error::Error for ResolveError {}
/// be the `CallError::Runtime(RuntimeError)` variant. /// be the `CallError::Runtime(RuntimeError)` variant.
/// ///
/// Comparing two `CallError`s always evaluates to false. /// Comparing two `CallError`s always evaluates to false.
#[derive(Debug, Clone)] #[derive(Debug)]
pub enum CallError { pub enum CallError {
Resolve(ResolveError), Resolve(ResolveError),
Runtime(RuntimeError), Runtime(RuntimeError),
@ -298,7 +265,7 @@ impl std::error::Error for CreationError {}
/// of a webassembly module. /// of a webassembly module.
/// ///
/// Comparing two `Error`s always evaluates to false. /// Comparing two `Error`s always evaluates to false.
#[derive(Debug, Clone)] #[derive(Debug)]
pub enum Error { pub enum Error {
CompileError(CompileError), CompileError(CompileError),
LinkError(Vec<LinkError>), LinkError(Vec<LinkError>),

View File

@ -6,7 +6,7 @@ use crate::{
types::{FuncSig, Type, WasmExternType}, types::{FuncSig, Type, WasmExternType},
vm::Ctx, vm::Ctx,
}; };
use std::{cell::UnsafeCell, fmt, marker::PhantomData, mem, panic, ptr, sync::Arc}; use std::{any::Any, cell::UnsafeCell, fmt, marker::PhantomData, mem, panic, ptr, sync::Arc};
thread_local! { thread_local! {
pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None); pub static EARLY_TRAPPER: UnsafeCell<Option<Box<dyn UserTrapper>>> = UnsafeCell::new(None);
@ -40,14 +40,14 @@ pub trait TrapEarly<Rets>
where where
Rets: WasmTypeList, Rets: WasmTypeList,
{ {
fn report(self) -> Result<Rets, String>; fn report(self) -> Result<Rets, Box<dyn Any>>;
} }
impl<Rets> TrapEarly<Rets> for Rets impl<Rets> TrapEarly<Rets> for Rets
where where
Rets: WasmTypeList, Rets: WasmTypeList,
{ {
fn report(self) -> Result<Rets, String> { fn report(self) -> Result<Rets, Box<dyn Any>> {
Ok(self) Ok(self)
} }
} }
@ -55,10 +55,10 @@ where
impl<Rets, E> TrapEarly<Rets> for Result<Rets, E> impl<Rets, E> TrapEarly<Rets> for Result<Rets, E>
where where
Rets: WasmTypeList, Rets: WasmTypeList,
E: fmt::Debug, E: Any,
{ {
fn report(self) -> Result<Rets, String> { fn report(self) -> Result<Rets, Box<dyn Any>> {
self.map_err(|err| format!("Error: {:?}", err)) self.map_err(|err| Box::new(err) as Box<dyn Any>)
} }
} }
@ -191,25 +191,17 @@ macro_rules! impl_traits {
extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: $x )* ) -> Rets::CStruct { extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly<Rets>, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: $x )* ) -> Rets::CStruct {
let f: FN = unsafe { mem::transmute_copy(&()) }; let f: FN = unsafe { mem::transmute_copy(&()) };
let msg = match panic::catch_unwind(panic::AssertUnwindSafe(|| { let err = match panic::catch_unwind(panic::AssertUnwindSafe(|| {
f( ctx $( ,$x )* ).report() f( ctx $( ,$x )* ).report()
})) { })) {
Ok(Ok(returns)) => return returns.into_c_struct(), Ok(Ok(returns)) => return returns.into_c_struct(),
Ok(Err(err)) => err, Ok(Err(err)) => err,
Err(err) => { Err(err) => err,
if let Some(s) = err.downcast_ref::<&str>() {
s.to_string()
} else if let Some(s) = err.downcast_ref::<String>() {
s.clone()
} else {
"a panic occurred, but no additional information is available".to_string()
}
},
}; };
unsafe { unsafe {
if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) { if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) {
early_trapper.do_early_trap(msg) early_trapper.do_early_trap(err)
} else { } else {
eprintln!("panic handling not setup"); eprintln!("panic handling not setup");
std::process::exit(1) std::process::exit(1)

View File

@ -568,7 +568,7 @@ fn {}_assert_malformed() {{
let assertion = if expected.len() > 0 && is_nan(&expected[0]) { let assertion = if expected.len() > 0 && is_nan(&expected[0]) {
format!( format!(
"let expected = {expected_result}; "let expected = {expected_result};
if let {return_type_destructure} = result.clone().unwrap().first().unwrap() {{ if let {return_type_destructure} = result.as_ref().unwrap().first().unwrap() {{
assert!((*result as {return_type}).is_nan()); assert!((*result as {return_type}).is_nan());
assert_eq!((*result as {return_type}).is_sign_positive(), (expected as {return_type}).is_sign_positive()); assert_eq!((*result as {return_type}).is_sign_positive(), (expected as {return_type}).is_sign_positive());
}} else {{ }} else {{

View File

@ -31,7 +31,7 @@ mod tests {
match result { match result {
Err(err) => match err { Err(err) => match err {
CallError::Runtime(RuntimeError::Unknown { msg }) => { CallError::Runtime(RuntimeError::Trap { msg }) => {
assert!(!msg.contains("segmentation violation")); assert!(!msg.contains("segmentation violation"));
assert!(!msg.contains("bus error")); assert!(!msg.contains("bus error"));
} }