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