process: inspect error in case of a fatal exception

This makes sure that errors that shut down the application are
inspected with `util.inspect()`. That makes sure that all extra
properties on the error will be visible and also that the stack trace
is highlighted (Node.js internal frames will be grey and node modules
are underlined).

PR-URL: https://github.com/nodejs/node/pull/27243
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
Ruben Bridgewater 2019-04-15 20:10:17 +02:00
parent ac2f2cd919
commit a9f518c901
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
11 changed files with 76 additions and 9 deletions

View File

@ -142,8 +142,12 @@ function createFatalException() {
if (exceptionHandlerState.captureFn !== null) {
exceptionHandlerState.captureFn(er);
} else if (!process.emit('uncaughtException', er, type)) {
// If someone handled it, then great. otherwise, die in C++ land
// If someone handled it, then great. Otherwise, die in C++ land
// since that means that we'll exit the process, emit the 'exit' event.
const { inspect } = require('internal/util/inspect');
const colors = internalBinding('util').guessHandleType(2) === 'TTY' &&
require('internal/tty').hasColors() ||
inspect.defaultOptions.colors;
try {
if (!process._exiting) {
process._exiting = true;
@ -157,6 +161,7 @@ function createFatalException() {
const { kExpandStackSymbol } = require('internal/util');
if (typeof er[kExpandStackSymbol] === 'function')
er[kExpandStackSymbol]();
er.stack = inspect(er, { colors });
} catch {
// Nothing to be done about it at this point.
}

View File

@ -15,4 +15,20 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
at *
at *
at *
at *
at * {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: Error: foo
at assert.throws.bar (*assert_throws_stack.js:*)
at getActual (assert.js:*)
at Function.throws (assert.js:*)
at Object.<anonymous> (*assert_throws_stack.js:*:*)
at *
at *
at *
at *
at *
at *,
expected: [Object],
operator: 'throws'
}

View File

@ -13,4 +13,10 @@ AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
at Module.load (internal/modules/cjs/loader.js:*:*)
at Function.Module._load (internal/modules/cjs/loader.js:*:*)
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
at internal/main/run_main_module.js:*:*
at internal/main/run_main_module.js:*:* {
generatedMessage: true,
code: 'ERR_ASSERTION',
actual: 1,
expected: 2,
operator: 'strictEqual'
}

View File

@ -16,4 +16,20 @@ AssertionError [ERR_ASSERTION]: ifError got unwanted exception: test error
at Module.load (internal/modules/cjs/loader.js:*:*)
at Function.Module._load (internal/modules/cjs/loader.js:*:*)
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
at internal/main/run_main_module.js:*:*
at internal/main/run_main_module.js:*:* {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: Error: test error
at c (*if-error-has-good-stack.js:*:*)
at b (*if-error-has-good-stack.js:*:*)
at a (*if-error-has-good-stack.js:*:*)
at Object.<anonymous> (*if-error-has-good-stack.js:*:*)
at Module._compile (internal/modules/cjs/loader.js:*:*)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:*:*)
at Module.load (internal/modules/cjs/loader.js:*:*)
at Function.Module._load (internal/modules/cjs/loader.js:*:*)
at Function.Module.runMain (internal/modules/cjs/loader.js:*:*)
at internal/main/run_main_module.js:*:*
expected: null,
operator: 'ifError'
}

View File

@ -3,4 +3,4 @@ before
JSON.stringify(array);
^
RangeError: Maximum call stack size exceeded
[RangeError: Maximum call stack size exceeded]

View File

@ -1,4 +1,4 @@
*test*message*throw_custom_error.js:*
throw ({ name: 'MyCustomError', message: 'This is a custom message' });
^
MyCustomError: This is a custom message
{ name: 'MyCustomError', message: 'This is a custom message' }

View File

@ -2,4 +2,4 @@ before
*test*message*throw_in_line_with_tabs.js:*
throw ({ foo: 'bar' });
^
[object Object]
{ foo: 'bar' }

View File

@ -1,4 +1,4 @@
*test*message*throw_non_error.js:*
throw ({ foo: 'bar' });
^
[object Object]
{ foo: 'bar' }

View File

@ -77,5 +77,5 @@ errExec('throws_error6.js', common.mustCall((err, stdout, stderr) => {
// Object that throws in toString() doesn't print garbage
errExec('throws_error7.js', common.mustCall((err, stdout, stderr) => {
assert.ok(/<toString\(\) threw exception/.test(stderr));
assert.ok(/throw {\r?\n\^\r?\n{ toString: \[Function: toString] }\r?\n$/.test(stderr));
}));

View File

@ -0,0 +1,10 @@
'use strict';
require('../common');
const { inspect } = require('util');
inspect.defaultOptions.colors = true;
const err = new TypeError('foobar');
err.bla = true;
throw err;

View File

@ -0,0 +1,14 @@
*test-fatal-error.js:*
throw err;
^
TypeError: foobar
at Object.<anonymous> (*test-fatal-error.js:*)
*[90m at *(internal*loader.js:*:*)*[39m
*[90m at *(internal*loader.js:*:*)*[39m
*[90m at *(internal*loader.js:*:*)*[39m
*[90m at *(internal*loader.js:*:*)*[39m
*[90m at *[39m
*[90m at *[39m {
bla: *[33mtrue*[39m
}