CVE-2026-5862
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifsrc/maglev/maglev-graph-builder.cc |
modified |
Files Changed
src/maglev/maglev-graph-builder.ccsrc/maglev/maglev-graph-builder.h
Patch
From a0570afad500d7882b2e4c5981ccb6cf00704df5 Mon Sep 17 00:00:00 2001 From: Victor Gomes <[email protected]> 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 <[email protected]> Reviewed-by: Toon Verwaest <[email protected]> Commit-Queue: Victor Gomes <[email protected]> Auto-Submit: Victor Gomes <[email protected]> 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);
Original Bug Report
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.