Crates.io | hw-exception |
lib.rs | hw-exception |
version | 0.1.0 |
source | src |
created_at | 2023-09-20 23:52:18.83039 |
updated_at | 2023-09-20 23:52:18.83039 |
description | Catch and handle hardware exceptions, such as page faults |
homepage | |
repository | https://github.com/dfoxfranke/hw-exception |
max_upload_size | |
id | 978962 |
size | 73,291 |
hw-exception
This Rust crate handles POSIX signals which are triggered in response to hardware exceptions. These signals include:
SIGILL
SIGFPE
SIGSEGV
SIGBUS
SIGTRAP
Examples of hardware exceptions which trigger them include:
Normally, receiving any of these signals indicates either a hardware failure or certain kinds of bugs which shouldn't be possible in safe Rust code. When they're received unexpectedly, the only sensible way to proceed is to abort the process and dump core, which is exactly what would normally happen. However, many use cases exist where such signals are expected, and recovery is possible. Here are just a few:
userfaultfd
crate as an alternative for
this and similar use cases.)SIGBUS
, which they can't guard against without running into TOCTOU
problems. Victims of such behavior can catch the signal and jump back to a
recovery point. (Consider the memfd
crate as an
alternative to avoid such complications.)SIGTRAP
upon hitting a breakpoint
they've set.Hardware exceptions are generally handled in one of three ways; this crate supports all of them to varying degrees. They are:
setjmp
to store a recovery point, and then
longjmp
back to it from the signal handler.The following example triggers a segmentation fault by dereferencing a null pointer, catches and recovers from it, and then prints a backtrace showing where the segfault occurred.
use hw_exception::*;
use std::backtrace::Backtrace;
fn main() {
unsafe {
// Register a hook for SIGSEGV, which captures and throws a backtrace.
register_hook(&[Signo::SIGSEGV], |e| {
let bt = Backtrace::force_capture();
throw((e, bt))
});
}
// Dereference a null pointer from within a `catch` block. Using `read_volatile`
// prevents this from being UB.
let result = catch(|| unsafe {
std::ptr::null::<usize>().read_volatile()
});
// Assert that this block resulted in an exception, and extract it.
let e = result.expect_err("dereferencing a null pointer should have segfaulted, but gave");
// Extract and print the backtrace
let bt : &Backtrace = e
.additional()
.expect("thrown exception info should have included additional data")
.downcast_ref()
.expect("additional data should have been a `Backtrace`");
println!("{}", bt);
}
See API docs on docs.rs.
This project licensed under the Apache License
2.0 with LLVM
exception. Unless you explicitly
state otherwise, any contribution intentionally submitted for inclusion in
hw-exception
by you, shall be licensed as Apache 2.0 with LLVM exception,
without any additional terms or conditions.