[heap] Initialize the owner on each page after lospace allocation

The least two bits of the owner field of a Page are used to determine
whether the Page is part of a large object. If these bits are not equal
to 0x11, the page is part of a large object and needs special handling
e.g. in MemoryChunk::FromAnyPointerAddress to determine which chunk it
belongs to.

This CL fixes an issue in which the store buffer overflows after
a large object space allocation but before the object has been fully
initialized. Store buffer overflow handling attempts to look up the
chunk of a page, but fails to do so correctly since the page's owner
field has not yet been initialized.

This CL ensures that the owner field of all pages belonging to a large
object allocation are initialized to a value that is interpreted
correctly.

BUG=chromium:672041

Committed: https://crrev.com/9b6808bfb5366beebe3af30a06f9851edb2039d4
Review-Url: https://codereview.chromium.org/2565713002
Cr-Original-Commit-Position: refs/heads/master@{#41641}
Cr-Commit-Position: refs/heads/master@{#41687}
This commit is contained in:
jgruber 2016-12-13 22:45:22 -08:00 committed by Commit bot
parent 825dd8a904
commit bbf3c697ae
4 changed files with 39 additions and 3 deletions

View File

@ -594,6 +594,17 @@ LargePage* LargePage::Initialize(Heap* heap, MemoryChunk* chunk,
FATAL("Code page is too large.");
}
heap->incremental_marking()->SetOldSpacePageFlags(chunk);
MSAN_ALLOCATED_UNINITIALIZED_MEMORY(chunk->area_start(), chunk->area_size());
// Initialize the owner field for each contained page (except the first, which
// is initialized by MemoryChunk::Initialize).
for (Address addr = chunk->address() + Page::kPageSize + Page::kOwnerOffset;
addr < chunk->area_end(); addr += Page::kPageSize) {
// Clear out kPageHeaderTag.
Memory::Address_at(addr) = 0;
}
return static_cast<LargePage*>(chunk);
}

View File

@ -2976,7 +2976,6 @@ AllocationResult LargeObjectSpace::AllocateRaw(int object_size,
InsertChunkMapEntries(page);
HeapObject* object = page->GetObject();
MSAN_ALLOCATED_UNINITIALIZED_MEMORY(object->address(), object_size);
if (Heap::ShouldZapGarbage()) {
// Make the object consistent so the heap can be verified in OldSpaceStep.

View File

@ -317,8 +317,11 @@ class MemoryChunk {
static const intptr_t kAlignmentMask = kAlignment - 1;
static const intptr_t kSizeOffset = 0;
static const intptr_t kFlagsOffset = kSizeOffset + kPointerSize;
static const intptr_t kFlagsOffset = kSizeOffset + kSizetSize;
static const intptr_t kAreaStartOffset = kFlagsOffset + kIntptrSize;
static const intptr_t kAreaEndOffset = kAreaStartOffset + kPointerSize;
static const intptr_t kReservationOffset = kAreaEndOffset + kPointerSize;
static const intptr_t kOwnerOffset = kReservationOffset + 2 * kPointerSize;
static const size_t kMinHeaderSize =
kSizeOffset + kSizetSize // size_t size

View File

@ -0,0 +1,23 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Trigger an infinite loop through RegExp.prototype[@@match], which results
// in unbounded growth of the results array.
// Limit the number of iterations to avoid OOM while still triggering large
// object space allocation.
const min_ptr_size = 4;
const max_regular_heap_object_size = 507136;
const num_iterations = max_regular_heap_object_size / min_ptr_size;
const RegExpPrototypeExec = RegExp.prototype.exec;
let i = 0;
RegExp.prototype.__defineGetter__("global", () => true);
RegExp.prototype.exec = function(str) {
return (i++ < num_iterations) ? RegExpPrototypeExec.call(this, str) : null;
};
"a".match();