Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactRace in v8
DescriptionRace in v8
ComponentV8
Bug ClassRace
Tracker355120682
Fix commitb8b01791845c (v8/v8) +8/-2
CISA KEVNot listed
CreditedChrome
Disclosed2025-12-02

Files Changed

  • src/objects/js-objects-inl.h
From b8b01791845cb77d5482f299310e9bfdcd012842 Mon Sep 17 00:00:00 2001
From: Nikolaos Papaspyrou <[email protected]>
Date: Tue, 21 Oct 2025 13:31:10 +0200
Subject: [PATCH] [objects] Avoid race in JSObject::GetEmbedderFieldCount

This CL fixes JSObject::GetEmbedderFieldCount, so that it only reads
the map's instance size field once. This avoids calculating an
inconsistent result, in case the map is concurrently updated.

Bug: 355120682
Change-Id: Ia6e003896998227b5b5bd88cc480b4bc1adbf9f2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7066814
Reviewed-by: Michael Lippautz <[email protected]>
Commit-Queue: Nikolaos Papaspyrou <[email protected]>
Cr-Commit-Position: refs/heads/main@{#103247}
---

diff --git a/src/objects/js-objects-inl.h b/src/objects/js-objects-inl.h
index f439860..e2d85ab 100644
--- a/src/objects/js-objects-inl.h
+++ b/src/objects/js-objects-inl.h
@@ -352,16 +352,22 @@
 
 // static
 int JSObject::GetEmbedderFieldCount(Tagged<Map> map) {
-  int instance_size = map->instance_size();
+  // We inline some code from Map::instance_size and Map::GetInObjectProperties
+  // here, to avoid reading the map's instance size field twice.
+  // See https://crbug.com/355120682.
+  int instance_size_in_words = map->instance_size_in_words();
+  int instance_size = instance_size_in_words << kTaggedSizeLog2;
   if (instance_size == kVariableSizeSentinel) return 0;
   // Embedder fields are located after the object header, whereas in-object
   // properties are located at the end of the object. We don't have to round up
   // the header size here because division by kEmbedderDataSlotSizeInTaggedSlots
   // will swallow potential padding in case of (kTaggedSize !=
   // kSystemPointerSize) anyway.
+  int in_object_properties =
+      instance_size_in_words - map->GetInObjectPropertiesStartInWords();
   return (((instance_size - GetEmbedderFieldsStartOffset(map)) >>
            kTaggedSizeLog2) -
-          map->GetInObjectProperties()) /
+          in_object_properties) /
          kEmbedderDataSlotSizeInTaggedSlots;
 }
 
Loading diff…

Original Bug Report

reported by [email protected]

cctest/test-inobject-slack-tracking/SubclassTypedArrayBuiltinNoInlineNew starts flaking

Failing test: cctest/test-inobject-slack-tracking/SubclassTypedArrayBuiltinNoInlineNew Failure link: https://cr-buildbucket.appspot.com/build/8741558669677733889 Link to Flako run: http://ci.chromium.org/b/8741554664431477521/infra Suspected commit: https://chromium-review.googlesource.com/c/v8/v8/+/5696786

Crash type: DCHECK failure

Crash state: JSObject::MayHaveEmbedderFields(map) implies UncheckedCast<JSObject>(obj)->GetEm

Error summary:

Fatal error in ../../src/objects/objects-body-descriptors-inl.h, line 109

Debug check failed: JSObject::MayHaveEmbedderFields(map) implies UncheckedCast<JSObject>(obj)->GetEmbedderFieldCount() == 0.

#FailureMessage Object: 0x16b84a738 ==== C stack trace ===============================

0   libv8_libbase.dylib                 0x0000000105f01148 v8::base::debug::StackTrace::StackTrace() + 24
1   libv8_libplatform.dylib             0x0000000105f44f28 v8::platform::(anonymous namespace)::PrintStackTrace() + 116
2   libv8_libbase.dylib                 0x0000000105ee4930 V8_Fatal(char const*, int, char const*, ...) + 352
3   libv8_libbase.dylib                 0x0000000105ee4264 v8::base::SetFatalFunction(void (*)(char const*, int, char const*)) + 0
4   libv8_for_testing.dylib             0x000000010e324434 void v8::internal::BodyDescriptorBase::IterateJSObjectBodyWithoutEmbedderFieldsImpl<v8::internal::ConcurrentMarkingVisitor>(v8::internal::Tagged<v8::internal::Map>, v8::internal::Tagged<v8::internal::HeapObject>, int, int, v8::internal::ConcurrentMarkingVisitor*) + 304
5   libv8_for_testing.dylib             0x000000010e326194 int v8::internal::HeapVisitor&lt;int, v8::internal::ConcurrentMarkingVisitor&gt;::VisitJSObjectSubclass&lt;v8::internal::JSTypedArray, v8::internal::JSTypedArray::BodyDescriptor&gt;(v8::internal::Tagged<v8::internal::Map>, v8::internal::Tagged<v8::internal::JSTypedArray>) + 136
6   libv8_for_testing.dylib             0x000000010e306870 v8::internal::ConcurrentMarking::RunMajor(v8::JobDelegate*, v8::base::EnumSet&lt;v8::internal::CodeFlushMode, int&gt;, unsigned int, bool) + 988
7   libv8_for_testing.dylib             0x000000010e366940 v8::internal::ConcurrentMarking::JobTaskMajor::Run(v8::JobDelegate*) + 480
8   libv8_libplatform.dylib             0x0000000105f43bd8 v8::platform::DefaultJobWorker::Run() + 260

Crash analysis hash: 3bdc04fbe0e20d5d823e093abdd16035

View on issue tracker