Skip to content

utilityProcess exit event reports incorrect code on Windows #49455

@rf-

Description

@rf-

Preflight Checklist

Electron Version

40.0.0

What operating system(s) are you using?

Windows

Operating System Version

Windows 11 (10.0.26100 Build 26100)

What arch are you using?

arm64 (including Apple Silicon)

Last Known Working Electron version

No response

Does the issue also appear in Chromium / Google Chrome?

I don't know how to test

Expected Behavior

The exit event in utilityProcess should include the correct exit code for the process, regardless of how it exits.

Actual Behavior

If you clone the attached gist and run npm install && npm run build && npm run start, you get the following output:

Utility process exited with code: 18446744072635812000

This also happens if you use the exit() function from cstdlib, but not if you call process.exit(0xC0000AA0) in utility.js for some reason.

The correct decimal value would be 3221228192.

Testcase Gist URL

https://gist.github.com/rf-/bbe5ecede1f2b10ac2bed4c46ac66509

Additional Information

I started looking into this because of a user report about a utility process crash. The logs reported the exit code 18446744072635812000, which seemed weirdly high and isn't documented anywhere.

I think the issue here is that exit codes on Windows are 32-bit unsigned integers, a.k.a. DWORDs, but they get passed from Chromium to Electron as int and then eventually get turned into 64-bit values by first extending the "signed" integer to 64 bits and then reinterpreting it as an unsigned value.

This works fine if the code is low enough to be interpreted as a positive int, but if it's interpreted as a negative int it gets mangled by the extension to 64 bits. Here's some Rust demonstrating this process:

let a: u32 = 0xC0E90002;
println!("{a:x} {a}"); // c0e90002 3236495362

let b: i32 = a as i32;
println!("{b:x} {b}"); // c0e90002 -1058471934

let c: i64 = b as i64;
println!("{c:x} {c}"); // ffffffffc0e90002 -1058471934

let d: u64 = c as u64;
println!("{d:x} {d}"); // ffffffffc0e90002 18446744072651079682

Then of course it gets turned into a 64-bit float by JavaScript, which loses precision since the value is so high. This is unfortunate since there are 70 different NTSTATUS codes that yield my original error code when sent through this process.

I haven't looked too closely at the relevant code on the Electron side, but I think the fix would just be to immediately cast the int value we get from Chromium to a uint so that subsequent conversions don't misinterpret the value?

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions