diff --git a/lib/llvm-backend/cpp/object_loader.hh b/lib/llvm-backend/cpp/object_loader.hh index 53bd2b0df..d8d74f69b 100644 --- a/lib/llvm-backend/cpp/object_loader.hh +++ b/lib/llvm-backend/cpp/object_loader.hh @@ -50,8 +50,8 @@ typedef struct { } callbacks_t; typedef struct { - size_t data, vtable; -} box_any_t; + size_t data; +} runtime_error_t; enum WasmTrapType { Unreachable = 0, @@ -121,7 +121,7 @@ private: struct WasmErrorSink { WasmTrapType *trap_out; - box_any_t *user_error; + runtime_error_t *user_error; }; struct WasmException : std::exception { @@ -149,14 +149,14 @@ public: struct UserException : UncatchableException { public: - UserException(size_t data, size_t vtable) : error_data({data, vtable}) {} + UserException(size_t data) : error_data({data}) {} virtual std::string description() const noexcept override { return "user exception"; } - // The parts of a `Box`. - box_any_t error_data; + // The pointer to `Option`. + runtime_error_t error_data; virtual void write_error(WasmErrorSink &out) const noexcept override { *out.user_error = error_data; @@ -274,10 +274,10 @@ result_t module_load(const uint8_t *mem_ptr, size_t mem_size, void module_delete(WasmModule *module) { delete module; } -// Throw a fat pointer that's assumed to be `*mut dyn Any` on the rust +// Throw a pointer that's assumed to be `*mut RuntimeError` on the rust // side. -[[noreturn]] void throw_any(size_t data, size_t vtable) { - unsafe_unwind(new UserException(data, vtable)); +[[noreturn]] void throw_runtime_error(size_t data) { + unsafe_unwind(new UserException(data)); } // Throw a pointer that's assumed to be codegen::BreakpointHandler on the @@ -288,7 +288,7 @@ void module_delete(WasmModule *module) { delete module; } bool cxx_invoke_trampoline(trampoline_t trampoline, void *ctx, void *func, void *params, void *results, WasmTrapType *trap_out, - box_any_t *user_error, void *invoke_env) noexcept { + runtime_error_t *user_error, void *invoke_env) noexcept { try { catch_unwind([trampoline, ctx, func, params, results]() { trampoline(ctx, func, params, results); diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index c3922b6be..18d5a8ce3 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -56,7 +56,7 @@ extern "C" { /// but this is cleaner, I think? #[cfg_attr(nightly, unwind(allowed))] #[allow(improper_ctypes)] - fn throw_runtime_error(data: RuntimeError) -> !; + fn throw_runtime_error(data: *mut Option) -> !; #[allow(improper_ctypes)] fn cxx_invoke_trampoline( @@ -475,8 +475,7 @@ impl RunnableModule for LLVMBackend { } unsafe fn do_early_trap(&self, data: RuntimeError) -> ! { - // maybe need to box leak it? - throw_runtime_error(data) + throw_runtime_error(Box::into_raw(Box::new(Some(data)))) } } diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 554628e25..385cef47d 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -35,6 +35,7 @@ use wasmer_runtime_core::{ backend::{CacheGen, CompilerConfig, Token}, cache::{Artifact, Error as CacheError}, codegen::*, + error::RuntimeError, memory::MemoryType, module::{ModuleInfo, ModuleInner}, parse::{wp_type_to_type, LoadError}, @@ -940,12 +941,11 @@ pub struct CodegenError { // prevents unused function elimination. #[no_mangle] pub unsafe extern "C" fn callback_trampoline( - b: *mut Option>, + b: *mut Option, callback: *mut BreakpointHandler, ) { let callback = Box::from_raw(callback); - let result: Result<(), Box> = - callback(BreakpointInfo { fault: None }); + let result: Result<(), RuntimeError> = callback(BreakpointInfo { fault: None }); match result { Ok(()) => *b = None, Err(e) => *b = Some(e), diff --git a/lib/middleware-common/src/metering.rs b/lib/middleware-common/src/metering.rs index a201403d2..d4db44f90 100644 --- a/lib/middleware-common/src/metering.rs +++ b/lib/middleware-common/src/metering.rs @@ -97,7 +97,9 @@ impl FunctionMiddleware for Metering { ty: WpTypeOrFuncType::Type(WpType::EmptyBlockType), })); sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new(|_| { - Err(RuntimeError::Metering(Box::new(ExecutionLimitExceededError))) + Err(RuntimeError::Metering(Box::new( + ExecutionLimitExceededError, + ))) })))); sink.push(Event::WasmOwned(Operator::End)); } diff --git a/lib/runtime-c-api/src/import/mod.rs b/lib/runtime-c-api/src/import/mod.rs index 79631de1c..c6d724f51 100644 --- a/lib/runtime-c-api/src/import/mod.rs +++ b/lib/runtime-c-api/src/import/mod.rs @@ -21,6 +21,7 @@ use wasmer::import::{ImportObject, ImportObjectIterator}; use wasmer::vm::Ctx; use wasmer::wasm::{Export, FuncSig, Global, Memory, Module, Table, Type}; use wasmer_runtime_core::{ + error::RuntimeError, export::{Context, FuncPointer}, module::ImportName, }; @@ -723,7 +724,7 @@ pub unsafe extern "C" fn wasmer_trap( (&*ctx.module) .runnable_module - .do_early_trap(Box::new(error_message)); // never returns + .do_early_trap(RuntimeError::User(Box::new(error_message))); // never returns // cbindgen does not generate a binding for a function that // returns `!`. Since we also need to error in some cases, the diff --git a/lib/runtime-c-api/tests/test-import-trap.c b/lib/runtime-c-api/tests/test-import-trap.c index 0e28208ec..c81df2311 100644 --- a/lib/runtime-c-api/tests/test-import-trap.c +++ b/lib/runtime-c-api/tests/test-import-trap.c @@ -69,7 +69,7 @@ int main() wasmer_last_error_message(error_str, error_len); printf("Error str: `%s`\n", error_str); - assert(0 == strcmp(error_str, "Call error: \"Hello\"")); + assert(0 == strcmp(error_str, "Call error: User supplied error: \"Hello\"")); printf("Destroying func\n"); wasmer_import_func_destroy(func); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 1e7d9296d..6262d8e8d 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -924,7 +924,7 @@ void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx); * // Allocate them and set them on the given instance. * my_data *data = malloc(sizeof(my_data)); * data->… = …; - * wasmer_instance_context_data_set(instance, (void*) my_data); + * wasmer_instance_context_data_set(instance, (void*) data); * * // You can read your data. * { diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 0bbf819cc..647e637d0 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -736,7 +736,7 @@ void *wasmer_instance_context_data_get(const wasmer_instance_context_t *ctx); /// // Allocate them and set them on the given instance. /// my_data *data = malloc(sizeof(my_data)); /// data->… = …; -/// wasmer_instance_context_data_set(instance, (void*) my_data); +/// wasmer_instance_context_data_set(instance, (void*) data); /// /// // You can read your data. /// { diff --git a/lib/runtime-core/src/error.rs b/lib/runtime-core/src/error.rs index b501c6067..44c12ad6e 100644 --- a/lib/runtime-core/src/error.rs +++ b/lib/runtime-core/src/error.rs @@ -265,10 +265,25 @@ pub enum InvokeError { /// extra TODO: investigate if this can be a `Box` instead (looks like probably no) /// TODO: EarlyTrap(Box), - /// Indicates an error that ocurred related to breakpoints. (currently Singlepass only) + /// Indicates an error that ocurred related to breakpoints. Breakpoint(Box), } +impl From for RuntimeError { + fn from(other: InvokeError) -> RuntimeError { + match other { + InvokeError::EarlyTrap(re) | InvokeError::Breakpoint(re) => *re, + _ => RuntimeError::InvokeError(other), + } + } +} + +impl PartialEq for RuntimeError { + fn eq(&self, _other: &RuntimeError) -> bool { + false + } +} + //impl std::error::Error for InvokeError {} impl std::error::Error for RuntimeError {} diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index cdd5078b5..44cae2683 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -28,9 +28,9 @@ pub mod raw { } use crate::codegen::{BreakpointInfo, BreakpointMap}; +use crate::error::{InvokeError, RuntimeError}; use crate::state::x64::{build_instance_image, read_stack, X64Register, GPR}; use crate::state::{CodeVersion, ExecutionStateImage, InstanceImage}; -use crate::error::{RuntimeError, InvokeError}; use crate::vm; use libc::{mmap, mprotect, siginfo_t, MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE}; use nix::sys::signal::{ @@ -344,11 +344,13 @@ extern "C" fn signal_trap_handler( // breakpoint let out: Option> = with_breakpoint_map(|bkpt_map| -> Option> { - bkpt_map.and_then(|x| x.get(&(fault.ip.get()))).map(|x| -> Result<(), RuntimeError> { - x(BreakpointInfo { - fault: Some(&fault), - }) - }) + bkpt_map.and_then(|x| x.get(&(fault.ip.get()))).map( + |x| -> Result<(), RuntimeError> { + x(BreakpointInfo { + fault: Some(&fault), + }) + }, + ) }); match out { Some(Ok(())) => { diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 7dd176b65..1c5bfb932 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -603,7 +603,7 @@ pub(crate) fn call_func_with_index_inner( Ok(()) } else { let error: RuntimeError = error_out - .map(RuntimeError::InvokeError) + .map(Into::into) .unwrap_or_else(|| RuntimeError::InvokeError(InvokeError::FailedWithNoError)); Err(error.into()) } diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index fb3f5d2b7..d7d5a6ee1 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -699,13 +699,13 @@ pub mod x64 { pub use super::x64_decl::*; use super::*; use crate::codegen::BreakpointMap; + use crate::error::RuntimeError; use crate::fault::{ catch_unsafe_unwind, get_boundary_register_preservation, run_on_alternative_stack, }; use crate::structures::TypedIndex; use crate::types::LocalGlobalIndex; use crate::vm::Ctx; - use crate::error::RuntimeError; #[allow(clippy::cast_ptr_alignment)] unsafe fn compute_vmctx_deref(vmctx: *const Ctx, seq: &[usize]) -> u64 { diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 4594bcd4f..b4db0fbac 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -590,7 +590,7 @@ macro_rules! impl_traits { ) { Ok(Rets::from_ret_array(rets)) } else { - Err(error_out.map_or_else(|| RuntimeError::InvokeError(InvokeError::FailedWithNoError), RuntimeError::InvokeError)) + Err(error_out.map_or_else(|| RuntimeError::InvokeError(InvokeError::FailedWithNoError), Into::into)) } } } diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index f51af7c58..63fd95dec 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -26,9 +26,9 @@ use wasmer_runtime_core::{ }, cache::{Artifact, Error as CacheError}, codegen::*, + error::{InvokeError, RuntimeError}, fault::{self, raw::register_preservation_trampoline}, loader::CodeMemory, - error::{InvokeError, RuntimeError}, memory::MemoryType, module::{ModuleInfo, ModuleInner}, state::{ diff --git a/src/commands/run.rs b/src/commands/run.rs index 432237937..12d3335e9 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -20,8 +20,8 @@ use wasmer_runtime::{ }; use wasmer_runtime_core::{ self, - error::RuntimeError, backend::{Compiler, CompilerConfig, MemoryBoundCheckMode}, + error::RuntimeError, loader::{Instance as LoadedInstance, LocalLoader}, Module, }; @@ -441,7 +441,7 @@ fn execute_wasi( if let RuntimeError::User(user_error) = err { if let Some(error_code) = user_error.downcast_ref::() { std::process::exit(error_code.code as i32) - } + } } return Err(format!("error: {:?}", err)); diff --git a/tests/high_level_api.rs b/tests/high_level_api.rs index 389e20c41..5d9ae70fb 100644 --- a/tests/high_level_api.rs +++ b/tests/high_level_api.rs @@ -268,7 +268,7 @@ wasmer_backends! { let result = foo.call(); - if let Err(RuntimeError(e)) = result { + if let Err(RuntimeError::User(e)) = result { let exit_code = e.downcast::().unwrap(); assert_eq!(exit_code.code, 42); } else { diff --git a/tests/imports.rs b/tests/imports.rs index e4ce07671..ed1a2da81 100644 --- a/tests/imports.rs +++ b/tests/imports.rs @@ -52,7 +52,7 @@ macro_rules! call_and_assert { expected_value, concat!("Expected right when calling `", stringify!($function), "`.") ), - (Err(RuntimeError(data)), Err(RuntimeError(expected_data))) => { + (Err(RuntimeError::User(data)), Err(RuntimeError::User(expected_data))) => { if let (Some(data), Some(expected_data)) = ( data.downcast_ref::<&str>(), expected_data.downcast_ref::<&str>(), @@ -406,7 +406,7 @@ wasmer_backends! { test!( test_fn, function_fn(i32) -> i32, (1) == Ok(2)); test!( test_closure, function_closure(i32) -> i32, (1) == Ok(2)); test!( test_fn_dynamic, function_fn_dynamic(i32) -> i32, (1) == Ok(2)); - test!( test_fn_dynamic_panic, function_fn_dynamic_panic(i32) -> i32, (1) == Err(RuntimeError(Box::new("test")))); + test!( test_fn_dynamic_panic, function_fn_dynamic_panic(i32) -> i32, (1) == Err(RuntimeError::User(Box::new("test")))); test!( test_closure_dynamic_0, @@ -460,31 +460,31 @@ wasmer_backends! { test_fn_trap, function_fn_trap(i32) -> i32, - (1) == Err(RuntimeError(Box::new(format!("foo {}", 2)))) + (1) == Err(RuntimeError::User(Box::new(format!("foo {}", 2)))) ); test!( test_closure_trap, function_closure_trap(i32) -> i32, - (1) == Err(RuntimeError(Box::new(format!("bar {}", 2)))) + (1) == Err(RuntimeError::User(Box::new(format!("bar {}", 2)))) ); test!( test_fn_trap_with_vmctx, function_fn_trap_with_vmctx(i32) -> i32, - (1) == Err(RuntimeError(Box::new(format!("baz {}", 2 + SHIFT)))) + (1) == Err(RuntimeError::User(Box::new(format!("baz {}", 2 + SHIFT)))) ); test!( test_closure_trap_with_vmctx, function_closure_trap_with_vmctx(i32) -> i32, - (1) == Err(RuntimeError(Box::new(format!("qux {}", 2 + SHIFT)))) + (1) == Err(RuntimeError::User(Box::new(format!("qux {}", 2 + SHIFT)))) ); test!( test_closure_trap_with_vmctx_and_env, function_closure_trap_with_vmctx_and_env(i32) -> i32, - (1) == Err(RuntimeError(Box::new(format!("! {}", 2 + shift + SHIFT)))) + (1) == Err(RuntimeError::User(Box::new(format!("! {}", 2 + shift + SHIFT)))) ); #[test] diff --git a/tests/middleware_common.rs b/tests/middleware_common.rs index 90516af0c..ca423661d 100644 --- a/tests/middleware_common.rs +++ b/tests/middleware_common.rs @@ -6,6 +6,7 @@ use wasmer::wasm::Func; use wasmer_middleware_common::metering::*; use wasmer_runtime_core::codegen::ModuleCodeGenerator; use wasmer_runtime_core::codegen::{MiddlewareChain, StreamingCompiler}; +use wasmer_runtime_core::error::RuntimeError; use wasmer_runtime_core::fault::{pop_code_version, push_code_version}; use wasmer_runtime_core::state::CodeVersion; @@ -179,10 +180,13 @@ fn middleware_test_traps_after_costly_call(backend: &'static str, compiler: impl } let err = result.unwrap_err(); - assert!(err - .0 - .downcast_ref::() - .is_some()); + if let RuntimeError::Metering(metering_err) = err { + assert!(metering_err + .downcast_ref::() + .is_some()); + } else { + assert!(false, "metering error not found"); + } // 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.