From cbd8eece0ebac7ad0423fd5737f6695f635de163 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 17 May 2018 16:25:36 +0200 Subject: [PATCH] repl: properly handle uncaughtException When running the REPL as standalone program it's now possible to use `process.on('uncaughtException', listener)`. It is going to use those listeners from now on and the regular error output is suppressed. It also fixes the issue that REPL instances started inside of an application would silence all application errors. It is now prohibited to add the exception listener in such REPL instances. Trying to add such listeners throws an `ERR_INVALID_REPL_INPUT` error. Fixes: https://github.com/nodejs/node/issues/19998 --- doc/api/errors.md | 11 ++- doc/api/repl.md | 34 ++++++++- lib/internal/errors.js | 1 + lib/repl.js | 59 +++++++++++---- .../parallel/test-repl-pretty-custom-stack.js | 2 - .../test-repl-uncaught-exception-async.js | 42 +++++++++++ ...test-repl-uncaught-exception-standalone.js | 38 ++++++++++ test/parallel/test-repl-uncaught-exception.js | 72 +++++++++++++++++++ 8 files changed, 242 insertions(+), 17 deletions(-) create mode 100644 test/parallel/test-repl-uncaught-exception-async.js create mode 100644 test/parallel/test-repl-uncaught-exception-standalone.js create mode 100644 test/parallel/test-repl-uncaught-exception.js diff --git a/doc/api/errors.md b/doc/api/errors.md index 79570ffb510ea9..d3266c256f617b 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1310,8 +1310,14 @@ An invalid `options.protocol` was passed. ### ERR_INVALID_REPL_EVAL_CONFIG -Both `breakEvalOnSigint` and `eval` options were set in the REPL config, which -is not supported. +Both `breakEvalOnSigint` and `eval` options were set in the [`REPL`][] config, +which is not supported. + + +### ERR_INVALID_REPL_INPUT + +The input may not be used in the [`REPL`][]. All prohibited inputs are +documented in the [`REPL`][]'s documentation. ### ERR_INVALID_RETURN_PROPERTY @@ -2307,6 +2313,7 @@ such as `process.stdout.on('data')`. [`Class: assert.AssertionError`]: assert.html#assert_class_assert_assertionerror [`ERR_INVALID_ARG_TYPE`]: #ERR_INVALID_ARG_TYPE [`EventEmitter`]: events.html#events_class_eventemitter +[`REPL`]: repl.html [`Writable`]: stream.html#stream_class_stream_writable [`child_process`]: child_process.html [`cipher.getAuthTag()`]: crypto.html#crypto_cipher_getauthtag diff --git a/doc/api/repl.md b/doc/api/repl.md index e0ec27b7e3bada..563817c632297f 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -138,16 +138,47 @@ global or scoped variable, the input `fs` will be evaluated on-demand as ``` #### Global Uncaught Exceptions + The REPL uses the [`domain`][] module to catch all uncaught exceptions for that REPL session. This use of the [`domain`][] module in the REPL has these side effects: -* Uncaught exceptions do not emit the [`'uncaughtException'`][] event. +* Uncaught exceptions only emit the [`'uncaughtException'`][] event if the + `repl` is used as standalone program. If the `repl` is included anywhere in + another application, adding a listener for this event will throw an + [`ERR_INVALID_REPL_INPUT`][] exception. * Trying to use [`process.setUncaughtExceptionCaptureCallback()`][] throws an [`ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE`][] error. +As standalone program: + +```js +process.on('uncaughtException', () => console.log('Uncaught')); + +throw new Error('foobar'); +// Uncaught +``` + +When used in another application: + +```js +process.on('uncaughtException', () => console.log('Uncaught')); +// TypeError [ERR_INVALID_REPL_INPUT]: Listeners for `uncaughtException` +// cannot be used in the REPL + +throw new Error('foobar'); +// Thrown: +// Error: foobar +``` + #### Assignment of the `_` (underscore) variable