High chrome Memory Corruption 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMemory corruption in V8
DescriptionMemory corruption in V8
ComponentV8
Sub-componentMaps
Bug ClassMemory Corruption
Tracker568894515
Fix commit5a4d7a78dbb4 (v8/v8) +29/-22
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-27

Changed Functions

FunctionChangeNotes
if
src/objects/map-updater.cc
modified
for
src/objects/transitions.cc
modified

Files Changed

  • src/objects/map-updater.cc
  • src/objects/transitions.cc
  • src/objects/transitions.h
  • src/objects/transitions-inl.h
From 5a4d7a78dbb4d7451e3925d6b3d1b68d261fad16 Mon Sep 17 00:00:00 2001
From: Igor Sheludko <[email protected]>
Date: Wed, 14 Oct 2026 15:37:46 +0200
Subject: [PATCH] [maps] Synchronize concurrent GetPrototypeTransition in TryUpdateNoLock

Make TransitionsAccessor::GetPrototypeTransition an instance method on
TransitionsAccessor and guard prototype transition cache lookups with
full_transition_array_access() when accessed concurrently from
MapUpdater::TryUpdateNoLock.

This pairs with the full_transition_array_access() lock already held in
TransitionsAccessor::PutPrototypeTransition during compaction and new
entry publication, preventing concurrent readers from observing
partially-initialized maps or in-progress array compactions.

Fixed: 568894515

TAG=agy
CONV=d848b9e2-cbea-4f48-a8e4-dec738f151e6

Change-Id: Ib04a65ac07c2c588cb9e3aecc412068e2902b9aa
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8576038
Commit-Queue: Jakob Linke <[email protected]>
Auto-Submit: Igor Sheludko <[email protected]>
Reviewed-by: Jakob Linke <[email protected]>
Cr-Commit-Position: refs/heads/main@{#110759}
---
diff --git a/src/objects/map-updater.cc b/src/objects/map-updater.cc
index d62c947..f143735 100644
--- a/src/objects/map-updater.cc
+++ b/src/objects/map-updater.cc
@@ -385,8 +385,9 @@
   }
 
   if (root_map->prototype() != old_map->prototype()) {
-    auto maybe_transition = TransitionsAccessor::GetPrototypeTransition(
-        isolate, root_map, old_map->prototype());
+    auto maybe_transition =
+        TransitionsAccessor(isolate, root_map, IsConcurrent(cmode))
+            .GetPrototypeTransition(old_map->prototype());
     if (!maybe_transition) {
       return {};
     }
diff --git a/src/objects/transitions-inl.h b/src/objects/transitions-inl.h
index af50967..b694790 100644
--- a/src/objects/transitions-inl.h
+++ b/src/objects/transitions-inl.h
@@ -400,6 +400,14 @@
   return MaybeHandle<Map>(result, isolate);
 }
 
+// static
+std::optional<Tagged<Map>> TransitionsAccessor::GetPrototypeTransition(
+    Isolate* isolate, Tagged<Map> map, Tagged<Object> prototype) {
+  // This helper is supposed to be used only from the main thread.
+  DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
+  return TransitionsAccessor(isolate, map).GetPrototypeTransition(prototype);
+}
+
 // TODO(375937549): Convert to uint32_t.
 int TransitionArray::number_of_transitions() const {
   if (ulength().value() < kFirstIndex) return 0;
diff --git a/src/objects/transitions.cc b/src/objects/transitions.cc
index bcadaa3..f20dde6 100644
--- a/src/objects/transitions.cc
+++ b/src/objects/transitions.cc
@@ -434,8 +434,8 @@
 
   const uint32_t header = TransitionArray::kProtoTransitionHeaderSize;
 
-  DirectHandle<WeakFixedArray> cache(GetPrototypeTransitions(isolate, *map),
-                                     isolate);
+  DirectHandle<WeakFixedArray> cache(
+      TransitionsAccessor(isolate, *map).GetPrototypeTransitions(), isolate);
   const uint32_t cache_len = cache->ulength().value();
   const uint32_t capacity = cache_len >= header ? cache_len - header : 0;
   const uint32_t transitions =
@@ -476,11 +476,13 @@
   return true;
 }
 
-// static
 std::optional<Tagged<Map>> TransitionsAccessor::GetPrototypeTransition(
-    Isolate* isolate, Tagged<Map> map, Tagged<Object> prototype) {
+    Tagged<Object> prototype) {
   DisallowGarbageCollection no_gc;
-  Tagged<WeakFixedArray> cache = GetPrototypeTransitions(isolate, map);
+  if (encoding() != kFullTransitionArray) return {};
+  base::MutexGuardIf guard(isolate_->full_transition_array_access(),
+                           concurrent_access_);
+  Tagged<WeakFixedArray> cache = GetPrototypeTransitions();
   const uint32_t length = TransitionArray::NumberOfPrototypeTransitions(cache);
   for (uint32_t i = 0; i < length; i++) {
     Tagged<MaybeObject> target =
@@ -497,19 +499,11 @@
   return {};
 }
 
-// static
-Tagged<WeakFixedArray> TransitionsAccessor::GetPrototypeTransitions(
-    Isolate* isolate, Tagged<Map> map) {
-  Tagged<MaybeObject> raw_transitions = map->raw_transitions(kAcquireLoad);
-  if (GetEncoding(isolate, raw_transitions) != kFullTransitionArray) {
-    return ReadOnlyRoots(isolate).empty_weak_fixed_array();
+Tagged<WeakFixedArray> TransitionsAccessor::GetPrototypeTransitions() {
+  if (!HasPrototypeTransitions()) {
+    return ReadOnlyRoots(isolate_).empty_weak_fixed_array();
   }
-  Tagged<TransitionArray> transition_array =
-      GetTransitionArray(isolate, raw_transitions);
-  if (!transition_array->HasPrototypeTransitions()) {
-    return ReadOnlyRoots(isolate).empty_weak_fixed_array();
-  }
-  return transition_array->GetPrototypeTransitions();
+  return transitions()->GetPrototypeTransitions();
 }
 
 // static
diff --git a/src/objects/transitions.h b/src/objects/transitions.h
index 408bcaf..d7e948e 100644
--- a/src/objects/transitions.h
+++ b/src/objects/transitions.h
@@ -185,8 +185,13 @@
   static bool PutPrototypeTransition(Isolate* isolate, DirectHandle<Map>,
                                      DirectHandle<Object> prototype,
                                      DirectHandle<Map> target_map);
-  static std::optional<Tagged<Map>> GetPrototypeTransition(
+
+  std::optional<Tagged<Map>> GetPrototypeTransition(Tagged<Object> prototype);
+  // Convenient helper for calling from the main thread, for other cases
+  // use the instance method above.
+  static inline std::optional<Tagged<Map>> GetPrototypeTransition(
       Isolate* isolate, Tagged<Map> map, Tagged<Object> prototype);
+
   bool HasPrototypeTransitions();
 
   // During the first-time Map::Update and Map::TryUpdate, the migration target
@@ -267,8 +272,7 @@
   static void SetPrototypeTransitions(
       Isolate* isolate, DirectHandle<Map> map,
       DirectHandle<WeakFixedArray> proto_transitions);
-  static Tagged<WeakFixedArray> GetPrototypeTransitions(Isolate* isolate,
-                                                        Tagged<Map> map);
+  Tagged<WeakFixedArray> GetPrototypeTransitions();
 
   static void InsertHelper(Isolate* isolate, DirectHandle<Map> map,
                            DirectHandle<Name> name, DirectHandle<Map> target,
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.