Hook up error propagation

This commit is contained in:
Lachlan Sneff
2019-04-22 15:06:40 -07:00
parent a42b7d3815
commit 706ddabf61
13 changed files with 185 additions and 124 deletions

View File

@ -27,6 +27,11 @@ thread_local! {
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any>>> = Cell::new(None);
}
pub enum RunErr {
Trap(WasmTrapInfo),
Error(Box<dyn Any>),
}
pub struct Caller {
handler_data: HandlerData,
trampolines: Arc<Trampolines>,
@ -59,7 +64,8 @@ impl RunnableModule for Caller {
func: NonNull<vm::Func>,
args: *const u64,
rets: *mut u64,
_trap_info: *mut WasmTrapInfo,
trap_info: *mut WasmTrapInfo,
user_error: *mut Option<Box<dyn Any>>,
invoke_env: Option<NonNull<c_void>>,
) -> bool {
let handler_data = &*invoke_env.unwrap().cast().as_ptr();
@ -68,14 +74,22 @@ impl RunnableModule for Caller {
let res = call_protected(handler_data, || {
// Leap of faith.
trampoline(ctx, func, args, rets);
})
.is_ok();
});
// the trampoline is called from C on windows
#[cfg(target_os = "windows")]
let res = call_protected(handler_data, trampoline, ctx, func, args, rets).is_ok();
let res = call_protected(handler_data, trampoline, ctx, func, args, rets);
res
match res {
Err(err) => {
match err {
RunErr::Trap(info) => *trap_info = info,
RunErr::Error(data) => *user_error = Some(data),
}
false
}
Ok(()) => true,
}
}
let trampoline = self

View File

