Skip to content

Commit a8dfe36

Browse files
trop[bot]Jomy2323
andauthored
fix: correct utility process exit code on Windows (#50387)
* fix: correct utility process exit code on Windows On Windows, process exit codes are 32-bit unsigned integers (DWORD). When passed from Chromium to Electron as a signed int and then implicitly converted to uint64_t, values with the high bit set (e.g., NTSTATUS codes) undergo sign extension, producing incorrect values. Cast the exit code to uint32_t before widening to uint64_t to prevent sign extension and preserve the original Windows exit code. Fixes #49455 Co-authored-by: João Silva <joaomrsilva@tecnico.ulisboa.pt> * fix: narrow HandleTermination and Shutdown to uint32_t, add tests Co-authored-by: João Silva <joaomrsilva@tecnico.ulisboa.pt> --------- Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: João Silva <joaomrsilva@tecnico.ulisboa.pt>
1 parent a495539 commit a8dfe36

3 files changed

Lines changed: 20 additions & 4 deletions

File tree

shell/browser/api/electron_api_utility_process.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ void UtilityProcessWrapper::OnServiceProcessLaunch(
258258
EmitWithoutEvent("spawn");
259259
}
260260

261-
void UtilityProcessWrapper::HandleTermination(uint64_t exit_code) {
261+
void UtilityProcessWrapper::HandleTermination(uint32_t exit_code) {
262262
// HandleTermination is called from multiple callsites,
263263
// we need to ensure we only process it for the first callsite.
264264
if (terminated_)
@@ -326,7 +326,7 @@ void UtilityProcessWrapper::CloseConnectorPort() {
326326
}
327327
}
328328

329-
void UtilityProcessWrapper::Shutdown(uint64_t exit_code) {
329+
void UtilityProcessWrapper::Shutdown(uint32_t exit_code) {
330330
node_service_remote_.reset();
331331
HandleTermination(exit_code);
332332
}

shell/browser/api/electron_api_utility_process.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class UtilityProcessWrapper final
5757
static gin_helper::Handle<UtilityProcessWrapper> Create(gin::Arguments* args);
5858
static raw_ptr<UtilityProcessWrapper> FromProcessId(base::ProcessId pid);
5959

60-
void Shutdown(uint64_t exit_code);
60+
void Shutdown(uint32_t exit_code);
6161

6262
// gin_helper::Wrappable
6363
static gin::DeprecatedWrapperInfo kWrapperInfo;
@@ -77,7 +77,7 @@ class UtilityProcessWrapper final
7777
void OnServiceProcessLaunch(const base::Process& process);
7878
void CloseConnectorPort();
7979

80-
void HandleTermination(uint64_t exit_code);
80+
void HandleTermination(uint32_t exit_code);
8181

8282
void PostMessage(gin::Arguments* args);
8383
bool Kill();

spec/api-utility-process-spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,22 @@ describe('utilityProcess module', () => {
129129
expect(code).to.equal(exitCode);
130130
});
131131

132+
ifit(process.platform === 'win32')('emits correct exit code when high bit is set on Windows', async () => {
133+
// NTSTATUS code with high bit set should not be mangled by sign extension.
134+
const exitCode = 0xC0000005;
135+
const child = utilityProcess.fork(path.join(fixturesPath, 'custom-exit.js'), [`--exitCode=${exitCode}`]);
136+
const [code] = await once(child, 'exit');
137+
expect(code).to.equal(exitCode);
138+
});
139+
140+
ifit(process.platform !== 'win32')('emits correct exit code when child process crashes on posix', async () => {
141+
// Crash exit codes should not be sign-extended to large 64-bit values.
142+
const child = utilityProcess.fork(path.join(fixturesPath, 'crash.js'));
143+
const [code] = await once(child, 'exit');
144+
expect(code).to.not.equal(0);
145+
expect(code).to.be.lessThanOrEqual(0xFFFFFFFF);
146+
});
147+
132148
it('does not run JS after process.exit is called', async () => {
133149
const file = path.join(os.tmpdir(), `no-js-after-exit-log-${Math.random()}`);
134150
const child = utilityProcess.fork(path.join(fixturesPath, 'no-js-after-exit.js'), [`--testPath=${file}`]);

0 commit comments

Comments
 (0)