Commit 670a0772fe8 for nodejs

commit 670a0772fe8b25002789b5d27cd5a1b44cb9c468
Author: Shelley Vohr <shelley.vohr@gmail.com>
Date:   Tue Sep 22 13:48:46 2026 +0000

    src: assert that an IsolateData outlives its Environments

    FreeIsolateData() while an Environment created from it is still alive
    left that Environment with a dangling pointer and failed later in
    unrelated code. Count the Environments using an IsolateData and CHECK
    in its destructor that none are left.

    Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
    PR-URL: https://github.com/nodejs/node/pull/66239
    Refs: https://github.com/nodejs/node/pull/65977
    Reviewed-By: James M Snell <jasnell@gmail.com>
    Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
    Reviewed-By: Anna Henningsen <anna@addaleax.net>

diff --git a/src/env.cc b/src/env.cc
index f429c44ee75..e96b6e6bb12 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -651,7 +651,10 @@ IsolateData::IsolateData(Isolate* isolate,
   }
 }

-IsolateData::~IsolateData() {}
+IsolateData::~IsolateData() {
+  // FreeIsolateData() before FreeEnvironment() of an Environment using it.
+  CHECK_EQ(environment_count_, 0);
+}

 // Deprecated API, embedders should use v8::Object::Wrap() directly instead.
 void SetCppgcReference(Isolate* isolate,
@@ -983,6 +986,7 @@ Environment::Environment(IsolateData* isolate_data,
                      ? AllocateEnvironmentThreadId().id
                      : thread_id.id),
       thread_name_(thread_name) {
+  isolate_data->AddEnvironment();
 #if HAVE_OPENSSL && NCRYPTO_USE_OPENSSL3_PROVIDER
   provider_digest_cache = std::make_unique<ncrypto::DigestCache>();
   provider_cipher_cache = std::make_unique<ncrypto::CipherCache>();
@@ -1304,6 +1308,7 @@ Environment::~Environment() {
     cpu_profiler_->Dispose();
     cpu_profiler_ = nullptr;
   }
+  isolate_data_->RemoveEnvironment();
 }

 void Environment::InitializeLibuv() {
diff --git a/src/env.h b/src/env.h
index 8e132ed42ac..75f3a66eda7 100644
--- a/src/env.h
+++ b/src/env.h
@@ -182,6 +182,9 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
   inline worker::Worker* worker_context() const;
   inline void set_worker_context(worker::Worker* context);

+  void AddEnvironment() { environment_count_++; }
+  void RemoveEnvironment() { environment_count_--; }
+
 #define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
 #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
 #define VS(PropertyName, StringValue) V(v8::String, PropertyName)
@@ -283,6 +286,7 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {

   std::shared_ptr<PerIsolateOptions> options_;
   worker::Worker* worker_context_ = nullptr;
+  size_t environment_count_ = 0;
   PerIsolateWrapperData* wrapper_data_;

   static Mutex isolate_data_mutex_;