Browse Source

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: https://github.com/nodejs/node/issues/2791

    BUG=chromium:530531
    R=mlippautz@chromium.org
    LOG=N

    Review URL: https://codereview.chromium.org/1327403002

    Cr-Commit-Position: refs/heads/master@{#30771}

Ref: https://github.com/nodejs/node/issues/2791
Ref: https://github.com/nodejs/node/pull/2912
PR-URL: https://github.com/nodejs/node/pull/3351
Reviewed-By: indutny - Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: bnoordhuis - Ben Noordhuis <info@bnoordhuis.nl>
v5.x
Fedor Indutny 9 years ago
committed by Ali Ijaz Sheikh
parent
commit
972a0c8515
  1. 28
      deps/v8/src/heap/mark-compact.cc
  2. 11
      deps/v8/src/heap/objects-visiting-inl.h
  3. 4
      deps/v8/src/heap/objects-visiting.cc
  4. 11
      deps/v8/src/heap/store-buffer.cc
  5. 28
      deps/v8/src/objects-inl.h
  6. 17
      deps/v8/src/objects.h
  7. 22
      deps/v8/test/cctest/test-api.cc

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

@ -2755,6 +2755,28 @@ void MarkCompactCollector::MigrateObjectMixed(HeapObject* dst, HeapObject* src,
Address base_pointer_slot = Address base_pointer_slot =
dst->address() + FixedTypedArrayBase::kBasePointerOffset; dst->address() + FixedTypedArrayBase::kBasePointerOffset;
RecordMigratedSlot(Memory::Object_at(base_pointer_slot), base_pointer_slot); RecordMigratedSlot(Memory::Object_at(base_pointer_slot), base_pointer_slot);
} else if (src->IsJSArrayBuffer()) {
heap()->MoveBlock(dst->address(), src->address(), size);
// Visit inherited JSObject properties and byte length of ArrayBuffer
Address regular_slot =
dst->address() + JSArrayBuffer::BodyDescriptor::kStartOffset;
Address regular_slots_end =
dst->address() + JSArrayBuffer::kByteLengthOffset + kPointerSize;
while (regular_slot < regular_slots_end) {
RecordMigratedSlot(Memory::Object_at(regular_slot), regular_slot);
regular_slot += kPointerSize;
}
// Skip backing store and visit just internal fields
Address internal_field_slot = dst->address() + JSArrayBuffer::kSize;
Address internal_fields_end =
dst->address() + JSArrayBuffer::kSizeWithInternalFields;
while (internal_field_slot < internal_fields_end) {
RecordMigratedSlot(Memory::Object_at(internal_field_slot),
internal_field_slot);
internal_field_slot += kPointerSize;
}
} else if (FLAG_unbox_double_fields) { } else if (FLAG_unbox_double_fields) {
Address dst_addr = dst->address(); Address dst_addr = dst->address();
Address src_addr = src->address(); Address src_addr = src->address();
@ -3178,6 +3200,12 @@ bool MarkCompactCollector::IsSlotInLiveObject(Address slot) {
if (object->IsFixedTypedArrayBase()) { if (object->IsFixedTypedArrayBase()) {
return static_cast<int>(slot - object->address()) == return static_cast<int>(slot - object->address()) ==
FixedTypedArrayBase::kBasePointerOffset; FixedTypedArrayBase::kBasePointerOffset;
} else if (object->IsJSArrayBuffer()) {
int off = static_cast<int>(slot - object->address());
return (off >= JSArrayBuffer::BodyDescriptor::kStartOffset &&
off <= JSArrayBuffer::kByteLengthOffset) ||
(off >= JSArrayBuffer::kSize &&
off < JSArrayBuffer::kSizeWithInternalFields);
} else if (FLAG_unbox_double_fields) { } else if (FLAG_unbox_double_fields) {
// Filter out slots that happen to point to unboxed double fields. // Filter out slots that happen to point to unboxed double fields.
LayoutDescriptorHelper helper(object->map()); LayoutDescriptorHelper helper(object->map());

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

@ -91,10 +91,8 @@ int StaticNewSpaceVisitor<StaticVisitor>::VisitJSArrayBuffer(
Map* map, HeapObject* object) { Map* map, HeapObject* object) {
Heap* heap = map->GetHeap(); Heap* heap = map->GetHeap();
VisitPointers( JSArrayBuffer::JSArrayBufferIterateBody<
heap, object, StaticNewSpaceVisitor<StaticVisitor> >(heap, object);
HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset),
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
if (!JSArrayBuffer::cast(object)->is_external()) { if (!JSArrayBuffer::cast(object)->is_external()) {
heap->RegisterLiveArrayBuffer(true, heap->RegisterLiveArrayBuffer(true,
JSArrayBuffer::cast(object)->backing_store()); JSArrayBuffer::cast(object)->backing_store());
@ -517,10 +515,7 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSArrayBuffer(
Map* map, HeapObject* object) { Map* map, HeapObject* object) {
Heap* heap = map->GetHeap(); Heap* heap = map->GetHeap();
StaticVisitor::VisitPointers( JSArrayBuffer::JSArrayBufferIterateBody<StaticVisitor>(heap, object);
heap, object,
HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset),
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
if (!JSArrayBuffer::cast(object)->is_external()) { if (!JSArrayBuffer::cast(object)->is_external()) {
heap->RegisterLiveArrayBuffer(false, heap->RegisterLiveArrayBuffer(false,
JSArrayBuffer::cast(object)->backing_store()); JSArrayBuffer::cast(object)->backing_store());

4
deps/v8/src/heap/objects-visiting.cc

@ -219,7 +219,6 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case JS_VALUE_TYPE: case JS_VALUE_TYPE:
case JS_DATE_TYPE: case JS_DATE_TYPE:
case JS_ARRAY_TYPE: case JS_ARRAY_TYPE:
case JS_ARRAY_BUFFER_TYPE:
case JS_TYPED_ARRAY_TYPE: case JS_TYPED_ARRAY_TYPE:
case JS_DATA_VIEW_TYPE: case JS_DATA_VIEW_TYPE:
case JS_SET_TYPE: case JS_SET_TYPE:
@ -235,6 +234,9 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
case JS_MESSAGE_OBJECT_TYPE: case JS_MESSAGE_OBJECT_TYPE:
JSObject::BodyDescriptor::IterateBody(this, object_size, v); JSObject::BodyDescriptor::IterateBody(this, object_size, v);
break; break;
case JS_ARRAY_BUFFER_TYPE:
JSArrayBuffer::JSArrayBufferIterateBody(this, v);
break;
case JS_FUNCTION_TYPE: case JS_FUNCTION_TYPE:
reinterpret_cast<JSFunction*>(this) reinterpret_cast<JSFunction*>(this)
->JSFunctionIterateBody(object_size, v); ->JSFunctionIterateBody(object_size, v);

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

@ -492,6 +492,17 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback) {
obj_address + FixedTypedArrayBase::kBasePointerOffset, obj_address + FixedTypedArrayBase::kBasePointerOffset,
obj_address + FixedTypedArrayBase::kHeaderSize, obj_address + FixedTypedArrayBase::kHeaderSize,
slot_callback); slot_callback);
} else if (heap_object->IsJSArrayBuffer()) {
FindPointersToNewSpaceInRegion(
obj_address +
JSArrayBuffer::BodyDescriptor::kStartOffset,
obj_address + JSArrayBuffer::kByteLengthOffset +
kPointerSize,
slot_callback);
FindPointersToNewSpaceInRegion(
obj_address + JSArrayBuffer::kSize,
obj_address + JSArrayBuffer::kSizeWithInternalFields,
slot_callback);
} else if (FLAG_unbox_double_fields) { } else if (FLAG_unbox_double_fields) {
LayoutDescriptorHelper helper(heap_object->map()); LayoutDescriptorHelper helper(heap_object->map());
DCHECK(!helper.all_fields_tagged()); DCHECK(!helper.all_fields_tagged());

28
deps/v8/src/objects-inl.h

@ -1483,6 +1483,8 @@ HeapObjectContents HeapObject::ContentType() {
} else if (type >= FIRST_FIXED_TYPED_ARRAY_TYPE && } else if (type >= FIRST_FIXED_TYPED_ARRAY_TYPE &&
type <= LAST_FIXED_TYPED_ARRAY_TYPE) { type <= LAST_FIXED_TYPED_ARRAY_TYPE) {
return HeapObjectContents::kMixedValues; return HeapObjectContents::kMixedValues;
} else if (type == JS_ARRAY_BUFFER_TYPE) {
return HeapObjectContents::kMixedValues;
} else if (type <= LAST_DATA_TYPE) { } else if (type <= LAST_DATA_TYPE) {
// TODO(jochen): Why do we claim that Code and Map contain only raw values? // TODO(jochen): Why do we claim that Code and Map contain only raw values?
return HeapObjectContents::kRawValues; return HeapObjectContents::kRawValues;
@ -6516,6 +6518,32 @@ void JSArrayBuffer::set_is_shared(bool value) {
} }
// static
template <typename StaticVisitor>
void JSArrayBuffer::JSArrayBufferIterateBody(Heap* heap, HeapObject* obj) {
StaticVisitor::VisitPointers(
heap, obj,
HeapObject::RawField(obj, JSArrayBuffer::BodyDescriptor::kStartOffset),
HeapObject::RawField(obj,
JSArrayBuffer::kByteLengthOffset + kPointerSize));
StaticVisitor::VisitPointers(
heap, obj, HeapObject::RawField(obj, JSArrayBuffer::kSize),
HeapObject::RawField(obj, JSArrayBuffer::kSizeWithInternalFields));
}
void JSArrayBuffer::JSArrayBufferIterateBody(HeapObject* obj,
ObjectVisitor* v) {
v->VisitPointers(
HeapObject::RawField(obj, JSArrayBuffer::BodyDescriptor::kStartOffset),
HeapObject::RawField(obj,
JSArrayBuffer::kByteLengthOffset + kPointerSize));
v->VisitPointers(
HeapObject::RawField(obj, JSArrayBuffer::kSize),
HeapObject::RawField(obj, JSArrayBuffer::kSizeWithInternalFields));
}
Object* JSArrayBufferView::byte_offset() const { Object* JSArrayBufferView::byte_offset() const {
if (WasNeutered()) return Smi::FromInt(0); if (WasNeutered()) return Smi::FromInt(0);
return Object::cast(READ_FIELD(this, kByteOffsetOffset)); return Object::cast(READ_FIELD(this, kByteOffsetOffset));

17
deps/v8/src/objects.h

@ -9451,9 +9451,14 @@ class JSArrayBuffer: public JSObject {
DECLARE_PRINTER(JSArrayBuffer) DECLARE_PRINTER(JSArrayBuffer)
DECLARE_VERIFIER(JSArrayBuffer) DECLARE_VERIFIER(JSArrayBuffer)
static const int kBackingStoreOffset = JSObject::kHeaderSize; static const int kByteLengthOffset = JSObject::kHeaderSize;
static const int kByteLengthOffset = kBackingStoreOffset + kPointerSize;
static const int kBitFieldSlot = kByteLengthOffset + kPointerSize; // NOTE: GC will visit objects fields:
// 1. From JSObject::BodyDescriptor::kStartOffset to kByteLengthOffset +
// kPointerSize
// 2. From start of the internal fields and up to the end of them
static const int kBackingStoreOffset = kByteLengthOffset + kPointerSize;
static const int kBitFieldSlot = kBackingStoreOffset + kPointerSize;
#if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT #if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT
static const int kBitFieldOffset = kBitFieldSlot; static const int kBitFieldOffset = kBitFieldSlot;
#else #else
@ -9464,6 +9469,12 @@ class JSArrayBuffer: public JSObject {
static const int kSizeWithInternalFields = static const int kSizeWithInternalFields =
kSize + v8::ArrayBuffer::kInternalFieldCount * kPointerSize; kSize + v8::ArrayBuffer::kInternalFieldCount * kPointerSize;
template <typename StaticVisitor>
static inline void JSArrayBufferIterateBody(Heap* heap, HeapObject* obj);
static inline void JSArrayBufferIterateBody(HeapObject* obj,
ObjectVisitor* v);
class IsExternal : public BitField<bool, 1, 1> {}; class IsExternal : public BitField<bool, 1, 1> {};
class IsNeuterable : public BitField<bool, 2, 1> {}; class IsNeuterable : public BitField<bool, 2, 1> {};
class WasNeutered : public BitField<bool, 3, 1> {}; class WasNeutered : public BitField<bool, 3, 1> {};

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

@ -14220,6 +14220,28 @@ THREADED_TEST(DataView) {
} }
THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope handle_scope(isolate);
// Make sure the pointer looks like a heap object
uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
// Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
// Should not crash
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
CcTest::heap()->CollectAllGarbage();
CcTest::heap()->CollectAllGarbage();
// Should not move the pointer
CHECK_EQ(ab->GetContents().Data(), store_ptr);
}
THREADED_TEST(SharedUint8Array) { THREADED_TEST(SharedUint8Array) {
i::FLAG_harmony_sharedarraybuffer = true; i::FLAG_harmony_sharedarraybuffer = true;
TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array, TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::FixedUint8Array,

Loading…
Cancel
Save