From 3e2fdff2cb2439de469de98cfa55c29b71418b58 Mon Sep 17 00:00:00 2001 From: Bryan English Date: Sat, 19 Jun 2021 13:47:43 -0400 Subject: [PATCH] async_hooks: check for empty contexts before removing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way we don't end up attempting to SetPromiseHooks on contexts that have already been collected. Fixes: https://github.com/nodejs/node/issues/39019 PR-URL: https://github.com/nodejs/node/pull/39095 Reviewed-By: Stephen Belanger Reviewed-By: Gerhard Stöbich Reviewed-By: Anna Henningsen Reviewed-By: Benjamin Gruenbaum Reviewed-By: Andrey Pechkurov Reviewed-By: Danielle Adams --- src/env-inl.h | 12 +++++++++++- test/parallel/test-async-hooks-vm-gc.js | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-async-hooks-vm-gc.js diff --git a/src/env-inl.h b/src/env-inl.h index 1f05bac239d429..ae5d231afb4776 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -127,6 +127,11 @@ inline void AsyncHooks::SetJSPromiseHooks(v8::Local init, js_promise_hooks_[2].Reset(env()->isolate(), after); js_promise_hooks_[3].Reset(env()->isolate(), resolve); for (auto it = contexts_.begin(); it != contexts_.end(); it++) { + if (it->IsEmpty()) { + it = contexts_.erase(it); + it--; + continue; + } PersistentToLocal::Weak(env()->isolate(), *it) ->SetPromiseHooks(init, before, after, resolve); } @@ -279,8 +284,13 @@ inline void AsyncHooks::RemoveContext(v8::Local ctx) { v8::Isolate* isolate = env()->isolate(); v8::HandleScope handle_scope(isolate); for (auto it = contexts_.begin(); it != contexts_.end(); it++) { + if (it->IsEmpty()) { + it = contexts_.erase(it); + it--; + continue; + } v8::Local saved_context = - PersistentToLocal::Weak(env()->isolate(), *it); + PersistentToLocal::Weak(isolate, *it); if (saved_context == ctx) { it->Reset(); contexts_.erase(it); diff --git a/test/parallel/test-async-hooks-vm-gc.js b/test/parallel/test-async-hooks-vm-gc.js new file mode 100644 index 00000000000000..da95e3579dcca4 --- /dev/null +++ b/test/parallel/test-async-hooks-vm-gc.js @@ -0,0 +1,15 @@ +// Flags: --expose-gc +'use strict'; + +require('../common'); +const asyncHooks = require('async_hooks'); +const vm = require('vm'); + +// This is a regression test for https://github.com/nodejs/node/issues/39019 +// +// It should not segfault. + +const hook = asyncHooks.createHook({ init() {} }).enable(); +vm.createContext(); +globalThis.gc(); +hook.disable();