From 6e8744b1167cd27e33f35e1eacbcb0078c85e6a5 Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Sat, 29 Nov 2025 17:32:52 +0800 Subject: [PATCH 1/2] Fix isolate cleanup segfault --- bindings/profilers/heap.cc | 50 +++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/bindings/profilers/heap.cc b/bindings/profilers/heap.cc index dc80992b..8417d0f4 100644 --- a/bindings/profilers/heap.cc +++ b/bindings/profilers/heap.cc @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include @@ -29,6 +31,24 @@ namespace dd { +// Track which isolates have cleanup hooks registered for heap profiler +static std::unordered_set g_heap_profiler_isolates; +static std::mutex g_heap_profiler_mutex; + +// Cleanup hook to stop heap profiler before isolate is destroyed +static void HeapProfilerCleanupHook(void* data) { + auto isolate = static_cast(data); + { + const std::lock_guard lock(g_heap_profiler_mutex); + g_heap_profiler_isolates.erase(isolate); + } + // Stop the sampling heap profiler to prevent crash during V8 teardown + auto heap_profiler = isolate->GetHeapProfiler(); + if (heap_profiler) { + heap_profiler->StopSamplingHeapProfiler(); + } +} + static size_t NearHeapLimit(void* data, size_t current_heap_limit, size_t initial_heap_limit); @@ -497,6 +517,19 @@ size_t NearHeapLimit(void* data, } NAN_METHOD(HeapProfiler::StartSamplingHeapProfiler) { + auto isolate = info.GetIsolate(); + + // Register cleanup hook if not already registered for this isolate + { + const std::lock_guard lock(g_heap_profiler_mutex); + if (g_heap_profiler_isolates.find(isolate) == + g_heap_profiler_isolates.end()) { + node::AddEnvironmentCleanupHook( + isolate, HeapProfilerCleanupHook, isolate); + g_heap_profiler_isolates.insert(isolate); + } + } + if (info.Length() == 2) { if (!info[0]->IsUint32()) { return Nan::ThrowTypeError("First argument type must be uint32."); @@ -508,10 +541,10 @@ NAN_METHOD(HeapProfiler::StartSamplingHeapProfiler) { uint64_t sample_interval = info[0].As()->Value(); int stack_depth = info[1].As()->Value(); - info.GetIsolate()->GetHeapProfiler()->StartSamplingHeapProfiler( - sample_interval, stack_depth); + isolate->GetHeapProfiler()->StartSamplingHeapProfiler(sample_interval, + stack_depth); } else { - info.GetIsolate()->GetHeapProfiler()->StartSamplingHeapProfiler(); + isolate->GetHeapProfiler()->StartSamplingHeapProfiler(); } } @@ -521,6 +554,17 @@ NAN_METHOD(HeapProfiler::StopSamplingHeapProfiler) { auto isolate = info.GetIsolate(); isolate->GetHeapProfiler()->StopSamplingHeapProfiler(); PerIsolateData::For(isolate)->GetHeapProfilerState().reset(); + + // Remove cleanup hook since profiler is explicitly stopped + { + const std::lock_guard lock(g_heap_profiler_mutex); + if (g_heap_profiler_isolates.find(isolate) != + g_heap_profiler_isolates.end()) { + node::RemoveEnvironmentCleanupHook( + isolate, HeapProfilerCleanupHook, isolate); + g_heap_profiler_isolates.erase(isolate); + } + } } // Signature: From cb40a8f7a0223815682b1c5f8e81c36ee8f7c190 Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Tue, 2 Dec 2025 00:50:01 +0800 Subject: [PATCH 2/2] Update heap.cc Co-authored-by: Attila Szegedi --- bindings/profilers/heap.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bindings/profilers/heap.cc b/bindings/profilers/heap.cc index 8417d0f4..7c6eaad4 100644 --- a/bindings/profilers/heap.cc +++ b/bindings/profilers/heap.cc @@ -558,11 +558,9 @@ NAN_METHOD(HeapProfiler::StopSamplingHeapProfiler) { // Remove cleanup hook since profiler is explicitly stopped { const std::lock_guard lock(g_heap_profiler_mutex); - if (g_heap_profiler_isolates.find(isolate) != - g_heap_profiler_isolates.end()) { + if (g_heap_profiler_isolates.erase(isolate) == 1) { node::RemoveEnvironmentCleanupHook( isolate, HeapProfilerCleanupHook, isolate); - g_heap_profiler_isolates.erase(isolate); } } }