Remove WasmTrapInfo and passExceptionCode in the generic Box<Any> container.

This commit is contained in:
losfair
2020-02-06 23:49:50 +08:00
parent 2c44b700c8
commit e0aafbe9dd
18 changed files with 166 additions and 248 deletions

View File

@ -8,7 +8,7 @@ use std::{any::Any, cell::Cell, ptr::NonNull, sync::Arc};
use wasmer_runtime_core::{ use wasmer_runtime_core::{
backend::RunnableModule, backend::RunnableModule,
module::ModuleInfo, module::ModuleInfo,
typed_func::{Trampoline, Wasm, WasmTrapInfo}, typed_func::{Trampoline, Wasm},
types::{LocalFuncIndex, SigIndex}, types::{LocalFuncIndex, SigIndex},
vm, vm,
}; };
@ -29,10 +29,7 @@ thread_local! {
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any + Send>>> = Cell::new(None); pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any + Send>>> = Cell::new(None);
} }
pub enum CallProtError { pub struct CallProtError(pub Box<dyn Any + Send>);
Trap(WasmTrapInfo),
Error(Box<dyn Any + Send>),
}
pub struct Caller { pub struct Caller {
handler_data: HandlerData, handler_data: HandlerData,
@ -66,8 +63,7 @@ impl RunnableModule for Caller {
func: NonNull<vm::Func>, func: NonNull<vm::Func>,
args: *const u64, args: *const u64,
rets: *mut u64, rets: *mut u64,
trap_info: *mut WasmTrapInfo, error_out: *mut Option<Box<dyn Any + Send>>,
user_error: *mut Option<Box<dyn Any + Send>>,
invoke_env: Option<NonNull<c_void>>, invoke_env: Option<NonNull<c_void>>,
) -> bool { ) -> bool {
let handler_data = &*invoke_env.unwrap().cast().as_ptr(); let handler_data = &*invoke_env.unwrap().cast().as_ptr();
@ -84,10 +80,7 @@ impl RunnableModule for Caller {
match res { match res {
Err(err) => { Err(err) => {
match err { *error_out = Some(err.0);
CallProtError::Trap(info) => *trap_info = info,
CallProtError::Error(data) => *user_error = Some(data),
}
false false
} }
Ok(()) => true, Ok(()) => true,

View File

@ -18,7 +18,7 @@ use nix::sys::signal::{
use std::cell::{Cell, UnsafeCell}; use std::cell::{Cell, UnsafeCell};
use std::ptr; use std::ptr;
use std::sync::Once; use std::sync::Once;
use wasmer_runtime_core::typed_func::WasmTrapInfo; use wasmer_runtime_core::backend::ExceptionCode;
extern "C" fn signal_trap_handler( extern "C" fn signal_trap_handler(
signum: ::nix::libc::c_int, signum: ::nix::libc::c_int,
@ -79,7 +79,7 @@ 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::Error(data)) Err(CallProtError(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());
@ -88,21 +88,25 @@ pub fn call_protected<T>(
srcloc: _, srcloc: _,
}) = handler_data.lookup(inst_ptr) }) = handler_data.lookup(inst_ptr)
{ {
Err(CallProtError::Trap(match Signal::from_c_int(signum) { Err(CallProtError(Box::new(match Signal::from_c_int(signum) {
Ok(SIGILL) => match trapcode { Ok(SIGILL) => match trapcode {
TrapCode::BadSignature => WasmTrapInfo::IncorrectCallIndirectSignature, TrapCode::BadSignature => ExceptionCode::IncorrectCallIndirectSignature,
TrapCode::IndirectCallToNull => WasmTrapInfo::CallIndirectOOB, TrapCode::IndirectCallToNull => ExceptionCode::CallIndirectOOB,
TrapCode::HeapOutOfBounds => WasmTrapInfo::MemoryOutOfBounds, TrapCode::HeapOutOfBounds => ExceptionCode::MemoryOutOfBounds,
TrapCode::TableOutOfBounds => WasmTrapInfo::CallIndirectOOB, TrapCode::TableOutOfBounds => ExceptionCode::CallIndirectOOB,
_ => WasmTrapInfo::Unknown, _ => {
return Err(CallProtError(Box::new(
"unknown clif trap code".to_string(),
)))
}
}, },
Ok(SIGSEGV) | Ok(SIGBUS) => WasmTrapInfo::MemoryOutOfBounds, Ok(SIGSEGV) | Ok(SIGBUS) => ExceptionCode::MemoryOutOfBounds,
Ok(SIGFPE) => WasmTrapInfo::IllegalArithmetic, Ok(SIGFPE) => ExceptionCode::IllegalArithmetic,
_ => unimplemented!( _ => unimplemented!(
"WasmTrapInfo::Unknown signal:{:?}", "ExceptionCode::Unknown signal:{:?}",
Signal::from_c_int(signum) Signal::from_c_int(signum)
), ),
})) })))
} 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",
@ -114,7 +118,7 @@ pub fn call_protected<T>(
}; };
// When the trap-handler is fully implemented, this will return more information. // When the trap-handler is fully implemented, this will return more information.
let s = format!("unknown trap at {:p} - {}", faulting_addr, signal); let s = format!("unknown trap at {:p} - {}", faulting_addr, signal);
Err(CallProtError::Error(Box::new(s))) Err(CallProtError(Box::new(s)))
} }
} }
} else { } else {

View File

@ -8,7 +8,8 @@ use std::{
ptr::{self, NonNull}, ptr::{self, NonNull},
}; };
use wasmer_runtime_core::{ use wasmer_runtime_core::{
typed_func::{Trampoline, WasmTrapInfo}, backend::ExceptionCode,
typed_func::Trampoline,
vm::{Ctx, Func}, vm::{Ctx, Func},
}; };
use wasmer_win_exception_handler::CallProtectedData; use wasmer_win_exception_handler::CallProtectedData;
@ -62,22 +63,22 @@ pub fn call_protected(
srcloc: _, srcloc: _,
}) = handler_data.lookup(instruction_pointer as _) }) = handler_data.lookup(instruction_pointer as _)
{ {
Err(CallProtError::Trap(match code as DWORD { Err(CallProtError(Box::new(match code as DWORD {
EXCEPTION_ACCESS_VIOLATION => WasmTrapInfo::MemoryOutOfBounds, EXCEPTION_ACCESS_VIOLATION => ExceptionCode::MemoryOutOfBounds,
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode { EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
TrapCode::BadSignature => WasmTrapInfo::IncorrectCallIndirectSignature, TrapCode::BadSignature => ExceptionCode::IncorrectCallIndirectSignature,
TrapCode::IndirectCallToNull => WasmTrapInfo::CallIndirectOOB, TrapCode::IndirectCallToNull => ExceptionCode::CallIndirectOOB,
TrapCode::HeapOutOfBounds => WasmTrapInfo::MemoryOutOfBounds, TrapCode::HeapOutOfBounds => ExceptionCode::MemoryOutOfBounds,
TrapCode::TableOutOfBounds => WasmTrapInfo::CallIndirectOOB, TrapCode::TableOutOfBounds => ExceptionCode::CallIndirectOOB,
TrapCode::UnreachableCodeReached => WasmTrapInfo::Unreachable, TrapCode::UnreachableCodeReached => ExceptionCode::Unreachable,
_ => WasmTrapInfo::Unknown, _ => ExceptionCode::Unknown,
}, },
EXCEPTION_STACK_OVERFLOW => WasmTrapInfo::Unknown, EXCEPTION_STACK_OVERFLOW => ExceptionCode::Unknown,
EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => { EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => {
WasmTrapInfo::IllegalArithmetic ExceptionCode::IllegalArithmetic
} }
_ => WasmTrapInfo::Unknown, _ => ExceptionCode::Unknown,
})) })))
} else { } else {
let signal = match code as DWORD { let signal = match code as DWORD {
EXCEPTION_FLT_DENORMAL_OPERAND EXCEPTION_FLT_DENORMAL_OPERAND
@ -110,7 +111,7 @@ pub fn call_protected(
exception_address, code, signal, exception_address, code, signal,
); );
Err(CallProtError::Error(Box::new(s))) Err(CallProtError(Box::new(s)))
} }
} }

View File

@ -30,7 +30,7 @@ use wasmer_runtime_core::{
module::ModuleInfo, module::ModuleInfo,
state::ModuleStateMap, state::ModuleStateMap,
structures::TypedIndex, structures::TypedIndex,
typed_func::{Trampoline, Wasm, WasmTrapInfo}, typed_func::{Trampoline, Wasm},
types::{LocalFuncIndex, SigIndex}, types::{LocalFuncIndex, SigIndex},
vm, vmcalls, vm, vmcalls,
}; };
@ -65,8 +65,7 @@ extern "C" {
func_ptr: NonNull<vm::Func>, func_ptr: NonNull<vm::Func>,
params: *const u64, params: *const u64,
results: *mut u64, results: *mut u64,
trap_out: *mut WasmTrapInfo, error_out: *mut Option<Box<dyn Any + Send>>,
user_error: *mut Option<Box<dyn Any + Send>>,
invoke_env: Option<NonNull<c_void>>, invoke_env: Option<NonNull<c_void>>,
) -> bool; ) -> bool;
} }

View File

@ -165,12 +165,10 @@ mod tests {
} }
let err = result.unwrap_err(); let err = result.unwrap_err();
match err { assert!(err
RuntimeError::Error { data } => { .0
assert!(data.downcast_ref::<ExecutionLimitExceededError>().is_some()); .downcast_ref::<ExecutionLimitExceededError>()
} .is_some());
_ => unreachable!(),
}
// verify it used the correct number of points // verify it used the correct number of points
assert_eq!(get_points_used(&instance), 109); // Used points will be slightly more than `limit` because of the way we do gas checking. assert_eq!(get_points_used(&instance), 109); // Used points will be slightly more than `limit` because of the way we do gas checking.

