Chrome · V8 › Maps
CVE-2026-118320
Memory Corruption in V8 (Maps)
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifsrc/objects/map-updater.cc |
modified | |
forsrc/objects/transitions.cc |
modified |
Files Changed
src/objects/map-updater.ccsrc/objects/transitions.ccsrc/objects/transitions.hsrc/objects/transitions-inl.h
Patch
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.
References
On This Page