Skip to content

Commit 80ebb42

Browse files
jkantrrefack
authored andcommitted
src: adjust windows abort behavior
Raising SIGABRT is handled in the CRT in windows, calling _exit() with ambiguous code "3" by default. This adjustment to the abort behavior gives a more sane exit code on abort, by calling _exit directly with code 134. PR-URL: #13947 Fixes: #12271 Refs: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/abort Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Richard Lau <[email protected]> Reviewed-By: Timothy Gu <[email protected]> Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Gireesh Punathil <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
1 parent 7535a94 commit 80ebb42

7 files changed

+33
-7
lines changed

doc/api/process.md

+2
Original file line numberDiff line numberDiff line change
@@ -1819,6 +1819,8 @@ cases:
18191819
value of the signal code. This is a standard Unix practice, since
18201820
exit codes are defined to be 7-bit integers, and signal exits set
18211821
the high-order bit, and then contain the value of the signal code.
1822+
For example, signal `SIGABRT` has value `6`, so the expected exit
1823+
code will be `128` + `6`, or `134`.
18221824

18231825

18241826
[`'exit'`]: #process_event_exit

src/util.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ template <typename T> using remove_reference = std::remove_reference<T>;
9595

9696
// Windows 8+ does not like abort() in Release mode
9797
#ifdef _WIN32
98-
#define ABORT_NO_BACKTRACE() raise(SIGABRT)
98+
#define ABORT_NO_BACKTRACE() _exit(134)
9999
#else
100100
#define ABORT_NO_BACKTRACE() abort()
101101
#endif

test/abort/test-abort-uncaught-exception.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function run(flags, signals) {
2121
child.on('exit', common.mustCall(function(code, sig) {
2222
if (common.isWindows) {
2323
if (signals)
24-
assert.strictEqual(code, 3);
24+
assert.strictEqual(code, 0xC0000005);
2525
else
2626
assert.strictEqual(code, 1);
2727
} else {

test/async-hooks/test-callback-error.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ assert.ok(!arg);
101101
child.on('close', (code, signal) => {
102102
clearTimeout(tO);
103103
if (common.isWindows) {
104-
assert.strictEqual(code, 3);
104+
assert.strictEqual(code, 134);
105105
assert.strictEqual(signal, null);
106106
} else {
107107
assert.strictEqual(code, null);

test/common/index.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -605,10 +605,10 @@ exports.nodeProcessAborted = function nodeProcessAborted(exitCode, signal) {
605605
// On Windows, 'aborts' are of 2 types, depending on the context:
606606
// (i) Forced access violation, if --abort-on-uncaught-exception is on
607607
// which corresponds to exit code 3221225477 (0xC0000005)
608-
// (ii) raise(SIGABRT) or abort(), which lands up in CRT library calls
609-
// which corresponds to exit code 3.
608+
// (ii) Otherwise, _exit(134) which is called in place of abort() due to
609+
// raising SIGABRT exiting with ambiguous exit code '3' by default
610610
if (exports.isWindows)
611-
expectedExitCodes = [3221225477, 3];
611+
expectedExitCodes = [0xC0000005, 134];
612612

613613
// When using --abort-on-uncaught-exception, V8 will use
614614
// base::OS::Abort to terminate the process.

test/parallel/test-windows-abort-exitcode.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ if (process.argv[2] === 'child') {
1616
} else {
1717
const child = spawn(process.execPath, [__filename, 'child']);
1818
child.on('exit', common.mustCall((code, signal) => {
19-
assert.strictEqual(code, 3);
19+
assert.strictEqual(code, 134);
2020
assert.strictEqual(signal, null);
2121
}));
2222
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
const common = require('../common');
3+
4+
// This test ensures that an out of memory error exits with code 134 on Windows
5+
6+
if (!common.isWindows) return common.skip('Windows-only');
7+
8+
const assert = require('assert');
9+
const { exec } = require('child_process');
10+
11+
if (process.argv[2] === 'heapBomb') {
12+
// heap bomb, imitates a memory leak quickly
13+
const fn = (nM) => [...Array(nM)].map((i) => fn(nM ** 2));
14+
fn(2);
15+
}
16+
17+
// --max-old-space-size=3 is the min 'old space' in V8, explodes fast
18+
const cmd = `"${process.execPath}" --max-old-space-size=3 "${__filename}"`;
19+
exec(`${cmd} heapBomb`, common.mustCall((err) => {
20+
const msg = `Wrong exit code of ${err.code}! Expected 134 for abort`;
21+
// Note: common.nodeProcessAborted() is not asserted here because it
22+
// returns true on 134 as well as 0xC0000005 (V8's base::OS::Abort)
23+
assert.strictEqual(err.code, 134, msg);
24+
}));

0 commit comments

Comments
 (0)