Skip to content

Commit

Permalink
Try #1401:
Browse files Browse the repository at this point in the history
  • Loading branch information
bors[bot] authored Apr 27, 2020
2 parents a4ab71e + cffdb38 commit def73b7
Show file tree
Hide file tree
Showing 25 changed files with 296 additions and 132 deletions.
1 change: 0 additions & 1 deletion examples/callback-guest/callback-guest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ extern "C" {
fn host_callback() -> u32;
}

#[no_mangle]
fn test_callback() -> u32 {
42
}
Expand Down
Binary file modified examples/callback-guest/callback-guest.wasm
Binary file not shown.
16 changes: 9 additions & 7 deletions lib/clif-backend/src/signal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use crate::{
trampoline::Trampolines,
};
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::{
backend::RunnableModule,
error::RuntimeError,
module::ModuleInfo,
typed_func::{Trampoline, Wasm},
types::{LocalFuncIndex, SigIndex},
Expand All @@ -26,11 +27,9 @@ pub use self::unix::*;
pub use self::windows::*;

thread_local! {
pub static TRAP_EARLY_DATA: Cell<Option<Box<dyn Any + Send>>> = Cell::new(None);
pub static TRAP_EARLY_DATA: Cell<Option<RuntimeError>> = Cell::new(None);
}

pub struct CallProtError(pub Box<dyn Any + Send>);

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

match res {
Err(err) => {
*error_out = Some(err.0);
// probably makes the most sense to actually do a translation here to a
// a generic type defined in runtime-core
// TODO: figure out _this_ error return story
*error_out = Some(err.into());
false
}
Ok(()) => true,
Expand All @@ -101,7 +103,7 @@ impl RunnableModule for Caller {
})
}