View File

@ -16,12 +16,7 @@ macro_rules! call_and_assert {
expected_value, expected_value,
concat!("Expected right when calling `", stringify!($function), "`.") concat!("Expected right when calling `", stringify!($function), "`.")
), ),
( (Err(RuntimeError(data)), Err(RuntimeError(expected_data))) => {
Err(RuntimeError::Error { data }),
Err(RuntimeError::Error {
data: expected_data,
}),
) => {
if let (Some(data), Some(expected_data)) = ( if let (Some(data), Some(expected_data)) = (
data.downcast_ref::<&str>(), data.downcast_ref::<&str>(),
expected_data.downcast_ref::<&str>(), expected_data.downcast_ref::<&str>(),
@ -260,35 +255,25 @@ test!(
test!( test!(
test_fn_trap, test_fn_trap,
function_fn_trap, function_fn_trap,
Err(RuntimeError::Error { Err(RuntimeError(Box::new(format!("foo {}", 2))))
data: Box::new(format!("foo {}", 2))
})
); );
test!( test!(
test_closure_trap, test_closure_trap,
function_closure_trap, function_closure_trap,
Err(RuntimeError::Error { Err(RuntimeError(Box::new(format!("bar {}", 2))))
data: Box::new(format!("bar {}", 2))
})
); );
test!( test!(
test_fn_trap_with_vmctx, test_fn_trap_with_vmctx,
function_fn_trap_with_vmctx, function_fn_trap_with_vmctx,
Err(RuntimeError::Error { Err(RuntimeError(Box::new(format!("baz {}", 2 + SHIFT))))
data: Box::new(format!("baz {}", 2 + SHIFT))
})
); );
test!( test!(
test_closure_trap_with_vmctx, test_closure_trap_with_vmctx,
function_closure_trap_with_vmctx, function_closure_trap_with_vmctx,
Err(RuntimeError::Error { Err(RuntimeError(Box::new(format!("qux {}", 2 + SHIFT))))
data: Box::new(format!("qux {}", 2 + SHIFT))
})
); );
test!( test!(
test_closure_trap_with_vmctx_and_env, test_closure_trap_with_vmctx_and_env,
function_closure_trap_with_vmctx_and_env, function_closure_trap_with_vmctx_and_env,
Err(RuntimeError::Error { Err(RuntimeError(Box::new(format!("! {}", 2 + shift + SHIFT))))
data: Box::new(format!("! {}", 2 + shift + SHIFT))
})
); );

View File

@ -13,6 +13,7 @@ use crate::{
module::ModuleInfo, module::ModuleInfo,
sys::Memory, sys::Memory,
}; };
use std::fmt;
use std::{any::Any, ptr::NonNull}; use std::{any::Any, ptr::NonNull};
use std::collections::HashMap; use std::collections::HashMap;
@ -158,13 +159,36 @@ impl ExceptionTable {
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum ExceptionCode { pub enum ExceptionCode {
/// An `unreachable` opcode was executed. /// An `unreachable` opcode was executed.
Unreachable, Unreachable = 0,
/// Call indirect incorrect signature trap.
IncorrectCallIndirectSignature = 1,
/// Memory out of bounds trap.
MemoryOutOfBounds = 2,
/// Call indirect out of bounds trap.
CallIndirectOOB = 3,
/// An arithmetic exception, e.g. divided by zero. /// An arithmetic exception, e.g. divided by zero.
Arithmetic, IllegalArithmetic = 4,
/// Misaligned atomic access trap.
MisalignedAtomicAccess = 5,
}
/// Memory access exception, e.g. misaligned/out-of-bound read/write. impl fmt::Display for ExceptionCode {
Memory, fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
ExceptionCode::Unreachable => "unreachable",
ExceptionCode::IncorrectCallIndirectSignature => {
"incorrect `call_indirect` signature"
}
ExceptionCode::MemoryOutOfBounds => "memory out-of-bounds access",
ExceptionCode::CallIndirectOOB => "`call_indirect` out-of-bounds",
ExceptionCode::IllegalArithmetic => "illegal arithmetic operation",
ExceptionCode::MisalignedAtomicAccess => "misaligned atomic access",
}
)
}
} }
pub trait Compiler { pub trait Compiler {

View File

@ -179,18 +179,7 @@ impl std::error::Error for LinkError {}
/// The main way to do this is `Instance.call`. /// The main way to do this is `Instance.call`.
/// ///
/// Comparing two `RuntimeError`s always evaluates to false. /// Comparing two `RuntimeError`s always evaluates to false.
pub enum RuntimeError { pub struct RuntimeError(pub Box<dyn Any + Send>);
/// Trap.
Trap {
/// Trap message.
msg: Box<str>,
},
/// Error.
Error {
/// Error data.
data: Box<dyn Any + Send>,
},
}
impl PartialEq for RuntimeError { impl PartialEq for RuntimeError {
fn eq(&self, _other: &RuntimeError) -> bool { fn eq(&self, _other: &RuntimeError) -> bool {
@ -200,11 +189,7 @@ impl PartialEq 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 { let data = &*self.0;
RuntimeError::Trap { ref msg } => {
write!(f, "WebAssembly trap occurred during runtime: {}", msg)
}
RuntimeError::Error { data } => {
if let Some(s) = data.downcast_ref::<String>() { if let Some(s) = data.downcast_ref::<String>() {
write!(f, "\"{}\"", s) write!(f, "\"{}\"", s)
} else if let Some(s) = data.downcast_ref::<&str>() { } else if let Some(s) = data.downcast_ref::<&str>() {
@ -216,8 +201,6 @@ impl std::fmt::Display for RuntimeError {
} }
} }
} }
}
}
impl std::fmt::Debug for RuntimeError { impl std::fmt::Debug for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {

View File

@ -13,7 +13,7 @@ use crate::{
sig_registry::SigRegistry, sig_registry::SigRegistry,
structures::TypedIndex, structures::TypedIndex,
table::Table, table::Table,
typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList}, typed_func::{Func, Wasm, WasmTypeList},
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value}, types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value},
vm::{self, InternalField}, vm::{self, InternalField},
}; };
@ -673,8 +673,7 @@ pub(crate) fn call_func_with_index_inner(
} = wasm; } = wasm;
let run_wasm = |result_space: *mut u64| unsafe { let run_wasm = |result_space: *mut u64| unsafe {
let mut trap_info = WasmTrapInfo::Unknown; let mut error_out = None;
let mut user_error = None;
let success = invoke( let success = invoke(
trampoline, trampoline,
@ -682,21 +681,16 @@ pub(crate) fn call_func_with_index_inner(
func_ptr, func_ptr,
raw_args.as_ptr(), raw_args.as_ptr(),
result_space, result_space,
&mut trap_info, &mut error_out,
&mut user_error,
invoke_env, invoke_env,
); );
if success { if success {
Ok(()) Ok(())
} else { } else {
if let Some(data) = user_error { Err(error_out
Err(RuntimeError::Error { data }) .map(RuntimeError)
} else { .unwrap_or_else(|| RuntimeError(Box::new("invoke(): Unknown error".to_string()))))
Err(RuntimeError::Trap {
msg: trap_info.to_string().into(),
})
}
} }
}; };

View File

@ -11,52 +11,12 @@ use std::{
any::Any, any::Any,
convert::Infallible, convert::Infallible,
ffi::c_void, ffi::c_void,
fmt,
marker::PhantomData, marker::PhantomData,
mem, panic, mem, panic,
ptr::{self, NonNull}, ptr::{self, NonNull},
sync::Arc, sync::Arc,
}; };
/// Wasm trap info.
#[repr(C)]
pub enum WasmTrapInfo {
/// Unreachable trap.
Unreachable = 0,
/// Call indirect incorrect signature trap.
IncorrectCallIndirectSignature = 1,
/// Memory out of bounds trap.
MemoryOutOfBounds = 2,
/// Call indirect out of bounds trap.
CallIndirectOOB = 3,
/// Illegal arithmetic trap.
IllegalArithmetic = 4,
/// Misaligned atomic access trap.
MisalignedAtomicAccess = 5,
/// Unknown trap.
Unknown,
}
impl fmt::Display for WasmTrapInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match self {
WasmTrapInfo::Unreachable => "unreachable",
WasmTrapInfo::IncorrectCallIndirectSignature => {
"incorrect `call_indirect` signature"
}
WasmTrapInfo::MemoryOutOfBounds => "memory out-of-bounds access",
WasmTrapInfo::CallIndirectOOB => "`call_indirect` out-of-bounds",
WasmTrapInfo::IllegalArithmetic => "illegal arithmetic operation",
WasmTrapInfo::MisalignedAtomicAccess => "misaligned atomic access",
WasmTrapInfo::Unknown => "unknown",
}
)
}
}
/// This is just an empty trait to constrict that types that /// This is just an empty trait to constrict that types that
/// can be put into the third/fourth (depending if you include lifetimes) /// can be put into the third/fourth (depending if you include lifetimes)
/// of the `Func` struct. /// of the `Func` struct.
@ -77,8 +37,7 @@ pub type Invoke = unsafe extern "C" fn(
func: NonNull<vm::Func>, func: NonNull<vm::Func>,
args: *const u64, args: *const u64,
rets: *mut u64, rets: *mut u64,
trap_info: *mut WasmTrapInfo, error_out: *mut Option<Box<dyn Any + Send>>,
user_error: *mut Option<Box<dyn Any + Send>>,
extra: Option<NonNull<c_void>>, extra: Option<NonNull<c_void>>,
) -> bool; ) -> bool;
@ -401,8 +360,7 @@ macro_rules! impl_traits {
let ( $( $x ),* ) = self; let ( $( $x ),* ) = self;
let args = [ $( $x.to_native().to_binary()),* ]; let args = [ $( $x.to_native().to_binary()),* ];
let mut rets = Rets::empty_ret_array(); let mut rets = Rets::empty_ret_array();
let mut trap = WasmTrapInfo::Unknown; let mut error_out = None;
let mut user_error = None;
if (wasm.invoke)( if (wasm.invoke)(
wasm.trampoline, wasm.trampoline,
@ -410,17 +368,14 @@ macro_rules! impl_traits {
f, f,
args.as_ptr(), args.as_ptr(),
rets.as_mut().as_mut_ptr(), rets.as_mut().as_mut_ptr(),
&mut trap, &mut error_out,
&mut user_error,
wasm.invoke_env wasm.invoke_env
) { ) {
Ok(Rets::from_ret_array(rets)) Ok(Rets::from_ret_array(rets))
} else { } else {
if let Some(data) = user_error { Err(error_out.map(RuntimeError).unwrap_or_else(|| {
Err(RuntimeError::Error { data }) RuntimeError(Box::new("invoke(): Unknown error".to_string()))
} else { }))
Err(RuntimeError::Trap { msg: trap.to_string().into() })
}
} }
} }
} }

