Define runtime error values explicitly in Singlepass

This commit is contained in:
Mark McCaskey 2020-04-24 13:21:45 -07:00
parent bfb6814f23
commit b9ec8f9845
12 changed files with 129 additions and 102 deletions

View File

@ -1,12 +1,12 @@
use crate::{ use crate::{
relocation::{TrapData, TrapSink, TrapCode}, relocation::{TrapData, TrapSink},
resolver::FuncResolver, resolver::FuncResolver,
trampoline::Trampolines, trampoline::Trampolines,
}; };
use libc::c_void; use libc::c_void;
use std::{any::Any, cell::Cell, ptr::NonNull, sync::Arc}; use std::{cell::Cell, ptr::NonNull, sync::Arc};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::{RunnableModule, ExceptionCode}, backend::RunnableModule,
error::{InvokeError, RuntimeError}, error::{InvokeError, RuntimeError},
module::ModuleInfo, module::ModuleInfo,
typed_func::{Trampoline, Wasm}, typed_func::{Trampoline, Wasm},
@ -30,23 +30,6 @@ thread_local! {
pub static TRAP_EARLY_DATA: Cell<Option<RuntimeError>> = Cell::new(None); pub static TRAP_EARLY_DATA: Cell<Option<RuntimeError>> = Cell::new(None);
} }
pub enum CallProtError {
UnknownTrap {
address: usize,
signal: &'static str,
},
TrapCode {
code: ExceptionCode,
srcloc: u32,
},
UnknownTrapCode {
trap_code: TrapCode,
srcloc: u32,
},
EarlyTrap(RuntimeError),
Misc(Box<dyn Any + Send>),
}
pub struct Caller { pub struct Caller {
handler_data: HandlerData, handler_data: HandlerData,
trampolines: Arc<Trampolines>, trampolines: Arc<Trampolines>,
@ -99,7 +82,7 @@ impl RunnableModule for Caller {
// probably makes the most sense to actually do a translation here to a // probably makes the most sense to actually do a translation here to a
// a generic type defined in runtime-core // a generic type defined in runtime-core
// TODO: figure out _this_ error return story // TODO: figure out _this_ error return story
*error_out = Some(err.0); *error_out = Some(err);
false false
} }
Ok(()) => true, Ok(()) => true,

View File

@ -10,7 +10,7 @@
//! unless you have memory unsafety elsewhere in your code. //! unless you have memory unsafety elsewhere in your code.
//! //!
use crate::relocation::{TrapCode, TrapData}; use crate::relocation::{TrapCode, TrapData};
use crate::signal::{CallProtError, HandlerData}; use crate::signal::HandlerData;
use libc::{c_int, c_void, siginfo_t}; use libc::{c_int, c_void, siginfo_t};
use nix::sys::signal::{ use nix::sys::signal::{
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV, sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
@ -19,6 +19,7 @@ use std::cell::{Cell, UnsafeCell};
use std::ptr; use std::ptr;
use std::sync::Once; use std::sync::Once;
use wasmer_runtime_core::backend::ExceptionCode; use wasmer_runtime_core::backend::ExceptionCode;
use wasmer_runtime_core::error::InvokeError;
extern "C" fn signal_trap_handler( extern "C" fn signal_trap_handler(
signum: ::nix::libc::c_int, signum: ::nix::libc::c_int,
@ -65,7 +66,7 @@ pub unsafe fn trigger_trap() -> ! {
pub fn call_protected<T>( pub fn call_protected<T>(
handler_data: &HandlerData, handler_data: &HandlerData,
f: impl FnOnce() -> T, f: impl FnOnce() -> T,
) -> Result<T, CallProtError> { ) -> Result<T, InvokeError> {
unsafe { unsafe {
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get()); let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
let prev_jmp_buf = *jmp_buf; let prev_jmp_buf = *jmp_buf;
@ -79,15 +80,11 @@ pub fn call_protected<T>(
*jmp_buf = prev_jmp_buf; *jmp_buf = prev_jmp_buf;
if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) { if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
Err(CallProtError::EarlyTrap(data)) Err(InvokeError::EarlyTrap(Box::new(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());
if let Some(TrapData { if let Some(TrapData { trapcode, srcloc }) = handler_data.lookup(inst_ptr) {
trapcode,
srcloc,
}) = handler_data.lookup(inst_ptr)
{
let code = match Signal::from_c_int(signum) { let code = match Signal::from_c_int(signum) {
Ok(SIGILL) => match trapcode { Ok(SIGILL) => match trapcode {
TrapCode::StackOverflow => ExceptionCode::MemoryOutOfBounds, TrapCode::StackOverflow => ExceptionCode::MemoryOutOfBounds,
@ -101,8 +98,8 @@ pub fn call_protected<T>(
TrapCode::BadConversionToInteger => ExceptionCode::IllegalArithmetic, TrapCode::BadConversionToInteger => ExceptionCode::IllegalArithmetic,
TrapCode::UnreachableCodeReached => ExceptionCode::Unreachable, TrapCode::UnreachableCodeReached => ExceptionCode::Unreachable,
_ => { _ => {
return Err(CallProtError::UnknownTrapCode { return Err(InvokeError::UnknownTrapCode {
trap_code: trapcode, trap_code: format!("{:?}", trapcode),
srcloc, srcloc,
}) })
} }
@ -114,10 +111,7 @@ pub fn call_protected<T>(
Signal::from_c_int(signum) Signal::from_c_int(signum)
), ),
}; };
Err(CallProtError::TrapCode { Err(InvokeError::TrapCode { srcloc, code })
srcloc,
code,
})
} else { } else {
let signal = match Signal::from_c_int(signum) { let signal = match Signal::from_c_int(signum) {
Ok(SIGFPE) => "floating-point exception", Ok(SIGFPE) => "floating-point exception",
@ -128,7 +122,7 @@ pub fn call_protected<T>(
_ => "unknown trapped signal", _ => "unknown 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(CallProtError::UnknownTrap { Err(InvokeError::UnknownTrap {
address: faulting_addr as usize, address: faulting_addr as usize,
signal, signal,
}) })

View File

@ -11,7 +11,6 @@ use inkwell::{
}; };
use libc::c_char; use libc::c_char;
use std::{ use std::{
any::Any,
cell::RefCell, cell::RefCell,
ffi::{c_void, CString}, ffi::{c_void, CString},
mem, mem,
@ -27,6 +26,7 @@ use wasmer_runtime_core::{
CacheGen, ExceptionCode, RunnableModule, CacheGen, ExceptionCode, RunnableModule,
}, },
cache::Error as CacheError, cache::Error as CacheError,
error::{InvokeError, RuntimeError},
module::ModuleInfo, module::ModuleInfo,
state::ModuleStateMap, state::ModuleStateMap,
structures::TypedIndex, structures::TypedIndex,
@ -56,7 +56,7 @@ extern "C" {
/// but this is cleaner, I think? /// but this is cleaner, I think?
#[cfg_attr(nightly, unwind(allowed))] #[cfg_attr(nightly, unwind(allowed))]
#[allow(improper_ctypes)] #[allow(improper_ctypes)]
fn throw_any(data: *mut dyn Any) -> !; fn throw_runtime_error(data: RuntimeError) -> !;
#[allow(improper_ctypes)] #[allow(improper_ctypes)]
fn cxx_invoke_trampoline( fn cxx_invoke_trampoline(
@ -66,7 +66,7 @@ extern "C" {
params: *const u64, params: *const u64,
results: *mut u64, results: *mut u64,
trap_out: *mut i32, trap_out: *mut i32,
error_out: *mut Option<Box<dyn Any + Send>>, error_out: *mut Option<InvokeError>,
invoke_env: Option<NonNull<c_void>>, invoke_env: Option<NonNull<c_void>>,
) -> bool; ) -> bool;
} }
@ -79,7 +79,7 @@ unsafe extern "C" fn invoke_trampoline(
func_ptr: NonNull<vm::Func>, func_ptr: NonNull<vm::Func>,
params: *const u64, params: *const u64,
results: *mut u64, results: *mut u64,
error_out: *mut Option<Box<dyn Any + Send>>, error_out: *mut Option<InvokeError>,
invoke_env: Option<NonNull<c_void>>, invoke_env: Option<NonNull<c_void>>,
) -> bool { ) -> bool {
let mut trap_out: i32 = -1; let mut trap_out: i32 = -1;
@ -95,15 +95,22 @@ unsafe extern "C" fn invoke_trampoline(
); );
// Translate trap code if an error occurred. // Translate trap code if an error occurred.
if !ret && (*error_out).is_none() && trap_out != -1 { if !ret && (*error_out).is_none() && trap_out != -1 {
*error_out = Some(Box::new(match trap_out { *error_out = {
0 => ExceptionCode::Unreachable, let exception_code = match trap_out {
1 => ExceptionCode::IncorrectCallIndirectSignature, 0 => ExceptionCode::Unreachable,
2 => ExceptionCode::MemoryOutOfBounds, 1 => ExceptionCode::IncorrectCallIndirectSignature,
3 => ExceptionCode::CallIndirectOOB, 2 => ExceptionCode::MemoryOutOfBounds,
4 => ExceptionCode::IllegalArithmetic, 3 => ExceptionCode::CallIndirectOOB,
5 => ExceptionCode::MisalignedAtomicAccess, 4 => ExceptionCode::IllegalArithmetic,
_ => return ret, 5 => ExceptionCode::MisalignedAtomicAccess,
})); _ => return ret,
};
Some(InvokeError::TrapCode {
code: exception_code,
// TODO:
srcloc: 0,
})
};
} }
ret ret
} }
@ -467,8 +474,9 @@ impl RunnableModule for LLVMBackend {
self.msm.clone() self.msm.clone()
} }
unsafe fn do_early_trap(&self, data: Box<dyn Any + Send>) -> ! { unsafe fn do_early_trap(&self, data: RuntimeError) -> ! {
throw_any(Box::leak(data)) // maybe need to box leak it?
throw_runtime_error(data)
} }
} }

View File

@ -1,5 +1,6 @@
use wasmer_runtime_core::{ use wasmer_runtime_core::{
codegen::{Event, EventSink, FunctionMiddleware, InternalEvent}, codegen::{Event, EventSink, FunctionMiddleware, InternalEvent},
error::RuntimeError,
module::ModuleInfo, module::ModuleInfo,
vm::{Ctx, InternalField}, vm::{Ctx, InternalField},
wasmparser::{Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType}, wasmparser::{Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType},
@ -96,7 +97,7 @@ impl FunctionMiddleware for Metering {
ty: WpTypeOrFuncType::Type(WpType::EmptyBlockType), ty: WpTypeOrFuncType::Type(WpType::EmptyBlockType),
})); }));
sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new(|_| { sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new(|_| {
Err(Box::new(ExecutionLimitExceededError)) Err(RuntimeError::Metering(Box::new(ExecutionLimitExceededError)))
})))); }))));
sink.push(Event::WasmOwned(Operator::End)); sink.push(Event::WasmOwned(Operator::End));
} }

View File

@ -6,13 +6,12 @@ use crate::{
backend::RunnableModule, backend::RunnableModule,
backend::{CacheGen, Compiler, CompilerConfig, Features, Token}, backend::{CacheGen, Compiler, CompilerConfig, Features, Token},
cache::{Artifact, Error as CacheError}, cache::{Artifact, Error as CacheError},
error::{CompileError, CompileResult}, error::{CompileError, CompileResult, RuntimeError},
module::{ModuleInfo, ModuleInner}, module::{ModuleInfo, ModuleInner},
structures::Map, structures::Map,
types::{FuncIndex, FuncSig, SigIndex}, types::{FuncIndex, FuncSig, SigIndex},
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
use std::any::Any;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
@ -23,7 +22,7 @@ use wasmparser::{Operator, Type as WpType};
/// A type that defines a function pointer, which is called when breakpoints occur. /// A type that defines a function pointer, which is called when breakpoints occur.
pub type BreakpointHandler = pub type BreakpointHandler =
Box<dyn Fn(BreakpointInfo) -> Result<(), Box<dyn Any + Send>> + Send + Sync + 'static>; Box<dyn Fn(BreakpointInfo) -> Result<(), RuntimeError> + Send + Sync + 'static>;
/// Maps instruction pointers to their breakpoint handlers. /// Maps instruction pointers to their breakpoint handlers.
pub type BreakpointMap = Arc<HashMap<usize, BreakpointHandler>>; pub type BreakpointMap = Arc<HashMap<usize, BreakpointHandler>>;

View File

@ -1,6 +1,6 @@
//! The error module contains the data structures and helper functions used to implement errors that //! The error module contains the data structures and helper functions used to implement errors that
//! are produced and returned from the wasmer runtime core. //! are produced and returned from the wasmer runtime core.
//use crate::backend::ExceptionCode; use crate::backend::ExceptionCode;
use crate::types::{FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor, Type}; use crate::types::{FuncSig, GlobalDescriptor, MemoryDescriptor, TableDescriptor, Type};
use core::borrow::Borrow; use core::borrow::Borrow;
use std::any::Any; use std::any::Any;
@ -222,31 +222,63 @@ impl std::error::Error for RuntimeError {}
/// extremely rare and impossible to handle. /// extremely rare and impossible to handle.
#[derive(Debug)] #[derive(Debug)]
pub enum RuntimeError { pub enum RuntimeError {
/// When an invoke returns an error (this is where exception codes come from?) /// When an invoke returns an error
InvokeError(InvokeError), InvokeError(InvokeError),
/// A metering triggered error value.
///
/// An error of this type indicates that it was returned by the metering system.
Metering(Box<dyn Any + Send>),
/// A user triggered error value. /// A user triggered error value.
/// ///
/// An error returned from a host function. /// An error returned from a host function.
User(Box<dyn Any + Send>) User(Box<dyn Any + Send>),
} }
/// TODO: /// TODO:
#[derive(Debug)] #[derive(Debug)]
pub enum InvokeError { pub enum InvokeError {
/// not yet handled error cases, ideally we should be able to handle them all
Misc(Box<dyn Any + Send>),
/// Indicates an exceptional circumstance such as a bug that should be reported or /// Indicates an exceptional circumstance such as a bug that should be reported or
/// a hardware failure. /// a hardware failure.
FailedWithNoError, FailedWithNoError,
/// TODO:
UnknownTrap {
/// TODO:
address: usize,
/// TODO:
signal: &'static str,
},
/// TODO:
TrapCode {
/// TODO:
code: ExceptionCode,
/// TODO:
srcloc: u32,
},
/// TODO:
UnknownTrapCode {
/// TODO:
trap_code: String,
/// TODO:
srcloc: u32,
},
/// extra TODO: investigate if this can be a `Box<InvokeError>` instead (looks like probably no)
/// TODO:
EarlyTrap(Box<RuntimeError>),
/// Indicates an error that ocurred related to breakpoints. (currently Singlepass only)
Breakpoint(Box<RuntimeError>),
} }
//impl std::error::Error for InvokeError {}
impl std::error::Error for RuntimeError {} impl std::error::Error 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 {
// TODO: ideally improve the error type of invoke // TODO: update invoke error formatting
RuntimeError::InvokeError(_) => write!(f, "Error when calling invoke"), RuntimeError::InvokeError(_) => write!(f, "Error when calling invoke"),
RuntimeError::Metering(_) => write!(f, "unknown metering error type"),
RuntimeError::User(user_error) => { RuntimeError::User(user_error) => {
write!(f, "User supplied error: ")?; write!(f, "User supplied error: ")?;
if let Some(s) = user_error.downcast_ref::<String>() { if let Some(s) = user_error.downcast_ref::<String>() {
@ -256,9 +288,9 @@ impl std::fmt::Display for RuntimeError {
} else if let Some(n) = user_error.downcast_ref::<i32>() { } else if let Some(n) = user_error.downcast_ref::<i32>() {
write!(f, "{}", n) write!(f, "{}", n)
} else { } else {
write!(f, "unknown error type") write!(f, "unknown user error type")
} }
}, }
} }
} }
} }
@ -270,8 +302,6 @@ impl From<InternalError> for RuntimeError {
} }
} }
*/ */
/// This error type is produced by resolving a wasm function /// This error type is produced by resolving a wasm function
/// given its name. /// given its name.

View File

@ -29,14 +29,14 @@ pub mod raw {
use crate::codegen::{BreakpointInfo, BreakpointMap}; use crate::codegen::{BreakpointInfo, BreakpointMap};
use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR}; use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR};
use crate::state::{CodeVersion, ExecutionStateImage}; use crate::state::{CodeVersion, ExecutionStateImage, InstanceImage};
use crate::error::{RuntimeError, InvokeError};
use crate::vm; use crate::vm;
use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE}; use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
use nix::sys::signal::{ use nix::sys::signal::{
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGINT, sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGINT,
SIGSEGV, SIGTRAP, SIGSEGV, SIGTRAP,
}; };
use std::any::Any;
use std::cell::{Cell, RefCell, UnsafeCell}; use std::cell::{Cell, RefCell, UnsafeCell};
use std::ffi::c_void; use std::ffi::c_void;
use std::process; use std::process;
@ -61,7 +61,7 @@ type SetJmpBuffer = [i32; SETJMP_BUFFER_LEN];
struct UnwindInfo { struct UnwindInfo {
jmpbuf: SetJmpBuffer, // in jmpbuf: SetJmpBuffer, // in
breakpoints: Option<BreakpointMap>, breakpoints: Option<BreakpointMap>,
payload: Option<Box<dyn Any + Send>>, // out payload: Option<RuntimeError>, // out
} }
/// A store for boundary register preservation. /// A store for boundary register preservation.
@ -182,7 +182,7 @@ pub unsafe fn clear_wasm_interrupt() {
pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>( pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
f: F, f: F,
breakpoints: Option<BreakpointMap>, breakpoints: Option<BreakpointMap>,
) -> Result<R, Box<dyn Any + Send>> { ) -> Result<R, RuntimeError> {
let unwind = UNWIND.with(|x| x.get()); let unwind = UNWIND.with(|x| x.get());
let old = (*unwind).take(); let old = (*unwind).take();
*unwind = Some(UnwindInfo { *unwind = Some(UnwindInfo {
@ -205,7 +205,7 @@ pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
} }
/// Begins an unsafe unwind. /// Begins an unsafe unwind.
pub unsafe fn begin_unsafe_unwind(e: Box<dyn Any + Send>) -> ! { pub unsafe fn begin_unsafe_unwind(e: RuntimeError) -> ! {
let unwind = UNWIND.with(|x| x.get()); let unwind = UNWIND.with(|x| x.get());
let inner = (*unwind) let inner = (*unwind)
.as_mut() .as_mut()
@ -279,7 +279,7 @@ extern "C" fn signal_trap_handler(
static ARCH: Architecture = Architecture::Aarch64; static ARCH: Architecture = Architecture::Aarch64;
let mut should_unwind = false; let mut should_unwind = false;
let mut unwind_result: Box<dyn Any + Send> = Box::new(()); let mut unwind_result: Option<Result<InstanceImage, RuntimeError>> = None;
unsafe { unsafe {
let fault = get_fault_info(siginfo as _, ucontext); let fault = get_fault_info(siginfo as _, ucontext);
@ -302,7 +302,7 @@ extern "C" fn signal_trap_handler(
) { ) {
match ib.ty { match ib.ty {
InlineBreakpointType::Middleware => { InlineBreakpointType::Middleware => {
let out: Option<Result<(), Box<dyn Any + Send>>> = let out: Option<Result<(), RuntimeError>> =
with_breakpoint_map(|bkpt_map| { with_breakpoint_map(|bkpt_map| {
bkpt_map.and_then(|x| x.get(&ip)).map(|x| { bkpt_map.and_then(|x| x.get(&ip)).map(|x| {
x(BreakpointInfo { x(BreakpointInfo {
@ -313,7 +313,7 @@ extern "C" fn signal_trap_handler(
if let Some(Ok(())) = out { if let Some(Ok(())) = out {
} else if let Some(Err(e)) = out { } else if let Some(Err(e)) = out {
should_unwind = true; should_unwind = true;
unwind_result = e; unwind_result = Some(Err(e));
} }
} }
} }
@ -328,7 +328,7 @@ extern "C" fn signal_trap_handler(
}) })
}); });
if should_unwind { if should_unwind {
begin_unsafe_unwind(unwind_result); begin_unsafe_unwind(unwind_result.unwrap().unwrap_err());
} }
if early_return { if early_return {
return; return;
@ -342,9 +342,9 @@ extern "C" fn signal_trap_handler(
match Signal::from_c_int(signum) { match Signal::from_c_int(signum) {
Ok(SIGTRAP) => { Ok(SIGTRAP) => {
// breakpoint // breakpoint
let out: Option<Result<(), Box<dyn Any + Send>>> = let out: Option<Result<(), RuntimeError>> =
with_breakpoint_map(|bkpt_map| { with_breakpoint_map(|bkpt_map| -> Option<Result<(), RuntimeError>> {
bkpt_map.and_then(|x| x.get(&(fault.ip.get()))).map(|x| { bkpt_map.and_then(|x| x.get(&(fault.ip.get()))).map(|x| -> Result<(), RuntimeError> {
x(BreakpointInfo { x(BreakpointInfo {
fault: Some(&fault), fault: Some(&fault),
}) })
@ -355,7 +355,7 @@ extern "C" fn signal_trap_handler(
return false; return false;
} }
Some(Err(e)) => { Some(Err(e)) => {
unwind_result = e; unwind_result = Some(Err(e));
return true; return true;
} }
None => {} None => {}
@ -387,7 +387,7 @@ extern "C" fn signal_trap_handler(
if is_suspend_signal { if is_suspend_signal {
// If this is a suspend signal, we parse the runtime state and return the resulting image. // If this is a suspend signal, we parse the runtime state and return the resulting image.
let image = build_instance_image(ctx, es_image); let image = build_instance_image(ctx, es_image);
unwind_result = Box::new(image); unwind_result = Some(Ok(image));
} else { } else {
// Otherwise, this is a real exception and we just throw it to the caller. // Otherwise, this is a real exception and we just throw it to the caller.
if !es_image.frames.is_empty() { if !es_image.frames.is_empty() {
@ -415,7 +415,11 @@ extern "C" fn signal_trap_handler(
None None
}); });
if let Some(code) = exc_code { if let Some(code) = exc_code {
unwind_result = Box::new(code); unwind_result = Some(Err(RuntimeError::InvokeError(InvokeError::TrapCode {
code,
// TODO:
srcloc: 0,
})));
} }
} }
@ -423,7 +427,7 @@ extern "C" fn signal_trap_handler(
}); });
if should_unwind { if should_unwind {
begin_unsafe_unwind(unwind_result); begin_unsafe_unwind(unwind_result.unwrap().unwrap_err());
} }
} }
} }

View File

@ -5,7 +5,7 @@
use crate::{ use crate::{
backend::RunnableModule, backend::RunnableModule,
backing::{ImportBacking, LocalBacking}, backing::{ImportBacking, LocalBacking},
error::{CallResult, ResolveError, ResolveResult, Result, RuntimeError, InvokeError}, error::{CallResult, InvokeError, ResolveError, ResolveResult, Result, RuntimeError},
export::{Context, Export, ExportIter, Exportable, FuncPointer}, export::{Context, Export, ExportIter, Exportable, FuncPointer},
global::Global, global::Global,
import::{ImportObject, LikeNamespace}, import::{ImportObject, LikeNamespace},
@ -587,15 +587,17 @@ pub(crate) fn call_func_with_index_inner(
let run_wasm = |result_space: *mut u64| -> CallResult<()> { let run_wasm = |result_space: *mut u64| -> CallResult<()> {
let mut error_out = None; let mut error_out = None;
let success = unsafe { invoke( let success = unsafe {
trampoline, invoke(
ctx_ptr, trampoline,
func_ptr, ctx_ptr,
raw_args.as_ptr(), func_ptr,
result_space, raw_args.as_ptr(),
&mut error_out, result_space,
invoke_env, &mut error_out,
)}; invoke_env,
)
};
if success { if success {
Ok(()) Ok(())

View File

@ -705,7 +705,7 @@ pub mod x64 {
use crate::structures::TypedIndex; use crate::structures::TypedIndex;
use crate::types::LocalGlobalIndex; use crate::types::LocalGlobalIndex;
use crate::vm::Ctx; use crate::vm::Ctx;
use std::any::Any; use crate::error::RuntimeError;
#[allow(clippy::cast_ptr_alignment)] #[allow(clippy::cast_ptr_alignment)]
unsafe fn compute_vmctx_deref(vmctx: *const Ctx, seq: &[usize]) -> u64 { unsafe fn compute_vmctx_deref(vmctx: *const Ctx, seq: &[usize]) -> u64 {
@ -738,7 +738,7 @@ pub mod x64 {
image: InstanceImage, image: InstanceImage,
vmctx: &mut Ctx, vmctx: &mut Ctx,
breakpoints: Option<BreakpointMap>, breakpoints: Option<BreakpointMap>,
) -> Result<u64, Box<dyn Any + Send>> { ) -> Result<u64, RuntimeError> {
let mut stack: Vec<u64> = vec![0; 1048576 * 8 / 8]; // 8MB stack let mut stack: Vec<u64> = vec![0; 1048576 * 8 / 8]; // 8MB stack
let mut stack_offset: usize = stack.len(); let mut stack_offset: usize = stack.len();

View File

@ -1,7 +1,7 @@
//! The typed func module implements a way of representing a wasm function //! The typed func module implements a way of representing a wasm function
//! with the correct types from rust. Function calls using a typed func have a low overhead. //! with the correct types from rust. Function calls using a typed func have a low overhead.
use crate::{ use crate::{
error::{RuntimeError, InvokeError}, error::{InvokeError, RuntimeError},
export::{Context, Export, FuncPointer}, export::{Context, Export, FuncPointer},
import::IsExport, import::IsExport,
types::{FuncSig, NativeWasmType, Type, WasmExternType}, types::{FuncSig, NativeWasmType, Type, WasmExternType},
@ -340,7 +340,9 @@ impl<'a> DynamicFunc<'a> {
Err(e) => { Err(e) => {
// At this point, there is an error that needs to be trapped. // At this point, there is an error that needs to be trapped.
drop(args); // Release the Vec which will leak otherwise. drop(args); // Release the Vec which will leak otherwise.
(&*vmctx.module).runnable_module.do_early_trap(RuntimeError::User(e)) (&*vmctx.module)
.runnable_module
.do_early_trap(RuntimeError::User(e))
} }
} }
} }

View File

@ -10,7 +10,6 @@ use dynasmrt::x64::Assembler;
use dynasmrt::{AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; use dynasmrt::{AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
any::Any,
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
ffi::c_void, ffi::c_void,
iter, mem, iter, mem,
@ -29,6 +28,7 @@ use wasmer_runtime_core::{
codegen::*, codegen::*,
fault::{self, raw::register_preservation_trampoline}, fault::{self, raw::register_preservation_trampoline},
loader::CodeMemory, loader::CodeMemory,
error::{InvokeError, RuntimeError},
memory::MemoryType, memory::MemoryType,
module::{ModuleInfo, ModuleInner}, module::{ModuleInfo, ModuleInner},
state::{ state::{
@ -214,7 +214,7 @@ pub struct X64FunctionCode {
breakpoints: Option< breakpoints: Option<
HashMap< HashMap<
AssemblyOffset, AssemblyOffset,
Box<dyn Fn(BreakpointInfo) -> Result<(), Box<dyn Any + Send>> + Send + Sync + 'static>, Box<dyn Fn(BreakpointInfo) -> Result<(), RuntimeError> + Send + Sync + 'static>,
>, >,
>, >,
returns: SmallVec<[WpType; 1]>, returns: SmallVec<[WpType; 1]>,
@ -507,7 +507,7 @@ impl RunnableModule for X64ExecutionContext {
func: NonNull<vm::Func>, func: NonNull<vm::Func>,
args: *const u64, args: *const u64,
rets: *mut u64, rets: *mut u64,
error_out: *mut Option<Box<dyn Any + Send>>, error_out: *mut Option<InvokeError>,
num_params_plus_one: Option<NonNull<c_void>>, num_params_plus_one: Option<NonNull<c_void>>,
) -> bool { ) -> bool {
let rm: &Box<dyn RunnableModule> = &(&*(*ctx).module).runnable_module; let rm: &Box<dyn RunnableModule> = &(&*(*ctx).module).runnable_module;
@ -655,7 +655,7 @@ impl RunnableModule for X64ExecutionContext {
true true
} }
Err(err) => { Err(err) => {
*error_out = Some(err); *error_out = Some(InvokeError::Breakpoint(Box::new(err)));
false false
} }
}; };
@ -680,7 +680,7 @@ impl RunnableModule for X64ExecutionContext {
}) })
} }
unsafe fn do_early_trap(&self, data: Box<dyn Any + Send>) -> ! { unsafe fn do_early_trap(&self, data: RuntimeError) -> ! {
fault::begin_unsafe_unwind(data); fault::begin_unsafe_unwind(data);
} }

View File

@ -20,6 +20,7 @@ use wasmer_runtime::{
}; };
use wasmer_runtime_core::{ use wasmer_runtime_core::{
self, self,
error::RuntimeError,
backend::{Compiler, CompilerConfig, MemoryBoundCheckMode}, backend::{Compiler, CompilerConfig, MemoryBoundCheckMode},
loader::{Instance as LoadedInstance, LocalLoader}, loader::{Instance as LoadedInstance, LocalLoader},
Module, Module,
@ -437,9 +438,12 @@ fn execute_wasi(
} }
if let Err(ref err) = result { if let Err(ref err) = result {
if let Some(error_code) = err.0.downcast_ref::<wasmer_wasi::ExitCode>() { if let RuntimeError::User(user_error) = err {
std::process::exit(error_code.code as i32) if let Some(error_code) = user_error.downcast_ref::<wasmer_wasi::ExitCode>() {
std::process::exit(error_code.code as i32)
}
} }
return Err(format!("error: {:?}", err)); return Err(format!("error: {:?}", err));
} }
} }