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
Tracker420697404
Fix commit62ee3244f3b2 (v8/v8) +18/-12
CISA KEVNot listed
CreditedShaheen Fazim
Disclosed2025-06-17

Changed Functions

FunctionChangeNotes
if
src/objects/js-regexp.cc
modified

Files Changed

  • src/objects/js-regexp.cc
From 62ee3244f3b212b92e22b8e2651afbed35de9768 Mon Sep 17 00:00:00 2001
From: pthier <pthier@chromium.org>
Date: Tue, 03 Jun 2025 09:16:02 +0200
Subject: [PATCH] [regexp] Use uint32_t over int in EscapeRegExpSource

While escaping the regexp source, a regular signed int might overflow,
while an uint32_t can always hold the maximum length for the escaped
source.

Fixed: 420697404
Change-Id: I61084b93d51a2729204332b4285922fd82ee8fc7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6611425
Reviewed-by: Jakob Linke <jgruber@chromium.org>
Auto-Submit: Patrick Thier <pthier@chromium.org>
Commit-Queue: Patrick Thier <pthier@chromium.org>
Cr-Commit-Position: refs/heads/main@{#100636}
---

diff --git a/src/objects/js-regexp.cc b/src/objects/js-regexp.cc
index e365ac4..6049036 100644
--- a/src/objects/js-regexp.cc
+++ b/src/objects/js-regexp.cc
@@ -189,10 +189,14 @@
 // WriteEscapedRegExpSource into a single function to deduplicate dispatch logic
 // and move related code closer to each other.
 template <typename Char>
-int CountAdditionalEscapeChars(DirectHandle<String> source,
-                               bool* needs_escapes_out) {
+uint32_t CountAdditionalEscapeChars(DirectHandle<String> source,
+                                    bool* needs_escapes_out) {
   DisallowGarbageCollection no_gc;
-  int escapes = 0;
+  uint32_t escapes = 0;
+  // The maximum growth-factor is 5 (for \u2028 and \u2029). Make sure that we
+  // won't overflow |escapes| given the current constraints on string length.
+  static_assert(uint64_t{String::kMaxLength} * 5 <
+                std::numeric_limits<decltype(escapes)>::max());
   bool needs_escapes = false;
   bool in_character_class = false;
   base::Vector<const Char> src = source->GetCharVector<Char>(no_gc);
@@ -231,14 +235,14 @@
     }
   }
   DCHECK(!in_character_class);
-  DCHECK_GE(escapes, 0);
   DCHECK_IMPLIES(escapes != 0, needs_escapes);
   *needs_escapes_out = needs_escapes;
   return escapes;
 }
 
 template <typename Char>
