-
Notifications
You must be signed in to change notification settings - Fork 17.1k
Description
Preflight Checklist
- I have read the Contributing Guidelines for this project.
- I agree to follow the Code of Conduct that this project adheres to.
- I have searched the issue tracker for a bug report that matches the one I want to file, without success.
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?