From e0aafbe9dd9b20da3c26963b5a7415fc5b59b549 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 6 Feb 2020 23:49:50 +0800 Subject: [PATCH 1/3] Remove `WasmTrapInfo` and pass`ExceptionCode` in the generic `Box` container. --- lib/clif-backend/src/signal/mod.rs | 15 ++---- lib/clif-backend/src/signal/unix.rs | 30 ++++++----- lib/clif-backend/src/signal/windows.rs | 29 ++++++----- lib/llvm-backend/src/backend.rs | 5 +- lib/middleware-common-tests/src/lib.rs | 10 ++-- lib/runtime-core-tests/tests/imports.rs | 27 +++------- lib/runtime-core/src/backend.rs | 34 ++++++++++-- lib/runtime-core/src/error.rs | 37 ++++--------- lib/runtime-core/src/instance.rs | 18 +++---- lib/runtime-core/src/typed_func.rs | 57 +++----------------- lib/runtime/examples/call.rs | 4 +- lib/runtime/tests/error_propagation.rs | 6 +-- lib/singlepass-backend/src/codegen_x64.rs | 44 ++++++++-------- lib/singlepass-backend/src/protect_unix.rs | 16 +++--- lib/spectests/tests/semantics.rs | 10 ++-- lib/spectests/tests/spectest.rs | 60 +++++++++------------- lib/wasi/src/lib.rs | 2 +- src/bin/wasmer.rs | 10 +--- 18 files changed, 166 insertions(+), 248 deletions(-) diff --git a/lib/clif-backend/src/signal/mod.rs b/lib/clif-backend/src/signal/mod.rs index 5526cc4e215..cb6e147b1a7 100644 --- a/lib/clif-backend/src/signal/mod.rs +++ b/lib/clif-backend/src/signal/mod.rs @@ -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, }; @@ -29,10 +29,7 @@ thread_local! { pub static TRAP_EARLY_DATA: Cell>> = Cell::new(None); } -pub enum CallProtError { - Trap(WasmTrapInfo), - Error(Box), -} +pub struct CallProtError(pub Box); pub struct Caller { handler_data: HandlerData, @@ -66,8 +63,7 @@ impl RunnableModule for Caller { func: NonNull, args: *const u64, rets: *mut u64, - trap_info: *mut WasmTrapInfo, - user_error: *mut Option>, + error_out: *mut Option>, invoke_env: Option>, ) -> bool { let handler_data = &*invoke_env.unwrap().cast().as_ptr(); @@ -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, diff --git a/lib/clif-backend/src/signal/unix.rs b/lib/clif-backend/src/signal/unix.rs index d8a8e33efb9..925b8f6d7f0 100644 --- a/lib/clif-backend/src/signal/unix.rs +++ b/lib/clif-backend/src/signal/unix.rs @@ -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, @@ -79,7 +79,7 @@ pub fn call_protected( *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()); @@ -88,21 +88,25 @@ pub fn call_protected( 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", @@ -114,7 +118,7 @@ pub fn call_protected( }; // 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 { diff --git a/lib/clif-backend/src/signal/windows.rs b/lib/clif-backend/src/signal/windows.rs index 363119c6ea7..ec1c82e9c64 100644 --- a/lib/clif-backend/src/signal/windows.rs +++ b/lib/clif-backend/src/signal/windows.rs @@ -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; @@ -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 @@ -110,7 +111,7 @@ pub fn call_protected( exception_address, code, signal, ); - Err(CallProtError::Error(Box::new(s))) + Err(CallProtError(Box::new(s))) } } diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 7edc3ca57a9..a905f8f9d1b 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -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, }; @@ -65,8 +65,7 @@ extern "C" { func_ptr: NonNull, params: *const u64, results: *mut u64, - trap_out: *mut WasmTrapInfo, - user_error: *mut Option>, + error_out: *mut Option>, invoke_env: Option>, ) -> bool; } diff --git a/lib/middleware-common-tests/src/lib.rs b/lib/middleware-common-tests/src/lib.rs index 20d69bb3d0a..02f953fc474 100644 --- a/lib/middleware-common-tests/src/lib.rs +++ b/lib/middleware-common-tests/src/lib.rs @@ -165,12 +165,10 @@ mod tests { } let err = result.unwrap_err(); - match err { - RuntimeError::Error { data } => { - assert!(data.downcast_ref::().is_some()); - } - _ => unreachable!(), - } + assert!(err + .0 + .downcast_ref::() + .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. diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs index 6b7223c6735..b461ad2b758 100644 --- a/lib/runtime-core-tests/tests/imports.rs +++ b/lib/runtime-core-tests/tests/imports.rs @@ -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>(), @@ -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)))) ); diff --git a/lib/runtime-core/src/backend.rs b/lib/runtime-core/src/backend.rs index bdb6628cd5f..db68e1715d2 100644 --- a/lib/runtime-core/src/backend.rs +++ b/lib/runtime-core/src/backend.rs @@ -13,6 +13,7 @@ use crate::{ module::ModuleInfo, sys::Memory, }; +use std::fmt; use std::{any::Any, ptr::NonNull}; use std::collections::HashMap; @@ -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 { diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index 266bd444e27..a685a8238f2 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -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, - }, - /// Error. - Error { - /// Error data. - data: Box, - }, -} +pub struct RuntimeError(pub Box); impl PartialEq for RuntimeError { fn eq(&self, _other: &RuntimeError) -> bool { @@ -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::() { - write!(f, "\"{}\"", s) - } else if let Some(s) = data.downcast_ref::<&str>() { - write!(f, "\"{}\"", s) - } else if let Some(exc_code) = data.downcast_ref::() { - write!(f, "Caught exception of type \"{:?}\".", exc_code) - } else { - write!(f, "unknown error") - } - } + let data = &*self.0; + if let Some(s) = data.downcast_ref::() { + write!(f, "\"{}\"", s) + } else if let Some(s) = data.downcast_ref::<&str>() { + write!(f, "\"{}\"", s) + } else if let Some(exc_code) = data.downcast_ref::() { + write!(f, "Caught exception of type \"{:?}\".", exc_code) + } else { + write!(f, "unknown error") } } } diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index d012ae8d6be..fff1797d777 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -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}, }; @@ -673,8 +673,7 @@ 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, @@ -682,21 +681,16 @@ pub(crate) fn call_func_with_index_inner( 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())))) } }; diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 71bf805ef92..513ede7fbc0 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -11,52 +11,12 @@ use std::{ any::Any, convert::Infallible, ffi::c_void, - fmt, marker::PhantomData, mem, panic, ptr::{self, NonNull}, 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 /// can be put into the third/fourth (depending if you include lifetimes) /// of the `Func` struct. @@ -77,8 +37,7 @@ pub type Invoke = unsafe extern "C" fn( func: NonNull, args: *const u64, rets: *mut u64, - trap_info: *mut WasmTrapInfo, - user_error: *mut Option>, + error_out: *mut Option>, extra: Option>, ) -> bool; @@ -401,8 +360,7 @@ macro_rules! impl_traits { let ( $( $x ),* ) = self; let args = [ $( $x.to_native().to_binary()),* ]; let mut rets = Rets::empty_ret_array(); - let mut trap = WasmTrapInfo::Unknown; - let mut user_error = None; + let mut error_out = None; if (wasm.invoke)( wasm.trampoline, @@ -410,17 +368,14 @@ macro_rules! impl_traits { f, args.as_ptr(), rets.as_mut().as_mut_ptr(), - &mut trap, - &mut user_error, + &mut error_out, wasm.invoke_env ) { Ok(Rets::from_ret_array(rets)) } else { - if let Some(data) = user_error { - Err(RuntimeError::Error { data }) - } else { - Err(RuntimeError::Trap { msg: trap.to_string().into() }) - } + Err(error_out.map(RuntimeError).unwrap_or_else(|| { + RuntimeError(Box::new("invoke(): Unknown error".to_string())) + })) } } } diff --git a/lib/runtime/examples/call.rs b/lib/runtime/examples/call.rs index cbc632d2ed9..e393354c52a 100644 --- a/lib/runtime/examples/call.rs +++ b/lib/runtime/examples/call.rs @@ -70,8 +70,8 @@ fn main() -> Result<(), error::Error> { println!("result: {:?}", result); - if let Err(RuntimeError::Error { data }) = result { - if let Ok(exit_code) = data.downcast::() { + if let Err(e) = result { + if let Ok(exit_code) = e.0.downcast::() { println!("exit code: {:?}", exit_code); } } diff --git a/lib/runtime/tests/error_propagation.rs b/lib/runtime/tests/error_propagation.rs index 44cfa3fd943..2a725e82f90 100644 --- a/lib/runtime/tests/error_propagation.rs +++ b/lib/runtime/tests/error_propagation.rs @@ -40,10 +40,10 @@ fn error_propagation() { let result = foo.call(); - if let Err(RuntimeError::Error { data }) = result { - let exit_code = data.downcast::().unwrap(); + if let Err(RuntimeError(e)) = result { + let exit_code = e.downcast::().unwrap(); assert_eq!(exit_code.code, 42); } else { - panic!("didn't return RuntimeError::Error") + panic!("didn't return RuntimeError") } } diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 27f79dc62a9..702e0d4cbc3 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -37,7 +37,7 @@ use wasmer_runtime_core::{ ModuleStateMap, OffsetInfo, SuspendOffset, WasmAbstractValue, }, structures::{Map, TypedIndex}, - typed_func::{Trampoline, Wasm, WasmTrapInfo}, + typed_func::{Trampoline, Wasm}, types::{ FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, @@ -375,8 +375,7 @@ impl RunnableModule for X64ExecutionContext { func: NonNull, args: *const u64, rets: *mut u64, - trap_info: *mut WasmTrapInfo, - user_error: *mut Option>, + error_out: *mut Option>, num_params_plus_one: Option>, ) -> bool { let rm: &Box = &(&*(*ctx).module).runnable_module; @@ -520,10 +519,7 @@ impl RunnableModule for X64ExecutionContext { true } Err(err) => { - match err { - protect_unix::CallProtError::Trap(info) => *trap_info = info, - protect_unix::CallProtError::Error(data) => *user_error = Some(data), - } + *error_out = Some(err.0); false } }; @@ -1010,14 +1006,14 @@ impl X64FunctionCode { Self::mark_trappable(a, m, fsm, control_stack); etable .offset_to_code - .insert(a.get_offset().0, ExceptionCode::Arithmetic); + .insert(a.get_offset().0, ExceptionCode::IllegalArithmetic); op(a, sz, Location::GPR(GPR::RCX)); } _ => { Self::mark_trappable(a, m, fsm, control_stack); etable .offset_to_code - .insert(a.get_offset().0, ExceptionCode::Arithmetic); + .insert(a.get_offset().0, ExceptionCode::IllegalArithmetic); 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_cmp(Size::S64, Location::GPR(tmp_bound), Location::GPR(tmp_addr)); - Self::mark_range_with_exception_code(a, etable, ExceptionCode::Memory, |a| { - a.emit_conditional_trap(Condition::Above) - }); + Self::mark_range_with_exception_code( + a, + etable, + ExceptionCode::MemoryOutOfBounds, + |a| a.emit_conditional_trap(Condition::Above), + ); m.release_temp_gpr(tmp_bound); } @@ -2045,13 +2044,16 @@ impl X64FunctionCode { Location::Imm32(align - 1), Location::GPR(tmp_aligncheck), ); - Self::mark_range_with_exception_code(a, etable, ExceptionCode::Memory, |a| { - a.emit_conditional_trap(Condition::NotEqual) - }); + Self::mark_range_with_exception_code( + a, + etable, + ExceptionCode::MemoryOutOfBounds, + |a| a.emit_conditional_trap(Condition::NotEqual), + ); 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) })?; @@ -2186,7 +2188,7 @@ impl X64FunctionCode { a.emit_label(trap); etable .offset_to_code - .insert(a.get_offset().0, ExceptionCode::Arithmetic); + .insert(a.get_offset().0, ExceptionCode::IllegalArithmetic); a.emit_ud2(); a.emit_label(end); } @@ -2314,7 +2316,7 @@ impl X64FunctionCode { a.emit_label(trap); etable .offset_to_code - .insert(a.get_offset().0, ExceptionCode::Arithmetic); + .insert(a.get_offset().0, ExceptionCode::IllegalArithmetic); a.emit_ud2(); a.emit_label(end); } @@ -2442,7 +2444,7 @@ impl FunctionCodeGenerator for X64FunctionCode { Self::mark_range_with_exception_code( a, self.exception_table.as_mut().unwrap(), - ExceptionCode::Memory, + ExceptionCode::MemoryOutOfBounds, |a| a.emit_conditional_trap(Condition::Below), ); } @@ -6311,7 +6313,7 @@ impl FunctionCodeGenerator for X64FunctionCode { Self::mark_range_with_exception_code( a, self.exception_table.as_mut().unwrap(), - ExceptionCode::Memory, + ExceptionCode::CallIndirectOOB, |a| a.emit_conditional_trap(Condition::BelowEqual), ); a.emit_mov(Size::S64, func_index, Location::GPR(table_count)); @@ -6342,7 +6344,7 @@ impl FunctionCodeGenerator for X64FunctionCode { Self::mark_range_with_exception_code( a, self.exception_table.as_mut().unwrap(), - ExceptionCode::Memory, + ExceptionCode::IncorrectCallIndirectSignature, |a| a.emit_conditional_trap(Condition::NotEqual), ); diff --git a/lib/singlepass-backend/src/protect_unix.rs b/lib/singlepass-backend/src/protect_unix.rs index e145d367e18..96f10748909 100644 --- a/lib/singlepass-backend/src/protect_unix.rs +++ b/lib/singlepass-backend/src/protect_unix.rs @@ -13,7 +13,6 @@ use std::any::Any; use std::cell::Cell; use wasmer_runtime_core::codegen::BreakpointMap; use wasmer_runtime_core::fault::{begin_unsafe_unwind, catch_unsafe_unwind, ensure_sighandler}; -use wasmer_runtime_core::typed_func::WasmTrapInfo; thread_local! { pub static TRAP_EARLY_DATA: Cell>> = Cell::new(None); @@ -23,10 +22,7 @@ pub unsafe fn trigger_trap() -> ! { begin_unsafe_unwind(Box::new(())); } -pub enum CallProtError { - Trap(WasmTrapInfo), - Error(Box), -} +pub struct CallProtError(pub Box); pub fn call_protected( f: impl FnOnce() -> T, @@ -37,13 +33,13 @@ pub fn call_protected( let ret = catch_unsafe_unwind(|| f(), breakpoints); match ret { Ok(x) => Ok(x), - Err(e) => { + Err(e) => Err(CallProtError( if let Some(data) = TRAP_EARLY_DATA.with(|cell| cell.replace(None)) { - Err(CallProtError::Error(data)) + data } else { - Err(CallProtError::Error(e)) - } - } + e + }, + )), } } } diff --git a/lib/spectests/tests/semantics.rs b/lib/spectests/tests/semantics.rs index eadbeef0e78..bdec931ede7 100644 --- a/lib/spectests/tests/semantics.rs +++ b/lib/spectests/tests/semantics.rs @@ -3,7 +3,7 @@ mod tests { use wabt::wat2wasm; use wasmer_runtime::{ error::{CallError, RuntimeError}, - ImportObject, + ExceptionCode, ImportObject, }; // The semantics of stack overflow are documented at: @@ -29,9 +29,11 @@ mod tests { match result { Err(err) => match err { - CallError::Runtime(RuntimeError::Trap { msg }) => { - assert!(!msg.contains("segmentation violation")); - assert!(!msg.contains("bus error")); + CallError::Runtime(RuntimeError(e)) => { + let exc_code = e + .downcast::() + .expect("expecting exception code"); + assert!(exc_code != ExceptionCode::Unknown); } _ => unimplemented!(), }, diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index 9c255740e12..5f8921613bd 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -674,54 +674,42 @@ mod tests { let call_result = maybe_call_result.unwrap(); use wasmer_runtime::error::{CallError, RuntimeError}; match call_result { - Err(e) => { - match e { - CallError::Resolve(_) => { + Err(e) => match e { + CallError::Resolve(_) => { + test_report.add_failure( + SpecFailure { + file: filename.to_string(), + line, + kind: format!("{}", "AssertTrap"), + message: format!("expected trap, got {:?}", e), + }, + &test_key, + excludes, + line, + ); + } + CallError::Runtime(RuntimeError(e)) => { + use wasmer_runtime::ExceptionCode; + if let Some(_) = data.downcast_ref::() { + test_report.count_passed(); + } else { test_report.add_failure( SpecFailure { file: filename.to_string(), line, kind: format!("{}", "AssertTrap"), - message: format!("expected trap, got {:?}", e), + message: format!( + "expected trap, got Runtime:Error {:?}", + r + ), }, &test_key, excludes, line, ); } - CallError::Runtime(r) => { - match r { - RuntimeError::Trap { .. } => { - // TODO assert message? - test_report.count_passed() - } - RuntimeError::Error { ref data } => { - use wasmer_runtime::ExceptionCode; - if let Some(_) = - data.downcast_ref::() - { - test_report.count_passed(); - } else { - test_report.add_failure( - SpecFailure { - file: filename.to_string(), - line, - kind: format!("{}", "AssertTrap"), - message: format!( - "expected trap, got Runtime:Error {:?}", - r - ), - }, - &test_key, - excludes, - line, - ); - } - } - } - } } - } + }, Ok(values) => { test_report.add_failure( SpecFailure { diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 3e541d2166d..6d9dd4fce65 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -43,7 +43,7 @@ pub use self::utils::{get_wasi_version, is_wasi_module, WasiVersion}; use wasmer_runtime_core::{func, import::ImportObject, imports}; -/// This is returned in the Box RuntimeError::Error variant. +/// This is returned in `RuntimeError`. /// Use `downcast` or `downcast_ref` to retrieve the `ExitCode`. pub struct ExitCode { pub code: syscalls::types::__wasi_exitcode_t, diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 7974d228537..0f2f694c1e2 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -482,7 +482,6 @@ fn execute_wasi( #[cfg(not(feature = "managed"))] { - use wasmer_runtime::error::RuntimeError; let result; #[cfg(unix)] @@ -521,13 +520,8 @@ fn execute_wasi( } if let Err(ref err) = result { - match err { - RuntimeError::Trap { msg } => return Err(format!("wasm trap occured: {}", msg)), - RuntimeError::Error { data } => { - if let Some(error_code) = data.downcast_ref::() { - std::process::exit(error_code.code as i32) - } - } + if let Some(error_code) = err.0.downcast_ref::() { + std::process::exit(error_code.code as i32) } return Err(format!("error: {:?}", err)); } From b40edd4512ab033291bf18c04df064337edb46b4 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 11 Feb 2020 03:03:05 +0800 Subject: [PATCH 2/3] Fix failures on test compilation. --- lib/clif-backend/src/signal/windows.rs | 10 +++++++--- lib/spectests/tests/semantics.rs | 4 +--- lib/spectests/tests/spectest.rs | 5 ++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/clif-backend/src/signal/windows.rs b/lib/clif-backend/src/signal/windows.rs index ec1c82e9c64..7d3e81d695f 100644 --- a/lib/clif-backend/src/signal/windows.rs +++ b/lib/clif-backend/src/signal/windows.rs @@ -71,13 +71,17 @@ pub fn call_protected( TrapCode::HeapOutOfBounds => ExceptionCode::MemoryOutOfBounds, TrapCode::TableOutOfBounds => ExceptionCode::CallIndirectOOB, TrapCode::UnreachableCodeReached => ExceptionCode::Unreachable, - _ => ExceptionCode::Unknown, + _ => return Err(CallProtError(Box::new("unknown trap code".to_string()))), }, - EXCEPTION_STACK_OVERFLOW => ExceptionCode::Unknown, + EXCEPTION_STACK_OVERFLOW => ExceptionCode::MemoryOutOfBounds, EXCEPTION_INT_DIVIDE_BY_ZERO | EXCEPTION_INT_OVERFLOW => { ExceptionCode::IllegalArithmetic } - _ => ExceptionCode::Unknown, + _ => { + return Err(CallProtError(Box::new( + "unknown exception code".to_string(), + ))) + } }))) } else { let signal = match code as DWORD { diff --git a/lib/spectests/tests/semantics.rs b/lib/spectests/tests/semantics.rs index bdec931ede7..2edfa7cd1c4 100644 --- a/lib/spectests/tests/semantics.rs +++ b/lib/spectests/tests/semantics.rs @@ -30,10 +30,8 @@ mod tests { match result { Err(err) => match err { CallError::Runtime(RuntimeError(e)) => { - let exc_code = e - .downcast::() + e.downcast::() .expect("expecting exception code"); - assert!(exc_code != ExceptionCode::Unknown); } _ => unimplemented!(), }, diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index 5f8921613bd..f8b7939f372 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -690,7 +690,7 @@ mod tests { } CallError::Runtime(RuntimeError(e)) => { use wasmer_runtime::ExceptionCode; - if let Some(_) = data.downcast_ref::() { + if let Some(_) = e.downcast_ref::() { test_report.count_passed(); } else { test_report.add_failure( @@ -699,8 +699,7 @@ mod tests { line, kind: format!("{}", "AssertTrap"), message: format!( - "expected trap, got Runtime:Error {:?}", - r + "expected trap, got RuntimeError" ), }, &test_key, From cc4b512bde565fec6b736fbde24db65e143b980a Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 11 Feb 2020 03:16:56 +0800 Subject: [PATCH 3/3] Fix clif trap code conversions. --- lib/clif-backend/src/signal/unix.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/clif-backend/src/signal/unix.rs b/lib/clif-backend/src/signal/unix.rs index 925b8f6d7f0..81f751f37b5 100644 --- a/lib/clif-backend/src/signal/unix.rs +++ b/lib/clif-backend/src/signal/unix.rs @@ -90,10 +90,16 @@ pub fn call_protected( { Err(CallProtError(Box::new(match Signal::from_c_int(signum) { Ok(SIGILL) => match trapcode { - TrapCode::BadSignature => ExceptionCode::IncorrectCallIndirectSignature, - TrapCode::IndirectCallToNull => ExceptionCode::CallIndirectOOB, + TrapCode::StackOverflow => ExceptionCode::MemoryOutOfBounds, TrapCode::HeapOutOfBounds => ExceptionCode::MemoryOutOfBounds, TrapCode::TableOutOfBounds => ExceptionCode::CallIndirectOOB, + TrapCode::OutOfBounds => ExceptionCode::MemoryOutOfBounds, + TrapCode::IndirectCallToNull => ExceptionCode::CallIndirectOOB, + TrapCode::BadSignature => ExceptionCode::IncorrectCallIndirectSignature, + TrapCode::IntegerOverflow => ExceptionCode::IllegalArithmetic, + TrapCode::IntegerDivisionByZero => ExceptionCode::IllegalArithmetic, + TrapCode::BadConversionToInteger => ExceptionCode::IllegalArithmetic, + TrapCode::UnreachableCodeReached => ExceptionCode::Unreachable, _ => { return Err(CallProtError(Box::new( "unknown clif trap code".to_string(),