#48110·servo

servoshell's crash_handler::install() is a no-op on Windows -- every native crash is silent, no console output, no WER event

Author: isaaliaCreated Sep 15, 2026Updated Sep 15, 2026

Describe the bug:

ports/servoshell/crash_handler.rs's install() is a real signal handler on macOS/Linux (catches SIGSEGV/SIGILL/SIGIOT/SIGBUS, prints a backtrace via the existing allocation-free backtrace::print, then re-raises for a core dump) but a complete no-op on Windows:

rust
#[cfg(not(any(target_os = "macos", target_os = "linux", target_os = "android")))]
pub fn install() {}

Consequence: every native crash on Windows (a segfault, an access violation, etc.) is completely silent — no console output, and in practice no Windows Error Reporting event either (cause unclear; possibly interacting with how the process terminates). This makes diagnosing any Windows-only crash (see #48109, filed today) much harder than it needs to be, since there's nothing to go on beyond "the process is gone."

Fix used downstream (happy to open a PR against this repo if useful — this is currently only in our fork): implement the Win32 equivalent using SetUnhandledExceptionFilter, reusing the same backtrace::print the Unix handler already calls:

rust
#[cfg(target_os = "windows")]
pub fn install() {
    use windows_sys::Win32::System::Diagnostics::Debug::{
        EXCEPTION_EXECUTE_HANDLER, EXCEPTION_POINTERS, SetUnhandledExceptionFilter,
    };

    unsafe extern "system" fn handler(exception_info: *const EXCEPTION_POINTERS) -> i32 {
        static BEEN_HERE_BEFORE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
        if !BEEN_HERE_BEFORE.swap(true, std::sync::atomic::Ordering::SeqCst) {
            let code = unsafe {
                (*exception_info).ExceptionRecord.as_ref().map(|r| r.ExceptionCode).unwrap_or(0)
            };
            let stderr = std::io::stderr();
            let mut stderr = stderr.lock();
            let _ = writeln!(&mut stderr, "Caught exception 0x{:X}", code as u32);
            let _ = crate::backtrace::print(&mut stderr);
        }
        EXCEPTION_EXECUTE_HANDLER
    }

    unsafe { SetUnhandledExceptionFilter(Some(handler)); }
}

Needs windows-sys features Win32_System_Diagnostics_Debug and Win32_System_Kernel (the latter for EXCEPTION_POINTERS, which is gated behind it).

Caveat found in practice: the backtrace this produces for an optimized/release crash is heavily symbol-garbled (repeated/misattributed frames) without full PDB coverage for the statically-linked C++ (mozjs) code — still strictly better than nothing, and it did surface real frames (e.g. SpiderMonkey symbols) that pointed the investigation in the right direction for #48109.

Platform: Windows 11.