unsafe fn do_early_trap(&self, data: Box<dyn Any + Send>) -> ! {
unsafe fn do_early_trap(&self, data: RuntimeError) -> ! {
TRAP_EARLY_DATA.with(|cell| cell.set(Some(data)));
trigger_trap()
}
Expand Down
31 changes: 16 additions & 15 deletions lib/clif-backend/src/signal/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//! unless you have memory unsafety elsewhere in your code.
//!
use crate::relocation::{TrapCode, TrapData};
use crate::signal::{CallProtError, HandlerData};
use crate::signal::HandlerData;
use libc::{c_int, c_void, siginfo_t};
use nix::sys::signal::{
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
Expand All @@ -19,6 +19,7 @@ use std::cell::{Cell, UnsafeCell};
use std::ptr;
use std::sync::Once;
use wasmer_runtime_core::backend::ExceptionCode;
use wasmer_runtime_core::error::InvokeError;

extern "C" fn signal_trap_handler(
signum: ::nix::libc::c_int,
Expand Down Expand Up @@ -65,7 +66,7 @@ pub unsafe fn trigger_trap() -> ! {
pub fn call_protected<T>(
handler_data: &HandlerData,
f: impl FnOnce() -> T,
) -> Result<T, CallProtError> {
) -> Result<T, InvokeError> {
unsafe {
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
let prev_jmp_buf = *jmp_buf;
Expand All @@ -79,16 +80,12 @@ 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(data))
Err(InvokeError::EarlyTrap(Box::new(data)))
} else {
let (faulting_addr, inst_ptr) = CAUGHT_ADDRESSES.with(|cell| cell.get());

if let Some(TrapData {
trapcode,
srcloc: _,
}) = handler_data.lookup(inst_ptr)
{
Err(CallProtError(Box::new(match Signal::from_c_int(signum) {
if let Some(TrapData { trapcode, srcloc }) = handler_data.lookup(inst_ptr) {
let code = match Signal::from_c_int(signum) {
Ok(SIGILL) => match trapcode {
TrapCode::StackOverflow => ExceptionCode::MemoryOutOfBounds,
TrapCode::HeapOutOfBounds => ExceptionCode::MemoryOutOfBounds,
Expand All @@ -101,9 +98,10 @@ pub fn call_protected<T>(
TrapCode::BadConversionToInteger => ExceptionCode::IllegalArithmetic,
TrapCode::UnreachableCodeReached => ExceptionCode::Unreachable,
_ => {
return Err(CallProtError(Box::new(
"unknown clif trap code".to_string(),
)))
return Err(InvokeError::UnknownTrapCode {
trap_code: format!("{:?}", trapcode),
srcloc,
})
}
},
Ok(SIGSEGV) | Ok(SIGBUS) => ExceptionCode::MemoryOutOfBounds,
Expand All @@ -112,7 +110,8 @@ pub fn call_protected<T>(
"ExceptionCode::Unknown signal:{:?}",
Signal::from_c_int(signum)
),
})))
};
Err(InvokeError::TrapCode { srcloc, code })
} else {
let signal = match Signal::from_c_int(signum) {
Ok(SIGFPE) => "floating-point exception",
Expand All @@ -123,8 +122,10 @@ pub fn call_protected<T>(
_ => "unknown trapped signal",
};
// When the trap-handler is fully implemented, this will return more information.
let s = format!("unknown trap at {:p} - {}", faulting_addr, signal);
Err(CallProtError(Box::new(s)))
Err(InvokeError::UnknownTrap {
address: faulting_addr as usize,
signal,
})
}
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion lib/llvm-backend/cpp/object_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ MemoryManager::~MemoryManager() {
callbacks.dealloc_memory(read_section.base, read_section.size);
callbacks.dealloc_memory(readwrite_section.base, readwrite_section.size);
}
void unwinding_setjmp(jmp_buf stack_out, void (*func)(void *), void *userdata) {
void unwinding_setjmp(jmp_buf &stack_out, void (*func)(void *), void *userdata) {
if (setjmp(stack_out)) {

} else {
Expand Down
26 changes: 14 additions & 12 deletions lib/llvm-backend/cpp/object_loader.hh
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ typedef struct {
visit_fde_t visit_fde;
} callbacks_t;

typedef struct {
size_t data, vtable;
} box_any_t;
using runtime_error_t = void*;

enum WasmTrapType {
Unreachable = 0,
Expand All @@ -65,6 +63,8 @@ enum WasmTrapType {

extern "C" void callback_trampoline(void *, void *);

extern "C" void copy_runtime_error(runtime_error_t src, runtime_error_t dst);

struct MemoryManager : llvm::RuntimeDyld::MemoryManager {
public:
MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {}
Expand Down Expand Up @@ -121,7 +121,7 @@ private:

struct WasmErrorSink {
WasmTrapType *trap_out;
box_any_t *user_error;
runtime_error_t user_error;
};

struct WasmException : std::exception {
Expand Down Expand Up @@ -149,17 +149,19 @@ public:

struct UserException : UncatchableException {
public:
UserException(size_t data, size_t vtable) : error_data({data, vtable}) {}
UserException(size_t data) {
error_data = reinterpret_cast<runtime_error_t>(data);
}

virtual std::string description() const noexcept override {
return "user exception";
}

// The parts of a `Box<dyn Any>`.
box_any_t error_data;
// The pointer to `Option<RuntimeError>`.
runtime_error_t error_data;

virtual void write_error(WasmErrorSink &out) const noexcept override {
*out.user_error = error_data;
copy_runtime_error(error_data, out.user_error);
}
};

Expand Down Expand Up @@ -274,10 +276,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 Option<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
Expand All @@ -288,7 +290,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);
Expand Down
49 changes: 32 additions & 17 deletions lib/llvm-backend/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use inkwell::{
};
use libc::c_char;
use std::{
any::Any,
cell::RefCell,
ffi::{c_void, CString},
mem,
Expand All @@ -27,6 +26,7 @@ use wasmer_runtime_core::{
CacheGen, ExceptionCode, RunnableModule,
},
cache::Error as CacheError,
error::{InvokeError, RuntimeError},
module::ModuleInfo,
state::ModuleStateMap,
structures::TypedIndex,
Expand All @@ -52,11 +52,9 @@ extern "C" {
fn throw_trap(ty: i32) -> !;
fn throw_breakpoint(ty: i64) -> !;

/// This should be the same as spliting up the fat pointer into two arguments,
/// but this is cleaner, I think?
#[cfg_attr(nightly, unwind(allowed))]
#[allow(improper_ctypes)]
fn throw_any(data: *mut dyn Any) -> !;
fn throw_runtime_error(data: *mut Option<RuntimeError>) -> !;

#[allow(improper_ctypes)]
fn cxx_invoke_trampoline(
Expand All @@ -66,11 +64,21 @@ extern "C" {
params: *const u64,
results: *mut u64,
trap_out: *mut i32,
error_out: *mut Option<Box<dyn Any + Send>>,
error_out: *mut Option<RuntimeError>,
invoke_env: Option<NonNull<c_void>>,
) -> bool;
}

#[no_mangle]
pub unsafe extern "C" fn copy_runtime_error(
src: *mut Option<RuntimeError>,
dst: *mut Option<RuntimeError>,
) {
assert_eq!(src as usize % mem::align_of::<Option<RuntimeError>>(), 0);
assert_eq!(dst as usize % mem::align_of::<Option<RuntimeError>>(), 0);
ptr::copy::<Option<RuntimeError>>(src, dst, 1);
}

/// `invoke_trampoline` is a wrapper around `cxx_invoke_trampoline`, for fixing up the obsoleted
/// `trap_out` in the C++ part.
unsafe extern "C" fn invoke_trampoline(
Expand All @@ -79,7 +87,7 @@ unsafe extern "C" fn invoke_trampoline(
func_ptr: NonNull<vm::Func>,
params: *const u64,
results: *mut u64,
error_out: *mut Option<Box<dyn Any + Send>>,
error_out: *mut Option<RuntimeError>,
invoke_env: Option<NonNull<c_void>>,
) -> bool {
let mut trap_out: i32 = -1;
Expand All @@ -95,15 +103,22 @@ unsafe extern "C" fn invoke_trampoline(
);
// Translate trap code if an error occurred.
if !ret && (*error_out).is_none() && trap_out != -1 {
*error_out = Some(Box::new(match trap_out {
0 => ExceptionCode::Unreachable,
1 => ExceptionCode::IncorrectCallIndirectSignature,
2 => ExceptionCode::MemoryOutOfBounds,
3 => ExceptionCode::CallIndirectOOB,
4 => ExceptionCode::IllegalArithmetic,
5 => ExceptionCode::MisalignedAtomicAccess,
_ => return ret,
}));
*error_out = {
let exception_code = match trap_out {
0 => ExceptionCode::Unreachable,
1 => ExceptionCode::IncorrectCallIndirectSignature,
2 => ExceptionCode::MemoryOutOfBounds,
3 => ExceptionCode::CallIndirectOOB,
4 => ExceptionCode::IllegalArithmetic,
5 => ExceptionCode::MisalignedAtomicAccess,
_ => return ret,
};
Some(RuntimeError::InvokeError(InvokeError::TrapCode {
code: exception_code,
// TODO:
srcloc: 0,
}))
};
}
ret
}
Expand Down Expand Up @@ -467,8 +482,8 @@ impl RunnableModule for LLVMBackend {
self.msm.clone()
}

unsafe fn do_early_trap(&self, data: Box<dyn Any + Send>) -> ! {
throw_any(Box::leak(data))
unsafe fn do_early_trap(&self, data: RuntimeError) -> ! {
throw_runtime_error(Box::into_raw(Box::new(Some(data))))
}
}

Expand Down
6 changes: 3 additions & 3 deletions lib/llvm-backend/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -940,12 +941,11 @@ pub struct CodegenError {
// prevents unused function elimination.
#[no_mangle]
pub unsafe extern "C" fn callback_trampoline(
b: *mut Option<Box<dyn std::any::Any>>,
b: *mut Option<RuntimeError>,
callback: *mut BreakpointHandler,
) {
let callback = Box::from_raw(callback);
let result: Result<(), Box<dyn std::any::Any + Send>> =
callback(BreakpointInfo { fault: None });
let result: Result<(), RuntimeError> = callback(BreakpointInfo { fault: None });
match result {
Ok(()) => *b = None,
Err(e) => *b = Some(e),
Expand Down
5 changes: 4 additions & 1 deletion lib/middleware-common/src/metering.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use wasmer_runtime_core::{
codegen::{Event, EventSink, FunctionMiddleware, InternalEvent},
error::RuntimeError,
module::ModuleInfo,
vm::{Ctx, InternalField},
wasmparser::{Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType},
Expand Down Expand Up @@ -96,7 +97,9 @@ impl FunctionMiddleware for Metering {
ty: WpTypeOrFuncType::Type(WpType::EmptyBlockType),
}));
sink.push(Event::Internal(InternalEvent::Breakpoint(Box::new(|_| {
Err(Box::new(ExecutionLimitExceededError))
Err(RuntimeError::Metering(Box::new(
ExecutionLimitExceededError,
)))
}))));
sink.push(Event::WasmOwned(Operator::End));
}
Expand Down
3 changes: 2 additions & 1 deletion lib/runtime-c-api/src/import/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit def73b7

Please sign in to comment.