Files
pnpm/.github/scripts/reset-error-mode.rs
T
Zoltan Kochan c1f66da54c ci(rust): clear the inherited error mode so Windows test aborts leave dumps (#17569)
The Windows test job has Windows Error Reporting write a minidump of
any crashing process, to find the source of the intermittent 0xc0000409
aborts (pnpm/tasks#239). The next abort on main left no dump.

WER writes no dump for a process whose error mode has
SEM_NOGPFAULTERRORBOX. Node (libuv) sets SEM_FAILCRITICALERRORS,
SEM_NOGPFAULTERRORBOX and SEM_NOOPENFILEERRORBOX at startup, and a child
inherits its parent's error mode. The tests run under Node
(measure-command.mjs and run-rust-tests.mjs), so every test binary
inherited 0x8003. The self-check passed only because it started pwsh
from the pwsh step shell, without Node in between.

Build a small cargo target runner with rustc that clears the error mode
and runs the test binary, and point CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUNNER
at it on Windows. The runner drops that variable from the test binary's
environment, since assert_cmd would otherwise start every pnpm a test
spawns through the runner too. The self-check now aborts a process
started from Node through the runner, the same path a test takes.
2026-11-02 14:31:15 +01:00

48 lines
1.8 KiB
Rust

//! Cargo target runner for the Windows CI test job: runs the given program
//! with the default error mode instead of the one it would inherit.
//!
//! Node (libuv) sets `SEM_NOGPFAULTERRORBOX` at startup, and a child process
//! inherits its parent's error mode. The test job starts `cargo nextest`
//! under Node, so every test binary inherited that flag, and with it Windows
//! Error Reporting writes no crash dump when the process aborts. The runner
//! clears the error mode, so a crashing test binary leaves a dump
//! (pnpm/tasks#239).
//!
//! The program runs without the runner variable: `assert_cmd` would otherwise
//! start every binary a test spawns through this runner as well, which
//! changes the parent process those binaries see. They still inherit the
//! cleared error mode.
//!
//! Built with plain `rustc` by the workflow, so it is not a workspace member.
use std::process::{Command, exit};
const RUNNER_VAR: &str = "CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUNNER";
#[link(name = "kernel32")]
unsafe extern "system" {
fn SetErrorMode(mode: u32) -> u32;
}
fn main() {
// SAFETY: SetErrorMode only changes the error mode of this process, which
// the child started below inherits.
unsafe { SetErrorMode(0) };
let mut args = std::env::args_os().skip(1);
let Some(program) = args.next() else {
eprintln!("usage: reset-error-mode <program> [args...]");
exit(2);
};
let status = Command::new(&program)
.args(args)
.env_remove(RUNNER_VAR)
.status()
.unwrap_or_else(|error| {
eprintln!("reset-error-mode: cannot run {}: {error}", program.to_string_lossy());
exit(2);
});
// On Windows the exit code always exists: an abort reports 0xc0000409 as
// a negative i32, which `exit` passes on unchanged.
exit(status.code().unwrap_or(1));
}