EmbarkStudios / crash-handling

Collection of crates to deal with crashes
Apache License 2.0
138 stars 13 forks source link

Add heap corruption exception handling #85

Closed h3r2tic closed 5 months ago

h3r2tic commented 5 months ago

Checklist

Description of Changes

We've been using crash-handler in Tiny Glade, and noticed a few quiet crashes, where our crash reporter had nothing to say. I suspect those are heap corruptions (in graphics drivers or DLLs that inject themselves into our app). Windows will not call the unhandled exception filter for those.

This PR adds a vectored exception handler that gets to act first. VEH is only used to process heap corruptions in this PR, allowing the unhandled exception filter to process the rest.

Disclaimer: I have no idea what I'm doing, but it catches an intentional heap corruption in my test. Here's the heap corruption code (source), for science of course:

unsafe fn corrupt_windows_heap() {
    use windows::core::PCSTR;
    use windows::Win32::Foundation::BOOL;
    use windows::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA};
    use windows::Win32::System::Memory::{GetProcessHeap, HeapHandle};

    let kernel32 = LoadLibraryA(PCSTR("kernel32.dll\0".as_ptr().cast()));
    if let Ok(kernel32) = kernel32 {
        eprintln!("Corrupting the windows heap");

        let heap_free: Option<
            unsafe extern "system" fn(HeapHandle, u32, *const core::ffi::c_void) -> BOOL,
        > = std::mem::transmute(GetProcAddress(
            kernel32,
            PCSTR("HeapFree\0".as_ptr().cast()),
        ));

        if let Some(heap_free) = heap_free {
            let heap = GetProcessHeap().unwrap();
            let bad_pointer = 3 as *mut core::ffi::c_void;
            heap_free(heap, 0, bad_pointer);
            eprintln!("Oh no, the heap is still alive :o");
        }
    } else {
        eprintln!("Can't corrupt heap: failed to load kernel32");
    }
}
windows = { version = "0.37", features = [
    "Win32_Foundation",
    "Win32_System_LibraryLoader",
    "Win32_System_Memory"
] }
gabrielesvelto commented 5 months ago

FYI we've had an VEH catching STATUS_HEAP_CORRUPTION exceptions in Firefox for a while, but several times the handler itself hits another crash before being able to process it. You might want a Windows Error Reporting runtime exception module to catch those "the world is on fire" crashes instead. We have one (see this and this) but it requires building and installing a separate DLL (plus registry modifications) so it might not be suitable for all projects. On the upside it can also catch FAST_FAIL_* exceptions which cannot be caught with VEH/SEH.

h3r2tic commented 5 months ago

Oooh, thanks for chiming in, @gabrielesvelto 💕 That's great to know for when we hear of silent crashes again 😅