-void WriteStringToCharVector(base::Vector<Char> v, int* d, const char* string) {
+void WriteStringToCharVector(base::Vector<Char> v, uint32_t* d,
+                             const char* string) {
   int s = 0;
   while (string[s] != '\0') v[(*d)++] = string[s++];
 }
@@ -249,13 +253,13 @@
   DisallowGarbageCollection no_gc;
   base::Vector<const Char> src = source->GetCharVector<Char>(no_gc);
   base::Vector<Char> dst(result->GetChars(no_gc), result->length());
-  int s = 0;
-  int d = 0;
+  uint32_t s = 0;
+  uint32_t d = 0;
   bool in_character_class = false;
-  while (s < src.length()) {
+  while (s < src.size()) {
     const Char c = src[s];
     if (c == '\\') {
-      if (s + 1 < src.length() && IsLineTerminator(src[s + 1])) {
+      if (s + 1 < src.size() && IsLineTerminator(src[s + 1])) {
         // This '\' is ignored since the next character itself will be escaped.
         s++;
         continue;
@@ -263,7 +267,7 @@
         // Escape. Copy this and next character.
         dst[d++] = src[s++];
       }
-      if (s == src.length()) break;
+      if (s == src.size()) break;
     } else if (c == '/' && !in_character_class) {
       // Not escaped forward-slash needs escape.
       dst[d++] = '\\';
@@ -303,11 +307,13 @@
   if (source->length() == 0) return isolate->factory()->query_colon_string();
   bool one_byte = String::IsOneByteRepresentationUnderneath(*source);
   bool needs_escapes = false;
-  int additional_escape_chars =
+  uint32_t additional_escape_chars =
       one_byte ? CountAdditionalEscapeChars<uint8_t>(source, &needs_escapes)
                : CountAdditionalEscapeChars<base::uc16>(source, &needs_escapes);
   if (!needs_escapes) return source;
-  int length = source->length() + additional_escape_chars;
+  DCHECK_LE(static_cast<uint64_t>(source->length()) + additional_escape_chars,
+            std::numeric_limits<uint32_t>::max());
+  uint32_t length = source->length() + additional_escape_chars;
   if (one_byte) {
     DirectHandle<SeqOneByteString> result;
     ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
Loading diff…

Original Bug Report

reported by fa...@gmail.com

Debug check failed: escapes >= 0 (-2005397586 vs. 0)

VULNERABILITY DETAILS

#
# Fatal error in ..\..\src\objects\js-regexp.cc, line 234
# Debug check failed: escapes >= 0 (-2005397586 vs. 0).
#
#
#
#FailureMessage Object: 00000012179FD550
==== C stack trace ===============================

	v8::base::debug::StackTrace::StackTrace [0x0x7fff2bb5b685+37] (D:\Browser\v8\v8\src\base\debug\stack_trace_win.cc:173)
	v8::platform::`anonymous namespace'::PrintStackTrace [0x0x7fff2bcdab89+57] (D:\Browser\v8\v8\src\libplatform\default-platform.cc:28)
	V8_Fatal [0x0x7fff2bb35463+323] (D:\Browser\v8\v8\src\base\logging.cc:214)
	v8::base::`anonymous namespace'::DefaultDcheckHandler [0x0x7fff2bb34e8c+44] (D:\Browser\v8\v8\src\base\logging.cc:59)
	V8_Dcheck [0x0x7fff2bb35571+81] (D:\Browser\v8\v8\src\base\logging.cc:228)
	v8::internal::`anonymous namespace'::CountAdditionalEscapeChars<unsigned short> [0x0x7ffeaae0b824+740] (D:\Browser\v8\v8\src\objects\js-regexp.cc:234)
	v8::internal::`anonymous namespace'::EscapeRegExpSource [0x0x7ffeaae08824+420] (D:\Browser\v8\v8\src\objects\js-regexp.cc:306)
	v8::internal::JSRegExp::Initialize [0x0x7ffeaae07dfa+618] (D:\Browser\v8\v8\src\objects\js-regexp.cc:344)
	v8::internal::JSRegExp::Initialize [0x0x7ffeaae08581+529] (D:\Browser\v8\v8\src\objects\js-regexp.cc:179)
	v8::internal::__RT_impl_Runtime_RegExpInitializeAndCompile [0x0x7ffeab3fe615+549] (D:\Browser\v8\v8\src\runtime\runtime-regexp.cc:2147)
	v8::internal::Runtime_RegExpInitializeAndCompile [0x0x7ffeab3fe10d+413] (D:\Browser\v8\v8\src\runtime\runtime-regexp.cc:2137)
	Builtins_CEntry_Return1_ArgvOnStack_NoBuiltinExit [0x0x7ffeaf6b5b41+65]
	Builtins_RegExpConstructor [0x0x7ffeaf5f40db+7579]
	Builtins_InterpreterPushArgsThenFastConstructFunction [0x0x7ffeaf247501+1089]
	Builtins_ConstructHandler [0x0x7ffeafe522c5+8261]
	Builtins_InterpreterEntryTrampoline [0x0x7ffeaf2467f2+370]
	Builtins_InterpreterEntryTrampoline [0x0x7ffeaf2467f2+370]
	Builtins_JSEntryTrampoline [0x0x7ffeaf239ce7+103]
	Builtins_JSEntry [0x0x7ffeaf23983f+255]
	v8::internal::GeneratedCode<unsigned long long,unsigned long long,unsigned long long,unsigned long long,unsigned long long,long long,unsigned long long **>::Call [0x0x7ffea9f5438c+108] (D:\Browser\v8\v8\src\execution\simulator.h:212)
	v8::internal::`anonymous namespace'::Invoke [0x0x7ffea9f503cd+5469] (D:\Browser\v8\v8\src\execution\execution.cc:441)
	v8::internal::Execution::CallScript [0x0x7ffea9f50c61+513] (D:\Browser\v8\v8\src\execution\execution.cc:542)
	v8::Script::Run [0x0x7ffea978b5cf+1135] (D:\Browser\v8\v8\src\api\api.cc:1964)
	v8::Script::Run [0x0x7ffea978b148+120] (D:\Browser\v8\v8\src\api\api.cc:1929)
	v8::Shell::ExecuteString [0x0x7ff6ae1d21b6+3142] (D:\Browser\v8\v8\src\d8\d8.cc:1030)
	v8::SourceGroup::Execute [0x0x7ff6ae1f7e26+1174] (D:\Browser\v8\v8\src\d8\d8.cc:5073)
	v8::Shell::RunMainIsolate [0x0x7ff6ae1ff287+631] (D:\Browser\v8\v8\src\d8\d8.cc:6027)
	v8::Shell::RunMain [0x0x7ff6ae1feced+205] (D:\Browser\v8\v8\src\d8\d8.cc:5935)
	v8::Shell::Main [0x0x7ff6ae201901+3873] (D:\Browser\v8\v8\src\d8\d8.cc:6801)
	main [0x0x7ff6ae202333+35] (D:\Browser\v8\v8\src\d8\d8.cc:6893)
	invoke_main [0x0x7ff6ae368489+57] (D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:79)
	__scrt_common_main_seh [0x0x7ff6ae3685c2+306] (D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288)
	__scrt_common_main [0x0x7ff6ae36864e+14] (D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:331)
	mainCRTStartup [0x0x7ff6ae36866e+14] (D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:17)
	BaseThreadInitThunk [0x0x7fff6adfe8d7+23]
	RtlUserThreadStart [0x0x7fff6cafc5dc+44]

VERSION

V8 version 13.9.0 (candidate)

REPRODUCTION CASE

Build: python3 tools/dev/gm.py x64.debug

Run: ./d8 poc.js


Reporter credit: Shaheen Fazim

View on issue tracker