mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 14:25:32 +00:00
Improved trap catching with call_protected macro
This commit is contained in:
parent
a316253b94
commit
e258875d4b
@ -4,12 +4,7 @@
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! get_instance_function {
|
macro_rules! get_instance_function {
|
||||||
($instance:expr, $func_index:expr) => {{
|
($instance:expr, $func_index:expr) => {{
|
||||||
use crate::sighandler::install_sighandler;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
unsafe {
|
|
||||||
install_sighandler();
|
|
||||||
};
|
|
||||||
let func_addr = $instance.get_function_pointer($func_index);
|
let func_addr = $instance.get_function_pointer($func_index);
|
||||||
unsafe { mem::transmute(func_addr) }
|
unsafe { mem::transmute(func_addr) }
|
||||||
}};
|
}};
|
||||||
|
11
src/main.rs
11
src/main.rs
@ -25,9 +25,10 @@ use structopt::StructOpt;
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
#[macro_use]
|
||||||
|
mod recovery;
|
||||||
pub mod apis;
|
pub mod apis;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
mod recovery;
|
|
||||||
pub mod sighandler;
|
pub mod sighandler;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod spectests;
|
mod spectests;
|
||||||
@ -86,7 +87,7 @@ fn execute_wasm(wasm_path: PathBuf) -> Result<(), String> {
|
|||||||
};
|
};
|
||||||
let main: extern "C" fn(u32, u32, &webassembly::Instance) =
|
let main: extern "C" fn(u32, u32, &webassembly::Instance) =
|
||||||
get_instance_function!(instance, func_index);
|
get_instance_function!(instance, func_index);
|
||||||
main(0, 0, &instance);
|
return call_protected!(main(0, 0, &instance)).map_err(|err| format!("{}", err));
|
||||||
} else {
|
} else {
|
||||||
let func_index =
|
let func_index =
|
||||||
instance
|
instance
|
||||||
@ -95,10 +96,10 @@ fn execute_wasm(wasm_path: PathBuf) -> Result<(), String> {
|
|||||||
Some(&webassembly::Export::Function(index)) => index,
|
Some(&webassembly::Export::Function(index)) => index,
|
||||||
_ => panic!("Main function not found"),
|
_ => panic!("Main function not found"),
|
||||||
});
|
});
|
||||||
instance.start_func(func_index).unwrap();
|
let main: extern "C" fn(&webassembly::Instance) =
|
||||||
|
get_instance_function!(instance, func_index);
|
||||||
|
return call_protected!(main(&instance)).map_err(|err| format!("{}", err));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(options: Run) {
|
fn run(options: Run) {
|
||||||
|
@ -5,35 +5,63 @@
|
|||||||
//! unless you have memory unsafety elsewhere in your code.
|
//! unless you have memory unsafety elsewhere in your code.
|
||||||
|
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
|
use nix::sys::signal::{Signal, SIGFPE, SIGILL, SIGSEGV, SIGBUS};
|
||||||
|
use super::webassembly::ErrorKind;
|
||||||
|
use super::sighandler::install_sighandler;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn setjmp(env: *mut ::nix::libc::c_void) -> ::nix::libc::c_int;
|
pub fn setjmp(env: *mut ::nix::libc::c_void) -> ::nix::libc::c_int;
|
||||||
fn longjmp(env: *mut ::nix::libc::c_void, val: ::nix::libc::c_int) -> !;
|
fn longjmp(env: *mut ::nix::libc::c_void, val: ::nix::libc::c_int) -> !;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SETJMP_BUFFER_LEN: usize = 27;
|
const SETJMP_BUFFER_LEN: usize = 27;
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static SETJMP_BUFFER: UnsafeCell<[::nix::libc::c_int; SETJMP_BUFFER_LEN]> = UnsafeCell::new([0; SETJMP_BUFFER_LEN]);
|
pub static SETJMP_BUFFER: UnsafeCell<[::nix::libc::c_int; SETJMP_BUFFER_LEN]> = UnsafeCell::new([0; SETJMP_BUFFER_LEN]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need a macro since the arguments we will provide to the funciton
|
||||||
|
// (and the return value) are not fixed to just one case: f(x) -> y
|
||||||
|
// but multiple: f(x) -> y, f(a,b) -> c, ...
|
||||||
|
// And right now it's impossible to handle with Rust function type system
|
||||||
|
|
||||||
/// Calls a WebAssembly function with longjmp receiver installed. If a non-WebAssembly function is passed in,
|
/// Calls a WebAssembly function with longjmp receiver installed. If a non-WebAssembly function is passed in,
|
||||||
/// the behavior of protected_call is undefined.
|
/// the behavior of call_protected is undefined.
|
||||||
pub unsafe fn protected_call<T, R>(f: fn(T) -> R, p: T) -> Result<R, i32> {
|
#[macro_export]
|
||||||
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
macro_rules! call_protected {
|
||||||
let prev_jmp_buf = *jmp_buf;
|
($x:expr) => {unsafe {
|
||||||
|
use crate::webassembly::ErrorKind;
|
||||||
|
use crate::recovery::{SETJMP_BUFFER, setjmp};
|
||||||
|
use crate::sighandler::install_sighandler;
|
||||||
|
|
||||||
let signum = setjmp(jmp_buf as *mut ::nix::libc::c_void);
|
use nix::sys::signal::{Signal, SIGFPE, SIGILL, SIGSEGV, SIGBUS};
|
||||||
if signum != 0 {
|
|
||||||
*jmp_buf = prev_jmp_buf;
|
let jmp_buf = SETJMP_BUFFER.with(|buf| buf.get());
|
||||||
Err(signum)
|
let prev_jmp_buf = *jmp_buf;
|
||||||
} else {
|
|
||||||
let ret = f(p); // TODO: Switch stack?
|
install_sighandler();
|
||||||
*jmp_buf = prev_jmp_buf;
|
|
||||||
Ok(ret)
|
let signum = setjmp(jmp_buf as *mut ::nix::libc::c_void);
|
||||||
}
|
if signum != 0 {
|
||||||
|
*jmp_buf = prev_jmp_buf;
|
||||||
|
let signal = match Signal::from_c_int(signum) {
|
||||||
|
Ok(SIGFPE) => "floating-point exception",
|
||||||
|
Ok(SIGILL) => "illegal instruction",
|
||||||
|
Ok(SIGSEGV) => "segmentation violation",
|
||||||
|
Ok(SIGBUS) => "bus error",
|
||||||
|
Err(_) => "error while getting the Signal",
|
||||||
|
_ => "unkown trapped signal",
|
||||||
|
};
|
||||||
|
Err(ErrorKind::RuntimeError(format!("trap - {}", signal)))
|
||||||
|
} else {
|
||||||
|
let ret = $x; // TODO: Switch stack?
|
||||||
|
*jmp_buf = prev_jmp_buf;
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Unwinds to last protected_call.
|
/// Unwinds to last protected_call.
|
||||||
pub unsafe fn do_unwind(signum: i32) -> ! {
|
pub unsafe fn do_unwind(signum: i32) -> ! {
|
||||||
// Since do_unwind is only expected to get called from WebAssembly code which doesn't hold any host resources (locks etc.)
|
// Since do_unwind is only expected to get called from WebAssembly code which doesn't hold any host resources (locks etc.)
|
||||||
|
@ -519,16 +519,13 @@ impl Instance {
|
|||||||
get_function_addr(&func_index, &self.import_functions, &self.functions)
|
get_function_addr(&func_index, &self.import_functions, &self.functions)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_func(&self, func_index: FuncIndex) -> Result<(), i32> {
|
pub fn start(&self) -> Result<(), ErrorKind> {
|
||||||
let func: fn(&Instance) = get_instance_function!(&self, func_index);
|
|
||||||
unsafe { recovery::protected_call(func, self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start(&self) -> Result<(), i32> {
|
|
||||||
if let Some(func_index) = self.start_func {
|
if let Some(func_index) = self.start_func {
|
||||||
self.start_func(func_index)
|
let func: fn(&Instance) = get_instance_function!(&self, func_index);
|
||||||
} else {
|
call_protected!(func(self))
|
||||||
panic!("start func not found")
|
}
|
||||||
|
else {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user