From b4ca1322545a9ae834b5c6b1fbc566706abd6bbb Mon Sep 17 00:00:00 2001 From: Gerhard Stoebich <18708370+Flarna@users.noreply.github.com> Date: Mon, 17 Feb 2020 00:17:24 +0100 Subject: [PATCH] async_hooks: executionAsyncResource matches in hooks Ensure that resource returned by executionAsyncResource() in before and after hook matches that resource causing this before/after calls. PR-URL: https://github.com/nodejs/node/pull/31821 Refs: https://github.com/nodejs/node/pull/30959 Reviewed-By: Anna Henningsen Reviewed-By: Minwoo Jung Reviewed-By: Chengzhong Wu Reviewed-By: Stephen Belanger Reviewed-By: Vladimir de Turckheim --- src/api/callback.cc | 18 +++--- .../test-async-exec-resource-match.js | 62 +++++++++++++++++++ 2 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 test/async-hooks/test-async-exec-resource-match.js diff --git a/src/api/callback.cc b/src/api/callback.cc index 74a7836391df2f..1fb85c5883f120 100644 --- a/src/api/callback.cc +++ b/src/api/callback.cc @@ -62,16 +62,16 @@ InternalCallbackScope::InternalCallbackScope(Environment* env, // If you hit this assertion, you forgot to enter the v8::Context first. CHECK_EQ(Environment::GetCurrent(env->isolate()), env); + env->async_hooks()->push_async_context( + async_context_.async_id, async_context_.trigger_async_id, object); + + pushed_ids_ = true; + if (asyncContext.async_id != 0 && !skip_hooks_) { // No need to check a return value because the application will exit if // an exception occurs. AsyncWrap::EmitBefore(env, asyncContext.async_id); } - - env->async_hooks()->push_async_context(async_context_.async_id, - async_context_.trigger_async_id, object); - - pushed_ids_ = true; } InternalCallbackScope::~InternalCallbackScope() { @@ -88,15 +88,15 @@ void InternalCallbackScope::Close() { env_->async_hooks()->clear_async_id_stack(); } + if (!failed_ && async_context_.async_id != 0 && !skip_hooks_) { + AsyncWrap::EmitAfter(env_, async_context_.async_id); + } + if (pushed_ids_) env_->async_hooks()->pop_async_context(async_context_.async_id); if (failed_) return; - if (async_context_.async_id != 0 && !skip_hooks_) { - AsyncWrap::EmitAfter(env_, async_context_.async_id); - } - if (env_->async_callback_scope_depth() > 1 || skip_task_queues_) { return; } diff --git a/test/async-hooks/test-async-exec-resource-match.js b/test/async-hooks/test-async-exec-resource-match.js new file mode 100644 index 00000000000000..f5ea2c2b13965a --- /dev/null +++ b/test/async-hooks/test-async-exec-resource-match.js @@ -0,0 +1,62 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const { readFile } = require('fs'); +const { + createHook, + executionAsyncResource, + AsyncResource +} = require('async_hooks'); + +// Ignore any asyncIds created before our hook is active. +let firstSeenAsyncId = -1; +const idResMap = new Map(); +const numExpectedCalls = 5; + +createHook({ + init: common.mustCallAtLeast( + (asyncId, type, triggerId, resource) => { + if (firstSeenAsyncId === -1) { + firstSeenAsyncId = asyncId; + } + assert.ok(idResMap.get(asyncId) === undefined); + idResMap.set(asyncId, resource); + }, numExpectedCalls), + before(asyncId) { + if (asyncId >= firstSeenAsyncId) { + beforeHook(asyncId); + } + }, + after(asyncId) { + if (asyncId >= firstSeenAsyncId) { + afterHook(asyncId); + } + } +}).enable(); + +const beforeHook = common.mustCallAtLeast( + (asyncId) => { + const res = idResMap.get(asyncId); + assert.ok(res !== undefined); + const execRes = executionAsyncResource(); + assert.ok(execRes === res, 'resource mismatch in before'); + }, numExpectedCalls); + +const afterHook = common.mustCallAtLeast( + (asyncId) => { + const res = idResMap.get(asyncId); + assert.ok(res !== undefined); + const execRes = executionAsyncResource(); + assert.ok(execRes === res, 'resource mismatch in after'); + }, numExpectedCalls); + +const res = new AsyncResource('TheResource'); +const initRes = idResMap.get(res.asyncId()); +assert.ok(initRes === res, 'resource mismatch in init'); +res.runInAsyncScope(common.mustCall(() => { + const execRes = executionAsyncResource(); + assert.ok(execRes === res, 'resource mismatch in cb'); +})); + +readFile(__filename, common.mustCall());