1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
//! A standalone test to assert that Wasmtime can operate in "no signal handlers
//! mode"
//!
//! This is a test for `Config::signals_based_traps(false)` which resides in its
//! own binary to assert properties about signal handlers that Wasmtime uses.
//! Due to the global nature of signals no other tests can be in this binary.
//! This will ensure that various trapping scenarios all work and additionally
//! signal handlers are not registered.
use anyhow::Result;
use wasmtime::{Config, Engine, Instance, Module, Store, Trap};
#[test]
#[cfg_attr(miri, ignore)]
fn no_host_trap_handlers() -> Result<()> {
let mut config = Config::new();
config.signals_based_traps(false);
let engine = Engine::new(&config)?;
let module = Module::new(
&engine,
r#"
(module
(memory 1)
(func (export "load") (param i32) (result i32)
(i32.load (local.get 0)))
(func (export "div") (param i32 i32) (result i32)
(i32.div_s (local.get 0) (local.get 1)))
(func (export "unreachable") unreachable)
(func $oflow (export "overflow") call $oflow)
)
"#,
)?;
let mut store = Store::new(&engine, ());
let instance = Instance::new(&mut store, &module, &[])?;
let load = instance.get_typed_func::<i32, i32>(&mut store, "load")?;
let div = instance.get_typed_func::<(i32, i32), i32>(&mut store, "div")?;
let unreachable = instance.get_typed_func::<(), ()>(&mut store, "unreachable")?;
let overflow = instance.get_typed_func::<(), ()>(&mut store, "overflow")?;
let trap = load
.call(&mut store, 1 << 20)
.unwrap_err()
.downcast::<Trap>()?;
assert_eq!(trap, Trap::MemoryOutOfBounds);
let trap = div
.call(&mut store, (1, 0))
.unwrap_err()
.downcast::<Trap>()?;
assert_eq!(trap, Trap::IntegerDivisionByZero);
let trap = unreachable
.call(&mut store, ())
.unwrap_err()
.downcast::<Trap>()?;
assert_eq!(trap, Trap::UnreachableCodeReached);
let trap = overflow
.call(&mut store, ())
.unwrap_err()
.downcast::<Trap>()?;
assert_eq!(trap, Trap::StackOverflow);
assert_host_signal_handlers_are_unset();
Ok(())
}
fn assert_host_signal_handlers_are_unset() {
#[cfg(unix)]
unsafe {
let mut prev = std::mem::zeroed::<libc::sigaction>();
let rc = libc::sigaction(libc::SIGILL, std::ptr::null(), &mut prev);
assert_eq!(rc, 0);
assert_eq!(
prev.sa_sigaction,
libc::SIG_DFL,
"fault handler was installed when it shouldn't have been"
);
}
#[cfg(windows)]
{
// Note that this can't be checked on Windows because vectored exception
// handlers work a bit differently and aren't as "global" as a signal
// handler. For now rely on the check above on unix to also guarantee
// that on Windows we don't register any vectored exception handlers.
}
}
|