High chrome Integer Overflow 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInteger overflow in V8
DescriptionInteger overflow in V8
ComponentV8
Bug ClassInteger Overflow
Tracker425583995
Fix commitc58fda1f0ec4 (v8/v8) +53/-11
CISA KEVNot listed
CreditedShaheen Fazim
Disclosed2025-07-15

Changed Functions

FunctionChangeNotes
V8_NODISCARD
src/codegen/arm64/macro-assembler-arm64.h
modified
if
src/codegen/arm64/macro-assembler-arm64.h
modified
for
test/mjsunit/regress/regress-425583995.js
modified

Files Changed

  • src/codegen/arm64/macro-assembler-arm64.cc
  • src/codegen/arm64/macro-assembler-arm64.h
  • test/mjsunit/regress/regress-425583995.js
From c58fda1f0ec46429dd66c2cacf6a98fac001e4fd Mon Sep 17 00:00:00 2001
From: Victor Gomes <victorgomes@chromium.org>
Date: Fri, 27 Jun 2025 12:40:10 +0200
Subject: [PATCH] [arm64] Ensure InstructionAccurateScope is called with correct count

The scope prevents veneer pool generation. We need to pass the
correct count of instructions to CheckVeneerPool inside the scope
constructor, otherwise we might overflow the veneer distance
margin in the next check (after the scope has ended).

Fixed: 425583995
Change-Id: Iebb81898c4f7999137fc784ce6704773614c2bb5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6683635
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#101089}
---

