mirror of
https://github.com/stablyai/orca.git
synced 2026-09-25 16:02:38 +00:00
* fix(crash-reporting): decode POSIX wait statuses for display and record Windows session-end reasons Chromium on POSIX hands render/child-process-gone the raw waitpid() status, so crash reports read "Exit code: 61696" where exit status 241 is meant (field: 61696=exit 241, 9=SIGKILL, 133=SIGTRAP+core, darwin crashed 5=SIGTRAP). Decode at the display layer only: the stored exitCode stays raw, Windows codes and launch-failed launch-error codes render unchanged, and the process-gone span gains a crash.exit_code_decoded attribute. Also durably record a system_session_end breadcrumb (with WindowSessionEndEvent reasons) when Windows session-end fires, so bundles can tell OS shutdown from a user task-kill in killed/exit-1 sweeps. * test(crash-reporting): pin the exit(0) no-suffix rendering Adversarial mutation review: removing the exit-0 suppression in formatCrashReportExitCode survived the suite — nothing pinned that a clean exit(0) renders without an '(exit status 0)' suffix. * test(crash-reporting): decode-attribute tests use synchronous child kills Renderer killed events gain a 250ms sibling-kill settle once the correlation branch lands, which (a) defers the span past the test's platform stub so the decode gate reads the real host platform, and (b) adds a deferred span that breaks the exact sink assertion. The decode gate is source-agnostic, and a non-recoverable child kill persists synchronously on every branch of the stack, so coverage is unchanged and the platform stub is deterministic on any CI host. * fix(crash-reporting): keep session-end reasons type-safe
58 lines
1.9 KiB
TypeScript
58 lines
1.9 KiB
TypeScript
// Chromium on POSIX surfaces the raw waitpid() status as the process-gone exit
|
|
// code, so crash reports show 61696 where "exit status 241" is meant. Decode for
|
|
// display only — the raw value stays the stored source of truth.
|
|
|
|
export type PosixWaitStatusDecode =
|
|
| { kind: 'exited'; exitStatus: number }
|
|
| { kind: 'signaled'; signal: number; signalName: string | null; coreDumped: boolean }
|
|
|
|
// Only numbers that are identical on Linux and macOS; naming a divergent one
|
|
// (e.g. 7 = SIGBUS on Linux but SIGEMT on macOS) would mislabel real crashes.
|
|
const POSIX_INVARIANT_SIGNAL_NAMES: Record<number, string> = {
|
|
1: 'SIGHUP',
|
|
2: 'SIGINT',
|
|
3: 'SIGQUIT',
|
|
4: 'SIGILL',
|
|
5: 'SIGTRAP',
|
|
6: 'SIGABRT',
|
|
8: 'SIGFPE',
|
|
9: 'SIGKILL',
|
|
11: 'SIGSEGV',
|
|
13: 'SIGPIPE',
|
|
14: 'SIGALRM',
|
|
15: 'SIGTERM'
|
|
}
|
|
|
|
const WAIT_STATUS_SIGNAL_MASK = 0x7f
|
|
const WAIT_STATUS_CORE_DUMP_FLAG = 0x80
|
|
const WAIT_STATUS_STOPPED_MARKER = 0x7f
|
|
|
|
export function decodePosixWaitStatus(status: number): PosixWaitStatusDecode | null {
|
|
if (!Number.isInteger(status) || status < 0 || status > 0xffff) {
|
|
return null
|
|
}
|
|
const signal = status & WAIT_STATUS_SIGNAL_MASK
|
|
if (signal === WAIT_STATUS_STOPPED_MARKER) {
|
|
// WIFSTOPPED/WIFCONTINUED shapes never describe a dead process.
|
|
return null
|
|
}
|
|
if (signal === 0) {
|
|
return { kind: 'exited', exitStatus: (status >> 8) & 0xff }
|
|
}
|
|
return {
|
|
kind: 'signaled',
|
|
signal,
|
|
signalName: POSIX_INVARIANT_SIGNAL_NAMES[signal] ?? null,
|
|
coreDumped: (status & WAIT_STATUS_CORE_DUMP_FLAG) !== 0
|
|
}
|
|
}
|
|
|
|
/** Human phrasing for a decoded status: "exit status 241", "SIGKILL", "SIGTRAP, core dumped", "signal 7". */
|
|
export function describePosixWaitStatus(decoded: PosixWaitStatusDecode): string {
|
|
if (decoded.kind === 'exited') {
|
|
return `exit status ${decoded.exitStatus}`
|
|
}
|
|
const name = decoded.signalName ?? `signal ${decoded.signal}`
|
|
return decoded.coreDumped ? `${name}, core dumped` : name
|
|
}
|