When a stack overflow exception occurs during async_hooks callbacks (which use TryCatchScope::kFatal), detect the specific "Maximum call stack size exceeded" RangeError and re-throw it instead of immediately calling FatalException. This allows user code to catch the exception with try-catch blocks instead of requiring uncaughtException handlers. The implementation adds IsStackOverflowError() helper to detect stack overflow RangeErrors and re-throws them in TryCatchScope destructor instead of calling FatalException. This fixes the issue where async_hooks would cause stack overflow exceptions to exit with code 7 (kExceptionInFatalExceptionHandler) instead of being catchable. Fixes: https://github.com/nodejs/node/issues/37989 Ref: https://hackerone.com/reports/3456295 PR-URL: https://github.com/nodejs-private/node-private/pull/773 Refs: https://hackerone.com/reports/3456295 Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> CVE-ID: CVE-2025-59466
29 lines
987 B
JavaScript
29 lines
987 B
JavaScript
'use strict';
|
|
|
|
// This test verifies that when the uncaughtException handler itself causes
|
|
// a stack overflow, the process exits with a non-zero exit code.
|
|
// This is important to ensure we don't silently swallow errors.
|
|
|
|
require('../common');
|
|
const assert = require('assert');
|
|
const { spawnSync } = require('child_process');
|
|
|
|
if (process.argv[2] === 'child') {
|
|
function f() { f(); }
|
|
process.on('uncaughtException', f);
|
|
throw new Error('X');
|
|
} else {
|
|
// Parent process - spawn the child and check exit code
|
|
const result = spawnSync(
|
|
process.execPath,
|
|
[__filename, 'child'],
|
|
{ encoding: 'utf8', timeout: 30000 }
|
|
);
|
|
|
|
// Should exit with non-zero exit code since the uncaughtException handler
|
|
// itself caused a stack overflow.
|
|
assert.notStrictEqual(result.status, 0,
|
|
`Expected non-zero exit code, got ${result.status}.\n` +
|
|
`stdout: ${result.stdout}\n` +
|
|
`stderr: ${result.stderr}`);
|
|
}
|