From 73ff11295704117d504cc0477214fa58f302ef63 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Mon, 4 Mar 2019 11:27:23 -0800 Subject: [PATCH 1/5] Change RuntimeError type and fix codebase to use it --- lib/clif-backend/src/signal/mod.rs | 8 ++-- lib/clif-backend/src/signal/unix.rs | 38 +++++++++---------- lib/runtime-core/src/backend.rs | 4 +- lib/runtime-core/src/error.rs | 59 +++++++---------------------- lib/runtime-core/src/typed_func.rs | 26 +++++-------- 5 files changed, 47 insertions(+), 88 deletions(-) diff --git a/lib/clif-backend/src/signal/mod.rs b/lib/clif-backend/src/signal/mod.rs index 9ccbf1822f3..7ec33d0e140 100644 --- a/lib/clif-backend/src/signal/mod.rs +++ b/lib/clif-backend/src/signal/mod.rs @@ -2,7 +2,7 @@ use crate::relocation::{TrapData, TrapSink}; use crate::trampoline::Trampolines; use hashbrown::HashSet; use libc::c_void; -use std::{cell::Cell, sync::Arc}; +use std::{any::Any, cell::Cell, sync::Arc}; use wasmer_runtime_core::{ backend::{ProtectedCaller, Token, UserTrapper}, error::RuntimeResult, @@ -25,14 +25,14 @@ pub use self::unix::*; pub use self::windows::*; thread_local! { - pub static TRAP_EARLY_DATA: Cell> = Cell::new(None); + pub static TRAP_EARLY_DATA: Cell>> = Cell::new(None); } pub struct Trapper; impl UserTrapper for Trapper { - unsafe fn do_early_trap(&self, msg: String) -> ! { - TRAP_EARLY_DATA.with(|cell| cell.set(Some(msg))); + unsafe fn do_early_trap(&self, data: Box) -> ! { + TRAP_EARLY_DATA.with(|cell| cell.set(Some(data))); trigger_trap() } } diff --git a/lib/clif-backend/src/signal/unix.rs b/lib/clif-backend/src/signal/unix.rs index 9d2f80eca3d..86cc536389d 100644 --- a/lib/clif-backend/src/signal/unix.rs +++ b/lib/clif-backend/src/signal/unix.rs @@ -79,8 +79,8 @@ pub fn call_protected(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R if signum != 0 { *jmp_buf = prev_jmp_buf; - if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) { - Err(RuntimeError::User { msg }) + if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) { + Err(RuntimeError::Panic { data }) } else { let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get()); @@ -91,28 +91,28 @@ pub fn call_protected(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R { Err(match Signal::from_c_int(signum) { Ok(SIGILL) => match trapcode { - TrapCode::BadSignature => RuntimeError::IndirectCallSignature { - table: TableIndex::new(0), + TrapCode::BadSignature => RuntimeError::Trap { + msg: "incorrect call_indirect signature".into(), }, - TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull { - table: TableIndex::new(0), + TrapCode::IndirectCallToNull => RuntimeError::Trap { + msg: "indirect call to null".into(), }, - TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess { - memory: MemoryIndex::new(0), - addr: None, + TrapCode::HeapOutOfBounds => RuntimeError::Trap { + msg: "memory out-of-bounds access".into(), }, - TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds { - table: TableIndex::new(0), + TrapCode::TableOutOfBounds => RuntimeError::Trap { + msg: "table out-of-bounds access".into(), }, - _ => RuntimeError::Unknown { - msg: "unknown trap".to_string(), + _ => RuntimeError::Trap { + msg: "unknown trap".into(), }, }, - Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::OutOfBoundsAccess { - memory: MemoryIndex::new(0), - addr: None, + Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::Trap { + msg: "memory out-of-bounds access".into(), + }, + Ok(SIGFPE) => RuntimeError::Trap { + msg: "illegal arithmetic operation".into(), }, - Ok(SIGFPE) => RuntimeError::IllegalArithmeticOperation, _ => unimplemented!(), } .into()) @@ -126,8 +126,8 @@ pub fn call_protected(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R _ => "unkown trapped signal", }; // When the trap-handler is fully implemented, this will return more information. - Err(RuntimeError::Unknown { - msg: format!("trap at {:p} - {}", faulting_addr, signal), + Err(RuntimeError::Trap { + msg: format!("unknown trap at {:p} - {}", faulting_addr, signal).into(), } .into()) } diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index e88383800b2..17266f2a572 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -12,7 +12,7 @@ use crate::{ module::ModuleInfo, sys::Memory, }; -use std::ptr::NonNull; +use std::{any::Any, ptr::NonNull}; pub mod sys { pub use crate::sys::*; @@ -78,7 +78,7 @@ pub trait ProtectedCaller: Send + Sync { } pub trait UserTrapper { - unsafe fn do_early_trap(&self, msg: String) -> !; + unsafe fn do_early_trap(&self, data: Box) -> !; } pub trait FuncResolver: Send + Sync { diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index 0e2ab6eb773..f1291448fc8 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -1,8 +1,9 @@ use crate::types::{ FuncSig, GlobalDescriptor, MemoryDescriptor, MemoryIndex, TableDescriptor, TableIndex, Type, + Value, }; use core::borrow::Borrow; -use std::sync::Arc; +use std::{any::Any, sync::Arc}; pub type Result = std::result::Result; pub type CompileResult = std::result::Result; @@ -120,28 +121,11 @@ impl std::error::Error for LinkError {} /// The main way to do this is `Instance.call`. /// /// Comparing two `RuntimeError`s always evaluates to false. -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum RuntimeError { - OutOfBoundsAccess { - memory: MemoryIndex, - addr: Option, - }, - TableOutOfBounds { - table: TableIndex, - }, - IndirectCallSignature { - table: TableIndex, - }, - IndirectCallToNull { - table: TableIndex, - }, - IllegalArithmeticOperation, - User { - msg: String, - }, - Unknown { - msg: String, - }, + Trap { msg: Box }, + Exception { data: Box<[Value]> }, + Panic { data: Box }, } impl PartialEq for RuntimeError { @@ -153,30 +137,13 @@ impl PartialEq for RuntimeError { impl std::fmt::Display for RuntimeError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - RuntimeError::IndirectCallSignature { table } => write!( - f, - "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::OutOfBoundsAccess { memory, addr } => match addr { - 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::Trap { ref msg } => { + write!(f, "WebAssembly trap occured during runtime: {}", msg) } - RuntimeError::Unknown { msg } => { - write!(f, "Unknown runtime error with message: \"{}\"", msg) + RuntimeError::Exception { ref data } => { + write!(f, "Uncaught WebAssembly exception: {:?}", data) } - RuntimeError::User { msg } => write!(f, "User runtime error with message: \"{}\"", msg), + RuntimeError::Panic { data: _ } => write!(f, "User-defined \"panic\""), } } } @@ -239,7 +206,7 @@ impl std::error::Error for ResolveError {} /// be the `CallError::Runtime(RuntimeError)` variant. /// /// Comparing two `CallError`s always evaluates to false. -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum CallError { Resolve(ResolveError), Runtime(RuntimeError), @@ -298,7 +265,7 @@ impl std::error::Error for CreationError {} /// of a webassembly module. /// /// Comparing two `Error`s always evaluates to false. -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum Error { CompileError(CompileError), LinkError(Vec), diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 6e59d0d4acf..6e2a4d26c7b 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -6,7 +6,7 @@ use crate::{ types::{FuncSig, Type, WasmExternType}, 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! { pub static EARLY_TRAPPER: UnsafeCell>> = UnsafeCell::new(None); @@ -40,14 +40,14 @@ pub trait TrapEarly where Rets: WasmTypeList, { - fn report(self) -> Result; + fn report(self) -> Result>; } impl TrapEarly for Rets where Rets: WasmTypeList, { - fn report(self) -> Result { + fn report(self) -> Result> { Ok(self) } } @@ -55,10 +55,10 @@ where impl TrapEarly for Result where Rets: WasmTypeList, - E: fmt::Debug, + E: Any, { - fn report(self) -> Result { - self.map_err(|err| format!("Error: {:?}", err)) + fn report(self) -> Result> { + self.map_err(|err| Box::new(err) as Box) } } @@ -191,25 +191,17 @@ macro_rules! impl_traits { extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: $x )* ) -> Rets::CStruct { 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() })) { Ok(Ok(returns)) => return returns.into_c_struct(), Ok(Err(err)) => err, - Err(err) => { - if let Some(s) = err.downcast_ref::<&str>() { - s.to_string() - } else if let Some(s) = err.downcast_ref::() { - s.clone() - } else { - "a panic occurred, but no additional information is available".to_string() - } - }, + Err(err) => err, }; unsafe { if let Some(early_trapper) = &*EARLY_TRAPPER.with(|ucell| ucell.get()) { - early_trapper.do_early_trap(msg) + early_trapper.do_early_trap(err) } else { eprintln!("panic handling not setup"); std::process::exit(1) From c0cb2e3ffb5a4cb5dac2ae059dd4cf878b95c5c1 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Mon, 4 Mar 2019 11:34:07 -0800 Subject: [PATCH 2/5] Fix spectests to work with new runtime error type --- lib/spectests/build/spectests.rs | 2 +- lib/spectests/tests/semantics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/spectests/build/spectests.rs b/lib/spectests/build/spectests.rs index 54d9404d6dc..01e9c52dc83 100644 --- a/lib/spectests/build/spectests.rs +++ b/lib/spectests/build/spectests.rs @@ -568,7 +568,7 @@ fn {}_assert_malformed() {{ let assertion = if expected.len() > 0 && is_nan(&expected[0]) { format!( "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_eq!((*result as {return_type}).is_sign_positive(), (expected as {return_type}).is_sign_positive()); }} else {{ diff --git a/lib/spectests/tests/semantics.rs b/lib/spectests/tests/semantics.rs index c364dca29b5..0bffa9dcaa6 100644 --- a/lib/spectests/tests/semantics.rs +++ b/lib/spectests/tests/semantics.rs @@ -31,7 +31,7 @@ mod tests { match result { Err(err) => match err { - CallError::Runtime(RuntimeError::Unknown { msg }) => { + CallError::Runtime(RuntimeError::Trap { msg }) => { assert!(!msg.contains("segmentation violation")); assert!(!msg.contains("bus error")); } From b79254e6bedb56e0822d47d2b5df3d4a9aa6e865 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Mon, 4 Mar 2019 11:48:38 -0800 Subject: [PATCH 3/5] Fix windows signal handler in the clif-backend --- lib/clif-backend/src/signal/windows.rs | 41 +++++++++++++------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/clif-backend/src/signal/windows.rs b/lib/clif-backend/src/signal/windows.rs index 191085d915d..1cb3e1066e7 100644 --- a/lib/clif-backend/src/signal/windows.rs +++ b/lib/clif-backend/src/signal/windows.rs @@ -57,35 +57,34 @@ pub fn call_protected( }) = handler_data.lookup(instruction_pointer as _) { Err(match signum as DWORD { - EXCEPTION_ACCESS_VIOLATION => RuntimeError::OutOfBoundsAccess { - memory: MemoryIndex::new(0), - addr: None, + EXCEPTION_ACCESS_VIOLATION => RuntimeError::Trap { + msg: "memory out-of-bounds access".into(), }, EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode { - TrapCode::BadSignature => RuntimeError::IndirectCallSignature { - table: TableIndex::new(0), + TrapCode::BadSignature => RuntimeError::Trap { + msg: "incorrect call_indirect signature".into(), }, - TrapCode::IndirectCallToNull => RuntimeError::IndirectCallToNull { - table: TableIndex::new(0), + TrapCode::IndirectCallToNull => RuntimeError::Trap { + msg: "indirect call to null".into(), }, - TrapCode::HeapOutOfBounds => RuntimeError::OutOfBoundsAccess { - memory: MemoryIndex::new(0), - addr: None, + TrapCode::HeapOutOfBounds => RuntimeError::Trap { + msg: "memory out-of-bounds access".into(), }, - TrapCode::TableOutOfBounds => RuntimeError::TableOutOfBounds { - table: TableIndex::new(0), + TrapCode::TableOutOfBounds => RuntimeError::Trap { + msg: "table out-of-bounds access".into(), }, - _ => RuntimeError::Unknown { - msg: "unknown trap".to_string(), + _ => RuntimeError::Trap { + msg: "unknown trap".into(), }, }, EXCEPTION_STACK_OVERFLOW => RuntimeError::Unknown { - msg: "unknown trap".to_string(), + msg: "stack overflow trap".to_string(), }, - EXCEPTION_INT_DIVIDE_BY_ZERO => RuntimeError::IllegalArithmeticOperation, - EXCEPTION_INT_OVERFLOW => RuntimeError::IllegalArithmeticOperation, - _ => RuntimeError::Unknown { - msg: "unknown trap".to_string(), + EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => RuntimeError::Trap { + msg: "illegal arithmetic operation".into(), + }, + _ => RuntimeError::Trap { + msg: "unknown trap".into(), }, } .into()) @@ -103,8 +102,8 @@ pub fn call_protected( _ => "unkown trapped signal", }; - Err(RuntimeError::Unknown { - msg: format!("trap at {} - {}", exception_address, signal), + Err(RuntimeError::Trap { + msg: format!("unknown trap at {} - {}", exception_address, signal), } .into()) } From dfebecfa04f2bc5d033f81feb7e42003626dbe14 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Mon, 4 Mar 2019 11:53:46 -0800 Subject: [PATCH 4/5] Add missing conversion --- lib/clif-backend/src/signal/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/clif-backend/src/signal/windows.rs b/lib/clif-backend/src/signal/windows.rs index 1cb3e1066e7..62a40860e15 100644 --- a/lib/clif-backend/src/signal/windows.rs +++ b/lib/clif-backend/src/signal/windows.rs @@ -103,7 +103,7 @@ pub fn call_protected( }; Err(RuntimeError::Trap { - msg: format!("unknown trap at {} - {}", exception_address, signal), + msg: format!("unknown trap at {} - {}", exception_address, signal).into(), } .into()) } From 44538678fd7635cec62305120ec336980f9d8d74 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Mon, 4 Mar 2019 11:57:33 -0800 Subject: [PATCH 5/5] final windows fix --- lib/clif-backend/src/signal/windows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/clif-backend/src/signal/windows.rs b/lib/clif-backend/src/signal/windows.rs index 62a40860e15..e5bd41994cc 100644 --- a/lib/clif-backend/src/signal/windows.rs +++ b/lib/clif-backend/src/signal/windows.rs @@ -77,8 +77,8 @@ pub fn call_protected( msg: "unknown trap".into(), }, }, - EXCEPTION_STACK_OVERFLOW => RuntimeError::Unknown { - msg: "stack overflow trap".to_string(), + EXCEPTION_STACK_OVERFLOW => RuntimeError::Trap { + msg: "stack overflow trap".into(), }, EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => RuntimeError::Trap { msg: "illegal arithmetic operation".into(),