#![allow(unsafe_code)]
pub use ch::debug_print;
use crash_handler as ch;
pub use sadness_generator::SadnessFlavor;
pub fn handles_crash(flavor: SadnessFlavor) {
let mut _handler = None;
unsafe {
_handler = Some(
ch::CrashHandler::attach(ch::make_crash_event(move |cc: &ch::CrashContext| {
cfg_if::cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "android"))] {
use ch::Signal;
assert_eq!(
cc.siginfo.ssi_signo,
match flavor {
SadnessFlavor::Abort => Signal::Abort,
SadnessFlavor::Bus => Signal::Bus,
SadnessFlavor::DivideByZero => Signal::Fpe,
SadnessFlavor::Illegal => Signal::Illegal,
SadnessFlavor::Segfault | SadnessFlavor::StackOverflow { .. } => {
Signal::Segv
}
SadnessFlavor::Trap => Signal::Trap,
} as u32,
);
//assert_eq!(cc.tid, tid);
// At least on linux these...aren't set. Which is weird
//assert_eq!(cc.siginfo.ssi_pid, std::process::id());
//assert_eq!(cc.siginfo.ssi_tid, tid as u32);
} else if #[cfg(target_os = "macos")] {
use ch::ExceptionType;
let exc = cc.exception.expect("we should have an exception");
let expected = match flavor {
SadnessFlavor::Abort => {
assert_eq!(exc.code, 0x10003); // EXC_SOFT_SIGNAL
assert_eq!(exc.subcode.unwrap(), libc::SIGABRT as _);
ExceptionType::Software
}
SadnessFlavor::Bus
| SadnessFlavor::Segfault
| SadnessFlavor::StackOverflow { .. } => {
if flavor == SadnessFlavor::Segfault {
// For EXC_BAD_ACCESS exceptions, the subcode will be the
// bad address we tried to access
assert_eq!(cc.exception.unwrap().subcode.unwrap(), sadness_generator::SEGFAULT_ADDRESS as _);
}
ExceptionType::BadAccess
},
SadnessFlavor::DivideByZero => ExceptionType::Arithmetic,
SadnessFlavor::Illegal => ExceptionType::BadInstruction,
SadnessFlavor::Trap => ExceptionType::Breakpoint,
SadnessFlavor::Guard => ExceptionType::Guard,
};
assert_eq!(exc.kind, expected as _);
} else if #[cfg(target_os = "windows")] {
use ch::ExceptionCode;
let ec = match flavor {
SadnessFlavor::Abort => ExceptionCode::Abort,
SadnessFlavor::DivideByZero => ExceptionCode::Fpe,
SadnessFlavor::Illegal => ExceptionCode::Illegal,
SadnessFlavor::InvalidParameter => ExceptionCode::InvalidParameter,
SadnessFlavor::Purecall => ExceptionCode::Purecall,
SadnessFlavor::Segfault => ExceptionCode::Segv,
SadnessFlavor::StackOverflow { .. }=> ExceptionCode::StackOverflow,
SadnessFlavor::Trap => ExceptionCode::Trap,
};
assert_eq!(
cc.exception_code, ec as u32,
"0x{:x} != 0x{:x}",
cc.exception_code, ec as u32
);
}
}
// Once we've verified we've received the exception we expected,
// we exit with a success code to satisfy cargo test. While
// we _could_ jump back on non-mac platforms (Mac can't since
// exceptions are handled on a different thread) this is a
// simpler approach that is consistent across platforms since
// we only have 1 test per binary
#[allow(clippy::exit)]
std::process::exit(0);
}))
.unwrap(),
);
#[inline(never)]
unsafe fn indirect(flavor: SadnessFlavor) {
flavor.make_sad();
}
indirect(flavor);
panic!("this should be impossible");
}
}