diff --git a/lib/clif-backend/src/call/sighandler.rs b/lib/clif-backend/src/call/sighandler.rs deleted file mode 100644 index cbaee828f..000000000 --- a/lib/clif-backend/src/call/sighandler.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Installing signal handlers allows us to handle traps and out-of-bounds memory -//! accesses that occur when runniing webassembly. -//! -//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622 -use crate::call::recovery; -use nix::libc::{c_void, siginfo_t}; -use nix::sys::signal::{ - sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGFPE, SIGILL, SIGSEGV, -}; - -pub unsafe fn install_sighandler() { - let sa = SigAction::new( - SigHandler::SigAction(signal_trap_handler), - SaFlags::SA_ONSTACK, - SigSet::empty(), - ); - sigaction(SIGFPE, &sa).unwrap(); - sigaction(SIGILL, &sa).unwrap(); - sigaction(SIGSEGV, &sa).unwrap(); - sigaction(SIGBUS, &sa).unwrap(); -} - -extern "C" fn signal_trap_handler( - signum: ::nix::libc::c_int, - siginfo: *mut siginfo_t, - ucontext: *mut c_void, -) { - unsafe { - recovery::do_unwind(signum, siginfo as _, ucontext); - } -} diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index a5afdf8b9..07bae97c6 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -1,12 +1,12 @@ #[cfg(feature = "cache")] mod cache; -mod call; mod func_env; mod libcalls; mod module; mod module_env; mod relocation; mod resolver; +mod signal; mod trampoline; use cranelift_codegen::{ diff --git a/lib/clif-backend/src/module.rs b/lib/clif-backend/src/module.rs index c5682d650..9654af7cc 100644 --- a/lib/clif-backend/src/module.rs +++ b/lib/clif-backend/src/module.rs @@ -1,6 +1,6 @@ #[cfg(feature = "cache")] use crate::cache::BackendCache; -use crate::{call::Caller, resolver::FuncResolverBuilder, trampoline::Trampolines}; +use crate::{resolver::FuncResolverBuilder, signal::Caller, trampoline::Trampolines}; use cranelift_codegen::{ir, isa}; use cranelift_entity::EntityRef; diff --git a/lib/clif-backend/src/resolver.rs b/lib/clif-backend/src/resolver.rs index d6e304340..315bd154a 100644 --- a/lib/clif-backend/src/resolver.rs +++ b/lib/clif-backend/src/resolver.rs @@ -4,12 +4,12 @@ use crate::{ trampoline::Trampolines, }; use crate::{ - call::HandlerData, libcalls, relocation::{ ExternalRelocation, LibCall, LocalRelocation, LocalTrapSink, Reloc, RelocSink, RelocationType, TrapSink, VmCall, VmCallKind, }, + signal::HandlerData, }; use byteorder::{ByteOrder, LittleEndian}; diff --git a/lib/clif-backend/src/call/mod.rs b/lib/clif-backend/src/signal/mod.rs similarity index 80% rename from lib/clif-backend/src/call/mod.rs rename to lib/clif-backend/src/signal/mod.rs index 43c8f682c..dbcd0c6b8 100644 --- a/lib/clif-backend/src/call/mod.rs +++ b/lib/clif-backend/src/signal/mod.rs @@ -1,11 +1,7 @@ -mod recovery; -mod sighandler; - -pub use self::recovery::{call_protected, HandlerData}; - +use crate::relocation::{TrapData, TrapSink}; use crate::trampoline::Trampolines; - use hashbrown::HashSet; +use libc::c_void; use std::sync::Arc; use wasmer_runtime_core::{ backend::{ProtectedCaller, Token}, @@ -16,6 +12,18 @@ use wasmer_runtime_core::{ vm::{self, ImportBacking}, }; +#[cfg(unix)] +mod unix; + +#[cfg(windows)] +mod windows; + +#[cfg(unix)] +pub use self::unix::*; + +#[cfg(windows)] +pub use self::windows::*; + pub struct Caller { func_export_set: HashSet, handler_data: HandlerData, @@ -146,3 +154,38 @@ fn get_func_from_index( (func_ptr, ctx, signature, sig_index) } + +unsafe impl Send for HandlerData {} +unsafe impl Sync for HandlerData {} + +pub struct HandlerData { + pub trap_data: TrapSink, + exec_buffer_ptr: *const c_void, + exec_buffer_size: usize, +} + +impl HandlerData { + pub fn new( + trap_data: TrapSink, + exec_buffer_ptr: *const c_void, + exec_buffer_size: usize, + ) -> Self { + Self { + trap_data, + exec_buffer_ptr, + exec_buffer_size, + } + } + + pub fn lookup(&self, ip: *const c_void) -> Option { + let ip = ip as usize; + let buffer_ptr = self.exec_buffer_ptr as usize; + + if buffer_ptr <= ip && ip < buffer_ptr + self.exec_buffer_size { + let offset = ip - buffer_ptr; + self.trap_data.lookup(offset) + } else { + None + } + } +} diff --git a/lib/clif-backend/src/call/recovery.rs b/lib/clif-backend/src/signal/unix.rs similarity index 88% rename from lib/clif-backend/src/call/recovery.rs rename to lib/clif-backend/src/signal/unix.rs index 54f4dfe0f..8e707433e 100644 --- a/lib/clif-backend/src/call/recovery.rs +++ b/lib/clif-backend/src/signal/unix.rs @@ -1,13 +1,20 @@ +//! Installing signal handlers allows us to handle traps and out-of-bounds memory +//! accesses that occur when runniing webassembly. +//! +//! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622 +//! //! When a WebAssembly module triggers any traps, we perform recovery here. //! //! This module uses TLS (thread-local storage) to track recovery information. Since the four signals we're handling //! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here //! unless you have memory unsafety elsewhere in your code. - -use crate::call::sighandler::install_sighandler; +//! use crate::relocation::{TrapCode, TrapData, TrapSink}; +use crate::signal::HandlerData; use libc::{c_int, c_void, siginfo_t}; -use nix::sys::signal::{Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV}; +use nix::sys::signal::{ + sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV, +}; use std::cell::{Cell, UnsafeCell}; use std::ptr; use std::sync::Once; @@ -17,11 +24,33 @@ use wasmer_runtime_core::{ types::{MemoryIndex, TableIndex}, }; +extern "C" fn signal_trap_handler( + signum: ::nix::libc::c_int, + siginfo: *mut siginfo_t, + ucontext: *mut c_void, +) { + unsafe { + do_unwind(signum, siginfo as _, ucontext); + } +} + extern "C" { pub fn setjmp(env: *mut c_void) -> c_int; fn longjmp(env: *mut c_void, val: c_int) -> !; } +pub unsafe fn install_sighandler() { + let sa = SigAction::new( + SigHandler::SigAction(signal_trap_handler), + SaFlags::SA_ONSTACK, + SigSet::empty(), + ); + sigaction(SIGFPE, &sa).unwrap(); + sigaction(SIGILL, &sa).unwrap(); + sigaction(SIGSEGV, &sa).unwrap(); + sigaction(SIGBUS, &sa).unwrap(); +} + const SETJMP_BUFFER_LEN: usize = 27; pub static SIGHANDLER_INIT: Once = Once::new(); @@ -31,41 +60,6 @@ thread_local! { pub static CURRENT_EXECUTABLE_BUFFER: Cell<*const c_void> = Cell::new(ptr::null()); } -unsafe impl Send for HandlerData {} -unsafe impl Sync for HandlerData {} - -pub struct HandlerData { - pub trap_data: TrapSink, - exec_buffer_ptr: *const c_void, - exec_buffer_size: usize, -} - -impl HandlerData { - pub fn new( - trap_data: TrapSink, - exec_buffer_ptr: *const c_void, - exec_buffer_size: usize, - ) -> Self { - Self { - trap_data, - exec_buffer_ptr, - exec_buffer_size, - } - } - - pub fn lookup(&self, ip: *const c_void) -> Option { - let ip = ip as usize; - let buffer_ptr = self.exec_buffer_ptr as usize; - - if buffer_ptr <= ip && ip < buffer_ptr + self.exec_buffer_size { - let offset = ip - buffer_ptr; - self.trap_data.lookup(offset) - } else { - None - } - } -} - pub fn call_protected(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult { unsafe { let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get()); diff --git a/lib/clif-backend/src/signal/windows.rs b/lib/clif-backend/src/signal/windows.rs new file mode 100644 index 000000000..bdd272ce9 --- /dev/null +++ b/lib/clif-backend/src/signal/windows.rs @@ -0,0 +1,6 @@ +use crate::signal::HandlerData; +use wasmer_runtime_core::error::RuntimeResult; + +pub fn call_protected(handler_data: &HandlerData, f: impl FnOnce() -> T) -> RuntimeResult { + unimplemented!("TODO"); +}