Chrome · V8
CVE-2026-14409
Logic Error in V8
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
GetConstructorHelpersrc/objects/js-objects.cc |
modified | |
JSGlobalObjectsrc/objects/js-objects.h |
modified | |
JSGlobalProxysrc/objects/js-objects.h |
modified |
Files Changed
src/objects/js-function.ccsrc/objects/js-function.hsrc/objects/js-objects.ccsrc/objects/js-objects.hsrc/objects/lookup.ccsrc/objects/lookup.h
Patch
From 5b5f77018c9296911170b4f886570c1735e97919 Mon Sep 17 00:00:00 2001
From: Dominik Inführ <dinfuehr@chromium.org>
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 <dinfuehr@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
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.
References
On This Page