Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use ExceptionCode for error representation. #1192

Merged
merged 7 commits into from
Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions lib/clif-backend/src/signal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{any::Any, cell::Cell, ptr::NonNull, sync::Arc};
use wasmer_runtime_core::{
backend::RunnableModule,
module::ModuleInfo,
typed_func::{Trampoline, Wasm, WasmTrapInfo},
typed_func::{Trampoline, Wasm},
types::{LocalFuncIndex, SigIndex},
vm,
};
Expand All @@ -29,10 +29,7 @@ thread_local! {
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any + Send>>> = Cell::new(None);
}

pub enum CallProtError {
Trap(WasmTrapInfo),
Error(Box<dyn Any + Send>),
}
pub struct CallProtError(pub Box<dyn Any + Send>);

pub struct Caller {
handler_data: HandlerData,
Expand Down Expand Up @@ -66,8 +63,7 @@ impl RunnableModule for Caller {
func: NonNull<vm::Func>,
args: *const u64,
rets: *mut u64,
trap_info: *mut WasmTrapInfo,
user_error: *mut Option<Box<dyn Any + Send>>,
error_out: *mut Option<Box<dyn Any + Send>>,
invoke_env: Option<NonNull<c_void>>,
) -> bool {
let handler_data = &*invoke_env.unwrap().cast().as_ptr();
Expand All @@ -84,10 +80,7 @@ impl RunnableModule for Caller {

match res {
Err(err) => {
match err {
CallProtError::Trap(info) => *trap_info = info,
CallProtError::Error(data) => *user_error = Some(data),
}
*error_out = Some(err.0);
false
}
Ok(()) => true,
Expand Down
30 changes: 17 additions & 13 deletions lib/clif-backend/src/signal/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use nix::sys::signal::{
use std::cell::{Cell, UnsafeCell};
use std::ptr;
use std::sync::Once;
use wasmer_runtime_core::typed_func::WasmTrapInfo;
use wasmer_runtime_core::backend::ExceptionCode;

extern "C" fn signal_trap_handler(
signum: ::nix::libc::c_int,
Expand Down Expand Up @@ -79,7 +79,7 @@ pub fn call_protected<T>(
*jmp_buf = prev_jmp_buf;

if let Some(data) = super::TRAP_EARLY_DATA.with(|cell| cell.replace(None)) {
Err(CallProtError::Error(data))
Err(CallProtError(data))
} else {
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());

Expand All @@ -88,21 +88,25 @@ pub fn call_protected<T>(
srcloc: _,
}) = 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 {
TrapCode::BadSignature => WasmTrapInfo::IncorrectCallIndirectSignature,
TrapCode::IndirectCallToNull => WasmTrapInfo::CallIndirectOOB,
TrapCode::HeapOutOfBounds => WasmTrapInfo::MemoryOutOfBounds,
TrapCode::TableOutOfBounds => WasmTrapInfo::CallIndirectOOB,
_ => WasmTrapInfo::Unknown,
TrapCode::BadSignature => ExceptionCode::IncorrectCallIndirectSignature,
TrapCode::IndirectCallToNull => ExceptionCode::CallIndirectOOB,
TrapCode::HeapOutOfBounds => ExceptionCode::MemoryOutOfBounds,
TrapCode::TableOutOfBounds => ExceptionCode::CallIndirectOOB,
_ => {
return Err(CallProtError(Box::new(
"unknown clif trap code".to_string(),
)))
}
},
Ok(SIGSEGV) | Ok(SIGBUS) => WasmTrapInfo::MemoryOutOfBounds,
Ok(SIGFPE) => WasmTrapInfo::IllegalArithmetic,
Ok(SIGSEGV) | Ok(SIGBUS) => ExceptionCode::MemoryOutOfBounds,
Ok(SIGFPE) => ExceptionCode::IllegalArithmetic,
_ => unimplemented!(
"WasmTrapInfo::Unknown signal:{:?}",
"ExceptionCode::Unknown signal:{:?}",
Signal::from_c_int(signum)
),
}))
})))
} else {
let signal = match Signal::from_c_int(signum) {
Ok(SIGFPE) => "floating-point exception",
Expand All @@ -114,7 +118,7 @@ pub fn call_protected<T>(
};
// When the trap-handler is fully implemented, this will return more information.
let s = format!("unknown trap at {:p} - {}", faulting_addr, signal);
Err(CallProtError::Error(Box::new(s)))
Err(CallProtError(Box::new(s)))
}
}
} else {
Expand Down
29 changes: 15 additions & 14 deletions lib/clif-backend/src/signal/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use std::{
ptr::{self, NonNull},
};
use wasmer_runtime_core::{
typed_func::{Trampoline, WasmTrapInfo},
backend::ExceptionCode,
typed_func::Trampoline,
vm::{Ctx, Func},
};
use wasmer_win_exception_handler::CallProtectedData;
Expand Down Expand Up @@ -62,22 +63,22 @@ pub fn call_protected(
srcloc: _,
}) = handler_data.lookup(instruction_pointer as _)
{
Err(CallProtError::Trap(match code as DWORD {
EXCEPTION_ACCESS_VIOLATION => WasmTrapInfo::MemoryOutOfBounds,
Err(CallProtError(Box::new(match code as DWORD {
EXCEPTION_ACCESS_VIOLATION => ExceptionCode::MemoryOutOfBounds,
EXCEPTION_ILLEGAL_INSTRUCTION => match trapcode {
TrapCode::BadSignature => WasmTrapInfo::IncorrectCallIndirectSignature,
TrapCode::IndirectCallToNull => WasmTrapInfo::CallIndirectOOB,
TrapCode::HeapOutOfBounds => WasmTrapInfo::MemoryOutOfBounds,
TrapCode::TableOutOfBounds => WasmTrapInfo::CallIndirectOOB,
TrapCode::UnreachableCodeReached => WasmTrapInfo::Unreachable,
_ => WasmTrapInfo::Unknown,
TrapCode::BadSignature => ExceptionCode::IncorrectCallIndirectSignature,
TrapCode::IndirectCallToNull => ExceptionCode::CallIndirectOOB,
TrapCode::HeapOutOfBounds => ExceptionCode::MemoryOutOfBounds,
TrapCode::TableOutOfBounds => ExceptionCode::CallIndirectOOB,
TrapCode::UnreachableCodeReached => ExceptionCode::Unreachable,
_ => ExceptionCode::Unknown,
},
EXCEPTION_STACK_OVERFLOW => WasmTrapInfo::Unknown,
EXCEPTION_STACK_OVERFLOW => ExceptionCode::Unknown,
EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => {
WasmTrapInfo::IllegalArithmetic
ExceptionCode::IllegalArithmetic
}
_ => WasmTrapInfo::Unknown,
}))
_ => ExceptionCode::Unknown,
})))
} else {
let signal = match code as DWORD {
EXCEPTION_FLT_DENORMAL_OPERAND
Expand Down Expand Up @@ -110,7 +111,7 @@ pub fn call_protected(
exception_address, code, signal,
);

Err(CallProtError::Error(Box::new(s)))
Err(CallProtError(Box::new(s)))
}
}

