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
47 lines
1.4 KiB
JavaScript
47 lines
1.4 KiB
JavaScript
'use strict';
|
|
|
|
// This test verifies that when a stack overflow occurs with async_hooks
|
|
// enabled, the exception can be caught by try-catch blocks in user code.
|
|
|
|
require('../common');
|
|
const assert = require('assert');
|
|
const { spawnSync } = require('child_process');
|
|
|
|
if (process.argv[2] === 'child') {
|
|
const { createHook } = require('async_hooks');
|
|
|
|
createHook({ init() {} }).enable();
|
|
|
|
function recursive(depth = 0) {
|
|
// Create a promise to trigger async_hooks init callback
|
|
new Promise(() => {});
|
|
return recursive(depth + 1);
|
|
}
|
|
|
|
try {
|
|
recursive();
|
|
// Should not reach here
|
|
process.exit(1);
|
|
} catch (err) {
|
|
assert.strictEqual(err.name, 'RangeError');
|
|
assert.match(err.message, /Maximum call stack size exceeded/);
|
|
console.log('SUCCESS: try-catch caught the stack overflow');
|
|
process.exit(0);
|
|
}
|
|
|
|
// Should not reach here
|
|
process.exit(2);
|
|
} else {
|
|
// Parent process - spawn the child and check exit code
|
|
const result = spawnSync(
|
|
process.execPath,
|
|
[__filename, 'child'],
|
|
{ encoding: 'utf8', timeout: 30000 }
|
|
);
|
|
|
|
assert.strictEqual(result.status, 0,
|
|
`Expected exit code 0 (try-catch worked), got ${result.status}.\n` +
|
|
`stdout: ${result.stdout}\n` +
|
|
`stderr: ${result.stderr}`);
|
|
assert.match(result.stdout, /SUCCESS: try-catch caught the stack overflow/);
|
|
}
|