catch assertion errors on win32

This commit is contained in:
andreafioraldi 2021-03-26 11:42:26 +01:00
parent 9c1f836ff2
commit 2cd046e1e8
2 changed files with 373 additions and 334 deletions

View File

@ -1,4 +1,5 @@
#include <stdint.h> #include <stdint.h>
#include <assert.h>
#define STBI_ASSERT(x) #define STBI_ASSERT(x)
#define STBI_NO_SIMD #define STBI_NO_SIMD
@ -20,6 +21,8 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
unsigned char *img = stbi_load_from_memory(data, size, &x, &y, &channels, 4); unsigned char *img = stbi_load_from_memory(data, size, &x, &y, &channels, 4);
free(img); free(img);
// if (x > 10000) free(img); // free crash
return 0; return 0;
} }

View File

@ -1,334 +1,370 @@
pub use crate::bolts::bindings::windows::win32::debug::EXCEPTION_POINTERS; pub use crate::bolts::bindings::windows::win32::debug::EXCEPTION_POINTERS;
use crate::{bolts::bindings::windows::win32::debug::SetUnhandledExceptionFilter, Error}; use crate::{bolts::bindings::windows::win32::debug::SetUnhandledExceptionFilter, Error};
use alloc::vec::Vec; use alloc::vec::Vec;
use core::{ use core::{
cell::UnsafeCell, cell::UnsafeCell,
convert::TryFrom, convert::TryFrom,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
ptr::write_volatile, ptr,
sync::atomic::{compiler_fence, Ordering}, ptr::write_volatile,
}; sync::atomic::{compiler_fence, Ordering},
use std::os::raw::{c_long, c_void}; };
use std::os::raw::{c_long, c_void};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use num_enum::{IntoPrimitive, TryFromPrimitive};
//const EXCEPTION_CONTINUE_EXECUTION: c_long = -1;
//const EXCEPTION_CONTINUE_SEARCH: c_long = 0; //const EXCEPTION_CONTINUE_EXECUTION: c_long = -1;
const EXCEPTION_EXECUTE_HANDLER: c_long = 1; //const EXCEPTION_CONTINUE_SEARCH: c_long = 0;
const EXCEPTION_EXECUTE_HANDLER: c_long = 1;
// From https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L611
pub const STATUS_WAIT_0: u32 = 0x00000000; // From https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-headers/crt/signal.h
pub const STATUS_ABANDONED_WAIT_0: u32 = 0x00000080; pub const SIGINT: i32 = 2;
pub const STATUS_USER_APC: u32 = 0x000000C0; pub const SIGILL: i32 = 4;
pub const STATUS_TIMEOUT: u32 = 0x00000102; pub const SIGABRT_COMPAT: i32 = 6;
pub const STATUS_PENDING: u32 = 0x00000103; pub const SIGFPE: i32 = 8;
pub const STATUS_SEGMENT_NOTIFICATION: u32 = 0x40000005; pub const SIGSEGV: i32 = 11;
pub const STATUS_FATAL_APP_EXIT: u32 = 0x40000015; pub const SIGTERM: i32 = 15;
pub const STATUS_GUARD_PAGE_VIOLATION: u32 = 0x80000001; pub const SIGBREAK: i32 = 21;
pub const STATUS_DATATYPE_MISALIGNMENT: u32 = 0x80000002; pub const SIGABRT: i32 = 22;
pub const STATUS_BREAKPOINT: u32 = 0x80000003; pub const SIGABRT2: i32 = 22;
pub const STATUS_SINGLE_STEP: u32 = 0x80000004;
pub const STATUS_LONGJUMP: u32 = 0x80000026; // From https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L611
pub const STATUS_UNWIND_CONSOLIDATE: u32 = 0x80000029; pub const STATUS_WAIT_0: u32 = 0x00000000;
pub const STATUS_ACCESS_VIOLATION: u32 = 0xC0000005; pub const STATUS_ABANDONED_WAIT_0: u32 = 0x00000080;
pub const STATUS_IN_PAGE_ERROR: u32 = 0xC0000006; pub const STATUS_USER_APC: u32 = 0x000000C0;
pub const STATUS_INVALID_HANDLE: u32 = 0xC0000008; pub const STATUS_TIMEOUT: u32 = 0x00000102;
pub const STATUS_NO_MEMORY: u32 = 0xC0000017; pub const STATUS_PENDING: u32 = 0x00000103;
pub const STATUS_ILLEGAL_INSTRUCTION: u32 = 0xC000001D; pub const STATUS_SEGMENT_NOTIFICATION: u32 = 0x40000005;
pub const STATUS_NONCONTINUABLE_EXCEPTION: u32 = 0xC0000025; pub const STATUS_FATAL_APP_EXIT: u32 = 0x40000015;
pub const STATUS_INVALID_DISPOSITION: u32 = 0xC0000026; pub const STATUS_GUARD_PAGE_VIOLATION: u32 = 0x80000001;
pub const STATUS_ARRAY_BOUNDS_EXCEEDED: u32 = 0xC000008C; pub const STATUS_DATATYPE_MISALIGNMENT: u32 = 0x80000002;
pub const STATUS_FLOAT_DENORMAL_OPERAND: u32 = 0xC000008D; pub const STATUS_BREAKPOINT: u32 = 0x80000003;
pub const STATUS_FLOAT_DIVIDE_BY_ZERO: u32 = 0xC000008E; pub const STATUS_SINGLE_STEP: u32 = 0x80000004;
pub const STATUS_FLOAT_INEXACT_RESULT: u32 = 0xC000008F; pub const STATUS_LONGJUMP: u32 = 0x80000026;
pub const STATUS_FLOAT_INVALID_OPERATION: u32 = 0xC0000090; pub const STATUS_UNWIND_CONSOLIDATE: u32 = 0x80000029;
pub const STATUS_FLOAT_OVERFLOW: u32 = 0xC0000091; pub const STATUS_ACCESS_VIOLATION: u32 = 0xC0000005;
pub const STATUS_FLOAT_STACK_CHECK: u32 = 0xC0000092; pub const STATUS_IN_PAGE_ERROR: u32 = 0xC0000006;
pub const STATUS_FLOAT_UNDERFLOW: u32 = 0xC0000093; pub const STATUS_INVALID_HANDLE: u32 = 0xC0000008;
pub const STATUS_INTEGER_DIVIDE_BY_ZERO: u32 = 0xC0000094; pub const STATUS_NO_MEMORY: u32 = 0xC0000017;
pub const STATUS_INTEGER_OVERFLOW: u32 = 0xC0000095; pub const STATUS_ILLEGAL_INSTRUCTION: u32 = 0xC000001D;
pub const STATUS_PRIVILEGED_INSTRUCTION: u32 = 0xC0000096; pub const STATUS_NONCONTINUABLE_EXCEPTION: u32 = 0xC0000025;
pub const STATUS_STACK_OVERFLOW: u32 = 0xC00000FD; pub const STATUS_INVALID_DISPOSITION: u32 = 0xC0000026;
pub const STATUS_DLL_NOT_FOUND: u32 = 0xC0000135; pub const STATUS_ARRAY_BOUNDS_EXCEEDED: u32 = 0xC000008C;
pub const STATUS_ORDINAL_NOT_FOUND: u32 = 0xC0000138; pub const STATUS_FLOAT_DENORMAL_OPERAND: u32 = 0xC000008D;
pub const STATUS_ENTRYPOINT_NOT_FOUND: u32 = 0xC0000139; pub const STATUS_FLOAT_DIVIDE_BY_ZERO: u32 = 0xC000008E;
pub const STATUS_CONTROL_C_EXIT: u32 = 0xC000013A; pub const STATUS_FLOAT_INEXACT_RESULT: u32 = 0xC000008F;
pub const STATUS_DLL_INIT_FAILED: u32 = 0xC0000142; pub const STATUS_FLOAT_INVALID_OPERATION: u32 = 0xC0000090;
pub const STATUS_FLOAT_MULTIPLE_FAULTS: u32 = 0xC00002B4; pub const STATUS_FLOAT_OVERFLOW: u32 = 0xC0000091;
pub const STATUS_FLOAT_MULTIPLE_TRAPS: u32 = 0xC00002B5; pub const STATUS_FLOAT_STACK_CHECK: u32 = 0xC0000092;
pub const STATUS_REG_NAT_CONSUMPTION: u32 = 0xC00002C9; pub const STATUS_FLOAT_UNDERFLOW: u32 = 0xC0000093;
pub const STATUS_HEAP_CORRUPTION: u32 = 0xC0000374; pub const STATUS_INTEGER_DIVIDE_BY_ZERO: u32 = 0xC0000094;
pub const STATUS_STACK_BUFFER_OVERRUN: u32 = 0xC0000409; pub const STATUS_INTEGER_OVERFLOW: u32 = 0xC0000095;
pub const STATUS_INVALID_CRUNTIME_PARAMETER: u32 = 0xC0000417; pub const STATUS_PRIVILEGED_INSTRUCTION: u32 = 0xC0000096;
pub const STATUS_ASSERTION_FAILURE: u32 = 0xC0000420; pub const STATUS_STACK_OVERFLOW: u32 = 0xC00000FD;
pub const STATUS_SXS_EARLY_DEACTIVATION: u32 = 0xC015000F; pub const STATUS_DLL_NOT_FOUND: u32 = 0xC0000135;
pub const STATUS_SXS_INVALID_DEACTIVATION: u32 = 0xC0150010; pub const STATUS_ORDINAL_NOT_FOUND: u32 = 0xC0000138;
pub const STATUS_ENTRYPOINT_NOT_FOUND: u32 = 0xC0000139;
#[derive(IntoPrimitive, TryFromPrimitive, Clone, Copy)] pub const STATUS_CONTROL_C_EXIT: u32 = 0xC000013A;
#[repr(u32)] pub const STATUS_DLL_INIT_FAILED: u32 = 0xC0000142;
pub enum ExceptionCode { pub const STATUS_FLOAT_MULTIPLE_FAULTS: u32 = 0xC00002B4;
// From https://docs.microsoft.com/en-us/windows/win32/debug/getexceptioncode pub const STATUS_FLOAT_MULTIPLE_TRAPS: u32 = 0xC00002B5;
AccessViolation = STATUS_ACCESS_VIOLATION, pub const STATUS_REG_NAT_CONSUMPTION: u32 = 0xC00002C9;
ArrayBoundsExceeded = STATUS_ARRAY_BOUNDS_EXCEEDED, pub const STATUS_HEAP_CORRUPTION: u32 = 0xC0000374;
Breakpoint = STATUS_BREAKPOINT, pub const STATUS_STACK_BUFFER_OVERRUN: u32 = 0xC0000409;
DatatypeMisalignment = STATUS_DATATYPE_MISALIGNMENT, pub const STATUS_INVALID_CRUNTIME_PARAMETER: u32 = 0xC0000417;
FltDenormalOperand = STATUS_FLOAT_DENORMAL_OPERAND, pub const STATUS_ASSERTION_FAILURE: u32 = 0xC0000420;
FltDivideByZero = STATUS_FLOAT_DIVIDE_BY_ZERO, pub const STATUS_SXS_EARLY_DEACTIVATION: u32 = 0xC015000F;
FltInexactResult = STATUS_FLOAT_INEXACT_RESULT, pub const STATUS_SXS_INVALID_DEACTIVATION: u32 = 0xC0150010;
FltInvalidOperation = STATUS_FLOAT_INVALID_OPERATION,
FltOverflow = STATUS_FLOAT_OVERFLOW, #[derive(IntoPrimitive, TryFromPrimitive, Clone, Copy)]
FltStackCheck = STATUS_FLOAT_STACK_CHECK, #[repr(u32)]
FltUnderflow = STATUS_FLOAT_UNDERFLOW, pub enum ExceptionCode {
GuardPageViolation = STATUS_GUARD_PAGE_VIOLATION, // From https://docs.microsoft.com/en-us/windows/win32/debug/getexceptioncode
IllegalInstruction = STATUS_ILLEGAL_INSTRUCTION, AccessViolation = STATUS_ACCESS_VIOLATION,
InPageError = STATUS_IN_PAGE_ERROR, ArrayBoundsExceeded = STATUS_ARRAY_BOUNDS_EXCEEDED,
IntegerDivideByZero = STATUS_INTEGER_DIVIDE_BY_ZERO, Breakpoint = STATUS_BREAKPOINT,
IntegerOverflow = STATUS_INTEGER_OVERFLOW, DatatypeMisalignment = STATUS_DATATYPE_MISALIGNMENT,
InvalidDisposition = STATUS_INVALID_DISPOSITION, FltDenormalOperand = STATUS_FLOAT_DENORMAL_OPERAND,
InvalidHandle = STATUS_INVALID_HANDLE, FltDivideByZero = STATUS_FLOAT_DIVIDE_BY_ZERO,
NoncontinuableException = STATUS_NONCONTINUABLE_EXCEPTION, FltInexactResult = STATUS_FLOAT_INEXACT_RESULT,
PrivilegedInstruction = STATUS_PRIVILEGED_INSTRUCTION, FltInvalidOperation = STATUS_FLOAT_INVALID_OPERATION,
SingleStep = STATUS_SINGLE_STEP, FltOverflow = STATUS_FLOAT_OVERFLOW,
StackOverflow = STATUS_STACK_OVERFLOW, FltStackCheck = STATUS_FLOAT_STACK_CHECK,
UnwindConsolidate = STATUS_UNWIND_CONSOLIDATE, FltUnderflow = STATUS_FLOAT_UNDERFLOW,
// Addition exceptions GuardPageViolation = STATUS_GUARD_PAGE_VIOLATION,
Wait0 = STATUS_WAIT_0, IllegalInstruction = STATUS_ILLEGAL_INSTRUCTION,
AbandonedWait0 = STATUS_ABANDONED_WAIT_0, InPageError = STATUS_IN_PAGE_ERROR,
UserAPC = STATUS_USER_APC, IntegerDivideByZero = STATUS_INTEGER_DIVIDE_BY_ZERO,
Timeout = STATUS_TIMEOUT, IntegerOverflow = STATUS_INTEGER_OVERFLOW,
Pending = STATUS_PENDING, InvalidDisposition = STATUS_INVALID_DISPOSITION,
SegmentNotification = STATUS_SEGMENT_NOTIFICATION, InvalidHandle = STATUS_INVALID_HANDLE,
FatalAppExit = STATUS_FATAL_APP_EXIT, NoncontinuableException = STATUS_NONCONTINUABLE_EXCEPTION,
Longjump = STATUS_LONGJUMP, PrivilegedInstruction = STATUS_PRIVILEGED_INSTRUCTION,
DLLNotFound = STATUS_DLL_NOT_FOUND, SingleStep = STATUS_SINGLE_STEP,
OrdinalNotFound = STATUS_ORDINAL_NOT_FOUND, StackOverflow = STATUS_STACK_OVERFLOW,
EntryPointNotFound = STATUS_ENTRYPOINT_NOT_FOUND, UnwindConsolidate = STATUS_UNWIND_CONSOLIDATE,
ControlCExit = STATUS_CONTROL_C_EXIT, // Addition exceptions
DllInitFailed = STATUS_DLL_INIT_FAILED, Wait0 = STATUS_WAIT_0,
FltMultipleFaults = STATUS_FLOAT_MULTIPLE_FAULTS, AbandonedWait0 = STATUS_ABANDONED_WAIT_0,
FltMultipleTraps = STATUS_FLOAT_MULTIPLE_TRAPS, UserAPC = STATUS_USER_APC,
RegNatConsumption = STATUS_REG_NAT_CONSUMPTION, Timeout = STATUS_TIMEOUT,
HeapCorruption = STATUS_HEAP_CORRUPTION, Pending = STATUS_PENDING,
StackBufferOverrun = STATUS_STACK_BUFFER_OVERRUN, SegmentNotification = STATUS_SEGMENT_NOTIFICATION,
InvalidCRuntimeParameter = STATUS_INVALID_CRUNTIME_PARAMETER, FatalAppExit = STATUS_FATAL_APP_EXIT,
AssertionFailure = STATUS_ASSERTION_FAILURE, Longjump = STATUS_LONGJUMP,
SXSEarlyDeactivation = STATUS_SXS_EARLY_DEACTIVATION, DLLNotFound = STATUS_DLL_NOT_FOUND,
SXSInvalidDeactivation = STATUS_SXS_INVALID_DEACTIVATION, OrdinalNotFound = STATUS_ORDINAL_NOT_FOUND,
} EntryPointNotFound = STATUS_ENTRYPOINT_NOT_FOUND,
ControlCExit = STATUS_CONTROL_C_EXIT,
pub static CRASH_EXCEPTIONS: &[ExceptionCode] = &[ DllInitFailed = STATUS_DLL_INIT_FAILED,
ExceptionCode::AccessViolation, FltMultipleFaults = STATUS_FLOAT_MULTIPLE_FAULTS,
ExceptionCode::ArrayBoundsExceeded, FltMultipleTraps = STATUS_FLOAT_MULTIPLE_TRAPS,
ExceptionCode::FltDivideByZero, RegNatConsumption = STATUS_REG_NAT_CONSUMPTION,
ExceptionCode::GuardPageViolation, HeapCorruption = STATUS_HEAP_CORRUPTION,
ExceptionCode::IllegalInstruction, StackBufferOverrun = STATUS_STACK_BUFFER_OVERRUN,
ExceptionCode::InPageError, InvalidCRuntimeParameter = STATUS_INVALID_CRUNTIME_PARAMETER,
ExceptionCode::IntegerDivideByZero, AssertionFailure = STATUS_ASSERTION_FAILURE,
ExceptionCode::InvalidHandle, SXSEarlyDeactivation = STATUS_SXS_EARLY_DEACTIVATION,
ExceptionCode::NoncontinuableException, SXSInvalidDeactivation = STATUS_SXS_INVALID_DEACTIVATION,
ExceptionCode::PrivilegedInstruction, }
ExceptionCode::StackOverflow,
ExceptionCode::HeapCorruption, pub static CRASH_EXCEPTIONS: &[ExceptionCode] = &[
ExceptionCode::StackBufferOverrun, ExceptionCode::AccessViolation,
ExceptionCode::AssertionFailure, ExceptionCode::ArrayBoundsExceeded,
]; ExceptionCode::FltDivideByZero,
ExceptionCode::GuardPageViolation,
impl PartialEq for ExceptionCode { ExceptionCode::IllegalInstruction,
fn eq(&self, other: &Self) -> bool { ExceptionCode::InPageError,
*self as u32 == *other as u32 ExceptionCode::IntegerDivideByZero,
} ExceptionCode::InvalidHandle,
} ExceptionCode::NoncontinuableException,
ExceptionCode::PrivilegedInstruction,
impl Eq for ExceptionCode {} ExceptionCode::StackOverflow,
ExceptionCode::HeapCorruption,
unsafe impl Sync for ExceptionCode {} ExceptionCode::StackBufferOverrun,
ExceptionCode::AssertionFailure,
impl Display for ExceptionCode { ];
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
match self { impl PartialEq for ExceptionCode {
ExceptionCode::AccessViolation => write!(f, "STATUS_ACCESS_VIOLATION")?, fn eq(&self, other: &Self) -> bool {
ExceptionCode::ArrayBoundsExceeded => write!(f, "STATUS_ARRAY_BOUNDS_EXCEEDED")?, *self as u32 == *other as u32
ExceptionCode::Breakpoint => write!(f, "STATUS_BREAKPOINT")?, }
ExceptionCode::DatatypeMisalignment => write!(f, "STATUS_DATATYPE_MISALIGNMENT")?, }
ExceptionCode::FltDenormalOperand => write!(f, "STATUS_FLOAT_DENORMAL_OPERAND")?,
ExceptionCode::FltDivideByZero => write!(f, "STATUS_FLOAT_DIVIDE_BY_ZERO")?, impl Eq for ExceptionCode {}
ExceptionCode::FltInexactResult => write!(f, "STATUS_FLOAT_INEXACT_RESULT")?,
ExceptionCode::FltInvalidOperation => write!(f, "STATUS_FLOAT_INVALID_OPERATION")?, unsafe impl Sync for ExceptionCode {}
ExceptionCode::FltOverflow => write!(f, "STATUS_FLOAT_OVERFLOW")?,
ExceptionCode::FltStackCheck => write!(f, "STATUS_FLOAT_STACK_CHECK")?, impl Display for ExceptionCode {
ExceptionCode::FltUnderflow => write!(f, "STATUS_FLOAT_UNDERFLOW")?, fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
ExceptionCode::GuardPageViolation => write!(f, "STATUS_GUARD_PAGE_VIOLATION")?, match self {
ExceptionCode::IllegalInstruction => write!(f, "STATUS_ILLEGAL_INSTRUCTION")?, ExceptionCode::AccessViolation => write!(f, "STATUS_ACCESS_VIOLATION")?,
ExceptionCode::InPageError => write!(f, "STATUS_IN_PAGE_ERROR")?, ExceptionCode::ArrayBoundsExceeded => write!(f, "STATUS_ARRAY_BOUNDS_EXCEEDED")?,
ExceptionCode::IntegerDivideByZero => write!(f, "STATUS_INTEGER_DIVIDE_BY_ZERO")?, ExceptionCode::Breakpoint => write!(f, "STATUS_BREAKPOINT")?,
ExceptionCode::IntegerOverflow => write!(f, "STATUS_INTEGER_OVERFLOW")?, ExceptionCode::DatatypeMisalignment => write!(f, "STATUS_DATATYPE_MISALIGNMENT")?,
ExceptionCode::InvalidDisposition => write!(f, "STATUS_INVALID_DISPOSITION")?, ExceptionCode::FltDenormalOperand => write!(f, "STATUS_FLOAT_DENORMAL_OPERAND")?,
ExceptionCode::InvalidHandle => write!(f, "STATUS_INVALID_HANDLE")?, ExceptionCode::FltDivideByZero => write!(f, "STATUS_FLOAT_DIVIDE_BY_ZERO")?,
ExceptionCode::NoncontinuableException => write!(f, "STATUS_NONCONTINUABLE_EXCEPTION")?, ExceptionCode::FltInexactResult => write!(f, "STATUS_FLOAT_INEXACT_RESULT")?,
ExceptionCode::PrivilegedInstruction => write!(f, "STATUS_PRIVILEGED_INSTRUCTION")?, ExceptionCode::FltInvalidOperation => write!(f, "STATUS_FLOAT_INVALID_OPERATION")?,
ExceptionCode::SingleStep => write!(f, "STATUS_SINGLE_STEP")?, ExceptionCode::FltOverflow => write!(f, "STATUS_FLOAT_OVERFLOW")?,
ExceptionCode::StackOverflow => write!(f, "STATUS_STACK_OVERFLOW")?, ExceptionCode::FltStackCheck => write!(f, "STATUS_FLOAT_STACK_CHECK")?,
ExceptionCode::UnwindConsolidate => write!(f, "STATUS_UNWIND_CONSOLIDATE")?, ExceptionCode::FltUnderflow => write!(f, "STATUS_FLOAT_UNDERFLOW")?,
ExceptionCode::Wait0 => write!(f, "STATUS_WAIT_0")?, ExceptionCode::GuardPageViolation => write!(f, "STATUS_GUARD_PAGE_VIOLATION")?,
ExceptionCode::AbandonedWait0 => write!(f, "STATUS_ABANDONED_WAIT_0")?, ExceptionCode::IllegalInstruction => write!(f, "STATUS_ILLEGAL_INSTRUCTION")?,
ExceptionCode::UserAPC => write!(f, "STATUS_USER_APC")?, ExceptionCode::InPageError => write!(f, "STATUS_IN_PAGE_ERROR")?,
ExceptionCode::Timeout => write!(f, "STATUS_TIMEOUT")?, ExceptionCode::IntegerDivideByZero => write!(f, "STATUS_INTEGER_DIVIDE_BY_ZERO")?,
ExceptionCode::Pending => write!(f, "STATUS_PENDING")?, ExceptionCode::IntegerOverflow => write!(f, "STATUS_INTEGER_OVERFLOW")?,
ExceptionCode::SegmentNotification => write!(f, "STATUS_SEGMENT_NOTIFICATION")?, ExceptionCode::InvalidDisposition => write!(f, "STATUS_INVALID_DISPOSITION")?,
ExceptionCode::FatalAppExit => write!(f, "STATUS_FATAL_APP_EXIT")?, ExceptionCode::InvalidHandle => write!(f, "STATUS_INVALID_HANDLE")?,
ExceptionCode::Longjump => write!(f, "STATUS_LONGJUMP")?, ExceptionCode::NoncontinuableException => write!(f, "STATUS_NONCONTINUABLE_EXCEPTION")?,
ExceptionCode::DLLNotFound => write!(f, "STATUS_DLL_NOT_FOUND")?, ExceptionCode::PrivilegedInstruction => write!(f, "STATUS_PRIVILEGED_INSTRUCTION")?,
ExceptionCode::OrdinalNotFound => write!(f, "STATUS_ORDINAL_NOT_FOUND")?, ExceptionCode::SingleStep => write!(f, "STATUS_SINGLE_STEP")?,
ExceptionCode::EntryPointNotFound => write!(f, "STATUS_ENTRYPOINT_NOT_FOUND")?, ExceptionCode::StackOverflow => write!(f, "STATUS_STACK_OVERFLOW")?,
ExceptionCode::ControlCExit => write!(f, "STATUS_CONTROL_C_EXIT")?, ExceptionCode::UnwindConsolidate => write!(f, "STATUS_UNWIND_CONSOLIDATE")?,
ExceptionCode::DllInitFailed => write!(f, "STATUS_DLL_INIT_FAILED")?, ExceptionCode::Wait0 => write!(f, "STATUS_WAIT_0")?,
ExceptionCode::FltMultipleFaults => write!(f, "STATUS_FLOAT_MULTIPLE_FAULTS")?, ExceptionCode::AbandonedWait0 => write!(f, "STATUS_ABANDONED_WAIT_0")?,
ExceptionCode::FltMultipleTraps => write!(f, "STATUS_FLOAT_MULTIPLE_TRAPS")?, ExceptionCode::UserAPC => write!(f, "STATUS_USER_APC")?,
ExceptionCode::RegNatConsumption => write!(f, "STATUS_REG_NAT_CONSUMPTION")?, ExceptionCode::Timeout => write!(f, "STATUS_TIMEOUT")?,
ExceptionCode::HeapCorruption => write!(f, "STATUS_HEAP_CORRUPTION")?, ExceptionCode::Pending => write!(f, "STATUS_PENDING")?,
ExceptionCode::StackBufferOverrun => write!(f, "STATUS_STACK_BUFFER_OVERRUN")?, ExceptionCode::SegmentNotification => write!(f, "STATUS_SEGMENT_NOTIFICATION")?,
ExceptionCode::InvalidCRuntimeParameter => { ExceptionCode::FatalAppExit => write!(f, "STATUS_FATAL_APP_EXIT")?,
write!(f, "STATUS_INVALID_CRUNTIME_PARAMETER")? ExceptionCode::Longjump => write!(f, "STATUS_LONGJUMP")?,
} ExceptionCode::DLLNotFound => write!(f, "STATUS_DLL_NOT_FOUND")?,
ExceptionCode::AssertionFailure => write!(f, "STATUS_ASSERTION_FAILURE")?, ExceptionCode::OrdinalNotFound => write!(f, "STATUS_ORDINAL_NOT_FOUND")?,
ExceptionCode::SXSEarlyDeactivation => write!(f, "STATUS_SXS_EARLY_DEACTIVATION")?, ExceptionCode::EntryPointNotFound => write!(f, "STATUS_ENTRYPOINT_NOT_FOUND")?,
ExceptionCode::SXSInvalidDeactivation => write!(f, "STATUS_SXS_INVALID_DEACTIVATION")?, ExceptionCode::ControlCExit => write!(f, "STATUS_CONTROL_C_EXIT")?,
}; ExceptionCode::DllInitFailed => write!(f, "STATUS_DLL_INIT_FAILED")?,
ExceptionCode::FltMultipleFaults => write!(f, "STATUS_FLOAT_MULTIPLE_FAULTS")?,
Ok(()) ExceptionCode::FltMultipleTraps => write!(f, "STATUS_FLOAT_MULTIPLE_TRAPS")?,
} ExceptionCode::RegNatConsumption => write!(f, "STATUS_REG_NAT_CONSUMPTION")?,
} ExceptionCode::HeapCorruption => write!(f, "STATUS_HEAP_CORRUPTION")?,
ExceptionCode::StackBufferOverrun => write!(f, "STATUS_STACK_BUFFER_OVERRUN")?,
pub static EXCEPTION_CODES_MAPPING: [ExceptionCode; 45] = [ ExceptionCode::InvalidCRuntimeParameter => {
ExceptionCode::AccessViolation, write!(f, "STATUS_INVALID_CRUNTIME_PARAMETER")?
ExceptionCode::ArrayBoundsExceeded, }
ExceptionCode::Breakpoint, ExceptionCode::AssertionFailure => write!(f, "STATUS_ASSERTION_FAILURE")?,
ExceptionCode::DatatypeMisalignment, ExceptionCode::SXSEarlyDeactivation => write!(f, "STATUS_SXS_EARLY_DEACTIVATION")?,
ExceptionCode::FltDenormalOperand, ExceptionCode::SXSInvalidDeactivation => write!(f, "STATUS_SXS_INVALID_DEACTIVATION")?,
ExceptionCode::FltDivideByZero, };
ExceptionCode::FltInexactResult,
ExceptionCode::FltInvalidOperation, Ok(())
ExceptionCode::FltOverflow, }
ExceptionCode::FltStackCheck, }
ExceptionCode::FltUnderflow,
ExceptionCode::GuardPageViolation, pub static EXCEPTION_CODES_MAPPING: [ExceptionCode; 45] = [
ExceptionCode::IllegalInstruction, ExceptionCode::AccessViolation,
ExceptionCode::InPageError, ExceptionCode::ArrayBoundsExceeded,
ExceptionCode::IntegerDivideByZero, ExceptionCode::Breakpoint,
ExceptionCode::IntegerOverflow, ExceptionCode::DatatypeMisalignment,
ExceptionCode::InvalidDisposition, ExceptionCode::FltDenormalOperand,
ExceptionCode::InvalidHandle, ExceptionCode::FltDivideByZero,
ExceptionCode::NoncontinuableException, ExceptionCode::FltInexactResult,
ExceptionCode::PrivilegedInstruction, ExceptionCode::FltInvalidOperation,
ExceptionCode::SingleStep, ExceptionCode::FltOverflow,
ExceptionCode::StackOverflow, ExceptionCode::FltStackCheck,
ExceptionCode::UnwindConsolidate, ExceptionCode::FltUnderflow,
ExceptionCode::Wait0, ExceptionCode::GuardPageViolation,
ExceptionCode::AbandonedWait0, ExceptionCode::IllegalInstruction,
ExceptionCode::UserAPC, ExceptionCode::InPageError,
ExceptionCode::Timeout, ExceptionCode::IntegerDivideByZero,
ExceptionCode::Pending, ExceptionCode::IntegerOverflow,
ExceptionCode::SegmentNotification, ExceptionCode::InvalidDisposition,
ExceptionCode::FatalAppExit, ExceptionCode::InvalidHandle,
ExceptionCode::Longjump, ExceptionCode::NoncontinuableException,
ExceptionCode::DLLNotFound, ExceptionCode::PrivilegedInstruction,
ExceptionCode::OrdinalNotFound, ExceptionCode::SingleStep,
ExceptionCode::EntryPointNotFound, ExceptionCode::StackOverflow,
ExceptionCode::ControlCExit, ExceptionCode::UnwindConsolidate,
ExceptionCode::DllInitFailed, ExceptionCode::Wait0,
ExceptionCode::FltMultipleFaults, ExceptionCode::AbandonedWait0,
ExceptionCode::FltMultipleTraps, ExceptionCode::UserAPC,
ExceptionCode::RegNatConsumption, ExceptionCode::Timeout,
ExceptionCode::HeapCorruption, ExceptionCode::Pending,
ExceptionCode::StackBufferOverrun, ExceptionCode::SegmentNotification,
ExceptionCode::InvalidCRuntimeParameter, ExceptionCode::FatalAppExit,
ExceptionCode::AssertionFailure, ExceptionCode::Longjump,
ExceptionCode::SXSEarlyDeactivation, ExceptionCode::DLLNotFound,
ExceptionCode::SXSInvalidDeactivation, ExceptionCode::OrdinalNotFound,
]; ExceptionCode::EntryPointNotFound,
ExceptionCode::ControlCExit,
pub trait Handler { ExceptionCode::DllInitFailed,
/// Handle an exception ExceptionCode::FltMultipleFaults,
fn handle( ExceptionCode::FltMultipleTraps,
&mut self, ExceptionCode::RegNatConsumption,
exception_code: ExceptionCode, ExceptionCode::HeapCorruption,
exception_pointers: *mut EXCEPTION_POINTERS, ExceptionCode::StackBufferOverrun,
); ExceptionCode::InvalidCRuntimeParameter,
/// Return a list of exceptions to handle ExceptionCode::AssertionFailure,
fn exceptions(&self) -> Vec<ExceptionCode>; ExceptionCode::SXSEarlyDeactivation,
} ExceptionCode::SXSInvalidDeactivation,
];
struct HandlerHolder {
handler: UnsafeCell<*mut dyn Handler>, pub trait Handler {
} /// Handle an exception
fn handle(
unsafe impl Send for HandlerHolder {} &mut self,
exception_code: ExceptionCode,
/// Keep track of which handler is registered for which exception exception_pointers: *mut EXCEPTION_POINTERS,
static mut EXCEPTION_HANDLERS: [Option<HandlerHolder>; 64] = [ );
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, /// Return a list of exceptions to handle
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, fn exceptions(&self) -> Vec<ExceptionCode>;
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, }
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
]; struct HandlerHolder {
handler: UnsafeCell<*mut dyn Handler>,
type NativeHandlerType = extern "system" fn(*mut EXCEPTION_POINTERS) -> c_long; }
static mut PREVIOUS_HANDLER: Option<NativeHandlerType> = None;
unsafe impl Send for HandlerHolder {}
/// Internal function that is being called whenever an exception arrives (stdcall).
unsafe extern "system" fn handle_exception(exception_pointers: *mut EXCEPTION_POINTERS) -> c_long { /// Keep track of which handler is registered for which exception
let code = exception_pointers static mut EXCEPTION_HANDLERS: [Option<HandlerHolder>; 64] = [
.as_mut() None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
.unwrap() None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
.exception_record None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
.as_mut() None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
.unwrap() ];
.exception_code;
let exception_code = ExceptionCode::try_from(code).unwrap(); unsafe fn internal_handle_exception(
let index = EXCEPTION_CODES_MAPPING exception_code: ExceptionCode,
.iter() exception_pointers: *mut EXCEPTION_POINTERS,
.position(|x| *x == exception_code) ) -> i32 {
.unwrap(); let index = EXCEPTION_CODES_MAPPING
let ret = match &EXCEPTION_HANDLERS[index] { .iter()
Some(handler_holder) => { .position(|x| *x == exception_code)
let handler = &mut **handler_holder.handler.get(); .unwrap();
handler.handle(exception_code, exception_pointers); match &EXCEPTION_HANDLERS[index] {
EXCEPTION_EXECUTE_HANDLER Some(handler_holder) => {
} let handler = &mut **handler_holder.handler.get();
None => EXCEPTION_EXECUTE_HANDLER, handler.handle(exception_code, exception_pointers);
}; EXCEPTION_EXECUTE_HANDLER
if let Some(prev_handler) = PREVIOUS_HANDLER { }
prev_handler(exception_pointers) None => EXCEPTION_EXECUTE_HANDLER,
} else { }
ret }
}
} type NativeHandlerType = extern "system" fn(*mut EXCEPTION_POINTERS) -> c_long;
static mut PREVIOUS_HANDLER: Option<NativeHandlerType> = None;
/// Setup Win32 exception handlers in a somewhat rusty way.
/// # Safety /// Internal function that is being called whenever an exception arrives (stdcall).
/// Exception handlers are usually ugly, handle with care! unsafe extern "system" fn handle_exception(exception_pointers: *mut EXCEPTION_POINTERS) -> c_long {
pub unsafe fn setup_exception_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> { let code = exception_pointers
let exceptions = handler.exceptions(); .as_mut()
for exception_code in exceptions { .unwrap()
let index = EXCEPTION_CODES_MAPPING .exception_record
.iter() .as_mut()
.position(|x| *x == exception_code) .unwrap()
.unwrap(); .exception_code;
write_volatile( let exception_code = ExceptionCode::try_from(code).unwrap();
&mut EXCEPTION_HANDLERS[index], // println!("Received {}", exception_code);
Some(HandlerHolder { let ret = internal_handle_exception(exception_code, exception_pointers);
handler: UnsafeCell::new(handler as *mut dyn Handler), if let Some(prev_handler) = PREVIOUS_HANDLER {
}), prev_handler(exception_pointers)
); } else {
} ret
compiler_fence(Ordering::SeqCst); }
}
if let Some(prev) = SetUnhandledExceptionFilter(Some(core::mem::transmute(
handle_exception as *const c_void, type NativeSignalHandlerType = unsafe extern "C" fn(i32);
))) { extern "C" {
PREVIOUS_HANDLER = Some(core::mem::transmute(prev as *const c_void)); fn signal(signum: i32, func: NativeSignalHandlerType) -> *const c_void;
} }
Ok(())
} unsafe extern "C" fn handle_signal(_signum: i32) {
// println!("Received signal {}", _signum);
internal_handle_exception(ExceptionCode::AssertionFailure, ptr::null_mut());
}
/// Setup Win32 exception handlers in a somewhat rusty way.
/// # Safety
/// Exception handlers are usually ugly, handle with care!
pub unsafe fn setup_exception_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> {
let exceptions = handler.exceptions();
let mut catch_assertions = false;
for exception_code in exceptions {
if exception_code == ExceptionCode::AssertionFailure {
catch_assertions = true;
}
let index = EXCEPTION_CODES_MAPPING
.iter()
.position(|x| *x == exception_code)
.unwrap();
write_volatile(
&mut EXCEPTION_HANDLERS[index],
Some(HandlerHolder {
handler: UnsafeCell::new(handler as *mut dyn Handler),
}),
);
}
compiler_fence(Ordering::SeqCst);
if catch_assertions {
signal(SIGABRT, handle_signal);
}
if let Some(prev) = SetUnhandledExceptionFilter(Some(core::mem::transmute(
handle_exception as *const c_void,
))) {
PREVIOUS_HANDLER = Some(core::mem::transmute(prev as *const c_void));
}
Ok(())
}