diff --git a/src/codegen/arm64/macro-assembler-arm64.cc b/src/codegen/arm64/macro-assembler-arm64.cc
index 74b995e..59c9aa6 100644
--- a/src/codegen/arm64/macro-assembler-arm64.cc
+++ b/src/codegen/arm64/macro-assembler-arm64.cc
@@ -1301,7 +1301,7 @@
                                 const CPURegister& src2,
                                 const CPURegister& src3) {
   // Ensure that we don't unintentially modify scratch or debug registers.
-  InstructionAccurateScope scope(this);
+  InstructionAccurateScope scope(this, count <= 2 ? 1 : 2);
 
   DCHECK(AreSameSizeAndType(src0, src1, src2, src3));
   DCHECK(size == src0.SizeInBytes());
@@ -1338,7 +1338,7 @@
                                const CPURegister& dst1, const CPURegister& dst2,
                                const CPURegister& dst3) {
   // Ensure that we don't unintentially modify scratch or debug registers.
-  InstructionAccurateScope scope(this);
+  InstructionAccurateScope scope(this, count <= 2 ? 1 : 2);
 
   DCHECK(AreSameSizeAndType(dst0, dst1, dst2, dst3));
   DCHECK(size == dst0.SizeInBytes());
@@ -1388,8 +1388,14 @@
 
 void MacroAssembler::PushCalleeSavedRegisters() {
   ASM_CODE_COMMENT(this);
+#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY
+  constexpr int kInstrCount = 11;
+#else
+  constexpr int kInstrCount = 10;
+#endif
+
   // Ensure that the macro-assembler doesn't use any scratch registers.
-  InstructionAccurateScope scope(this);
+  InstructionAccurateScope scope(this, kInstrCount);
 
   MemOperand tos(sp, -2 * static_cast<int>(kXRegSize), PreIndex);
 
@@ -1422,8 +1428,14 @@
 
 void MacroAssembler::PopCalleeSavedRegisters() {
   ASM_CODE_COMMENT(this);
+#ifdef V8_ENABLE_CONTROL_FLOW_INTEGRITY
+  constexpr int kInstrCount = 11;
+#else
+  constexpr int kInstrCount = 10;
+#endif
+
   // Ensure that the macro-assembler doesn't use any scratch registers.
-  InstructionAccurateScope scope(this);
+  InstructionAccurateScope scope(this, kInstrCount);
 
   MemOperand tos(sp, 2 * kXRegSize, PostIndex);
 
diff --git a/src/codegen/arm64/macro-assembler-arm64.h b/src/codegen/arm64/macro-assembler-arm64.h
index b9ca871..84cc32e 100644
--- a/src/codegen/arm64/macro-assembler-arm64.h
+++ b/src/codegen/arm64/macro-assembler-arm64.h
@@ -2494,7 +2494,7 @@
 // emitted is what you specified when creating the scope.
 class V8_NODISCARD InstructionAccurateScope {
  public:
-  explicit InstructionAccurateScope(MacroAssembler* masm, size_t count = 0)
+  explicit InstructionAccurateScope(MacroAssembler* masm, size_t count)
       : masm_(masm),
         block_pool_(masm, count * kInstrSize)
 #ifdef DEBUG
@@ -2502,12 +2502,11 @@
         size_(count * kInstrSize)
 #endif
   {
+    DCHECK_GT(count, 0);
     masm_->CheckVeneerPool(false, true, count * kInstrSize);
     masm_->StartBlockVeneerPool();
 #ifdef DEBUG
-    if (count != 0) {
-      masm_->bind(&start_);
-    }
+    masm_->bind(&start_);
     previous_allow_macro_instructions_ = masm_->allow_macro_instructions();
     masm_->set_allow_macro_instructions(false);
 #endif
@@ -2516,9 +2515,7 @@
   ~InstructionAccurateScope() {
     masm_->EndBlockVeneerPool();
 #ifdef DEBUG
-    if (start_.is_bound()) {
-      DCHECK(masm_->SizeOfCodeGeneratedSince(&start_) == size_);
-    }
+    DCHECK(masm_->SizeOfCodeGeneratedSince(&start_) == size_);
     masm_->set_allow_macro_instructions(previous_allow_macro_instructions_);
 #endif
   }
diff --git a/test/mjsunit/regress/regress-425583995.js b/test/mjsunit/regress/regress-425583995.js
new file mode 100644
index 0000000..eaed312c
--- /dev/null
+++ b/test/mjsunit/regress/regress-425583995.js
@@ -0,0 +1,33 @@
+// Copyright 2025 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
+
+const topLevel = %GetFunctionForCurrentFrame();
+%PrepareFunctionForOptimization(topLevel);
+
+function g(
+  // Too many arguments to fit here manually and overflow int32 calculation
+) {
+  return arguments.length + 1;
+}
+
+var num_args = 40000; // large number to cause overflow
+
+// Construct argument list string
+var argsList = "";
+for (var i = 0; i < num_args; i++) argsList += "a" + i + ",";
+argsList = argsList.slice(0, -1);
+
+// Construct function source to return sum of all args
+var body = "return arguments.length + 1;";
+
+// Create large argument function dynamically
+var bigArgFunc = new Function(argsList, body);
+
+// Call many times to trigger OSR in v8 maglev
+for (var i = 0; i < 2; i++) {
+  bigArgFunc(0);
+  %OptimizeOsr();
+}
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/test/mjsunit/regress/regress-425583995.js b/test/mjsunit/regress/regress-425583995.js
new file mode 100644
index 0000000..eaed312c
--- /dev/null
+++ b/test/mjsunit/regress/regress-425583995.js
@@ -0,0 +1,33 @@
+// Copyright 2025 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
+
+const topLevel = %GetFunctionForCurrentFrame();
+%PrepareFunctionForOptimization(topLevel);
+
+function g(
+  // Too many arguments to fit here manually and overflow int32 calculation
+) {
+  return arguments.length + 1;
+}
+
+var num_args = 40000; // large number to cause overflow
+
+// Construct argument list string
+var argsList = "";
+for (var i = 0; i < num_args; i++) argsList += "a" + i + ",";
+argsList = argsList.slice(0, -1);
+
+// Construct function source to return sum of all args
+var body = "return arguments.length + 1;";
+
+// Create large argument function dynamically
+var bigArgFunc = new Function(argsList, body);
+
+// Call many times to trigger OSR in v8 maglev
+for (var i = 0; i < 2; i++) {
+  bigArgFunc(0);
+  %OptimizeOsr();
+}
Loading diff…

Original Bug Report

reported by fa...@gmail.com

Debug check failed: pc_offset() < unresolved_branches_first_limit()


#
# Fatal error in ../../src/codegen/arm64/assembler-arm64.cc, line 4917
# Debug check failed: pc_offset() < unresolved_branches_first_limit().
#
#
#
#FailureMessage Object: 0x16d305468
==== C stack trace ===============================

    0   libv8_libbase.dylib                 0x0000000104389ee8 v8::base::debug::StackTrace::StackTrace() + 24
    1   libv8_libplatform.dylib             0x00000001043c67c8 v8::platform::(anonymous namespace)::PrintStackTrace() + 116
    2   libv8_libbase.dylib                 0x000000010436d5cc V8_Fatal(char const*, int, char const*, ...) + 352
    3   libv8_libbase.dylib                 0x000000010436ced0 v8::base::SetFatalFunction(void (*)(char const*, int, char const*)) + 0
    4   libv8.dylib                         0x000000010c96b6dc v8::internal::Assembler::CheckVeneerPool(bool, bool, unsigned long) + 232
    5   libv8.dylib                         0x000000010aeb3208 v8::internal::Assembler::Emit(unsigned int) + 132
    6   libv8.dylib                         0x000000010c96bc8c v8::internal::Assembler::EmitVeneers(bool, bool, unsigned long) + 908
    7   libv8.dylib                         0x000000010c977f14 v8::internal::MacroAssembler::PushHelper(int, int, v8::internal::CPURegister const&, v8::internal::CPURegister const&, v8::internal::CPURegister const&, v8::internal::CPURegister const&) + 136
    8   libv8.dylib                         0x000000010c3a8d48 void v8::internal::maglev::detail::PushIteratorReverse<v8::internal::maglev::RepeatIterator<v8::internal::Register>>(v8::internal::maglev::MaglevAssembler*, v8::base::iterator_range<v8::internal::maglev::RepeatIterator<v8::internal::Register>>) + 324
    9   libv8.dylib                         0x000000010c3a8aec void v8::internal::maglev::detail::PushIteratorReverse<std::__Cr::reverse_iterator<v8::internal::maglev::Input*>, v8::base::iterator_range<v8::internal::maglev::RepeatIterator<v8::internal::Register>>>(v8::internal::maglev::MaglevAssembler*, v8::base::iterator_range<std::__Cr::reverse_iterator<v8::internal::maglev::Input*>>, v8::base::iterator_range<v8::internal::maglev::RepeatIterator<v8::internal::Register>>) + 108
    10  libv8.dylib                         0x000000010c35ff7c v8::internal::maglev::CallKnownJSFunction::GenerateCode(v8::internal::maglev::MaglevAssembler*, v8::internal::maglev::ProcessingState const&) + 356
    11  libv8.dylib                         0x000000010bf32110 v8::internal::maglev::ProcessResult v8::internal::maglev::NodeMultiProcessor<v8::internal::maglev::(anonymous namespace)::SafepointingNodeProcessor, v8::internal::maglev::(anonymous namespace)::MaglevCodeGeneratingNodeProcessor>::Process<v8::internal::maglev::CallKnownJSFunction>(v8::internal::maglev::CallKnownJSFunction*, v8::internal::maglev::ProcessingState const&) + 1160
    12  libv8.dylib                         0x000000010beef718 v8::internal::maglev::MaglevCodeGenerator::EmitCode() + 7092
    13  libv8.dylib                         0x000000010beed8d4 v8::internal::maglev::MaglevCodeGenerator::Assemble() + 48
    14  libv8.dylib                         0x000000010bfc82f0 v8::internal::maglev::MaglevCompiler::Compile(v8::internal::LocalIsolate*, v8::internal::maglev::MaglevCompilationInfo*) + 5532
    15  libv8.dylib                         0x000000010c0e514c v8::internal::maglev::MaglevCompilationJob::ExecuteJobImpl(v8::internal::RuntimeCallStats*, v8::internal::LocalIsolate*) + 96
    16  libv8.dylib                         0x000000010af9587c v8::internal::OptimizedCompilationJob::ExecuteJob(v8::internal::RuntimeCallStats*, v8::internal::LocalIsolate*) + 160
    17  libv8.dylib                         0x000000010c0e718c v8::internal::maglev::MaglevConcurrentDispatcher::JobTask::Run(v8::JobDelegate*) + 856
    18  libv8_libplatform.dylib             0x00000001043c52cc v8::platform::DefaultJobWorker::Run() + 292
    19  libv8_libplatform.dylib             0x00000001043c7d0c v8::platform::DefaultWorkerThreadsTaskRunner::WorkerThread::Run() + 276
    20  libv8_libbase.dylib                 0x00000001043882ec v8::base::ThreadEntry(void*) + 180
    21  libsystem_pthread.dylib             0x00000001911fac0c _pthread_start + 136
    22  libsystem_pthread.dylib             0x00000001911f5b80 thread_start + 8
zsh: trace trap  ./v8/v8/out/debug/d8 poc.js

VERSION

V8 version 13.9.0 (candidate)

REPRODUCTION CASE

Build: v8 Debug build, MacOS arm64

Run: ./d8 poc.js


Reporter credit: Shaheen Fazim

View on issue tracker