diff options
author | Fedor Indutny <fedor@indutny.com> | 2015-09-16 10:57:30 -0700 |
---|---|---|
committer | Fedor Indutny <fedor@indutny.com> | 2015-09-16 17:32:47 -0700 |
commit | 2b8a06b32347ac16eaac820227a4672dbe05c134 (patch) | |
tree | 996414bad8047049a4b108ca4e38482fe34dc30c /deps | |
parent | 5f6579d3661b5a55ccefdcbc4e24d4b1ebea6588 (diff) | |
download | node-new-2b8a06b32347ac16eaac820227a4672dbe05c134.tar.gz |
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}
Fix: https://github.com/nodejs/node/issues/2791
PR-URL: https://github.com/nodejs/node/pull/2912
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps')
-rw-r--r-- | deps/v8/src/heap/mark-compact.cc | 28 | ||||
-rw-r--r-- | deps/v8/src/heap/objects-visiting-inl.h | 11 | ||||
-rw-r--r-- | deps/v8/src/heap/store-buffer.cc | 11 | ||||
-rw-r--r-- | deps/v8/src/objects-inl.h | 28 | ||||
-rw-r--r-- | deps/v8/src/objects.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/objects.h | 17 | ||||
-rw-r--r-- | deps/v8/test/cctest/test-api.cc | 22 |
7 files changed, 109 insertions, 12 deletions
diff --git a/deps/v8/src/heap/mark-compact.cc b/deps/v8/src/heap/mark-compact.cc index 508d49913f..45f5af3f4d 100644 --- a/deps/v8/src/heap/mark-compact.cc +++ b/deps/v8/src/heap/mark-compact.cc @@ -2782,6 +2782,28 @@ void MarkCompactCollector::MigrateObjectMixed(HeapObject* dst, HeapObject* src, Address base_pointer_slot = dst->address() + FixedTypedArrayBase::kBasePointerOffset; 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) { Address dst_addr = dst->address(); Address src_addr = src->address(); @@ -3206,6 +3228,12 @@ bool MarkCompactCollector::IsSlotInLiveObject(Address slot) { if (object->IsFixedTypedArrayBase()) { return static_cast<int>(slot - object->address()) == 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) { // Filter out slots that happen to point to unboxed double fields. LayoutDescriptorHelper helper(object->map()); diff --git a/deps/v8/src/heap/objects-visiting-inl.h b/deps/v8/src/heap/objects-visiting-inl.h index 0103054822..bdb801a1f9 100644 --- a/deps/v8/src/heap/objects-visiting-inl.h +++ b/deps/v8/src/heap/objects-visiting-inl.h @@ -81,10 +81,8 @@ int StaticNewSpaceVisitor<StaticVisitor>::VisitJSArrayBuffer( Map* map, HeapObject* object) { Heap* heap = map->GetHeap(); - VisitPointers( - heap, - HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset), - HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields)); + JSArrayBuffer::JSArrayBufferIterateBody< + StaticNewSpaceVisitor<StaticVisitor> >(heap, object); if (!JSArrayBuffer::cast(object)->is_external()) { heap->RegisterLiveArrayBuffer(true, JSArrayBuffer::cast(object)->backing_store()); @@ -503,10 +501,7 @@ void StaticMarkingVisitor<StaticVisitor>::VisitJSArrayBuffer( Map* map, HeapObject* object) { Heap* heap = map->GetHeap(); - StaticVisitor::VisitPointers( - heap, - HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset), - HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields)); + JSArrayBuffer::JSArrayBufferIterateBody<StaticVisitor>(heap, object); if (!JSArrayBuffer::cast(object)->is_external()) { heap->RegisterLiveArrayBuffer(false, JSArrayBuffer::cast(object)->backing_store()); diff --git a/deps/v8/src/heap/store-buffer.cc b/deps/v8/src/heap/store-buffer.cc index 03f587f215..efdd0b4708 100644 --- a/deps/v8/src/heap/store-buffer.cc +++ b/deps/v8/src/heap/store-buffer.cc @@ -503,6 +503,17 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback) { obj_address + FixedTypedArrayBase::kBasePointerOffset, obj_address + FixedTypedArrayBase::kHeaderSize, 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) { LayoutDescriptorHelper helper(heap_object->map()); DCHECK(!helper.all_fields_tagged()); diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index fbc2c4ee76..3caf52bff4 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -1503,6 +1503,8 @@ HeapObjectContents HeapObject::ContentType() { } else if (type >= FIRST_FIXED_TYPED_ARRAY_TYPE && type <= LAST_FIXED_TYPED_ARRAY_TYPE) { return HeapObjectContents::kMixedValues; + } else if (type == JS_ARRAY_BUFFER_TYPE) { + return HeapObjectContents::kMixedValues; } else if (type <= LAST_DATA_TYPE) { // TODO(jochen): Why do we claim that Code and Map contain only raw values? return HeapObjectContents::kRawValues; @@ -6091,6 +6093,32 @@ void JSArrayBuffer::set_is_shared(bool value) { } +// static +template <typename StaticVisitor> +void JSArrayBuffer::JSArrayBufferIterateBody(Heap* heap, HeapObject* obj) { + StaticVisitor::VisitPointers( + heap, + HeapObject::RawField(obj, JSArrayBuffer::BodyDescriptor::kStartOffset), + HeapObject::RawField(obj, + JSArrayBuffer::kByteLengthOffset + kPointerSize)); + StaticVisitor::VisitPointers( + heap, 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 { if (WasNeutered()) return Smi::FromInt(0); return Object::cast(READ_FIELD(this, kByteOffsetOffset)); diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 2b042fda8e..5c863855f8 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -1420,7 +1420,6 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case JS_VALUE_TYPE: case JS_DATE_TYPE: case JS_ARRAY_TYPE: - case JS_ARRAY_BUFFER_TYPE: case JS_TYPED_ARRAY_TYPE: case JS_DATA_VIEW_TYPE: case JS_SET_TYPE: @@ -1436,6 +1435,9 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case JS_MESSAGE_OBJECT_TYPE: JSObject::BodyDescriptor::IterateBody(this, object_size, v); break; + case JS_ARRAY_BUFFER_TYPE: + JSArrayBuffer::JSArrayBufferIterateBody(this, v); + break; case JS_FUNCTION_TYPE: reinterpret_cast<JSFunction*>(this) ->JSFunctionIterateBody(object_size, v); diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 7e4fcbafeb..563618ab71 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -10014,9 +10014,14 @@ class JSArrayBuffer: public JSObject { DECLARE_PRINTER(JSArrayBuffer) DECLARE_VERIFIER(JSArrayBuffer) - static const int kBackingStoreOffset = JSObject::kHeaderSize; - static const int kByteLengthOffset = kBackingStoreOffset + kPointerSize; - static const int kBitFieldSlot = kByteLengthOffset + kPointerSize; + static const int kByteLengthOffset = JSObject::kHeaderSize; + + // 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 static const int kBitFieldOffset = kBitFieldSlot; #else @@ -10027,6 +10032,12 @@ class JSArrayBuffer: public JSObject { static const int kSizeWithInternalFields = 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 IsNeuterable : public BitField<bool, 2, 1> {}; class WasNeutered : public BitField<bool, 3, 1> {}; diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index e464a67e00..ad3190a711 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -14169,6 +14169,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) { i::FLAG_harmony_sharedarraybuffer = true; TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array, |