Skip to content

Commit

Permalink
Try #2305:
Browse files Browse the repository at this point in the history
  • Loading branch information
bors[bot] authored May 11, 2021
2 parents f2e9a57 + 1863fcb commit d5ca8ad
Show file tree
Hide file tree
Showing 17 changed files with 355 additions and 259 deletions.
1 change: 1 addition & 0 deletions lib/api/src/externals/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ impl Function {
// Call the trampoline.
if let Err(error) = unsafe {
wasmer_call_trampoline(
&self.store,
self.exported.vm_function.vmctx,
trampoline,
self.exported.vm_function.address,
Expand Down
3 changes: 2 additions & 1 deletion lib/api/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@ impl Module {
// of this steps traps, we still need to keep the instance alive
// as some of the Instance elements may have placed in other
// instance tables.
self.artifact.finish_instantiation(&instance_handle)?;
self.artifact
.finish_instantiation(&self.store, &instance_handle)?;

Ok(instance_handle)
}
Expand Down
5 changes: 3 additions & 2 deletions lib/api/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ macro_rules! impl_native_traits {
};
unsafe {
wasmer_vm::wasmer_call_trampoline(
&self.store,
self.vmctx(),
trampoline,
self.address(),
Expand All @@ -145,8 +146,8 @@ macro_rules! impl_native_traits {
// TODO: we can probably remove this copy by doing some clever `transmute`s.
// we know it's not overlapping because `using_rets_array` is false
std::ptr::copy_nonoverlapping(src_pointer,
rets_list,
num_rets);
rets_list,
num_rets);
}
}
Ok(Rets::from_array(rets_list_array))
Expand Down
25 changes: 20 additions & 5 deletions lib/api/src/store.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::tunables::BaseTunables;
use loupe::MemoryUsage;
use std::any::Any;
use std::fmt;
use std::sync::Arc;
#[cfg(all(feature = "compiler", feature = "engine"))]
use wasmer_compiler::CompilerConfig;
use wasmer_engine::{Engine, Tunables};
use wasmer_engine::{is_wasm_pc, Engine, Tunables};
use wasmer_vm::{init_traps, SignalHandler, TrapInfo};

/// The store represents all global state that can be manipulated by
/// WebAssembly programs. It consists of the runtime representation
Expand All @@ -28,17 +30,18 @@ impl Store {
where
E: Engine + ?Sized,
{
Self {
engine: engine.cloned(),
tunables: Arc::new(BaseTunables::for_target(engine.target())),
}
Self::new_with_tunables(engine, BaseTunables::for_target(engine.target()))
}

/// Creates a new `Store` with a specific [`Engine`] and [`Tunables`].
pub fn new_with_tunables<E>(engine: &E, tunables: impl Tunables + Send + Sync + 'static) -> Self
where
E: Engine + ?Sized,
{
// Make sure the signal handlers are installed.
// This is required for handling traps.
init_traps(is_wasm_pc);

Self {
engine: engine.cloned(),
tunables: Arc::new(tunables),
Expand Down Expand Up @@ -69,6 +72,18 @@ impl PartialEq for Store {
}
}

unsafe impl TrapInfo for Store {
#[inline]
fn as_any(&self) -> &dyn Any {
self
}
fn custom_signal_handler(&self, _call: &dyn Fn(&SignalHandler) -> bool) -> bool {
// Setting a custom handler is implemented for now, please open an issue
// in the Wasmer Github repo if you are interested in this.
false
}
}

// We only implement default if we have assigned a default compiler and engine
#[cfg(all(feature = "default-compiler", feature = "default-engine"))]
impl Default for Store {
Expand Down
3 changes: 2 additions & 1 deletion lib/compiler-cranelift/src/sink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,9 @@ fn translate_ir_trapcode(trap: ir::TrapCode) -> TrapCode {
ir::TrapCode::IntegerDivisionByZero => TrapCode::IntegerDivisionByZero,
ir::TrapCode::BadConversionToInteger => TrapCode::BadConversionToInteger,
ir::TrapCode::UnreachableCodeReached => TrapCode::UnreachableCodeReached,
ir::TrapCode::Interrupt => TrapCode::Interrupt,
ir::TrapCode::Interrupt => unimplemented!("Interrupts not supported"),
ir::TrapCode::User(_user_code) => unimplemented!("User trap code not supported"),
// ir::TrapCode::Interrupt => TrapCode::Interrupt,
// ir::TrapCode::User(user_code) => TrapCode::User(user_code),
}
}
5 changes: 3 additions & 2 deletions lib/engine/src/artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use wasmer_types::{
};
use wasmer_vm::{
FuncDataRegistry, FunctionBodyPtr, InstanceAllocator, InstanceHandle, MemoryStyle, ModuleInfo,
TableStyle, VMSharedSignatureIndex, VMTrampoline,
TableStyle, TrapInfo, VMSharedSignatureIndex, VMTrampoline,
};

/// An `Artifact` is the product that the `Engine`
Expand Down Expand Up @@ -161,6 +161,7 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
/// See [`InstanceHandle::finish_instantiation`].
unsafe fn finish_instantiation(
&self,
trap_info: &dyn TrapInfo,
handle: &InstanceHandle,
) -> Result<(), InstantiationError> {
let data_initializers = self
Expand All @@ -172,7 +173,7 @@ pub trait Artifact: Send + Sync + Upcastable + MemoryUsage {
})
.collect::<Vec<_>>();
handle
.finish_instantiation(&data_initializers)
.finish_instantiation(trap_info, &data_initializers)
.map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))
}
}
Expand Down
9 changes: 8 additions & 1 deletion lib/engine/src/trap/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct RuntimeError {
#[derive(Debug)]
enum RuntimeErrorSource {
Generic(String),
OOM,
User(Box<dyn Error + Send + Sync>),
Trap(TrapCode),
}
Expand All @@ -25,6 +26,7 @@ impl fmt::Display for RuntimeErrorSource {
match self {
Self::Generic(s) => write!(f, "{}", s),
Self::User(s) => write!(f, "{}", s),
Self::OOM => write!(f, "Wasmer VM out of memory"),
Self::Trap(s) => write!(f, "{}", s.message()),
}
}
Expand Down Expand Up @@ -66,6 +68,7 @@ impl RuntimeError {
pub fn from_trap(trap: Trap) -> Self {
let info = FRAME_INFO.read().unwrap();
match trap {
// A user error
Trap::User(error) => {
match error.downcast::<Self>() {
// The error is already a RuntimeError, we return it directly
Expand All @@ -78,6 +81,10 @@ impl RuntimeError {
),
}
}
// A trap caused by the VM being Out of Memory
Trap::OOM { backtrace } => {
Self::new_with_trace(&info, None, RuntimeErrorSource::OOM, backtrace)
}
// A trap caused by an error on the generated machine code for a Wasm function
Trap::Wasm {
pc,
Expand All @@ -92,7 +99,7 @@ impl RuntimeError {
Self::new_with_trace(&info, Some(pc), RuntimeErrorSource::Trap(code), backtrace)
}
// A trap triggered manually from the Wasmer runtime
Trap::Runtime {
Trap::Lib {
trap_code,
backtrace,
} => Self::new_with_trace(&info, None, RuntimeErrorSource::Trap(trap_code), backtrace),
Expand Down
9 changes: 9 additions & 0 deletions lib/engine/src/trap/frame_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ pub struct GlobalFrameInfo {
ranges: BTreeMap<usize, ModuleInfoFrameInfo>,
}

/// Returns whether the `pc`, according to globally registered information,
/// is a wasm trap or not.
pub fn is_wasm_pc(pc: usize) -> bool {
let frame_info = FRAME_INFO.read().unwrap();
let module_info = frame_info.module_info(pc);
let is_wasm_pc = module_info.is_some();
is_wasm_pc
}

/// An RAII structure used to unregister a module's frame information when the
/// module is destroyed.
#[derive(MemoryUsage)]
Expand Down
4 changes: 2 additions & 2 deletions lib/engine/src/trap/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ mod error;
mod frame_info;
pub use error::RuntimeError;
pub use frame_info::{
register as register_frame_info, FrameInfo, FunctionExtent, GlobalFrameInfoRegistration,
FRAME_INFO,
is_wasm_pc, register as register_frame_info, FrameInfo, FunctionExtent,
GlobalFrameInfoRegistration, FRAME_INFO,
};
57 changes: 11 additions & 46 deletions lib/vm/src/instance/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::global::Global;
use crate::imports::Imports;
use crate::memory::{Memory, MemoryError};
use crate::table::{Table, TableElement};
use crate::trap::{catch_traps, init_traps, Trap, TrapCode};
use crate::trap::{catch_traps, Trap, TrapCode, TrapInfo};
use crate::vmcontext::{
VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody,
VMFunctionEnvironment, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport,
Expand All @@ -32,7 +32,7 @@ use loupe::{MemoryUsage, MemoryUsageTracker};
use memoffset::offset_of;
use more_asserts::assert_lt;
use std::any::Any;
use std::cell::{Cell, RefCell};
use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use std::ffi;
Expand Down Expand Up @@ -98,10 +98,6 @@ pub(crate) struct Instance {
/// Hosts can store arbitrary per-instance information here.
host_state: Box<dyn Any>,

/// Handler run when `SIGBUS`, `SIGFPE`, `SIGILL`, or `SIGSEGV` are caught by the instance thread.
#[loupe(skip)]
pub(crate) signal_handler: Cell<Option<Box<SignalHandler>>>,

/// Functions to operate on host environments in the imports
/// and pointers to the environments.
///
Expand Down Expand Up @@ -397,7 +393,7 @@ impl Instance {
}

/// Invoke the WebAssembly start function of the instance, if one is present.
fn invoke_start_function(&self) -> Result<(), Trap> {
fn invoke_start_function(&self, trap_info: &dyn TrapInfo) -> Result<(), Trap> {
let start_index = match self.module.start_function {
Some(idx) => idx,
None => return Ok(()),
Expand Down Expand Up @@ -426,7 +422,7 @@ impl Instance {

// Make the call.
unsafe {
catch_traps(callee_vmctx, || {
catch_traps(trap_info, || {
mem::transmute::<*const VMFunctionBody, unsafe extern "C" fn(VMFunctionEnvironment)>(
callee_address,
)(callee_vmctx)
Expand Down Expand Up @@ -669,7 +665,7 @@ impl Instance {
.map_or(true, |n| n as usize > elem.len())
|| dst.checked_add(len).map_or(true, |m| m > table.size())
{
return Err(Trap::new_from_runtime(TrapCode::TableAccessOutOfBounds));
return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
}

for (dst, src) in (dst..dst + len).zip(src..src + len) {
Expand Down Expand Up @@ -702,7 +698,7 @@ impl Instance {
.checked_add(len)
.map_or(true, |n| n as usize > table_size)
{
return Err(Trap::new_from_runtime(TrapCode::TableAccessOutOfBounds));
return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
}

for i in start_index..(start_index + len) {
Expand Down Expand Up @@ -821,7 +817,7 @@ impl Instance {
.checked_add(len)
.map_or(true, |m| m > memory.current_length)
{
return Err(Trap::new_from_runtime(TrapCode::HeapAccessOutOfBounds));
return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
}

let src_slice = &data[src as usize..(src + len) as usize];
Expand Down Expand Up @@ -935,7 +931,6 @@ impl InstanceHandle {
passive_data,
host_state,
funcrefs,
signal_handler: Cell::new(None),
imported_function_envs,
vmctx: VMContext {},
};
Expand Down Expand Up @@ -1000,9 +995,6 @@ impl InstanceHandle {
VMBuiltinFunctionsArray::initialized(),
);

// Ensure that our signal handlers are ready for action.
init_traps();

// Perform infallible initialization in this constructor, while fallible
// initialization is deferred to the `initialize` method.
initialize_passive_elements(instance);
Expand All @@ -1023,6 +1015,7 @@ impl InstanceHandle {
/// Only safe to call immediately after instantiation.
pub unsafe fn finish_instantiation(
&self,
trap_info: &dyn TrapInfo,
data_initializers: &[DataInitializer<'_>],
) -> Result<(), Trap> {
let instance = self.instance().as_ref();
Expand All @@ -1033,7 +1026,7 @@ impl InstanceHandle {

// The WebAssembly spec specifies that the start function is
// invoked automatically at instantiation time.
instance.invoke_start_function()?;
instance.invoke_start_function(trap_info)?;
Ok(())
}

Expand Down Expand Up @@ -1270,34 +1263,6 @@ impl InstanceHandle {
}
}

cfg_if::cfg_if! {
if #[cfg(unix)] {
pub type SignalHandler = dyn Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool;

impl InstanceHandle {
/// Set a custom signal handler
pub fn set_signal_handler<H>(&self, handler: H)
where
H: 'static + Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool,
{
self.instance().as_ref().signal_handler.set(Some(Box::new(handler)));
}
}
} else if #[cfg(target_os = "windows")] {
pub type SignalHandler = dyn Fn(winapi::um::winnt::PEXCEPTION_POINTERS) -> bool;

impl InstanceHandle {
/// Set a custom signal handler
pub fn set_signal_handler<H>(&self, handler: H)
where
H: 'static + Fn(winapi::um::winnt::PEXCEPTION_POINTERS) -> bool,
{
self.instance().as_ref().signal_handler.set(Some(Box::new(handler)));
}
}
}
}

/// Compute the offset for a memory data initializer.
fn get_memory_init_start(init: &DataInitializer<'_>, instance: &Instance) -> usize {
let mut start = init.location.offset;
Expand Down Expand Up @@ -1363,7 +1328,7 @@ fn initialize_tables(instance: &Instance) -> Result<(), Trap> {
.checked_add(init.elements.len())
.map_or(true, |end| end > table.size() as usize)
{
return Err(Trap::new_from_runtime(TrapCode::TableAccessOutOfBounds));
return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
}

for (i, func_idx) in init.elements.iter().enumerate() {
Expand Down Expand Up @@ -1421,7 +1386,7 @@ fn initialize_memories(
.checked_add(init.data.len())
.map_or(true, |end| end > memory.current_length.try_into().unwrap())
{
return Err(Trap::new_from_runtime(TrapCode::HeapAccessOutOfBounds));
return Err(Trap::lib(TrapCode::HeapAccessOutOfBounds));
}

unsafe {
Expand Down
6 changes: 3 additions & 3 deletions lib/vm/src/libcalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ pub unsafe extern "C" fn wasmer_vm_table_get(
// TODO: type checking, maybe have specialized accessors
match instance.table_get(table_index, elem_index) {
Some(table_ref) => table_ref.into(),
None => raise_lib_trap(Trap::new_from_runtime(TrapCode::TableAccessOutOfBounds)),
None => raise_lib_trap(Trap::lib(TrapCode::TableAccessOutOfBounds)),
}
}

Expand All @@ -360,7 +360,7 @@ pub unsafe extern "C" fn wasmer_vm_imported_table_get(
// TODO: type checking, maybe have specialized accessors
match instance.imported_table_get(table_index, elem_index) {
Some(table_ref) => table_ref.into(),
None => raise_lib_trap(Trap::new_from_runtime(TrapCode::TableAccessOutOfBounds)),
None => raise_lib_trap(Trap::lib(TrapCode::TableAccessOutOfBounds)),
}
}

Expand Down Expand Up @@ -668,7 +668,7 @@ pub unsafe extern "C" fn wasmer_vm_data_drop(vmctx: *mut VMContext, data_index:
/// `wasmer_call_trampoline` must have been previously called.
#[no_mangle]
pub unsafe extern "C" fn wasmer_vm_raise_trap(trap_code: TrapCode) -> ! {
let trap = Trap::new_from_runtime(trap_code);
let trap = Trap::lib(trap_code);
raise_lib_trap(trap)
}

Expand Down
Loading

0 comments on commit d5ca8ad

Please sign in to comment.