mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-13 17:11:21 +00:00
Make runtime and trap errors well defined (WIP)
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
error::CompileResult,
|
||||
error::{CompileResult, RuntimeError},
|
||||
module::ModuleInner,
|
||||
state::ModuleStateMap,
|
||||
typed_func::Wasm,
|
||||
@ -282,7 +282,7 @@ pub trait RunnableModule: Send + Sync {
|
||||
fn get_trampoline(&self, info: &ModuleInfo, sig_index: SigIndex) -> Option<Wasm>;
|
||||
|
||||
/// Trap an error.
|
||||
unsafe fn do_early_trap(&self, data: Box<dyn Any + Send>) -> !;
|
||||
unsafe fn do_early_trap(&self, data: RuntimeError) -> !;
|
||||
|
||||
/// Returns the machine code associated with this module.
|
||||
fn get_code(&self) -> Option<&[u8]> {
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! The error module contains the data structures and helper functions used to implement errors that
|
||||
//! 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 core::borrow::Borrow;
|
||||
use std::any::Any;
|
||||
@ -173,6 +173,7 @@ impl std::fmt::Display for LinkError {
|
||||
|
||||
impl std::error::Error for LinkError {}
|
||||
|
||||
/*
|
||||
/// This is the error type returned when calling
|
||||
/// a WebAssembly function.
|
||||
///
|
||||
@ -210,6 +211,68 @@ impl std::fmt::Debug for RuntimeError {
|
||||
|
||||
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 (this is where exception codes come from?)
|
||||
InvokeError(InvokeError),
|
||||
/// A user triggered error value.
|
||||
///
|
||||
/// An error returned from a host function.
|
||||
User(Box<dyn Any + Send>)
|
||||
}
|
||||
|
||||
/// TODO:
|
||||
#[derive(Debug)]
|
||||
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
|
||||
/// a hardware failure.
|
||||
FailedWithNoError,
|
||||
}
|
||||
|
||||
impl std::error::Error for RuntimeError {}
|
||||
|
||||
impl std::fmt::Display for RuntimeError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
// TODO: ideally improve the error type of invoke
|
||||
RuntimeError::InvokeError(_) => write!(f, "Error when calling invoke"),
|
||||
RuntimeError::User(user_error) => {
|
||||
write!(f, "User supplied error: ")?;
|
||||
if let Some(s) = user_error.downcast_ref::<String>() {
|
||||
write!(f, "\"{}\"", s)
|
||||
} else if let Some(s) = user_error.downcast_ref::<&str>() {
|
||||
write!(f, "\"{}\"", s)
|
||||
} else if let Some(n) = user_error.downcast_ref::<i32>() {
|
||||
write!(f, "{}", n)
|
||||
} else {
|
||||
write!(f, "unknown error type")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl From<InternalError> for RuntimeError {
|
||||
fn from(other: InternalError) -> Self {
|
||||
RuntimeError(Box::new(other))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/// This error type is produced by resolving a wasm function
|
||||
/// given its name.
|
||||
///
|
||||
|
@ -5,7 +5,7 @@
|
||||
use crate::{
|
||||
backend::RunnableModule,
|
||||
backing::{ImportBacking, LocalBacking},
|
||||
error::{CallResult, ResolveError, ResolveResult, Result, RuntimeError},
|
||||
error::{CallResult, ResolveError, ResolveResult, Result, RuntimeError, InvokeError},
|
||||
export::{Context, Export, ExportIter, Exportable, FuncPointer},
|
||||
global::Global,
|
||||
import::{ImportObject, LikeNamespace},
|
||||
@ -584,10 +584,10 @@ pub(crate) fn call_func_with_index_inner(
|
||||
invoke_env,
|
||||
} = wasm;
|
||||
|
||||
let run_wasm = |result_space: *mut u64| unsafe {
|
||||
let run_wasm = |result_space: *mut u64| -> CallResult<()> {
|
||||
let mut error_out = None;
|
||||
|
||||
let success = invoke(
|
||||
let success = unsafe { invoke(
|
||||
trampoline,
|
||||
ctx_ptr,
|
||||
func_ptr,
|
||||
@ -595,14 +595,15 @@ pub(crate) fn call_func_with_index_inner(
|
||||
result_space,
|
||||
&mut error_out,
|
||||
invoke_env,
|
||||
);
|
||||
)};
|
||||
|
||||
if success {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(error_out
|
||||
.map(RuntimeError)
|
||||
.unwrap_or_else(|| RuntimeError(Box::new("invoke(): Unknown error".to_string()))))
|
||||
let error: RuntimeError = error_out
|
||||
.map(RuntimeError::InvokeError)
|
||||
.unwrap_or_else(|| RuntimeError::InvokeError(InvokeError::FailedWithNoError));
|
||||
Err(error.into())
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! 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.
|
||||
use crate::{
|
||||
error::RuntimeError,
|
||||
error::{RuntimeError, InvokeError},
|
||||
export::{Context, Export, FuncPointer},
|
||||
import::IsExport,
|
||||
types::{FuncSig, NativeWasmType, Type, WasmExternType},
|
||||
@ -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<Box<dyn Any + Send>>,
|
||||
error_out: *mut Option<InvokeError>,
|
||||
extra: Option<NonNull<c_void>>,
|
||||
) -> bool;
|
||||
|
||||
@ -340,7 +340,7 @@ impl<'a> DynamicFunc<'a> {
|
||||
Err(e) => {
|
||||
// At this point, there is an error that needs to be trapped.
|
||||
drop(args); // Release the Vec which will leak otherwise.
|
||||
(&*vmctx.module).runnable_module.do_early_trap(e)
|
||||
(&*vmctx.module).runnable_module.do_early_trap(RuntimeError::User(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -588,9 +588,7 @@ macro_rules! impl_traits {
|
||||
) {
|
||||
Ok(Rets::from_ret_array(rets))
|
||||
} else {
|
||||
Err(error_out.map(RuntimeError).unwrap_or_else(|| {
|
||||
RuntimeError(Box::new("invoke(): Unknown error".to_string()))
|
||||
}))
|
||||
Err(error_out.map_or_else(|| RuntimeError::InvokeError(InvokeError::FailedWithNoError), RuntimeError::InvokeError))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -678,9 +676,10 @@ macro_rules! impl_traits {
|
||||
Ok(Ok(returns)) => return returns.into_c_struct(),
|
||||
Ok(Err(err)) => {
|
||||
let b: Box<_> = err.into();
|
||||
b as Box<dyn Any + Send>
|
||||
RuntimeError::User(b as Box<dyn Any + Send>)
|
||||
},
|
||||
Err(err) => err,
|
||||
// TODO(blocking): this line is wrong!
|
||||
Err(err) => RuntimeError::User(err),
|
||||
};
|
||||
|
||||
// At this point, there is an error that needs to
|
||||
@ -791,9 +790,10 @@ macro_rules! impl_traits {
|
||||
Ok(Ok(returns)) => return returns.into_c_struct(),
|
||||
Ok(Err(err)) => {
|
||||
let b: Box<_> = err.into();
|
||||
b as Box<dyn Any + Send>
|
||||
RuntimeError::User(b as Box<dyn Any + Send>)
|
||||
},
|
||||
Err(err) => err,
|
||||
// TODO(blocking): this line is wrong!
|
||||
Err(err) => RuntimeError::User(err),
|
||||
};
|
||||
|
||||
// At this point, there is an error that needs to
|
||||
|
Reference in New Issue
Block a user