diff options
author | Jeremy Whitlock <jwhitlock@apache.org> | 2015-10-05 13:08:53 -0700 |
---|---|---|
committer | Julien Gilli <julien.gilli@joyent.com> | 2015-10-05 18:12:43 -0700 |
commit | 77a10ed05f1e413818d29f07cbb268108b1f08fa (patch) | |
tree | 525e3e0d9c31b94baf34f9e689e95f657df00bf9 /lib/domain.js | |
parent | 49dec1afd8c310d6995a62893d59b171e2f021cc (diff) | |
download | node-new-77a10ed05f1e413818d29f07cbb268108b1f08fa.tar.gz |
src: fix --abort-on-uncaught-exception
Revert 0af4c9ea7434e4f505dbe071357e4bc3b4ab2a8a, parts of
921f2de6cf999b5a4663615e37967b4269d755fe and port
https://github.com/nodejs/node-v0.x-archive/pull/25835 from v0.12 to
master so that node aborts at the right time when an error is thrown
and --abort-on-uncaught-exception is used.
Fixes #3035.
PR: #3036
PR-URL: https://github.com/nodejs/node/pull/3036
Reviewed-By: Ben Noordhuis <ben@strongloop.com>
Diffstat (limited to 'lib/domain.js')
-rw-r--r-- | lib/domain.js | 88 |
1 files changed, 59 insertions, 29 deletions
diff --git a/lib/domain.js b/lib/domain.js index 4ee4d71b19..b6321a20f8 100644 --- a/lib/domain.js +++ b/lib/domain.js @@ -59,6 +59,20 @@ Domain.prototype._disposed = undefined; // Called by process._fatalException in case an error was thrown. Domain.prototype._errorHandler = function errorHandler(er) { var caught = false; + var self = this; + + function emitError() { + var handled = self.emit('error', er); + + // Exit all domains on the stack. Uncaught exceptions end the + // current tick and no domains should be left on the stack + // between ticks. + stack.length = 0; + exports.active = process.domain = null; + + return handled; + } + // ignore errors on disposed domains. // // XXX This is a bit stupid. We should probably get rid of @@ -71,38 +85,54 @@ Domain.prototype._errorHandler = function errorHandler(er) { er.domain = this; er.domainThrown = true; } - // wrap this in a try/catch so we don't get infinite throwing - try { - // One of three things will happen here. - // - // 1. There is a handler, caught = true - // 2. There is no handler, caught = false - // 3. It throws, caught = false - // - // If caught is false after this, then there's no need to exit() - // the domain, because we're going to crash the process anyway. - caught = this.emit('error', er); - // Exit all domains on the stack. Uncaught exceptions end the - // current tick and no domains should be left on the stack - // between ticks. - stack.length = 0; - exports.active = process.domain = null; - } catch (er2) { - // The domain error handler threw! oh no! - // See if another domain can catch THIS error, - // or else crash on the original one. - // If the user already exited it, then don't double-exit. - if (this === exports.active) { - stack.pop(); + // The top-level domain-handler is handled separately. + // + // The reason is that if V8 was passed a command line option + // asking it to abort on an uncaught exception (currently + // "--abort-on-uncaught-exception"), we want an uncaught exception + // in the top-level domain error handler to make the + // process abort. Using try/catch here would always make V8 think + // that these exceptions are caught, and thus would prevent it from + // aborting in these cases. + if (stack.length === 1) { + try { + // Set the _emittingTopLevelDomainError so that we know that, even + // if technically the top-level domain is still active, it would + // be ok to abort on an uncaught exception at this point + process._emittingTopLevelDomainError = true; + caught = emitError(); + } finally { + process._emittingTopLevelDomainError = false; } - if (stack.length) { - exports.active = process.domain = stack[stack.length - 1]; - caught = process._fatalException(er2); - } else { - caught = false; + } else { + // wrap this in a try/catch so we don't get infinite throwing + try { + // One of three things will happen here. + // + // 1. There is a handler, caught = true + // 2. There is no handler, caught = false + // 3. It throws, caught = false + // + // If caught is false after this, then there's no need to exit() + // the domain, because we're going to crash the process anyway. + caught = emitError(); + } catch (er2) { + // The domain error handler threw! oh no! + // See if another domain can catch THIS error, + // or else crash on the original one. + // If the user already exited it, then don't double-exit. + if (this === exports.active) { + stack.pop(); + } + if (stack.length) { + exports.active = process.domain = stack[stack.length - 1]; + caught = process._fatalException(er2); + } else { + caught = false; + } + return caught; } - return caught; } return caught; }; |