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
@ -21,5 +22,7 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
free(img); free(img);
// if (x > 10000) free(img); // free crash
return 0; return 0;
} }

View File

@ -7,6 +7,7 @@ use core::{
cell::UnsafeCell, cell::UnsafeCell,
convert::TryFrom, convert::TryFrom,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
ptr,
ptr::write_volatile, ptr::write_volatile,
sync::atomic::{compiler_fence, Ordering}, sync::atomic::{compiler_fence, Ordering},
}; };
@ -18,6 +19,17 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
//const EXCEPTION_CONTINUE_SEARCH: c_long = 0; //const EXCEPTION_CONTINUE_SEARCH: c_long = 0;
const EXCEPTION_EXECUTE_HANDLER: c_long = 1; const EXCEPTION_EXECUTE_HANDLER: c_long = 1;
// From https://github.com/Alexpux/mingw-w64/blob/master/mingw-w64-headers/crt/signal.h
pub const SIGINT: i32 = 2;
pub const SIGILL: i32 = 4;
pub const SIGABRT_COMPAT: i32 = 6;
pub const SIGFPE: i32 = 8;
pub const SIGSEGV: i32 = 11;
pub const SIGTERM: i32 = 15;
pub const SIGBREAK: i32 = 21;
pub const SIGABRT: i32 = 22;
pub const SIGABRT2: i32 = 22;
// From https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L611 // From https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L611
pub const STATUS_WAIT_0: u32 = 0x00000000; pub const STATUS_WAIT_0: u32 = 0x00000000;
pub const STATUS_ABANDONED_WAIT_0: u32 = 0x00000080; pub const STATUS_ABANDONED_WAIT_0: u32 = 0x00000080;
@ -274,6 +286,24 @@ static mut EXCEPTION_HANDLERS: [Option<HandlerHolder>; 64] = [
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,
]; ];
unsafe fn internal_handle_exception(
exception_code: ExceptionCode,
exception_pointers: *mut EXCEPTION_POINTERS,
) -> i32 {
let index = EXCEPTION_CODES_MAPPING
.iter()
.position(|x| *x == exception_code)
.unwrap();
match &EXCEPTION_HANDLERS[index] {
Some(handler_holder) => {
let handler = &mut **handler_holder.handler.get();
handler.handle(exception_code, exception_pointers);
EXCEPTION_EXECUTE_HANDLER
}
None => EXCEPTION_EXECUTE_HANDLER,
}
}
type NativeHandlerType = extern "system" fn(*mut EXCEPTION_POINTERS) -> c_long; type NativeHandlerType = extern "system" fn(*mut EXCEPTION_POINTERS) -> c_long;
static mut PREVIOUS_HANDLER: Option<NativeHandlerType> = None; static mut PREVIOUS_HANDLER: Option<NativeHandlerType> = None;
@ -287,18 +317,8 @@ unsafe extern "system" fn handle_exception(exception_pointers: *mut EXCEPTION_PO
.unwrap() .unwrap()
.exception_code; .exception_code;
let exception_code = ExceptionCode::try_from(code).unwrap(); let exception_code = ExceptionCode::try_from(code).unwrap();
let index = EXCEPTION_CODES_MAPPING // println!("Received {}", exception_code);
.iter() let ret = internal_handle_exception(exception_code, exception_pointers);
.position(|x| *x == exception_code)
.unwrap();
let ret = match &EXCEPTION_HANDLERS[index] {
Some(handler_holder) => {
let handler = &mut **handler_holder.handler.get();
handler.handle(exception_code, exception_pointers);
EXCEPTION_EXECUTE_HANDLER
}
None => EXCEPTION_EXECUTE_HANDLER,
};
if let Some(prev_handler) = PREVIOUS_HANDLER { if let Some(prev_handler) = PREVIOUS_HANDLER {
prev_handler(exception_pointers) prev_handler(exception_pointers)
} else { } else {
@ -306,12 +326,26 @@ unsafe extern "system" fn handle_exception(exception_pointers: *mut EXCEPTION_PO
} }
} }
type NativeSignalHandlerType = unsafe extern "C" fn(i32);
extern "C" {
fn signal(signum: i32, func: NativeSignalHandlerType) -> *const c_void;
}
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. /// Setup Win32 exception handlers in a somewhat rusty way.
/// # Safety /// # Safety
/// Exception handlers are usually ugly, handle with care! /// Exception handlers are usually ugly, handle with care!
pub unsafe fn setup_exception_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> { pub unsafe fn setup_exception_handler<T: 'static + Handler>(handler: &mut T) -> Result<(), Error> {
let exceptions = handler.exceptions(); let exceptions = handler.exceptions();
let mut catch_assertions = false;
for exception_code in exceptions { for exception_code in exceptions {
if exception_code == ExceptionCode::AssertionFailure {
catch_assertions = true;
}
let index = EXCEPTION_CODES_MAPPING let index = EXCEPTION_CODES_MAPPING
.iter() .iter()
.position(|x| *x == exception_code) .position(|x| *x == exception_code)
@ -324,7 +358,9 @@ pub unsafe fn setup_exception_handler<T: 'static + Handler>(handler: &mut T) ->
); );
} }
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
if catch_assertions {
signal(SIGABRT, handle_signal);
}
if let Some(prev) = SetUnhandledExceptionFilter(Some(core::mem::transmute( if let Some(prev) = SetUnhandledExceptionFilter(Some(core::mem::transmute(
handle_exception as *const c_void, handle_exception as *const c_void,
))) { ))) {