From e97daee2e5a57592631765fb9c3ca04a2dd9def4 Mon Sep 17 00:00:00 2001 From: Hannes Payer Date: Tue, 16 Jan 2018 09:22:42 +0100 Subject: [PATCH] [heap] Register executable MemoryChunks. Bug: chromium:774108,v8:6792 Change-Id: If0ff62b959b74b7be4e00b04d7a734ab95b8ecb6 Reviewed-on: https://chromium-review.googlesource.com/867040 Reviewed-by: Michael Starzinger Commit-Queue: Hannes Payer Cr-Commit-Position: refs/heads/master@{#50610} --- src/heap/heap-inl.h | 4 ++++ src/heap/spaces.cc | 13 +++++++++++-- src/heap/spaces.h | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/heap/heap-inl.h b/src/heap/heap-inl.h index 2efe47daad..3e64c64964 100644 --- a/src/heap/heap-inl.h +++ b/src/heap/heap-inl.h @@ -624,6 +624,7 @@ CodeSpaceMemoryModificationScope::CodeSpaceMemoryModificationScope(Heap* heap) LargePage* page = heap_->lo_space()->first_page(); while (page != nullptr) { if (page->IsFlagSet(MemoryChunk::IS_EXECUTABLE)) { + CHECK(heap_->memory_allocator()->IsMemoryChunkExecutable(page)); page->SetReadAndWritable(); } page = page->next_page(); @@ -638,6 +639,7 @@ CodeSpaceMemoryModificationScope::~CodeSpaceMemoryModificationScope() { LargePage* page = heap_->lo_space()->first_page(); while (page != nullptr) { if (page->IsFlagSet(MemoryChunk::IS_EXECUTABLE)) { + CHECK(heap_->memory_allocator()->IsMemoryChunkExecutable(page)); page->SetReadAndExecutable(); } page = page->next_page(); @@ -654,12 +656,14 @@ CodePageMemoryModificationScope::CodePageMemoryModificationScope( DCHECK(chunk_->owner()->identity() == CODE_SPACE || (chunk_->owner()->identity() == LO_SPACE && chunk_->IsFlagSet(MemoryChunk::IS_EXECUTABLE))); + CHECK(chunk_->heap()->memory_allocator()->IsMemoryChunkExecutable(chunk_)); chunk_->SetReadAndWritable(); } } CodePageMemoryModificationScope::~CodePageMemoryModificationScope() { if (scope_active_) { + CHECK(chunk_->heap()->memory_allocator()->IsMemoryChunkExecutable(chunk_)); chunk_->SetReadAndExecutable(); } } diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc index dd0f388725..5bbeaa892d 100644 --- a/src/heap/spaces.cc +++ b/src/heap/spaces.cc @@ -826,8 +826,13 @@ MemoryChunk* MemoryAllocator::AllocateChunk(size_t reserve_area_size, owner); } - return MemoryChunk::Initialize(heap, base, chunk_size, area_start, area_end, - executable, owner, &reservation); + MemoryChunk* chunk = + MemoryChunk::Initialize(heap, base, chunk_size, area_start, area_end, + executable, owner, &reservation); + + if (executable) RegisterExecutableMemoryChunk(chunk); + + return chunk; } void Page::ResetAllocatedBytes() { allocated_bytes_ = area_size(); } @@ -970,6 +975,8 @@ void MemoryAllocator::PreFreeMemory(MemoryChunk* chunk) { } chunk->SetFlag(MemoryChunk::PRE_FREED); + + if (chunk->executable()) UnregisterExecutableMemoryChunk(chunk); } @@ -1722,6 +1729,7 @@ void PagedSpace::ReleasePage(Page* page) { void PagedSpace::SetReadAndExecutable() { DCHECK(identity() == CODE_SPACE); for (Page* page : *this) { + CHECK(heap_->memory_allocator()->IsMemoryChunkExecutable(page)); page->SetReadAndExecutable(); } } @@ -1729,6 +1737,7 @@ void PagedSpace::SetReadAndExecutable() { void PagedSpace::SetReadAndWritable() { DCHECK(identity() == CODE_SPACE); for (Page* page : *this) { + CHECK(heap_->memory_allocator()->IsMemoryChunkExecutable(page)); page->SetReadAndWritable(); } } diff --git a/src/heap/spaces.h b/src/heap/spaces.h index 08fef7d6e3..a1ca07a0a8 100644 --- a/src/heap/spaces.h +++ b/src/heap/spaces.h @@ -1359,6 +1359,12 @@ class V8_EXPORT_PRIVATE MemoryAllocator { // and false otherwise. bool CommitBlock(Address start, size_t size, Executability executable); + // Checks if an allocated MemoryChunk was intended to be used for executable + // memory. + bool IsMemoryChunkExecutable(MemoryChunk* chunk) { + return executable_memory_.find(chunk) != executable_memory_.end(); + } + // Uncommit a contiguous block of memory [start..(start+size)[. // start is not nullptr, the size is greater than zero, and the // block is contained in the initial chunk. Returns true if it succeeded @@ -1409,6 +1415,17 @@ class V8_EXPORT_PRIVATE MemoryAllocator { } while ((high > ptr) && !highest_ever_allocated_.TrySetValue(ptr, high)); } + void RegisterExecutableMemoryChunk(MemoryChunk* chunk) { + DCHECK(chunk->IsFlagSet(MemoryChunk::IS_EXECUTABLE)); + DCHECK_EQ(executable_memory_.find(chunk), executable_memory_.end()); + executable_memory_.insert(chunk); + } + + void UnregisterExecutableMemoryChunk(MemoryChunk* chunk) { + DCHECK_NE(executable_memory_.find(chunk), executable_memory_.end()); + executable_memory_.erase(chunk); + } + Isolate* isolate_; CodeRange* code_range_; @@ -1431,6 +1448,9 @@ class V8_EXPORT_PRIVATE MemoryAllocator { VirtualMemory last_chunk_; Unmapper unmapper_; + // Data structure to remember allocated executable memory chunks. + std::unordered_set executable_memory_; + friend class heap::TestCodeRangeScope; DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryAllocator);