mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-05 02:20:19 +00:00
Define runtime error values explicitly in Singlepass
This commit is contained in:
parent
bfb6814f23
commit
b9ec8f9845
@ -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,
|
||||||
|
@ -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,
|
||||||
})
|
})
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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>>;
|
||||||
|
@ -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.
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(())
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user