View File

@ -70,8 +70,8 @@ fn main() -> Result<(), error::Error> {
println!("result: {:?}", result); println!("result: {:?}", result);
if let Err(RuntimeError::Error { data }) = result { if let Err(e) = result {
if let Ok(exit_code) = data.downcast::<ExitCode>() { if let Ok(exit_code) = e.0.downcast::<ExitCode>() {
println!("exit code: {:?}", exit_code); println!("exit code: {:?}", exit_code);
} }
} }

View File

@ -40,10 +40,10 @@ fn error_propagation() {
let result = foo.call(); let result = foo.call();
if let Err(RuntimeError::Error { data }) = result { if let Err(RuntimeError(e)) = result {
let exit_code = data.downcast::<ExitCode>().unwrap(); let exit_code = e.downcast::<ExitCode>().unwrap();
assert_eq!(exit_code.code, 42); assert_eq!(exit_code.code, 42);
} else { } else {
panic!("didn't return RuntimeError::Error") panic!("didn't return RuntimeError")
} }
} }

View File

@ -37,7 +37,7 @@ use wasmer_runtime_core::{
ModuleStateMap, OffsetInfo, SuspendOffset, WasmAbstractValue, ModuleStateMap, OffsetInfo, SuspendOffset, WasmAbstractValue,
}, },
structures::{Map, TypedIndex}, structures::{Map, TypedIndex},
typed_func::{Trampoline, Wasm, WasmTrapInfo}, typed_func::{Trampoline, Wasm},
types::{ types::{
FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
TableIndex, Type, TableIndex, Type,
@ -375,8 +375,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,
trap_info: *mut WasmTrapInfo, error_out: *mut Option<Box<dyn Any + Send>>,
user_error: *mut Option<Box<dyn Any + Send>>,
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;
@ -520,10 +519,7 @@ impl RunnableModule for X64ExecutionContext {
true true
} }
Err(err) => { Err(err) => {
match err { *error_out = Some(err.0);
protect_unix::CallProtError::Trap(info) => *trap_info = info,
protect_unix::CallProtError::Error(data) => *user_error = Some(data),
}
false false
} }
}; };
@ -1010,14 +1006,14 @@ impl X64FunctionCode {
Self::mark_trappable(a, m, fsm, control_stack); Self::mark_trappable(a, m, fsm, control_stack);
etable etable
.offset_to_code .offset_to_code
.insert(a.get_offset().0, ExceptionCode::Arithmetic); .insert(a.get_offset().0, ExceptionCode::IllegalArithmetic);
op(a, sz, Location::GPR(GPR::RCX)); op(a, sz, Location::GPR(GPR::RCX));
} }
_ => { _ => {
Self::mark_trappable(a, m, fsm, control_stack); Self::mark_trappable(a, m, fsm, control_stack);
etable etable
.offset_to_code .offset_to_code
.insert(a.get_offset().0, ExceptionCode::Arithmetic); .insert(a.get_offset().0, ExceptionCode::IllegalArithmetic);
op(a, sz, loc); op(a, sz, loc);
} }
} }
@ -2003,9 +1999,12 @@ impl X64FunctionCode {
a.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_addr)); a.emit_add(Size::S64, Location::GPR(tmp_base), Location::GPR(tmp_addr));
a.emit_cmp(Size::S64, Location::GPR(tmp_bound), Location::GPR(tmp_addr)); a.emit_cmp(Size::S64, Location::GPR(tmp_bound), Location::GPR(tmp_addr));
Self::mark_range_with_exception_code(a, etable, ExceptionCode::Memory, |a| { Self::mark_range_with_exception_code(
a.emit_conditional_trap(Condition::Above) a,
}); etable,
ExceptionCode::MemoryOutOfBounds,
|a| a.emit_conditional_trap(Condition::Above),
);
m.release_temp_gpr(tmp_bound); m.release_temp_gpr(tmp_bound);
} }
@ -2045,13 +2044,16 @@ impl X64FunctionCode {
Location::Imm32(align - 1), Location::Imm32(align - 1),
Location::GPR(tmp_aligncheck), Location::GPR(tmp_aligncheck),
); );
Self::mark_range_with_exception_code(a, etable, ExceptionCode::Memory, |a| { Self::mark_range_with_exception_code(
a.emit_conditional_trap(Condition::NotEqual) a,
}); etable,
ExceptionCode::MemoryOutOfBounds,
|a| a.emit_conditional_trap(Condition::NotEqual),
);
m.release_temp_gpr(tmp_aligncheck); m.release_temp_gpr(tmp_aligncheck);
} }
Self::mark_range_with_exception_code(a, etable, ExceptionCode::Memory, |a| { Self::mark_range_with_exception_code(a, etable, ExceptionCode::MemoryOutOfBounds, |a| {
cb(a, m, tmp_addr) cb(a, m, tmp_addr)
})?; })?;
@ -2186,7 +2188,7 @@ impl X64FunctionCode {
a.emit_label(trap); a.emit_label(trap);
etable etable
.offset_to_code .offset_to_code
.insert(a.get_offset().0, ExceptionCode::Arithmetic); .insert(a.get_offset().0, ExceptionCode::IllegalArithmetic);
a.emit_ud2(); a.emit_ud2();
a.emit_label(end); a.emit_label(end);
} }
@ -2314,7 +2316,7 @@ impl X64FunctionCode {
a.emit_label(trap); a.emit_label(trap);
etable etable
.offset_to_code .offset_to_code
.insert(a.get_offset().0, ExceptionCode::Arithmetic); .insert(a.get_offset().0, ExceptionCode::IllegalArithmetic);
a.emit_ud2(); a.emit_ud2();
a.emit_label(end); a.emit_label(end);
} }
@ -2442,7 +2444,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
Self::mark_range_with_exception_code( Self::mark_range_with_exception_code(
a, a,
self.exception_table.as_mut().unwrap(), self.exception_table.as_mut().unwrap(),
ExceptionCode::Memory, ExceptionCode::MemoryOutOfBounds,
|a| a.emit_conditional_trap(Condition::Below), |a| a.emit_conditional_trap(Condition::Below),
); );
} }
@ -6311,7 +6313,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
Self::mark_range_with_exception_code( Self::mark_range_with_exception_code(
a, a,
self.exception_table.as_mut().unwrap(), self.exception_table.as_mut().unwrap(),
ExceptionCode::Memory, ExceptionCode::CallIndirectOOB,
|a| a.emit_conditional_trap(Condition::BelowEqual), |a| a.emit_conditional_trap(Condition::BelowEqual),
); );
a.emit_mov(Size::S64, func_index, Location::GPR(table_count)); a.emit_mov(Size::S64, func_index, Location::GPR(table_count));
@ -6342,7 +6344,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
Self::mark_range_with_exception_code( Self::mark_range_with_exception_code(
a, a,
self.exception_table.as_mut().unwrap(), self.exception_table.as_mut().unwrap(),
ExceptionCode::Memory, ExceptionCode::IncorrectCallIndirectSignature,
|a| a.emit_conditional_trap(Condition::NotEqual), |a| a.emit_conditional_trap(Condition::NotEqual),
); );