@ -10,7 +10,7 @@
//! unless you have memory unsafety elsewhere in your code.
//!
use crate::relocation::{TrapCode, TrapData};
use crate::signal::HandlerData;
use crate::signal::{HandlerData, RunErr};
use libc::{c_int, c_void, siginfo_t};
use nix::sys::signal::{
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
@ -18,7 +18,7 @@ use nix::sys::signal::{
use std::cell::{Cell, UnsafeCell};
use std::ptr;
use std::sync::Once;
use wasmer_runtime_core::error::{RuntimeError, RuntimeResult};
use wasmer_runtime_core::typed_func::WasmTrapInfo;
extern "C" fn signal_trap_handler(
signum: ::nix::libc::c_int,
@ -62,7 +62,7 @@ pub unsafe fn trigger_trap() -> ! {
longjmp(jmp_buf as *mut c_void, 0)
}
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult<T> {
pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> Result<T, RunErr> {
unsafe {
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
let prev_jmp_buf = *jmp_buf;
@ -76,7 +76,7 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
*jmp_buf = prev_jmp_buf;
if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
Err(RuntimeError::Error { data })
Err(RunErr::Error(data))
} else {
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());
@ -85,33 +85,18 @@ pub fn call_protected<T>(handler_data: &HandlerData, f: impl FnOnce() -> T) -> R
srcloc: _,
}) = handler_data.lookup(inst_ptr)
{
Err(match Signal::from_c_int(signum) {
Err(RunErr::Trap(match Signal::from_c_int(signum) {
Ok(SIGILL) => match trapcode {
TrapCode::BadSignature => RuntimeError::Trap {
msg: "incorrect call_indirect signature".into(),
},
TrapCode::IndirectCallToNull => RuntimeError::Trap {
msg: "indirect call to null".into(),
},
TrapCode::HeapOutOfBounds => RuntimeError::Trap {
msg: "memory out-of-bounds access".into(),
},
TrapCode::TableOutOfBounds => RuntimeError::Trap {
msg: "table out-of-bounds access".into(),
},
_ => RuntimeError::Trap {
msg: "unknown trap".into(),
},
},
Ok(SIGSEGV) | Ok(SIGBUS) => RuntimeError::Trap {
msg: "memory out-of-bounds access".into(),
},
Ok(SIGFPE) => RuntimeError::Trap {
msg: "illegal arithmetic operation".into(),
TrapCode::BadSignature => WasmTrapInfo::IncorrectCallIndirectSignature,
TrapCode::IndirectCallToNull => WasmTrapInfo::CallIndirectOOB,
TrapCode::HeapOutOfBounds => WasmTrapInfo::MemoryOutOfBounds,
TrapCode::TableOutOfBounds => WasmTrapInfo::CallIndirectOOB,
_ => WasmTrapInfo::Unknown,
},
Ok(SIGSEGV) | Ok(SIGBUS) => WasmTrapInfo::MemoryOutOfBounds,
Ok(SIGFPE) => WasmTrapInfo::IllegalArithmetic,
_ => unimplemented!(),
}
.into())
}))
} else {
let signal = match Signal::from_c_int(signum) {
Ok(SIGFPE) => "floating-point exception",
@ -122,10 +107,8 @@ pub fn call_protected<T>(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::Trap {
msg: format!("unknown trap at {:p} - {}", faulting_addr, signal).into(),
}
.into())
let s = format!("unknown trap at {:p} - {}", faulting_addr, signal);
Err(RunErr::Error(Box::new(s)))
}
}
} else {

View File

@ -1,10 +1,11 @@
use crate::relocation::{TrapCode, TrapData};
use crate::signal::HandlerData;
use crate::signal::{HandlerData, RunErr};
use crate::trampoline::Trampoline;
use std::cell::Cell;
use std::ffi::c_void;
use std::ptr::{self, NonNull};
use wasmer_runtime_core::error::{RuntimeError, RuntimeResult};
use wasmer_runtime_core::typed_func::WasmTrapInfo;
use wasmer_runtime_core::vm::Ctx;
use wasmer_runtime_core::vm::Func;
use wasmer_win_exception_handler::CallProtectedData;
@ -28,7 +29,7 @@ pub fn call_protected(
func: NonNull<Func>,
param_vec: *const u64,
return_vec: *mut u64,
) -> RuntimeResult<()> {
) -> Result<(), RunErr> {
// TODO: trap early
// user code error
// if let Some(msg) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
@ -52,38 +53,22 @@ pub fn call_protected(
srcloc: _,
}) = handler_data.lookup(instruction_pointer as _)
{
Err(match signum as DWORD {
EXCEPTION_ACCESS_VIOLATION => RuntimeError::Trap {
msg: "memory out-of-bounds access".into(),
},
Err(RunErr::Trap(match signum as DWORD {
EXCEPTION_ACCESS_VIOLATION => WasmTrapInfo::MemoryOutOfBounds,
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
TrapCode::BadSignature => RuntimeError::Trap {
msg: "incorrect call_indirect signature".into(),
},
TrapCode::IndirectCallToNull => RuntimeError::Trap {
msg: "indirect call to null".into(),
},
TrapCode::HeapOutOfBounds => RuntimeError::Trap {
msg: "memory out-of-bounds access".into(),
},
TrapCode::TableOutOfBounds => RuntimeError::Trap {
msg: "table out-of-bounds access".into(),
},
_ => RuntimeError::Trap {
msg: "unknown trap".into(),
},
TrapCode::BadSignature => WasmTrapInfo::IncorrectCallIndirectSignature,
TrapCode::IndirectCallToNull => WasmTrapInfo::CallIndirectOOB,
TrapCode::HeapOutOfBounds => WasmTrapInfo::MemoryOutOfBounds,
TrapCode::TableOutOfBounds => WasmTrapInfo::CallIndirectOOB,
TrapCode::UnreachableCodeReached => WasmTrapInfo::Unreachable,
_ => WasmTrapInfo::Unknown,
},
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(),
},
_ => RuntimeError::Trap {
msg: "unknown trap".into(),
},
}
.into())
EXCEPTION_STACK_OVERFLOW => WasmTrapInfo::Unknown,
EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => {
WasmTrapInfo::IllegalArithmetic
}
_ => WasmTrapInfo::Unknown,
}))
} else {
let signal = match signum as DWORD {
EXCEPTION_FLT_DENORMAL_OPERAND
@ -98,10 +83,9 @@ pub fn call_protected(
_ => "unkown trapped signal",
};
Err(RuntimeError::Trap {
msg: format!("unknown trap at {} - {}", exception_address, signal).into(),
}
.into())
let s = format!("unknown trap at {} - {}", exception_address, signal);
Err(RunErr::Error(Box::new(s)))
}
}