Skip to content

Commit 2b8a06b

Browse files
committed
deps: backport 0d01728 from v8's upstream
Original commit message: [objects] do not visit ArrayBuffer's backing store ArrayBuffer's backing store is a pointer to external heap, and can't be treated as a heap object. Doing so will result in crashes, when the backing store is unaligned. See: nodejs#2791 BUG=chromium:530531 [email protected] LOG=N Review URL: https://codereview.chromium.org/1327403002 Cr-Commit-Position: refs/heads/master@{nodejs#30771} Fix: nodejs#2791 PR-URL: nodejs#2912 Reviewed-By: Jeremiah Senkpiel <[email protected]> Reviewed-By: Trevor Norris <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]>
1 parent 5f6579d commit 2b8a06b

File tree

7 files changed

+109
-12
lines changed

7 files changed

+109
-12
lines changed

deps/v8/src/heap/mark-compact.cc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2782,6 +2782,28 @@ void MarkCompactCollector::MigrateObjectMixed(HeapObject* dst, HeapObject* src,
27822782
Address base_pointer_slot =
27832783
dst->address() + FixedTypedArrayBase::kBasePointerOffset;
27842784
RecordMigratedSlot(Memory::Object_at(base_pointer_slot), base_pointer_slot);
2785+
} else if (src->IsJSArrayBuffer()) {
2786+
heap()->MoveBlock(dst->address(), src->address(), size);
2787+
2788+
// Visit inherited JSObject properties and byte length of ArrayBuffer
2789+
Address regular_slot =
2790+
dst->address() + JSArrayBuffer::BodyDescriptor::kStartOffset;
2791+
Address regular_slots_end =
2792+
dst->address() + JSArrayBuffer::kByteLengthOffset + kPointerSize;
2793+
while (regular_slot < regular_slots_end) {
2794+
RecordMigratedSlot(Memory::Object_at(regular_slot), regular_slot);
2795+
regular_slot += kPointerSize;
2796+
}
2797+
2798+
// Skip backing store and visit just internal fields
2799+
Address internal_field_slot = dst->address() + JSArrayBuffer::kSize;
2800+
Address internal_fields_end =
2801+
dst->address() + JSArrayBuffer::kSizeWithInternalFields;
2802+
while (internal_field_slot < internal_fields_end) {
2803+
RecordMigratedSlot(Memory::Object_at(internal_field_slot),
2804+
internal_field_slot);
2805+
internal_field_slot += kPointerSize;
2806+
}
27852807
} else if (FLAG_unbox_double_fields) {
27862808
Address dst_addr = dst->address();
27872809
Address src_addr = src->address();
@@ -3206,6 +3228,12 @@ bool MarkCompactCollector::IsSlotInLiveObject(Address slot) {
32063228
if (object->IsFixedTypedArrayBase()) {
32073229
return static_cast<int>(slot - object->address()) ==
32083230
FixedTypedArrayBase::kBasePointerOffset;
3231+
} else if (object->IsJSArrayBuffer()) {
3232+
int off = static_cast<int>(slot - object->address());
3233+
return (off >= JSArrayBuffer::BodyDescriptor::kStartOffset &&
3234+
off <= JSArrayBuffer::kByteLengthOffset) ||
3235+
(off >= JSArrayBuffer::kSize &&
3236+
off < JSArrayBuffer::kSizeWithInternalFields);
32093237
} else if (FLAG_unbox_double_fields) {
32103238
// Filter out slots that happen to point to unboxed double fields.
32113239
LayoutDescriptorHelper helper(object->map());

deps/v8/src/heap/objects-visiting-inl.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,8 @@ int StaticNewSpaceVisitor<StaticVisitor>::VisitJSArrayBuffer(
8181
Map* map, HeapObject* object) {
8282
Heap* heap = map->GetHeap();
8383

84-
VisitPointers(
85-
heap,
86-
HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset),
87-
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
84+
JSArrayBuffer::JSArrayBufferIterateBody<
85+
StaticNewSpaceVisitor<StaticVisitor> >(heap, object);
8886
if (!JSArrayBuffer::cast(object)->is_external()) {
8987
heap->RegisterLiveArrayBuffer(true,
9088
JSArrayBuffer::cast(object)->backing_store());
@@ -503,10 +501,7 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSArrayBuffer(
503501
Map* map, HeapObject* object) {
504502
Heap* heap = map->GetHeap();
505503

506-
StaticVisitor::VisitPointers(
507-
heap,
508-
HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset),
509-
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
504+
JSArrayBuffer::JSArrayBufferIterateBody<StaticVisitor>(heap, object);
510505
if (!JSArrayBuffer::cast(object)->is_external()) {
511506
heap->RegisterLiveArrayBuffer(false,
512507
JSArrayBuffer::cast(object)->backing_store());

deps/v8/src/heap/store-buffer.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,17 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback) {
503503
obj_address + FixedTypedArrayBase::kBasePointerOffset,
504504
obj_address + FixedTypedArrayBase::kHeaderSize,
505505
slot_callback);
506+
} else if (heap_object->IsJSArrayBuffer()) {
507+
FindPointersToNewSpaceInRegion(
508+
obj_address +
509+
JSArrayBuffer::BodyDescriptor::kStartOffset,
510+
obj_address + JSArrayBuffer::kByteLengthOffset +
511+
kPointerSize,
512+
slot_callback);
513+
FindPointersToNewSpaceInRegion(
514+
obj_address + JSArrayBuffer::kSize,
515+
obj_address + JSArrayBuffer::kSizeWithInternalFields,
516+
slot_callback);
506517
} else if (FLAG_unbox_double_fields) {
507518
LayoutDescriptorHelper helper(heap_object->map());
508519
DCHECK(!helper.all_fields_tagged());

deps/v8/src/objects-inl.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,8 @@ HeapObjectContents HeapObject::ContentType() {
15031503
} else if (type >= FIRST_FIXED_TYPED_ARRAY_TYPE &&
15041504
type <= LAST_FIXED_TYPED_ARRAY_TYPE) {
15051505
return HeapObjectContents::kMixedValues;
1506+
} else if (type == JS_ARRAY_BUFFER_TYPE) {
1507+
return HeapObjectContents::kMixedValues;
15061508
} else if (type <= LAST_DATA_TYPE) {
15071509
// TODO(jochen): Why do we claim that Code and Map contain only raw values?
15081510
return HeapObjectContents::kRawValues;
@@ -6091,6 +6093,32 @@ void JSArrayBuffer::set_is_shared(bool value) {
60916093
}
60926094

60936095

6096+
// static
6097+
template <typename StaticVisitor>
6098+
void JSArrayBuffer::JSArrayBufferIterateBody(Heap* heap, HeapObject* obj) {
6099+
StaticVisitor::VisitPointers(
6100+
heap,
6101+
HeapObject::RawField(obj, JSArrayBuffer::BodyDescriptor::kStartOffset),
6102+
HeapObject::RawField(obj,
6103+
JSArrayBuffer::kByteLengthOffset + kPointerSize));
6104+
StaticVisitor::VisitPointers(
6105+
heap, HeapObject::RawField(obj, JSArrayBuffer::kSize),
6106+
HeapObject::RawField(obj, JSArrayBuffer::kSizeWithInternalFields));
6107+
}
6108+
6109+
6110+
void JSArrayBuffer::JSArrayBufferIterateBody(HeapObject* obj,
6111+
ObjectVisitor* v) {
6112+
v->VisitPointers(
6113+
HeapObject::RawField(obj, JSArrayBuffer::BodyDescriptor::kStartOffset),
6114+
HeapObject::RawField(obj,
6115+
JSArrayBuffer::kByteLengthOffset + kPointerSize));
6116+
v->VisitPointers(
6117+
HeapObject::RawField(obj, JSArrayBuffer::kSize),
6118+
HeapObject::RawField(obj, JSArrayBuffer::kSizeWithInternalFields));
6119+
}
6120+
6121+
60946122
Object* JSArrayBufferView::byte_offset() const {
60956123
if (WasNeutered()) return Smi::FromInt(0);
60966124
return Object::cast(READ_FIELD(this, kByteOffsetOffset));

deps/v8/src/objects.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1420,7 +1420,6 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
14201420
case JS_VALUE_TYPE:
14211421
case JS_DATE_TYPE:
14221422
case JS_ARRAY_TYPE:
1423-
case JS_ARRAY_BUFFER_TYPE:
14241423
case JS_TYPED_ARRAY_TYPE:
14251424
case JS_DATA_VIEW_TYPE:
14261425
case JS_SET_TYPE:
@@ -1436,6 +1435,9 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
14361435
case JS_MESSAGE_OBJECT_TYPE:
14371436
JSObject::BodyDescriptor::IterateBody(this, object_size, v);
14381437
break;
1438+
case JS_ARRAY_BUFFER_TYPE:
1439+
JSArrayBuffer::JSArrayBufferIterateBody(this, v);
1440+
break;
14391441
case JS_FUNCTION_TYPE:
14401442
reinterpret_cast<JSFunction*>(this)
14411443
->JSFunctionIterateBody(object_size, v);

deps/v8/src/objects.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10014,9 +10014,14 @@ class JSArrayBuffer: public JSObject {
1001410014
DECLARE_PRINTER(JSArrayBuffer)
1001510015
DECLARE_VERIFIER(JSArrayBuffer)
1001610016

10017-
static const int kBackingStoreOffset = JSObject::kHeaderSize;
10018-
static const int kByteLengthOffset = kBackingStoreOffset + kPointerSize;
10019-
static const int kBitFieldSlot = kByteLengthOffset + kPointerSize;
10017+
static const int kByteLengthOffset = JSObject::kHeaderSize;
10018+
10019+
// NOTE: GC will visit objects fields:
10020+
// 1. From JSObject::BodyDescriptor::kStartOffset to kByteLengthOffset +
10021+
// kPointerSize
10022+
// 2. From start of the internal fields and up to the end of them
10023+
static const int kBackingStoreOffset = kByteLengthOffset + kPointerSize;
10024+
static const int kBitFieldSlot = kBackingStoreOffset + kPointerSize;
1002010025
#if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT
1002110026
static const int kBitFieldOffset = kBitFieldSlot;
1002210027
#else
@@ -10027,6 +10032,12 @@ class JSArrayBuffer: public JSObject {
1002710032
static const int kSizeWithInternalFields =
1002810033
kSize + v8::ArrayBuffer::kInternalFieldCount * kPointerSize;
1002910034

10035+
template <typename StaticVisitor>
10036+
static inline void JSArrayBufferIterateBody(Heap* heap, HeapObject* obj);
10037+
10038+
static inline void JSArrayBufferIterateBody(HeapObject* obj,
10039+
ObjectVisitor* v);
10040+
1003010041
class IsExternal : public BitField<bool, 1, 1> {};
1003110042
class IsNeuterable : public BitField<bool, 2, 1> {};
1003210043
class WasNeutered : public BitField<bool, 3, 1> {};

deps/v8/test/cctest/test-api.cc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14169,6 +14169,28 @@ THREADED_TEST(DataView) {
1416914169
}
1417014170

1417114171

14172+
THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
14173+
LocalContext env;
14174+
v8::Isolate* isolate = env->GetIsolate();
14175+
v8::HandleScope handle_scope(isolate);
14176+
14177+
// Make sure the pointer looks like a heap object
14178+
uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
14179+
14180+
// Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
14181+
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
14182+
14183+
// Should not crash
14184+
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
14185+
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
14186+
CcTest::heap()->CollectAllGarbage();
14187+
CcTest::heap()->CollectAllGarbage();
14188+
14189+
// Should not move the pointer
14190+
CHECK_EQ(ab->GetContents().Data(), store_ptr);
14191+
}
14192+
14193+
1417214194
THREADED_TEST(SharedUint8Array) {
1417314195
i::FLAG_harmony_sharedarraybuffer = true;
1417414196
TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array,

0 commit comments

Comments
 (0)