Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in V8
DescriptionInappropriate implementation in V8
ComponentV8
Bug ClassLogic Error
Tracker513810921
Fix commit5b5f77018c92 (v8/v8) +35/-34
CISA KEVNot listed
CreditedYuntao You (@GraVity0) of Bytedance Wuheng Lab
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
GetConstructorHelper
src/objects/js-objects.cc
modified
JSGlobalObject
src/objects/js-objects.h
modified
JSGlobalProxy
src/objects/js-objects.h
modified

Files Changed

  • src/objects/js-function.cc
  • src/objects/js-function.h
  • src/objects/js-objects.cc
  • src/objects/js-objects.h
  • src/objects/lookup.cc
  • src/objects/lookup.h
From 5b5f77018c9296911170b4f886570c1735e97919 Mon Sep 17 00:00:00 2001
From: Dominik Inführ <[email protected]>
Date: Tue, 19 May 2026 15:24:07 +0200
Subject: [PATCH] [objects] Prevent allocations in JSReceiver::GetConstructor()

The heap snapshot generator uses GetConstructor() to provide a
better object name. However, this method allocates in some cases.
This CL removes this allocation by passing the already existing
AllocationPolicy to the GetDebugName() methods as well.

Bug: 513810921
Change-Id: I3f7abd2c7bfb5cf61d25390a77d7718d6409f1b5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7858355
Commit-Queue: Dominik Inführ <[email protected]>
Reviewed-by: Igor Sheludko <[email protected]>
Cr-Commit-Position: refs/heads/main@{#107510}
---

diff --git a/src/objects/js-function.cc b/src/objects/js-function.cc
index 119c7f3..d6a945f 100644
--- a/src/objects/js-function.cc
+++ b/src/objects/js-function.cc
@@ -1366,7 +1366,8 @@
 }  // namespace
 
 DirectHandle<String> JSFunction::GetDebugName(
-    Isolate* isolate, DirectHandle<JSFunction> function) {
+    Isolate* isolate, DirectHandle<JSFunction> function,
+    AllowAllocation allow_allocation) {
   // Below we use the same fast-path that we already established for
   // Function.prototype.bind(), where we avoid a slow "name" property
   // lookup if the DescriptorArray for the |function| still has the
@@ -1386,7 +1387,7 @@
     if (IsString(*name)) return Cast<String>(name);
   }
   return SharedFunctionInfo::DebugName(
-      isolate, direct_handle(function->shared(), isolate));
+      isolate, direct_handle(function->shared(), isolate), allow_allocation);
 }
 
 bool JSFunction::SetName(Isolate* isolate, DirectHandle<JSFunction> function,
diff --git a/src/objects/js-function.h b/src/objects/js-function.h
index 18d98f3..89e6b75 100644
--- a/src/objects/js-function.h
+++ b/src/objects/js-function.h
@@ -455,8 +455,9 @@
 
   // The function's name if it is configured, otherwise shared function info
   // debug name.
-  static DirectHandle<String> GetDebugName(Isolate* isolate,
-                                           DirectHandle<JSFunction> function);
+  static DirectHandle<String> GetDebugName(
+      Isolate* isolate, DirectHandle<JSFunction> function,
+      AllowAllocation allow_allocation = AllowAllocation::kYes);
 
   // The function's string representation implemented according to
   // ES6 section 19.2.3.5 Function.prototype.toString ( ).
diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
index 77bc101..f218fd6 100644
--- a/src/objects/js-objects.cc
+++ b/src/objects/js-objects.cc
@@ -168,7 +168,7 @@
 }
 
 Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it,
