mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
Add a signal handler for macos and linux.
Implementation Notes: - To avoid setjmp, longjmp, and the mess that those create, we instead set the interrupting context of the signal handler to return into the `throw_trap` routine. To my surprise, this actually works. The stack ends up getting unwound normally and the memory-oob error is caught by the trampoline.
This commit is contained in:
parent
57bfa9b0a4
commit
caf2205936
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1213,6 +1213,7 @@ dependencies = [
|
|||||||
"inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)",
|
"inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)",
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.49 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -12,6 +12,7 @@ hashbrown = "0.1.8"
|
|||||||
smallvec = "0.6.8"
|
smallvec = "0.6.8"
|
||||||
goblin = "0.0.20"
|
goblin = "0.0.20"
|
||||||
libc = "0.2.49"
|
libc = "0.2.49"
|
||||||
|
nix = "0.13.0"
|
||||||
capstone = "0.5.0"
|
capstone = "0.5.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
@ -115,7 +115,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t type_id, value_num;
|
uint32_t type_id, value_num;
|
||||||
uint64_t values[];
|
uint64_t values[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WasmModule {
|
struct WasmModule {
|
||||||
@ -140,7 +140,7 @@ extern "C" {
|
|||||||
return RESULT_OK;
|
return RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void throw_trap(WasmTrap::Type ty) {
|
[[noreturn]] void throw_trap(WasmTrap::Type ty) {
|
||||||
throw WasmTrap(ty);
|
throw WasmTrap(ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,6 +243,10 @@ impl LLVMBackend {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
crate::platform::install_signal_handler();
|
||||||
|
}
|
||||||
|
|
||||||
if res != LLVMResult::OK {
|
if res != LLVMResult::OK {
|
||||||
panic!("failed to load object")
|
panic!("failed to load object")
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
use libc::{c_void, siginfo_t};
|
||||||
|
use nix::sys::signal::{
|
||||||
|
sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV,
|
||||||
|
};
|
||||||
|
|
||||||
/// `__register_frame` and `__deregister_frame` on macos take a single fde as an
|
/// `__register_frame` and `__deregister_frame` on macos take a single fde as an
|
||||||
/// argument, so we need to parse the fde table here.
|
/// argument, so we need to parse the fde table here.
|
||||||
///
|
///
|
||||||
@ -33,3 +38,104 @@ pub unsafe fn visit_fde(addr: *mut u8, size: usize, visitor: extern "C" fn(*mut
|
|||||||
pub unsafe fn visit_fde(addr: *mut u8, size: usize, visitor: extern "C" fn(*mut u8)) {
|
pub unsafe fn visit_fde(addr: *mut u8, size: usize, visitor: extern "C" fn(*mut u8)) {
|
||||||
visitor(addr);
|
visitor(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn throw_trap(ty: i32) -> !;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn install_signal_handler() {
|
||||||
|
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 {
|
||||||
|
/// By setting the instruction pointer of the interrupted context
|
||||||
|
/// to `throw_trap` and the register of the first argument
|
||||||
|
/// to the trap ID, we can approximate throwing an exception
|
||||||
|
/// from a signal handler.
|
||||||
|
set_context_to_throw(ucontext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||||
|
unsafe fn set_context_to_throw(ucontext: *mut c_void) {
|
||||||
|
use libc::{ucontext_t, RDI, RIP};
|
||||||
|
|
||||||
|
let ucontext = ucontext as *mut ucontext_t;
|
||||||
|
(*ucontext).uc_mcontext.gregs[RIP as usize] = throw_trap as u64;
|
||||||
|
(*ucontext).uc_mcontext.gregs[RDI as usize] = 2; // `MemoryOutOfBounds` variant.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||||
|
unsafe fn set_context_to_throw(ucontext: *mut c_void) {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct ucontext_t {
|
||||||
|
uc_onstack: u32,
|
||||||
|
uc_sigmask: u32,
|
||||||
|
uc_stack: libc::stack_t,
|
||||||
|
uc_link: *const ucontext_t,
|
||||||
|
uc_mcsize: u64,
|
||||||
|
uc_mcontext: *mut mcontext_t,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
struct exception_state {
|
||||||
|
trapno: u16,
|
||||||
|
cpu: u16,
|
||||||
|
err: u32,
|
||||||
|
faultvaddr: u64,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
struct regs {
|
||||||
|
rax: u64,
|
||||||
|
rbx: u64,
|
||||||
|
rcx: u64,
|
||||||
|
rdx: u64,
|
||||||
|
rdi: u64,
|
||||||
|
rsi: u64,
|
||||||
|
rbp: u64,
|
||||||
|
rsp: u64,
|
||||||
|
r8: u64,
|
||||||
|
r9: u64,
|
||||||
|
r10: u64,
|
||||||
|
r11: u64,
|
||||||
|
r12: u64,
|
||||||
|
r13: u64,
|
||||||
|
r14: u64,
|
||||||
|
r15: u64,
|
||||||
|
rip: u64,
|
||||||
|
rflags: u64,
|
||||||
|
cs: u64,
|
||||||
|
fs: u64,
|
||||||
|
gs: u64,
|
||||||
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct mcontext_t {
|
||||||
|
es: exception_state,
|
||||||
|
ss: regs,
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
let ucontext = ucontext as *mut ucontext_t;
|
||||||
|
(*(*ucontext).uc_mcontext).ss.rip = throw_trap as u64;
|
||||||
|
(*(*ucontext).uc_mcontext).ss.rdi = 2; // `MemoryOutOfBounds` variant.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(
|
||||||
|
all(target_os = "macos", target_arch = "x86_64"),
|
||||||
|
all(target_os = "linux", target_arch = "x86_64"),
|
||||||
|
)))]
|
||||||
|
compile_error!("This crate doesn't yet support compiling on operating systems other than linux and macos and architectures other than x86_64");
|
||||||
|
@ -4,9 +4,12 @@ use wabt::wat2wasm;
|
|||||||
|
|
||||||
static WAT: &'static str = r#"
|
static WAT: &'static str = r#"
|
||||||
(module
|
(module
|
||||||
|
(memory 1)
|
||||||
(type (;0;) (func (param i32) (result i32)))
|
(type (;0;) (func (param i32) (result i32)))
|
||||||
(func (;0;) (type 0) (param i32) (result i32)
|
(func (;0;) (type 0) (param i32) (result i32)
|
||||||
unreachable)
|
i32.const 0x20000
|
||||||
|
i32.load
|
||||||
|
)
|
||||||
(export "select_trap_l" (func 0))
|
(export "select_trap_l" (func 0))
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
Loading…
Reference in New Issue
Block a user