View File

@ -13,7 +13,6 @@ use std::any::Any;
use std::cell::Cell; use std::cell::Cell;
use wasmer_runtime_core::codegen::BreakpointMap; use wasmer_runtime_core::codegen::BreakpointMap;
use wasmer_runtime_core::fault::{begin_unsafe_unwind, catch_unsafe_unwind, ensure_sighandler}; use wasmer_runtime_core::fault::{begin_unsafe_unwind, catch_unsafe_unwind, ensure_sighandler};
use wasmer_runtime_core::typed_func::WasmTrapInfo;
thread_local! { thread_local! {
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any + Send>>> = Cell::new(None); pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any + Send>>> = Cell::new(None);
@ -23,10 +22,7 @@ pub unsafe fn trigger_trap() -> ! {
begin_unsafe_unwind(Box::new(())); begin_unsafe_unwind(Box::new(()));
} }
pub enum CallProtError { pub struct CallProtError(pub Box<dyn Any + Send>);
Trap(WasmTrapInfo),
Error(Box<dyn Any + Send>),
}
pub fn call_protected<T>( pub fn call_protected<T>(
f: impl FnOnce() -> T, f: impl FnOnce() -> T,
@ -37,13 +33,13 @@ pub fn call_protected<T>(
let ret = catch_unsafe_unwind(|| f(), breakpoints); let ret = catch_unsafe_unwind(|| f(), breakpoints);
match ret { match ret {
Ok(x) => Ok(x), Ok(x) => Ok(x),
Err(e) => { Err(e) => Err(CallProtError(
if let Some(data) = TRAP_EARLY_DATA.with(|cell| cell.replace(None)) { if let Some(data) = TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
Err(CallProtError::Error(data)) data
} else { } else {
Err(CallProtError::Error(e)) e
} },
} )),
} }
} }
} }

