Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4acea14

Browse filesBrowse 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 <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent d348496 commit 4acea14
Copy full SHA for 4acea14

File tree

Expand file treeCollapse file tree

2 files changed

+44
-25
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+44
-25
lines changed
Open diff view settings
Collapse file

‎lib/internal/bootstrap_node.js‎

Copy file name to clipboardExpand all lines: lib/internal/bootstrap_node.js
+20-25Lines changed: 20 additions & 25 deletions
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

Collapse file
+24Lines changed: 24 additions & 0 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.