-                                           AllocationPolicy allocation_policy) {
+                                           AllowAllocation allow_allocation) {
   for (;; it->Next()) {
     switch (it->state()) {
       case LookupIterator::INTERCEPTOR:
@@ -209,7 +209,7 @@
       case LookupIterator::TYPED_ARRAY_INDEX_NOT_FOUND:
         return it->isolate()->factory()->undefined_value();
       case LookupIterator::DATA:
-        return it->GetDataValue(allocation_policy);
+        return it->GetDataValue(allow_allocation);
       case LookupIterator::NOT_FOUND:
         return it->isolate()->factory()->undefined_value();
       case LookupIterator::MODULE_NAMESPACE: {
@@ -601,6 +601,7 @@
 namespace {
 std::pair<MaybeDirectHandle<JSFunction>, DirectHandle<String>>
 GetConstructorHelper(Isolate* isolate, DirectHandle<JSReceiver> receiver) {
+  DisallowGarbageCollection no_gc;
   // If the object was instantiated simply with base == new.target, the
   // constructor on the map provides the most accurate name.
   // Don't provide the info for prototypes, since their constructors are
@@ -613,7 +614,7 @@
       DirectHandle<JSFunction> constructor =
           Cast<JSFunction>(maybe_constructor);
       DirectHandle<String> name =
-          JSFunction::GetDebugName(isolate, constructor);
+          JSFunction::GetDebugName(isolate, constructor, AllowAllocation::kNo);
       if (name->length() != 0 &&
           !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
         return std::make_pair(indirect_handle(constructor, isolate), name);
@@ -636,8 +637,8 @@
     LookupIterator it_to_string_tag(
         isolate, receiver, isolate->factory()->to_string_tag_symbol(), current,
         LookupIterator::OWN_SKIP_INTERCEPTOR);
-    auto maybe_to_string_tag = JSReceiver::GetDataProperty(
-        &it_to_string_tag, AllocationPolicy::kAllocationDisallowed);
+    auto maybe_to_string_tag =
+        JSReceiver::GetDataProperty(&it_to_string_tag, AllowAllocation::kNo);
     if (IsString(*maybe_to_string_tag)) {
       return std::make_pair(MaybeHandle<JSFunction>(),
                             Cast<String>(maybe_to_string_tag));
@@ -673,12 +674,13 @@
       LookupIterator it_constructor(
           isolate, receiver, isolate->factory()->constructor_string(), current,
           LookupIterator::OWN_SKIP_INTERCEPTOR);
-      auto maybe_constructor = JSReceiver::GetDataProperty(
-          &it_constructor, AllocationPolicy::kAllocationDisallowed);
+      auto maybe_constructor =
+          JSReceiver::GetDataProperty(&it_constructor, AllowAllocation::kNo);
       if (IsJSFunction(*maybe_constructor)) {
         auto constructor = Cast<JSFunction>(maybe_constructor);
         auto name = SharedFunctionInfo::DebugName(
-            isolate, direct_handle(constructor->shared(), isolate));
+            isolate, direct_handle(constructor->shared(), isolate),
+            AllowAllocation::kNo);
 
         if (name->length() != 0 &&
             !name->Equals(ReadOnlyRoots(isolate).Object_string())) {
diff --git a/src/objects/js-objects.h b/src/objects/js-objects.h
index 2585096..9ef4c49 100644
--- a/src/objects/js-objects.h
+++ b/src/objects/js-objects.h
@@ -23,10 +23,6 @@
 
 namespace v8::internal {
 
-// Enum for functions that offer a second mode that does not cause allocations.
-// Used in conjunction with LookupIterator and unboxed double fields.
-enum class AllocationPolicy { kAllocationAllowed, kAllocationDisallowed };
-
 enum InstanceType : uint16_t;
 class JSGlobalObject;
 class JSGlobalProxy;
@@ -335,8 +331,8 @@
                                                DirectHandle<JSReceiver> object,
                                                DirectHandle<Name> name);
   V8_EXPORT_PRIVATE static Handle<Object> GetDataProperty(
-      LookupIterator* it, AllocationPolicy allocation_policy =
-                              AllocationPolicy::kAllocationAllowed);
+      LookupIterator* it,
+      AllowAllocation allow_allocation = AllowAllocation::kYes);
 
   // Retrieves a permanent object identity hash code. The undefined value might
   // be returned in case no hash was created yet.
diff --git a/src/objects/lookup.cc b/src/objects/lookup.cc
index 681b70c..bf5ba6a 100644
--- a/src/objects/lookup.cc
+++ b/src/objects/lookup.cc
@@ -996,7 +996,7 @@
 }
 
 DirectHandle<Object> LookupIterator::FetchValue(
-    AllocationPolicy allocation_policy) const {
+    AllowAllocation allow_allocation) const {
   Tagged<Object> result;
   DCHECK_NE(state_, STRING_LOOKUP_START_OBJECT);
   DCHECK(!IsWasmObject(*holder_));
@@ -1020,8 +1020,8 @@
     DirectHandle<JSObject> holder = GetHolder<JSObject>();
     FieldIndex field_index =
         FieldIndex::ForDetails(holder->map(), property_details_);
-    if (allocation_policy == AllocationPolicy::kAllocationDisallowed &&
-        field_index.is_inobject() && field_index.is_double()) {
+    if (allow_allocation == AllowAllocation::kNo && field_index.is_inobject() &&
+        field_index.is_double()) {
       return isolate_->factory()->undefined_value();
     }
     return JSObject::FastPropertyAt(
@@ -1132,7 +1132,7 @@
 }
 
 Handle<Object> LookupIterator::GetStringPropertyValue(
-    AllocationPolicy allocation_policy) const {
+    AllowAllocation allow_allocation) const {
   DCHECK_EQ(state_, STRING_LOOKUP_START_OBJECT);
   if (IsElement()) {
     DirectHandle<String> string = Cast<String>(lookup_start_object_);
@@ -1149,9 +1149,9 @@
 }
 
 Handle<Object> LookupIterator::GetDataValue(
-    AllocationPolicy allocation_policy) const {
+    AllowAllocation allow_allocation) const {
   DCHECK_EQ(DATA, state_);
-  return indirect_handle(FetchValue(allocation_policy), isolate_);
+  return indirect_handle(FetchValue(allow_allocation), isolate_);
 }
 
 DirectHandle<Object> LookupIterator::GetDataValue(SeqCstAccessTag tag) const {
diff --git a/src/objects/lookup.h b/src/objects/lookup.h
index f1807b2..d5666a3 100644
--- a/src/objects/lookup.h
+++ b/src/objects/lookup.h
@@ -262,10 +262,9 @@
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.