mirror of
https://github.com/fluencelabs/wasmer
synced 2025-04-02 07:51:03 +00:00
Merge branch 'master' into feature/emscripten-for-bundling
This commit is contained in:
commit
84c8be6b33
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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>),
|
||||||
|
@ -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)
|
||||||
|
@ -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 {{
|
||||||
|
@ -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"));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user