Skip to content

Commit 4acea14

Browse files
apapirovskiMylesBorins
authored andcommitted
process: do not directly schedule _tickCallback in _fatalException
When a process encounters a _fatalException that is caught, it should schedule execution of nextTicks but not in an arbitrary place of the next Immediates queue. Instead, add a no-op function to the queue that will ensure processImmediate runs, which will then ensure that nextTicks are processed at the end. Backport-PR-URL: #19006 PR-URL: #17841 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent d348496 commit 4acea14

File tree

2 files changed

+44
-25
lines changed

2 files changed

+44
-25
lines changed

lib/internal/bootstrap_node.js

+20-25
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,8 @@
409409
}
410410
}
411411

412+
function noop() {}
413+
412414
function setupProcessFatal() {
413415
const async_wrap = process.binding('async_wrap');
414416
// Arrays containing hook flags and ids for async_hook calls.
@@ -419,23 +421,15 @@
419421
kDefaultTriggerAsyncId, kStackLength } = async_wrap.constants;
420422

421423
process._fatalException = function(er) {
422-
var caught;
423-
424424
// It's possible that kDefaultTriggerAsyncId was set for a constructor
425425
// call that threw and was never cleared. So clear it now.
426426
async_id_fields[kDefaultTriggerAsyncId] = -1;
427427

428428
if (exceptionHandlerState.captureFn !== null) {
429429
exceptionHandlerState.captureFn(er);
430-
caught = true;
431-
}
432-
433-
if (!caught)
434-
caught = process.emit('uncaughtException', er);
435-
436-
// If someone handled it, then great. otherwise, die in C++ land
437-
// since that means that we'll exit the process, emit the 'exit' event
438-
if (!caught) {
430+
} else if (!process.emit('uncaughtException', er)) {
431+
// If someone handled it, then great. otherwise, die in C++ land
432+
// since that means that we'll exit the process, emit the 'exit' event
439433
try {
440434
if (!process._exiting) {
441435
process._exiting = true;
@@ -444,24 +438,25 @@
444438
} catch (er) {
445439
// nothing to be done about it at this point.
446440
}
441+
return false;
442+
}
447443

444+
// If we handled an error, then make sure any ticks get processed
445+
// by ensuring that the next Immediate cycle isn't empty
446+
NativeModule.require('timers').setImmediate(noop);
447+
448+
// Emit the after() hooks now that the exception has been handled.
449+
if (async_hook_fields[kAfter] > 0) {
450+
const { emitAfter } = NativeModule.require('internal/async_hooks');
451+
do {
452+
emitAfter(async_id_fields[kExecutionAsyncId]);
453+
} while (async_hook_fields[kStackLength] > 0);
454+
// Or completely empty the id stack.
448455
} else {
449-
// If we handled an error, then make sure any ticks get processed
450-
NativeModule.require('timers').setImmediate(process._tickCallback);
451-
452-
// Emit the after() hooks now that the exception has been handled.
453-
if (async_hook_fields[kAfter] > 0) {
454-
do {
455-
NativeModule.require('internal/async_hooks').emitAfter(
456-
async_id_fields[kExecutionAsyncId]);
457-
} while (async_hook_fields[kStackLength] > 0);
458-
// Or completely empty the id stack.
459-
} else {
460-
clearAsyncIdStack();
461-
}
456+
clearAsyncIdStack();
462457
}
463458

464-
return caught;
459+
return true;
465460
};
466461
}
467462

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
6+
// If a process encounters an uncaughtException, it should schedule
7+
// processing of nextTicks on the next Immediates cycle but not
8+
// before all Immediates are handled
9+
10+
let stage = 0;
11+
12+
process.once('uncaughtException', common.expectsError({
13+
type: Error,
14+
message: 'caughtException'
15+
}));
16+
17+
setImmediate(() => {
18+
stage++;
19+
process.nextTick(() => assert.strictEqual(stage, 2));
20+
});
21+
const now = Date.now();
22+
setTimeout(() => setImmediate(() => stage++), 1);
23+
while (now + 10 >= Date.now());
24+
throw new Error('caughtException');

0 commit comments

Comments
 (0)