Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in V8
DescriptionInappropriate implementation in V8
ComponentV8
Bug ClassLogic Error
Tracker470566252
Fix commita0570afad500 (v8/v8) +27/-11
CISA KEVNot listed
CreditedGoogle
Disclosed2026-04-07

Changed Functions

FunctionChangeNotes
if
src/maglev/maglev-graph-builder.cc
modified

Files Changed

  • src/maglev/maglev-graph-builder.cc
  • src/maglev/maglev-graph-builder.h
From a0570afad500d7882b2e4c5981ccb6cf00704df5 Mon Sep 17 00:00:00 2001
From: Victor Gomes <victorgomes@chromium.org>
Date: Fri, 09 Jan 2026 15:13:28 +0100
Subject: [PATCH] [maglev] Fix deopt use counting for deopt scope data

We shouldn't count the deopt use when creating the scope data,
but only when creating the deopt frame.

If the scope was unused, then we were over counting,
not really a correctness issue though.

If the scope was used twice, we were under counting and
we can underflow the counting when removing the use of
a node.

Fixed: 470566252
Change-Id: I7b6f5647d1ed1f9a7c915d3682f10cfc71a5924c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7415271
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#104601}
---

diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc
index 1afdb79..c3e2247 100644
--- a/src/maglev/maglev-graph-builder.cc
+++ b/src/maglev/maglev-graph-builder.cc
@@ -427,8 +427,6 @@
                                : builder->zone()->CloneVector(parameters),
             builder->GetContext(), maybe_js_target}) {
     builder->current_interpreter_frame().virtual_objects().Snapshot();
-    builder->AddDeoptUse(
-        data_.get<DeoptFrame::BuiltinContinuationFrameData>().context);
     if (parameters.size() > 0) {
       if (InlinedAllocation* receiver =
               parameters[0]->TryCast<InlinedAllocation>()) {
@@ -437,10 +435,6 @@
         // meterialized object.
         receiver->ForceEscaping();
       }
-      for (ValueNode* node :
-           data_.get<DeoptFrame::BuiltinContinuationFrameData>().parameters) {
-        builder->AddDeoptUse(node);
-      }
     } else {
       DCHECK(data_.get<DeoptFrame::BuiltinContinuationFrameData>()
                  .parameters.empty());
@@ -453,10 +447,6 @@
             *builder->compilation_unit(), builder->GetCurrentSourcePosition(),
             receiver, builder->GetContext()}) {
     builder_->current_interpreter_frame().virtual_objects().Snapshot();
-    builder_->AddDeoptUse(
-        data_.get<DeoptFrame::ConstructInvokeStubFrameData>().receiver);
-    builder_->AddDeoptUse(
-        data_.get<DeoptFrame::ConstructInvokeStubFrameData>().context);
   }
 
   ~DeoptFrameScopeBase() {
@@ -1562,8 +1552,9 @@
         [&](ValueNode* node, interpreter::Register) { AddDeoptUse(node); });
     AddDeoptUse(latest_checkpointed_frame_->as_interpreted().closure());
 
-    const EagerDeoptFrameScope* deopt_scope = current_eager_deopt_scope_;
+    EagerDeoptFrameScope* deopt_scope = current_eager_deopt_scope_;
     if (deopt_scope != nullptr) {
+      AddDeoptUseToScopeData(deopt_scope->data());
       latest_checkpointed_frame_ = zone()->New<DeoptFrame>(
           deopt_scope->data(),
           RecursivelyWrapDeoptFrameWithContinuations(
@@ -1589,6 +1580,27 @@
                          result_location, result_size);
 }
 
+void MaglevGraphBuilder::AddDeoptUseToScopeData(DeoptFrame::FrameData& data) {
+  switch (data.tag()) {
+    case DeoptFrame::FrameType::kInterpretedFrame:
+    case DeoptFrame::FrameType::kInlinedArgumentsFrame:
+      // These frames are never created as deopt scope.
+      UNREACHABLE();
+    case DeoptFrame::FrameType::kConstructInvokeStubFrame:
+      AddDeoptUse(
+          data.get<DeoptFrame::ConstructInvokeStubFrameData>().receiver);
+      AddDeoptUse(data.get<DeoptFrame::ConstructInvokeStubFrameData>().context);
+      break;
+    case DeoptFrame::FrameType::kBuiltinContinuationFrame:
+      AddDeoptUse(data.get<DeoptFrame::BuiltinContinuationFrameData>().context);
+      for (ValueNode* node :
+           data.get<DeoptFrame::BuiltinContinuationFrameData>().parameters) {
+        AddDeoptUse(node);
+      }
+      break;
+  }
+}
+
 DeoptFrame* MaglevGraphBuilder::GetDeoptFrameForLazyDeoptHelper(
     interpreter::Register result_location, int result_size,
     LazyDeoptFrameScope* scope, bool mark_accumulator_dead, bool can_throw) {
@@ -1665,6 +1677,8 @@
   DCHECK(interpreter::Bytecodes::WritesOrClobbersAccumulator(
       iterator_.current_bytecode()));
 
+  AddDeoptUseToScopeData(scope->data());
+
   // Mark the accumulator dead in parent frames since we know that the
   // continuation will write it.
   return zone()->New<DeoptFrame>(
diff --git a/src/maglev/maglev-graph-builder.h b/src/maglev/maglev-graph-builder.h
index bae2273..cae3658 100644
--- a/src/maglev/maglev-graph-builder.h
+++ b/src/maglev/maglev-graph-builder.h
@@ -1583,6 +1583,8 @@
   void AddDeoptUse(VirtualObject* alloc);
   void AddNonEscapingUses(InlinedAllocation* allocation, int use_count);
 
+  void AddDeoptUseToScopeData(DeoptFrame::FrameData& data);
+
   std::optional<VirtualObject*> TryGetNonEscapingArgumentsObject(
       ValueNode* value);
 
Loading diff…

Original Bug Report

reported by 24...@project.gserviceaccount.com

DCHECK failure in use_count_ > 0 in maglev-ir.h

Detailed Report: https://clusterfuzz.com/testcase?key=6688632614092800

Fuzzer: ochang_js_fuzzer Job Type: linux32_asan_d8_dbg Platform Id: linux

Crash Type: DCHECK failure Crash Address: Crash State: use_count_ > 0 in maglev-ir.h V8_Dcheck v8::internal::maglev::ValueNode::remove_use

Sanitizer: address (ASAN)

Regressed: https://clusterfuzz.com/revisions?job=linux32_asan_d8_dbg&range=104326:104327

Reproducer Testcase: https://clusterfuzz.com/download?testcase_id=6688632614092800

Issue filed automatically.

To reproduce this, please build the target in this report and run it against the reproducer testcase. Please use the GN arguments provided at bottom of this report when building the binary.

If you have trouble reproducing, please also export the environment variables listed under “[Environment]” in the crash stacktrace.

If you have any feedback on reproducing test cases, let us know at https://forms.gle/Yh3qCYFveHj6E5jz5 so we can improve.

View on issue tracker