From bc3fb1188184dcb1fea70dbfdcdf598aec936dce Mon Sep 17 00:00:00 2001 From: "kmillikin@chromium.org" Date: Tue, 24 Mar 2009 12:47:53 +0000 Subject: [PATCH] Add basic infrastructure for protecting V8's heap when leaving the VM and unprotecting it when (re)entering. The functionality is enabled by the flag --protect-heap and requires V8 to be built with ENABLE_HEAP_PROTECTION and ENABLE_LOGGING_AND_PROFILING defined. Implemented on Linux and Windows but not yet for other platforms. Review URL: http://codereview.chromium.org/53004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1595 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/flag-definitions.h | 16 +++++++- src/globals.h | 3 +- src/heap.cc | 24 ++++++++++++ src/heap.h | 6 +++ src/log.cc | 35 +++++++++++++++-- src/platform-freebsd.cc | 14 +++++++ src/platform-linux.cc | 31 +++++++++++---- src/platform-macos.cc | 27 +++++++++++--- src/platform-nullos.cc | 14 +++++++ src/platform-win32.cc | 33 ++++++++++++---- src/platform.h | 12 ++++-- src/spaces-inl.h | 37 ++++++++++++++++++ src/spaces.cc | 83 ++++++++++++++++++++++++++++++++++------- src/spaces.h | 44 +++++++++++++++++++++- tools/test.py | 8 ++-- 15 files changed, 337 insertions(+), 50 deletions(-) diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 911ab8c47c..c3580c5ed3 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -337,8 +337,20 @@ DEFINE_bool(log_regexp, false, "Log regular expression execution.") DEFINE_bool(sliding_state_window, false, "Update sliding state window counters.") DEFINE_string(logfile, "v8.log", "Specify the name of the log file.") -DEFINE_bool(oprofile, false, - "Enable JIT agent for OProfile.") +DEFINE_bool(oprofile, false, "Enable JIT agent for OProfile.") + +// +// Heap protection flags +// Using heap protection requires ENABLE_LOGGING_AND_PROFILING as well. +// +#ifdef ENABLE_HEAP_PROTECTION +#undef FLAG +#define FLAG FLAG_FULL + +DEFINE_bool(protect_heap, false, + "Protect/unprotect V8's heap when leaving/entring the VM.") + +#endif // // Disassembler only flags diff --git a/src/globals.h b/src/globals.h index 584ec62ab6..1579c3dfd4 100644 --- a/src/globals.h +++ b/src/globals.h @@ -359,7 +359,8 @@ struct AccessorDescriptor { V(JS) \ V(GC) \ V(COMPILER) \ - V(OTHER) + V(OTHER) \ + V(EXTERNAL) enum StateTag { #define DEF_STATE_TAG(name) name, diff --git a/src/heap.cc b/src/heap.cc index 8bab00e331..46ad2dd918 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -2861,6 +2861,30 @@ void Heap::Shrink() { } +#ifdef ENABLE_HEAP_PROTECTION + +void Heap::Protect() { + new_space_.Protect(); + map_space_->Protect(); + old_pointer_space_->Protect(); + old_data_space_->Protect(); + code_space_->Protect(); + lo_space_->Protect(); +} + + +void Heap::Unprotect() { + new_space_.Unprotect(); + map_space_->Unprotect(); + old_pointer_space_->Unprotect(); + old_data_space_->Unprotect(); + code_space_->Unprotect(); + lo_space_->Unprotect(); +} + +#endif + + #ifdef DEBUG class PrintHandleVisitor: public ObjectVisitor { diff --git a/src/heap.h b/src/heap.h index c83c2e8c54..ccc552f8d0 100644 --- a/src/heap.h +++ b/src/heap.h @@ -273,6 +273,12 @@ class Heap : public AllStatic { return new_space_.allocation_limit_address(); } +#ifdef ENABLE_HEAP_PROTECTION + // Protect/unprotect the heap by marking all spaces read-only/writable. + static void Protect(); + static void Unprotect(); +#endif + // Allocates and initializes a new JavaScript object based on a // constructor. // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation diff --git a/src/log.cc b/src/log.cc index 59198274b6..f3443faf05 100644 --- a/src/log.cc +++ b/src/log.cc @@ -29,10 +29,12 @@ #include "v8.h" +#include "bootstrapper.h" #include "log.h" -#include "platform.h" -#include "string-stream.h" #include "macro-assembler.h" +#include "platform.h" +#include "serialize.h" +#include "string-stream.h" namespace v8 { namespace internal { @@ -1115,10 +1117,23 @@ VMState::VMState(StateTag state) { if (FLAG_log_state_changes) { LOG(UncheckedStringEvent("Entering", StateToString(state_))); - if (previous_) { + if (previous_ != NULL) { LOG(UncheckedStringEvent("From", StateToString(previous_->state_))); } } + +#ifdef ENABLE_HEAP_PROTECTION + if (FLAG_protect_heap && previous_ != NULL) { + if (state_ == EXTERNAL) { + // We are leaving V8. + ASSERT(previous_ == NULL || previous_->state_ != EXTERNAL); + Heap::Protect(); + } else { + // Are we entering V8? + if (previous_->state_ == EXTERNAL) Heap::Unprotect(); + } + } +#endif } @@ -1127,10 +1142,22 @@ VMState::~VMState() { if (FLAG_log_state_changes) { LOG(UncheckedStringEvent("Leaving", StateToString(state_))); - if (previous_) { + if (previous_ != NULL) { LOG(UncheckedStringEvent("To", StateToString(previous_->state_))); } } + +#ifdef ENABLE_HEAP_PROTECTION + if (FLAG_protect_heap && previous_ != NULL) { + if (state_ == EXTERNAL) { + // Are we (re)entering V8? + if (previous_->state_ != EXTERNAL) Heap::Unprotect(); + } else { + // Are we leaving V8? + if (previous_->state_ == EXTERNAL) Heap::Protect(); + } + } +#endif } #endif diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc index 9a15d85aeb..b6e2558e6f 100644 --- a/src/platform-freebsd.cc +++ b/src/platform-freebsd.cc @@ -257,6 +257,20 @@ void OS::Free(void* buf, const size_t length) { } +#ifdef ENABLE_HEAP_PROTECTION + +void OS::Protect(void* address, size_t size) { + UNIMPLEMENTED(); +} + + +void OS::Unprotect(void* address, size_t size, bool is_executable) { + UNIMPLEMENTED(); +} + +#endif + + void OS::Sleep(int milliseconds) { unsigned int ms = static_cast(milliseconds); usleep(1000 * ms); diff --git a/src/platform-linux.cc b/src/platform-linux.cc index f1cac0969f..393bf12608 100644 --- a/src/platform-linux.cc +++ b/src/platform-linux.cc @@ -234,9 +234,9 @@ size_t OS::AllocateAlignment() { void* OS::Allocate(const size_t requested, size_t* allocated, - bool executable) { + bool is_executable) { const size_t msize = RoundUp(requested, sysconf(_SC_PAGESIZE)); - int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0); + int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (mbase == MAP_FAILED) { LOG(StringEvent("OS::Allocate", "mmap failed")); @@ -248,12 +248,29 @@ void* OS::Allocate(const size_t requested, } -void OS::Free(void* buf, const size_t length) { +void OS::Free(void* address, const size_t size) { // TODO(1240712): munmap has a return value which is ignored here. - munmap(buf, length); + munmap(address, size); } +#ifdef ENABLE_HEAP_PROTECTION + +void OS::Protect(void* address, size_t size) { + // TODO(1240712): mprotect has a return value which is ignored here. + mprotect(address, size, PROT_READ); +} + + +void OS::Unprotect(void* address, size_t size, bool is_executable) { + // TODO(1240712): mprotect has a return value which is ignored here. + int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); + mprotect(address, size, prot); +} + +#endif + + void OS::Sleep(int milliseconds) { unsigned int ms = static_cast(milliseconds); usleep(1000 * ms); @@ -267,7 +284,7 @@ void OS::Abort() { void OS::DebugBreak() { -#if defined (__arm__) || defined(__thumb__) +#ifdef ARM asm("bkpt 0"); #else asm("int $3"); @@ -418,8 +435,8 @@ bool VirtualMemory::IsReserved() { } -bool VirtualMemory::Commit(void* address, size_t size, bool executable) { - int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0); +bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { + int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); if (MAP_FAILED == mmap(address, size, prot, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, kMmapFd, kMmapFdOffset)) { diff --git a/src/platform-macos.cc b/src/platform-macos.cc index 586880f41b..a9a9cdb457 100644 --- a/src/platform-macos.cc +++ b/src/platform-macos.cc @@ -228,9 +228,9 @@ size_t OS::AllocateAlignment() { void* OS::Allocate(const size_t requested, size_t* allocated, - bool executable) { + bool is_executable) { const size_t msize = RoundUp(requested, getpagesize()); - int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0); + int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0); if (mbase == MAP_FAILED) { LOG(StringEvent("OS::Allocate", "mmap failed")); @@ -242,12 +242,26 @@ void* OS::Allocate(const size_t requested, } -void OS::Free(void* buf, const size_t length) { +void OS::Free(void* address, const size_t size) { // TODO(1240712): munmap has a return value which is ignored here. - munmap(buf, length); + munmap(address, size); } +#ifdef ENABLE_HEAP_PROTECTION + +void OS::Protect(void* address, size_t size) { + UNIMPLEMENTED(); +} + + +void OS::Unprotect(void* address, size_t size, bool is_executable) { + UNIMPLEMENTED(); +} + +#endif + + void OS::Sleep(int milliseconds) { usleep(1000 * milliseconds); } @@ -370,8 +384,8 @@ bool VirtualMemory::IsReserved() { } -bool VirtualMemory::Commit(void* address, size_t size, bool executable) { - int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0); +bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { + int prot = PROT_READ | PROT_WRITE | (is_executable ? PROT_EXEC : 0); if (MAP_FAILED == mmap(address, size, prot, MAP_PRIVATE | MAP_ANON | MAP_FIXED, kMmapFd, kMmapFdOffset)) { @@ -389,6 +403,7 @@ bool VirtualMemory::Uncommit(void* address, size_t size) { kMmapFd, kMmapFdOffset) != MAP_FAILED; } + class ThreadHandle::PlatformData : public Malloced { public: explicit PlatformData(ThreadHandle::Kind kind) { diff --git a/src/platform-nullos.cc b/src/platform-nullos.cc index 98cb23032a..3a50b9ddda 100644 --- a/src/platform-nullos.cc +++ b/src/platform-nullos.cc @@ -173,6 +173,20 @@ void OS::Free(void* buf, const size_t length) { } +#ifdef ENABLE_HEAP_PROTECTION + +void OS::Protect(void* address, size_t size) { + UNIMPLEMENTED(); +} + + +void OS::Unprotect(void* address, size_t size, bool is_executable) { + UNIMPLEMENTED(); +} + +#endif + + void OS::Sleep(int milliseconds) { UNIMPLEMENTED(); } diff --git a/src/platform-win32.cc b/src/platform-win32.cc index 04e786005d..f5d0913581 100644 --- a/src/platform-win32.cc +++ b/src/platform-win32.cc @@ -801,12 +801,12 @@ size_t OS::AllocateAlignment() { void* OS::Allocate(const size_t requested, size_t* allocated, - bool executable) { + bool is_executable) { // VirtualAlloc rounds allocated size to page size automatically. size_t msize = RoundUp(requested, GetPageSize()); // Windows XP SP2 allows Data Excution Prevention (DEP). - int prot = executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; + int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; LPVOID mbase = VirtualAlloc(NULL, msize, MEM_COMMIT | MEM_RESERVE, prot); if (mbase == NULL) { LOG(StringEvent("OS::Allocate", "VirtualAlloc failed")); @@ -821,13 +821,32 @@ void* OS::Allocate(const size_t requested, } -void OS::Free(void* buf, const size_t length) { +void OS::Free(void* address, const size_t size) { // TODO(1240712): VirtualFree has a return value which is ignored here. - VirtualFree(buf, 0, MEM_RELEASE); - USE(length); + VirtualFree(address, 0, MEM_RELEASE); + USE(size); } +#ifdef ENABLE_HEAP_PROTECTION + +void OS::Protect(void* address, size_t size) { + // TODO(1240712): VirtualProtect has a return value which is ignored here. + DWORD old_protect; + VirtualProtect(address, size, PAGE_READONLY, &old_protect); +} + + +void OS::Unprotect(void* address, size_t size, bool is_executable) { + // TODO(1240712): VirtualProtect has a return value which is ignored here. + DWORD new_protect = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; + DWORD old_protect; + VirtualProtect(address, size, new_protect, &old_protect); +} + +#endif + + void OS::Sleep(int milliseconds) { ::Sleep(milliseconds); } @@ -1299,8 +1318,8 @@ VirtualMemory::~VirtualMemory() { } -bool VirtualMemory::Commit(void* address, size_t size, bool executable) { - int prot = executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; +bool VirtualMemory::Commit(void* address, size_t size, bool is_executable) { + int prot = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; if (NULL == VirtualAlloc(address, size, MEM_COMMIT, prot)) { return false; } diff --git a/src/platform.h b/src/platform.h index e910bd1a14..27b701776d 100644 --- a/src/platform.h +++ b/src/platform.h @@ -168,11 +168,17 @@ class OS { // Returns the address of allocated memory, or NULL if failed. static void* Allocate(const size_t requested, size_t* allocated, - bool executable); - static void Free(void* buf, const size_t length); + bool is_executable); + static void Free(void* address, const size_t size); // Get the Alignment guaranteed by Allocate(). static size_t AllocateAlignment(); +#ifdef ENABLE_HEAP_PROTECTION + // Protect/unprotect a block of memory by marking it read-only/writable. + static void Protect(void* address, size_t size); + static void Unprotect(void* address, size_t size, bool is_executable); +#endif + // Returns an indication of whether a pointer is in a space that // has been allocated by Allocate(). This method may conservatively // always return false, but giving more accurate information may @@ -267,7 +273,7 @@ class VirtualMemory { size_t size() { return size_; } // Commits real memory. Returns whether the operation succeeded. - bool Commit(void* address, size_t size, bool executable); + bool Commit(void* address, size_t size, bool is_executable); // Uncommit real memory. Returns whether the operation succeeded. bool Uncommit(void* address, size_t size); diff --git a/src/spaces-inl.h b/src/spaces-inl.h index 7a81db32fc..d7cddb4fd5 100644 --- a/src/spaces-inl.h +++ b/src/spaces-inl.h @@ -219,6 +219,43 @@ PagedSpace* MemoryAllocator::PageOwner(Page* page) { } +bool MemoryAllocator::InInitialChunk(Address address) { + if (initial_chunk_ == NULL) return false; + + Address start = static_cast
(initial_chunk_->address()); + return (start <= address) && (address < start + initial_chunk_->size()); +} + + +#ifdef ENABLE_HEAP_PROTECTION + +void MemoryAllocator::Protect(Address start, size_t size) { + OS::Protect(start, size); +} + + +void MemoryAllocator::Unprotect(Address start, + size_t size, + Executability executable) { + OS::Unprotect(start, size, executable); +} + + +void MemoryAllocator::ProtectChunkFromPage(Page* page) { + int id = GetChunkId(page); + OS::Protect(chunks_[id].address(), chunks_[id].size()); +} + + +void MemoryAllocator::UnprotectChunkFromPage(Page* page) { + int id = GetChunkId(page); + OS::Unprotect(chunks_[id].address(), chunks_[id].size(), + chunks_[id].owner()->executable() == EXECUTABLE); +} + +#endif + + // -------------------------------------------------------------------------- // PagedSpace diff --git a/src/spaces.cc b/src/spaces.cc index b10139edb9..ea40d52116 100644 --- a/src/spaces.cc +++ b/src/spaces.cc @@ -302,9 +302,8 @@ Page* MemoryAllocator::CommitPages(Address start, size_t size, *num_pages = PagesInChunk(start, size); ASSERT(*num_pages > 0); ASSERT(initial_chunk_ != NULL); - ASSERT(initial_chunk_->address() <= start); - ASSERT(start + size <= reinterpret_cast
(initial_chunk_->address()) - + initial_chunk_->size()); + ASSERT(InInitialChunk(start)); + ASSERT(InInitialChunk(start + size - 1)); if (!initial_chunk_->Commit(start, size, owner->executable() == EXECUTABLE)) { return Page::FromAddress(NULL); } @@ -325,9 +324,8 @@ bool MemoryAllocator::CommitBlock(Address start, ASSERT(start != NULL); ASSERT(size > 0); ASSERT(initial_chunk_ != NULL); - ASSERT(initial_chunk_->address() <= start); - ASSERT(start + size <= reinterpret_cast
(initial_chunk_->address()) - + initial_chunk_->size()); + ASSERT(InInitialChunk(start)); + ASSERT(InInitialChunk(start + size - 1)); if (!initial_chunk_->Commit(start, size, executable)) return false; Counters::memory_allocated.Increment(size); @@ -407,14 +405,7 @@ void MemoryAllocator::DeleteChunk(int chunk_id) { // We cannot free a chunk contained in the initial chunk because it was not // allocated with AllocateRawMemory. Instead we uncommit the virtual // memory. - bool in_initial_chunk = false; - if (initial_chunk_ != NULL) { - Address start = static_cast
(initial_chunk_->address()); - Address end = start + initial_chunk_->size(); - in_initial_chunk = (start <= c.address()) && (c.address() < end); - } - - if (in_initial_chunk) { + if (InInitialChunk(c.address())) { // TODO(1240712): VirtualMemory::Uncommit has a return value which // is ignored here. initial_chunk_->Uncommit(c.address(), c.size()); @@ -529,6 +520,28 @@ void PagedSpace::TearDown() { } +#ifdef ENABLE_HEAP_PROTECTION + +void PagedSpace::Protect() { + Page* page = first_page_; + while (page->is_valid()) { + MemoryAllocator::ProtectChunkFromPage(page); + page = MemoryAllocator::FindLastPageInSameChunk(page)->next_page(); + } +} + + +void PagedSpace::Unprotect() { + Page* page = first_page_; + while (page->is_valid()) { + MemoryAllocator::UnprotectChunkFromPage(page); + page = MemoryAllocator::FindLastPageInSameChunk(page)->next_page(); + } +} + +#endif + + void PagedSpace::ClearRSet() { PageIterator it(this, PageIterator::ALL_PAGES); while (it.has_next()) { @@ -834,6 +847,24 @@ void NewSpace::TearDown() { } +#ifdef ENABLE_HEAP_PROTECTION + +void NewSpace::Protect() { + MemoryAllocator::Protect(ToSpaceLow(), Capacity()); + MemoryAllocator::Protect(FromSpaceLow(), Capacity()); +} + + +void NewSpace::Unprotect() { + MemoryAllocator::Unprotect(ToSpaceLow(), Capacity(), + to_space_.executable()); + MemoryAllocator::Unprotect(FromSpaceLow(), Capacity(), + from_space_.executable()); +} + +#endif + + void NewSpace::Flip() { SemiSpace tmp = from_space_; from_space_ = to_space_; @@ -2242,6 +2273,30 @@ void LargeObjectSpace::TearDown() { } +#ifdef ENABLE_HEAP_PROTECTION + +void LargeObjectSpace::Protect() { + LargeObjectChunk* chunk = first_chunk_; + while (chunk != NULL) { + MemoryAllocator::Protect(chunk->address(), chunk->size()); + chunk = chunk->next(); + } +} + + +void LargeObjectSpace::Unprotect() { + LargeObjectChunk* chunk = first_chunk_; + while (chunk != NULL) { + bool is_code = chunk->GetObject()->IsCode(); + MemoryAllocator::Unprotect(chunk->address(), chunk->size(), + is_code ? EXECUTABLE : NOT_EXECUTABLE); + chunk = chunk->next(); + } +} + +#endif + + Object* LargeObjectSpace::AllocateRawInternal(int requested_size, int object_size, Executability executable) { diff --git a/src/spaces.h b/src/spaces.h index 8a3dc5b647..3138cc3609 100644 --- a/src/spaces.h +++ b/src/spaces.h @@ -277,16 +277,22 @@ class Space : public Malloced { public: Space(AllocationSpace id, Executability executable) : id_(id), executable_(executable) {} + virtual ~Space() {} + // Does the space need executable memory? Executability executable() { return executable_; } + // Identity used in error reporting. AllocationSpace identity() { return id_; } + virtual int Size() = 0; + #ifdef DEBUG virtual void Verify() = 0; virtual void Print() = 0; #endif + private: AllocationSpace id_; Executability executable_; @@ -396,6 +402,17 @@ class MemoryAllocator : public AllStatic { static Page* FindFirstPageInSameChunk(Page* p); static Page* FindLastPageInSameChunk(Page* p); +#ifdef ENABLE_HEAP_PROTECTION + // Protect/unprotect a block of memory by marking it read-only/writable. + static inline void Protect(Address start, size_t size); + static inline void Unprotect(Address start, size_t size, + Executability executable); + + // Protect/unprotect a chunk given a page in the chunk. + static inline void ProtectChunkFromPage(Page* page); + static inline void UnprotectChunkFromPage(Page* page); +#endif + #ifdef DEBUG // Reports statistic info of the space. static void ReportStatistics(); @@ -460,6 +477,9 @@ class MemoryAllocator : public AllStatic { // Returns the chunk id that a page belongs to. static inline int GetChunkId(Page* p); + // True if the address lies in the initial chunk. + static inline bool InInitialChunk(Address address); + // Initializes pages in a chunk. Returns the first page address. // This function and GetChunkId() are provided for the mark-compact // collector to rebuild page headers in the from space, which is @@ -669,7 +689,6 @@ class AllocationStats BASE_EMBEDDED { class PagedSpace : public Space { - friend class PageIterator; public: // Creates a space with a maximum capacity, and an id. PagedSpace(int max_capacity, AllocationSpace id, Executability executable); @@ -764,6 +783,12 @@ class PagedSpace : public Space { // Ensures that the capacity is at least 'capacity'. Returns false on failure. bool EnsureCapacity(int capacity); +#ifdef ENABLE_HEAP_PROTECTION + // Protect/unprotect the space by marking it read-only/writable. + void Protect(); + void Unprotect(); +#endif + #ifdef DEBUG // Print meta info and objects in this space. virtual void Print(); @@ -834,6 +859,8 @@ class PagedSpace : public Space { // Returns the number of total pages in this space. int CountTotalPages(); #endif + + friend class PageIterator; }; @@ -1117,6 +1144,12 @@ class NewSpace : public Space { bool ToSpaceContains(Address a) { return to_space_.Contains(a); } bool FromSpaceContains(Address a) { return from_space_.Contains(a); } +#ifdef ENABLE_HEAP_PROTECTION + // Protect/unprotect the space by marking it read-only/writable. + virtual void Protect(); + virtual void Unprotect(); +#endif + #ifdef DEBUG // Verify the active semispace. virtual void Verify(); @@ -1554,7 +1587,6 @@ class LargeObjectChunk { class LargeObjectSpace : public Space { - friend class LargeObjectIterator; public: explicit LargeObjectSpace(AllocationSpace id); virtual ~LargeObjectSpace() {} @@ -1606,6 +1638,12 @@ class LargeObjectSpace : public Space { // Checks whether the space is empty. bool IsEmpty() { return first_chunk_ == NULL; } +#ifdef ENABLE_HEAP_PROTECTION + // Protect/unprotect the space by marking it read-only/writable. + void Protect(); + void Unprotect(); +#endif + #ifdef DEBUG virtual void Verify(); virtual void Print(); @@ -1635,6 +1673,8 @@ class LargeObjectSpace : public Space { // required for extra_object_bytes of extra pointers (in bytes). static inline int ExtraRSetBytesFor(int extra_object_bytes); + friend class LargeObjectIterator; + public: TRACK_MEMORY("LargeObjectSpace") }; diff --git a/tools/test.py b/tools/test.py index 2b55d65eb6..848b01753d 100755 --- a/tools/test.py +++ b/tools/test.py @@ -163,7 +163,7 @@ class SimpleProgressIndicator(ProgressIndicator): print failed.output.stdout.strip() print "Command: %s" % EscapeCommand(failed.command) if failed.HasCrashed(): - print "--- CRASHED ---" + print "--- CRASHED ---" if len(self.failed) == 0: print "===" print "=== All tests succeeded" @@ -244,7 +244,7 @@ class CompactProgressIndicator(ProgressIndicator): print self.templates['stderr'] % stderr print "Command: %s" % EscapeCommand(output.command) if output.HasCrashed(): - print "--- CRASHED ---" + print "--- CRASHED ---" def Truncate(self, str, length): if length and (len(str) > (length - 3)): @@ -345,7 +345,7 @@ class TestCase(object): def GetSource(self): return "(no source available)" - + def RunCommand(self, command): full_command = self.context.processor(command) output = Execute(full_command, self.context, self.context.timeout) @@ -411,7 +411,7 @@ def Win32SetErrorMode(mode): except ImportError: pass return prev_error_mode - + def RunProcess(context, timeout, args, **rest): if context.verbose: print "#", " ".join(args) popen_args = args