From 700f766bea10c7f22fe11809e60226501ea69a4c Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Thu, 6 Jan 2022 22:04:30 -0800 Subject: [PATCH] process: ignore asyncId 0 in exception handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Today, the global uncaught exception handler is the only place where asyncId 0 is not ignored and we still proceed to call emitAfter. This would've already failed one of our correctness tests in async_hooks if not for some other code meant to handle a different edge case. Fixes: https://github.com/nodejs/node/issues/22982 PR-URL: https://github.com/nodejs/node/pull/41424 Reviewed-By: Gerhard Stöbich Reviewed-By: Antoine du Hamel Reviewed-By: James M Snell --- lib/internal/process/execution.js | 9 +++++++-- test/async-hooks/init-hooks.js | 3 --- .../test-unhandled-exception-valid-ids.js | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 test/async-hooks/test-unhandled-exception-valid-ids.js diff --git a/lib/internal/process/execution.js b/lib/internal/process/execution.js index 2bed5f3c762cf0..1311349951c5b9 100644 --- a/lib/internal/process/execution.js +++ b/lib/internal/process/execution.js @@ -20,7 +20,8 @@ const { clearAsyncIdStack, hasAsyncIdStack, afterHooksExist, - emitAfter + emitAfter, + popAsyncContext, } = require('internal/async_hooks'); // shouldAbortOnUncaughtToggle is a typed array for faster @@ -183,7 +184,11 @@ function createOnGlobalUncaughtException() { // Emit the after() hooks now that the exception has been handled. if (afterHooksExist()) { do { - emitAfter(executionAsyncId()); + const asyncId = executionAsyncId(); + if (asyncId === 0) + popAsyncContext(0); + else + emitAfter(asyncId); } while (hasAsyncIdStack()); } // And completely empty the id stack, including anything that may be diff --git a/test/async-hooks/init-hooks.js b/test/async-hooks/init-hooks.js index 59ecc96b881a5a..5d697036602902 100644 --- a/test/async-hooks/init-hooks.js +++ b/test/async-hooks/init-hooks.js @@ -168,9 +168,6 @@ class ActivityCollector { } const err = new Error(`Found a handle whose ${hook}` + ' hook was invoked but not its init hook'); - // Don't throw if we see invocations due to an assertion in a test - // failing since we want to list the assertion failure instead - if (/process\._fatalException/.test(err.stack)) return null; throw err; } return h; diff --git a/test/async-hooks/test-unhandled-exception-valid-ids.js b/test/async-hooks/test-unhandled-exception-valid-ids.js new file mode 100644 index 00000000000000..09e5823452fd4d --- /dev/null +++ b/test/async-hooks/test-unhandled-exception-valid-ids.js @@ -0,0 +1,17 @@ +'use strict'; + +const common = require('../common'); +const initHooks = require('./init-hooks'); + +const hooks = initHooks(); +hooks.enable(); + +setImmediate(() => { + throw new Error(); +}); + +setTimeout(() => { + throw new Error(); +}, 1); + +process.on('uncaughtException', common.mustCall(2));