View File

@ -3,7 +3,7 @@ mod tests {
use wabt::wat2wasm; use wabt::wat2wasm;
use wasmer_runtime::{ use wasmer_runtime::{
error::{CallError, RuntimeError}, error::{CallError, RuntimeError},
ImportObject, ExceptionCode, ImportObject,
}; };
// The semantics of stack overflow are documented at: // The semantics of stack overflow are documented at:
@ -29,9 +29,11 @@ mod tests {
match result { match result {
Err(err) => match err { Err(err) => match err {
CallError::Runtime(RuntimeError::Trap { msg }) => { CallError::Runtime(RuntimeError(e)) => {
assert!(!msg.contains("segmentation violation")); let exc_code = e
assert!(!msg.contains("bus error")); .downcast::<ExceptionCode>()
.expect("expecting exception code");
assert!(exc_code != ExceptionCode::Unknown);
} }
_ => unimplemented!(), _ => unimplemented!(),
}, },

View File

@ -674,8 +674,7 @@ mod tests {
let call_result = maybe_call_result.unwrap(); let call_result = maybe_call_result.unwrap();
use wasmer_runtime::error::{CallError, RuntimeError}; use wasmer_runtime::error::{CallError, RuntimeError};
match call_result { match call_result {
Err(e) => { Err(e) => match e {
match e {
CallError::Resolve(_) => { CallError::Resolve(_) => {
test_report.add_failure( test_report.add_failure(
SpecFailure { SpecFailure {
@ -689,17 +688,9 @@ mod tests {
line, line,
); );
} }
CallError::Runtime(r) => { CallError::Runtime(RuntimeError(e)) => {
match r {
RuntimeError::Trap { .. } => {
// TODO assert message?
test_report.count_passed()
}
RuntimeError::Error { ref data } => {
use wasmer_runtime::ExceptionCode; use wasmer_runtime::ExceptionCode;
if let Some(_) = if let Some(_) = data.downcast_ref::<ExceptionCode>() {
data.downcast_ref::<ExceptionCode>()
{
test_report.count_passed(); test_report.count_passed();
} else { } else {
test_report.add_failure( test_report.add_failure(
@ -718,10 +709,7 @@ mod tests {
); );
} }
} }
} },
}
}
}
Ok(values) => { Ok(values) => {
test_report.add_failure( test_report.add_failure(
SpecFailure { SpecFailure {

View File

@ -43,7 +43,7 @@ pub use self::utils::{get_wasi_version, is_wasi_module, WasiVersion};
use wasmer_runtime_core::{func, import::ImportObject, imports}; use wasmer_runtime_core::{func, import::ImportObject, imports};
/// This is returned in the Box<dyn Any> RuntimeError::Error variant. /// This is returned in `RuntimeError`.
/// Use `downcast` or `downcast_ref` to retrieve the `ExitCode`. /// Use `downcast` or `downcast_ref` to retrieve the `ExitCode`.
pub struct ExitCode { pub struct ExitCode {
pub code: syscalls::types::__wasi_exitcode_t, pub code: syscalls::types::__wasi_exitcode_t,

View File

@ -482,7 +482,6 @@ fn execute_wasi(
#[cfg(not(feature = "managed"))] #[cfg(not(feature = "managed"))]
{ {
use wasmer_runtime::error::RuntimeError;
let result; let result;
#[cfg(unix)] #[cfg(unix)]
@ -521,14 +520,9 @@ fn execute_wasi(
} }
if let Err(ref err) = result { if let Err(ref err) = result {
match err { if let Some(error_code) = err.0.downcast_ref::<wasmer_wasi::ExitCode>() {
RuntimeError::Trap { msg } => return Err(format!("wasm trap occured: {}", msg)),
RuntimeError::Error { data } => {
if let Some(error_code) = data.downcast_ref::<wasmer_wasi::ExitCode>() {
std::process::exit(error_code.code as i32) std::process::exit(error_code.code as i32)
} }
}
}
return Err(format!("error: {:?}", err)); return Err(format!("error: {:?}", err));
} }
} }