Commit 2423c8ab authored by jschuh@chromium.org's avatar jschuh@chromium.org

Add a guard page in front of metadata allocations.

BUG=104752



Review URL: http://codereview.chromium.org/8570023

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112260 0039d316-1c4b-4281-b951-d872f2087c98
parent 32780605
...@@ -34,6 +34,10 @@ ...@@ -34,6 +34,10 @@
#include "common.h" #include "common.h"
#include "system-alloc.h" #include "system-alloc.h"
#if defined(HAVE_UNISTD_H) && defined(HAVE_GETPAGESIZE)
#include <unistd.h> // for getpagesize
#endif
namespace tcmalloc { namespace tcmalloc {
// Note: the following only works for "n"s that fit in 32-bits, but // Note: the following only works for "n"s that fit in 32-bits, but
...@@ -201,7 +205,13 @@ void SizeMap::Dump(TCMalloc_Printer* out) { ...@@ -201,7 +205,13 @@ void SizeMap::Dump(TCMalloc_Printer* out) {
// Metadata allocator -- keeps stats about how many bytes allocated. // Metadata allocator -- keeps stats about how many bytes allocated.
static uint64_t metadata_system_bytes_ = 0; static uint64_t metadata_system_bytes_ = 0;
void* MetaDataAlloc(size_t bytes) { void* MetaDataAlloc(size_t bytes) {
void* result = TCMalloc_SystemAlloc(bytes, NULL); static size_t pagesize;
#ifdef HAVE_GETPAGESIZE
if (pagesize == 0)
pagesize = getpagesize();
#endif
void* result = TCMalloc_SystemAlloc(bytes, NULL, pagesize);
if (result != NULL) { if (result != NULL) {
metadata_system_bytes_ += bytes; metadata_system_bytes_ += bytes;
} }
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "common.h" // for MetaDataAlloc #include "common.h" // for MetaDataAlloc
#include "free_list.h" // for FL_Push/FL_Pop #include "free_list.h" // for FL_Push/FL_Pop
#include "internal_logging.h" // for ASSERT, CRASH #include "internal_logging.h" // for ASSERT, CRASH
#include "system-alloc.h" // for TCMalloc_SystemAddGuard
namespace tcmalloc { namespace tcmalloc {
...@@ -74,7 +75,20 @@ class PageHeapAllocator { ...@@ -74,7 +75,20 @@ class PageHeapAllocator {
"tcmalloc data (%d bytes, object-size %d)\n", "tcmalloc data (%d bytes, object-size %d)\n",
kAllocIncrement, static_cast<int>(sizeof(T))); kAllocIncrement, static_cast<int>(sizeof(T)));
} }
free_avail_ = kAllocIncrement;
// This guard page protects the metadata from being corrupted by a
// buffer overrun. We currently have no mechanism for freeing it, since
// we never release the metadata buffer. If that changes we'll need to
// add something like TCMalloc_SystemRemoveGuard.
size_t guard_size = TCMalloc_SystemAddGuard(free_area_,
kAllocIncrement);
free_area_ += guard_size;
free_avail_ = kAllocIncrement - guard_size;
if (free_avail_ < sizeof(T)) {
CRASH("FATAL ERROR: Insufficient memory to guard internal tcmalloc "
"data (%d bytes, object-size %d, guard-size %d)\n",
kAllocIncrement, static_cast<int>(sizeof(T)), guard_size);
}
} }
result = free_area_; result = free_area_;
free_area_ += sizeof(T); free_area_ += sizeof(T);
......
...@@ -103,8 +103,7 @@ union MemoryAligner { ...@@ -103,8 +103,7 @@ union MemoryAligner {
static SpinLock spinlock(SpinLock::LINKER_INITIALIZED); static SpinLock spinlock(SpinLock::LINKER_INITIALIZED);
#if defined(HAVE_MMAP) || defined(MADV_DONTNEED) #ifdef HAVE_GETPAGESIZE
// Page size is initialized on demand (only needed for mmap-based allocators)
static size_t pagesize = 0; static size_t pagesize = 0;
#endif #endif
...@@ -484,6 +483,21 @@ void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, ...@@ -484,6 +483,21 @@ void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
return result; return result;
} }
size_t TCMalloc_SystemAddGuard(void* start, size_t size) {
#ifdef HAVE_GETPAGESIZE
if (pagesize == 0)
pagesize = getpagesize();
if (size < pagesize || (reinterpret_cast<size_t>(start) % pagesize) != 0)
return 0;
if (!mprotect(start, pagesize, PROT_NONE))
return pagesize;
#endif
return 0;
}
void TCMalloc_SystemRelease(void* start, size_t length) { void TCMalloc_SystemRelease(void* start, size_t length) {
#ifdef MADV_DONTNEED #ifdef MADV_DONTNEED
if (FLAGS_malloc_devmem_start) { if (FLAGS_malloc_devmem_start) {
......
...@@ -77,6 +77,11 @@ extern void TCMalloc_SystemRelease(void* start, size_t length); ...@@ -77,6 +77,11 @@ extern void TCMalloc_SystemRelease(void* start, size_t length);
// function to fail. // function to fail.
extern void TCMalloc_SystemCommit(void* start, size_t length); extern void TCMalloc_SystemCommit(void* start, size_t length);
// Guards the first page in the supplied range of memory and returns the size
// of the guard page. Will return 0 if a guard cannot be added to the page
// (e.g. start is not aligned or size is not large enough).
extern size_t TCMalloc_SystemAddGuard(void* start, size_t size);
// The current system allocator. // The current system allocator.
extern PERFTOOLS_DLL_DECL SysAllocator* sys_alloc; extern PERFTOOLS_DLL_DECL SysAllocator* sys_alloc;
......
...@@ -259,6 +259,31 @@ extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, ...@@ -259,6 +259,31 @@ extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
return result; return result;
} }
size_t TCMalloc_SystemAddGuard(void* start, size_t size) {
static size_t pagesize = 0;
if (pagesize == 0) {
SYSTEM_INFO system_info;
GetSystemInfo(&system_info);
pagesize = system_info.dwPageSize;
}
// We know that TCMalloc_SystemAlloc will give us a correct page alignment
// regardless, so we can just assert to detect erroneous callers.
assert(reinterpret_cast<size_t>(start) % pagesize == 0);
// Add a guard page to catch metadata corruption. We're using the
// PAGE_GUARD flag rather than NO_ACCESS because we want the unique
// exception in crash reports.
DWORD permissions = 0;
if (size > pagesize &&
VirtualProtect(start, pagesize, PAGE_READONLY | PAGE_GUARD,
&permissions)) {
return pagesize;
}
return 0;
}
void TCMalloc_SystemRelease(void* start, size_t length) { void TCMalloc_SystemRelease(void* start, size_t length) {
if (VirtualFree(start, length, MEM_DECOMMIT)) if (VirtualFree(start, length, MEM_DECOMMIT))
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment