Fix new RuntimeError implementation for the Singlepass backend

This commit is contained in:
Mark McCaskey
2020-04-26 12:05:12 -07:00
parent 9723270f96
commit 89af5dc107
7 changed files with 73 additions and 49 deletions

View File

@ -213,27 +213,6 @@ impl std::error::Error for RuntimeError {}
*/
/// An `InternalError` is an error that happened inside of Wasmer and is a
/// catch-all for errors that would otherwise be returned as
/// `RuntimeError(Box::new(<string>))`.
///
/// This type provides greater visibility into the kinds of things that may fail
/// and improves the ability of users to handle them, though these errors may be
/// extremely rare and impossible to handle.
#[derive(Debug)]
pub enum RuntimeError {
/// When an invoke returns an error
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.
///
/// An error returned from a host function.
User(Box<dyn Any + Send>),
}
/// TODO:
#[derive(Debug)]
pub enum InvokeError {
@ -278,14 +257,39 @@ impl From<InvokeError> for RuntimeError {
}
}
//impl std::error::Error for InvokeError {}
/// An `InternalError` is an error that happened inside of Wasmer and is a
/// catch-all for errors that would otherwise be returned as
/// `RuntimeError(Box::new(<string>))`.
///
/// This type provides greater visibility into the kinds of things that may fail
/// and improves the ability of users to handle them, though these errors may be
/// extremely rare and impossible to handle.
#[derive(Debug)]
pub enum RuntimeError {
/// When an invoke returns an error
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 frozen state of Wasm used to pause and resume execution. Not strictly an
/// "error", but this happens while executing and therefore is a `RuntimeError`
/// from the persective of the caller that expected the code to fully execute.
InstanceImage(Box<dyn Any + Send>),
/// A user triggered error value.
///
/// An error returned from a host function.
User(Box<dyn Any + Send>),
}
impl PartialEq for RuntimeError {
fn eq(&self, _other: &RuntimeError) -> bool {
false
}
}
//impl std::error::Error for InvokeError {}
impl std::error::Error for RuntimeError {}
impl std::fmt::Display for RuntimeError {
@ -294,6 +298,10 @@ impl std::fmt::Display for RuntimeError {
// TODO: update invoke error formatting
RuntimeError::InvokeError(_) => write!(f, "Error when calling invoke"),
RuntimeError::Metering(_) => write!(f, "unknown metering error type"),
RuntimeError::InstanceImage(_) => write!(
f,
"Execution interrupted by a suspend signal: instance image returned"
),
RuntimeError::User(user_error) => {
write!(f, "User supplied error: ")?;
if let Some(s) = user_error.downcast_ref::<String>() {

View File

@ -30,7 +30,7 @@ pub mod raw {
use crate::codegen::{BreakpointInfo, BreakpointMap};
use crate::error::{InvokeError, RuntimeError};
use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR};
use crate::state::{CodeVersion, ExecutionStateImage, InstanceImage};
use crate::state::{CodeVersion, ExecutionStateImage};
use crate::vm;
use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE};
use nix::sys::signal::{
@ -61,7 +61,7 @@ type SetJmpBuffer = [i32; SETJMP_BUFFER_LEN];
struct UnwindInfo {
jmpbuf: SetJmpBuffer, // in
breakpoints: Option<BreakpointMap>,
payload: Option<RuntimeError>, // out
payload: Option<Box<RuntimeError>>, // out
}
/// A store for boundary register preservation.
@ -195,7 +195,7 @@ pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
// error
let ret = (*unwind).as_mut().unwrap().payload.take().unwrap();
*unwind = old;
Err(ret)
Err(*ret)
} else {
let ret = f();
// implicit control flow to the error case...
@ -205,7 +205,7 @@ pub unsafe fn catch_unsafe_unwind<R, F: FnOnce() -> R>(
}
/// Begins an unsafe unwind.
pub unsafe fn begin_unsafe_unwind(e: RuntimeError) -> ! {
pub unsafe fn begin_unsafe_unwind(e: Box<RuntimeError>) -> ! {
let unwind = UNWIND.with(|x| x.get());
let inner = (*unwind)
.as_mut()
@ -279,7 +279,11 @@ extern "C" fn signal_trap_handler(
static ARCH: Architecture = Architecture::Aarch64;
let mut should_unwind = false;
let mut unwind_result: Option<Result<InstanceImage, RuntimeError>> = None;
let mut unwind_result: Option<Box<RuntimeError>> = None;
let get_unwind_result = |uw_result: Option<Box<RuntimeError>>| -> Box<RuntimeError> {
uw_result
.unwrap_or_else(|| Box::new(RuntimeError::InvokeError(InvokeError::FailedWithNoError)))
};
unsafe {
let fault = get_fault_info(siginfo as _, ucontext);
@ -313,7 +317,7 @@ extern "C" fn signal_trap_handler(
if let Some(Ok(())) = out {
} else if let Some(Err(e)) = out {
should_unwind = true;
unwind_result = Some(Err(e));
unwind_result = Some(Box::new(e));
}
}
}
@ -328,7 +332,7 @@ extern "C" fn signal_trap_handler(
})
});
if should_unwind {
begin_unsafe_unwind(unwind_result.unwrap().unwrap_err());
begin_unsafe_unwind(get_unwind_result(unwind_result));
}
if early_return {
return;
@ -357,7 +361,7 @@ extern "C" fn signal_trap_handler(
return false;
}
Some(Err(e)) => {
unwind_result = Some(Err(e));
unwind_result = Some(Box::new(e));
return true;
}
None => {}
@ -389,7 +393,7 @@ extern "C" fn signal_trap_handler(
if is_suspend_signal {
// If this is a suspend signal, we parse the runtime state and return the resulting image.
let image = build_instance_image(ctx, es_image);
unwind_result = Some(Ok(image));
unwind_result = Some(Box::new(RuntimeError::InstanceImage(Box::new(image))));
} else {
// Otherwise, this is a real exception and we just throw it to the caller.
if !es_image.frames.is_empty() {
@ -417,11 +421,12 @@ extern "C" fn signal_trap_handler(
None
});
if let Some(code) = exc_code {
unwind_result = Some(Err(RuntimeError::InvokeError(InvokeError::TrapCode {
code,
// TODO:
srcloc: 0,
})));
unwind_result =
Some(Box::new(RuntimeError::InvokeError(InvokeError::TrapCode {
code,
// TODO:
srcloc: 0,
})));
}
}
@ -429,7 +434,7 @@ extern "C" fn signal_trap_handler(
});
if should_unwind {
begin_unsafe_unwind(unwind_result.unwrap().unwrap_err());
begin_unsafe_unwind(get_unwind_result(unwind_result));
}
}
}

View File

@ -37,7 +37,7 @@ pub type Invoke = unsafe extern "C" fn(
func: NonNull<vm::Func>,
args: *const u64,
rets: *mut u64,
error_out: *mut Option<InvokeError>,
error_out: *mut Option<RuntimeError>,
extra: Option<NonNull<c_void>>,
) -> bool;