Chrome · V8
CVE-2025-13721
Race in V8
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
src/objects/js-objects-inl.h
Patch
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<int, v8::internal::ConcurrentMarkingVisitor>::VisitJSObjectSubclass<v8::internal::JSTypedArray, v8::internal::JSTypedArray::BodyDescriptor>(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<v8::internal::CodeFlushMode, int>, 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
References
On This Page