CVE-2026-4461
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
fortest/mjsunit/maglev/regress-490558172-1.js |
modified | |
iftest/mjsunit/maglev/regress-490558172-1.js |
modified | |
fortest/mjsunit/maglev/regress-490558172-2.js |
modified | |
iftest/mjsunit/maglev/regress-490558172-2.js |
modified |
Files Changed
src/maglev/maglev-graph-builder.cctest/mjsunit/maglev/regress-490558172-1.jstest/mjsunit/maglev/regress-490558172-2.js
Patch
From 0fff08a529f436a8eedb8d1f1b4cc5bcee4bf670 Mon Sep 17 00:00:00 2001
From: Darius Mercadier <dmercadier@chromium.org>
Date: Wed, 11 Mar 2026 07:57:37 +0100
Subject: [PATCH] [maglev] Stop eliding Smi checks because of CheckValueEqualsInt32
If a Phi goes through a CheckValueEqualsInt32 then we record a
constant int32 alternative for this Phi.
If the Phi is then the input to a BuildCheckSmi, we'll update the KNA
to record that this Phi is a Smi but won't insert a Smi check if the
int32 constant alternative is in range. Notably, this doesn't call
UseRequiresSmi, which means that when materializing this Phi, we won't
really know that it needs to be a Smi rather than a HeapObject.
Where is goes wrong is if this phi has a use that requires it to be
materialized to HeapObject (this isn't easy to construct, cf the -2.js
repro in this CL: I used a secondary Phi to trigger this), then we'll
always materialize it as a HeapObject and never as a Smi, which can
be wrong if we store it in a Smi field.
Fixed: 490558172
Change-Id: Idcc7077187a3e952f7d3eb42150525d33cefe430
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7653635
Auto-Submit: Darius Mercadier <dmercadier@chromium.org>
Reviewed-by: Victor Gomes <victorgomes@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#105717}
---
diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc
index 9f8d4c9..6dfedbd 100644
--- a/src/maglev/maglev-graph-builder.cc
+++ b/src/maglev/maglev-graph-builder.cc
@@ -4183,6 +4183,7 @@
return EmitUnconditionalDeopt(DeoptimizeReason::kSmi);
}
if (EnsureType(object, NodeType::kSmi) && elidable) return object;
+ RecordSmiUse(object);
// For constants, we may be able to skip the runtime check.
if (std::optional<int32_t> constant_value = TryGetInt32Constant(object)) {
if (Smi::IsValid(constant_value.value())) return object;
@@ -4203,7 +4204,6 @@
AddNewNodeNoInputConversion<CheckHoleyFloat64IsSmi>({object});
break;
case ValueRepresentation::kTagged:
- RecordSmiUse(object);
AddNewNodeNoInputConversion<CheckSmi>({object});
break;
case ValueRepresentation::kIntPtr:
diff --git a/test/mjsunit/maglev/regress-490558172-1.js b/test/mjsunit/maglev/regress-490558172-1.js
new file mode 100644
index 0000000..6f5fd14
--- /dev/null
+++ b/test/mjsunit/maglev/regress-490558172-1.js
@@ -0,0 +1,32 @@
+// Copyright 2026 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --verify-heap
+
+let cst = 11;
+
+let o = { x : 17 };
+o.x = 25;
+
+function foo(c) {
+ for (let i = 0; i < 42; i++) {
+ if (i == 11) {
+ cst = i; // Will insert a CheckValueEqualsInt32
+ o.x = i; // Will not insert a CheckSmi because CheckValueEqualsInt32
+ // registers an Smi-sized Int32 constant alternative.
+ }
+ }
+}
+
+%PrepareFunctionForOptimization(foo);
+foo(true);
+foo(true);
+
+o.x = 42;
+
+%OptimizeMaglevOnNextCall(foo);
+foo(true);
+
+assertEquals(11, cst);
+assertEquals(11, o.x);
diff --git a/test/mjsunit/maglev/regress-490558172-2.js b/test/mjsunit/maglev/regress-490558172-2.js
new file mode 100644
index 0000000..f6fdb91
--- /dev/null
+++ b/test/mjsunit/maglev/regress-490558172-2.js
@@ -0,0 +1,49 @@
+// Copyright 2026 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --verify-heap --maglev
+
+const non_smi_int32 = 0x40000000;
+let cst = 47;
+
+let o1 = { x : 17 };
+o1.x = 25;
+
+let o2 = { y : "abc" };
+o2.y = [];
+
+function foo(c) {
+ let phi = 42;
+ for (let i = 0; i < 10; i++) {
+ if (i == 5) {
+ cst = phi; // Will insert a CheckValueEqualsInt32
+ // Requires Smi.
+ o1.x = phi; // Will not insert a CheckSmi because CheckValueEqualsInt32
+ // registers an Smi-sized Int32 constant alternative.
+
+ }
+ phi++;
+ }
+ let phi2 = c ? phi : non_smi_int32;
+ // Requires HeapNumber
+ o2.y = phi2;
+}
+
+%PrepareFunctionForOptimization(foo);
+foo(false);
+foo(false);
+
+%OptimizeMaglevOnNextCall(foo);
+foo(false);
+assertOptimized(foo);
+
+assertEquals(47, cst);
+assertEquals(47, o1.x);
+assertEquals(non_smi_int32, o2.y);
+
+foo(true);
+assertUnoptimized(foo);
+assertEquals(47, cst);
+assertEquals(47, o1.x);
+assertEquals(52, o2.y);
Regression Test / PoC
diff --git a/test/mjsunit/maglev/regress-490558172-1.js b/test/mjsunit/maglev/regress-490558172-1.js
new file mode 100644
index 0000000..6f5fd14
--- /dev/null
+++ b/test/mjsunit/maglev/regress-490558172-1.js
@@ -0,0 +1,32 @@
+// Copyright 2026 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --verify-heap
+
+let cst = 11;
+
+let o = { x : 17 };
+o.x = 25;
+
+function foo(c) {
+ for (let i = 0; i < 42; i++) {
+ if (i == 11) {
+ cst = i; // Will insert a CheckValueEqualsInt32
+ o.x = i; // Will not insert a CheckSmi because CheckValueEqualsInt32
+ // registers an Smi-sized Int32 constant alternative.
+ }
+ }
+}
+
+%PrepareFunctionForOptimization(foo);
+foo(true);
+foo(true);
+
+o.x = 42;
+
+%OptimizeMaglevOnNextCall(foo);
+foo(true);
+
+assertEquals(11, cst);
+assertEquals(11, o.x);
diff --git a/test/mjsunit/maglev/regress-490558172-2.js b/test/mjsunit/maglev/regress-490558172-2.js
new file mode 100644
index 0000000..f6fdb91
--- /dev/null
+++ b/test/mjsunit/maglev/regress-490558172-2.js
@@ -0,0 +1,49 @@
+// Copyright 2026 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --verify-heap --maglev
+
+const non_smi_int32 = 0x40000000;
+let cst = 47;
+
+let o1 = { x : 17 };
+o1.x = 25;
+
+let o2 = { y : "abc" };
+o2.y = [];
+
+function foo(c) {
+ let phi = 42;
+ for (let i = 0; i < 10; i++) {
+ if (i == 5) {
+ cst = phi; // Will insert a CheckValueEqualsInt32
+ // Requires Smi.
+ o1.x = phi; // Will not insert a CheckSmi because CheckValueEqualsInt32
+ // registers an Smi-sized Int32 constant alternative.
+
+ }
+ phi++;
+ }
+ let phi2 = c ? phi : non_smi_int32;
+ // Requires HeapNumber
+ o2.y = phi2;
+}
+
+%PrepareFunctionForOptimization(foo);
+foo(false);
+foo(false);
+
+%OptimizeMaglevOnNextCall(foo);
+foo(false);
+assertOptimized(foo);
+
+assertEquals(47, cst);
+assertEquals(47, o1.x);
+assertEquals(non_smi_int32, o2.y);
+
+foo(true);
+assertUnoptimized(foo);
+assertEquals(47, cst);
+assertEquals(47, o1.x);
+assertEquals(52, o2.y);
Original Bug Report
Wrong CheckSmi elision because of CheckValueEqualsInt32
Detailed Report: https://clusterfuzz.com/testcase?key=6504068423811072
Fuzzer: None Job Type: linux_asan_d8_dbg Platform Id: linux
Crash Type: DCHECK failure Crash Address: Crash State: value->Is<Phi>() implies value->StaticTypeIs(broker(), NodeType::kSmi) || value- v8::internal::maglev::MaglevGraphBuilder::CanElideWriteBarrier v8::internal::maglev::MaglevGraphBuilder::BuildStoreTaggedFieldNoWriteBarrier
Sanitizer: address (ASAN)
Regressed: https://clusterfuzz.com/revisions?job=linux_asan_d8_dbg&range=105606:105607
Reproducer Testcase: https://clusterfuzz.com/download?testcase_id=6504068423811072
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.