Expand Down
5 changes: 2 additions & 3 deletions lib/llvm-backend/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use wasmer_runtime_core::{
module::ModuleInfo,
state::ModuleStateMap,
structures::TypedIndex,
typed_func::{Trampoline, Wasm, WasmTrapInfo},
typed_func::{Trampoline, Wasm},
types::{LocalFuncIndex, SigIndex},
vm, vmcalls,
};
Expand Down Expand Up @@ -65,8 +65,7 @@ extern "C" {
func_ptr: NonNull<vm::Func>,
params: *const u64,
results: *mut u64,
trap_out: *mut WasmTrapInfo,
user_error: *mut Option<Box<dyn Any + Send>>,
error_out: *mut Option<Box<dyn Any + Send>>,
invoke_env: Option<NonNull<c_void>>,
) -> bool;
}
Expand Down
10 changes: 4 additions & 6 deletions lib/middleware-common-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,10 @@ mod tests {
}

let err = result.unwrap_err();
match err {
RuntimeError::Error { data } => {
assert!(data.downcast_ref::<ExecutionLimitExceededError>().is_some());
}
_ => unreachable!(),
}
assert!(err
.0
.downcast_ref::<ExecutionLimitExceededError>()
.is_some());

// 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.
Expand Down
27 changes: 6 additions & 21 deletions lib/runtime-core-tests/tests/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,7 @@ macro_rules! call_and_assert {
expected_value,
concat!("Expected right when calling `", stringify!($function), "`.")
),
(
Err(RuntimeError::Error { data }),
Err(RuntimeError::Error {
data: expected_data,
}),
) => {
(Err(RuntimeError(data)), Err(RuntimeError(expected_data))) => {
if let (Some(data), Some(expected_data)) = (
data.downcast_ref::<&str>(),
expected_data.downcast_ref::<&str>(),
Expand Down Expand Up @@ -260,35 +255,25 @@ test!(
test!(
test_fn_trap,
function_fn_trap,
Err(RuntimeError::Error {
data: Box::new(format!("foo {}", 2))
})
Err(RuntimeError(Box::new(format!("foo {}", 2))))
);
test!(
test_closure_trap,
function_closure_trap,
Err(RuntimeError::Error {
data: Box::new(format!("bar {}", 2))
})
Err(RuntimeError(Box::new(format!("bar {}", 2))))
);
test!(
test_fn_trap_with_vmctx,
function_fn_trap_with_vmctx,
Err(RuntimeError::Error {
data: Box::new(format!("baz {}", 2 + SHIFT))
})
Err(RuntimeError(Box::new(format!("baz {}", 2 + SHIFT))))
);
test!(
test_closure_trap_with_vmctx,
function_closure_trap_with_vmctx,
Err(RuntimeError::Error {
data: Box::new(format!("qux {}", 2 + SHIFT))
})
Err(RuntimeError(Box::new(format!("qux {}", 2 + SHIFT))))
);
test!(
test_closure_trap_with_vmctx_and_env,
function_closure_trap_with_vmctx_and_env,
Err(RuntimeError::Error {
data: Box::new(format!("! {}", 2 + shift + SHIFT))
})
Err(RuntimeError(Box::new(format!("! {}", 2 + shift + SHIFT))))
);
34 changes: 29 additions & 5 deletions lib/runtime-core/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{
module::ModuleInfo,
sys::Memory,
};
use std::fmt;
use std::{any::Any, ptr::NonNull};

use std::collections::HashMap;
Expand Down Expand Up @@ -158,13 +159,36 @@ impl ExceptionTable {
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum ExceptionCode {
/// 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.
Arithmetic,
IllegalArithmetic = 4,
/// Misaligned atomic access trap.
MisalignedAtomicAccess = 5,
}

/// Memory access exception, e.g. misaligned/out-of-bound read/write.
Memory,
impl fmt::Display for ExceptionCode {
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 {
Expand Down
37 changes: 10 additions & 27 deletions lib/runtime-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,18 +179,7 @@ impl std::error::Error for LinkError {}
/// The main way to do this is `Instance.call`.
///
/// Comparing two `RuntimeError`s always evaluates to false.
pub enum RuntimeError {
/// Trap.
Trap {
/// Trap message.
msg: Box<str>,
},
/// Error.
Error {
/// Error data.
data: Box<dyn Any + Send>,
},
}
pub struct RuntimeError(pub Box<dyn Any + Send>);

impl PartialEq for RuntimeError {
fn eq(&self, _other: &RuntimeError) -> bool {
Expand All @@ -200,21 +189,15 @@ impl PartialEq for RuntimeError {

impl std::fmt::Display for RuntimeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
RuntimeError::Trap { ref msg } => {
write!(f, "WebAssembly trap occurred during runtime: {}", msg)
}
RuntimeError::Error { data } => {
if let Some(s) = data.downcast_ref::<String>() {
write!(f, "\"{}\"", s)
} else if let Some(s) = data.downcast_ref::<&str>() {
write!(f, "\"{}\"", s)
} else if let Some(exc_code) = data.downcast_ref::<ExceptionCode>() {
write!(f, "Caught exception of type \"{:?}\".", exc_code)
} else {
write!(f, "unknown error")
}
}
let data = &*self.0;
if let Some(s) = data.downcast_ref::<String>() {
write!(f, "\"{}\"", s)
} else if let Some(s) = data.downcast_ref::<&str>() {
write!(f, "\"{}\"", s)
} else if let Some(exc_code) = data.downcast_ref::<ExceptionCode>() {
write!(f, "Caught exception of type \"{:?}\".", exc_code)
} else {
write!(f, "unknown error")
}
}
}
Expand Down
18 changes: 6 additions & 12 deletions lib/runtime-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
sig_registry::SigRegistry,
structures::TypedIndex,
table::Table,
typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList},
typed_func::{Func, Wasm, WasmTypeList},
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value},
vm::{self, InternalField},
};
Expand Down Expand Up @@ -673,30 +673,24 @@ pub(crate) fn call_func_with_index_inner(
} = wasm;

let run_wasm = |result_space: *mut u64| unsafe {
let mut trap_info = WasmTrapInfo::Unknown;
let mut user_error = None;
let mut error_out = None;

let success = invoke(
trampoline,
ctx_ptr,
func_ptr,
raw_args.as_ptr(),
result_space,
&mut trap_info,
&mut user_error,
&mut error_out,
invoke_env,
);

if success {
Ok(())
} else {
if let Some(data) = user_error {
Err(RuntimeError::Error { data })
} else {
Err(RuntimeError::Trap {
msg: trap_info.to_string().into(),
})
}
Err(error_out
.map(RuntimeError)
.unwrap_or_else(|| RuntimeError(Box::new("invoke(): Unknown error".to_string()))))
}
};

Expand Down
Loading