| Index: base/allocator/allocator_shim_win.cc
|
| diff --git a/base/allocator/allocator_shim_win.cc b/base/allocator/allocator_shim_win.cc
|
| index 0ebaa6b54c7e20baa29d7a2fab7e0d35120e75e3..1e7fe19f9520e0fd091c521e7d02ce306cd21c4e 100644
|
| --- a/base/allocator/allocator_shim_win.cc
|
| +++ b/base/allocator/allocator_shim_win.cc
|
| @@ -11,32 +11,41 @@
|
| // This shim make it possible to perform additional checks on allocations
|
| // before passing them to the Heap functions.
|
|
|
| -// new_mode behaves similarly to MSVC's _set_new_mode.
|
| -// If flag is 0 (default), calls to malloc will behave normally.
|
| -// If flag is 1, calls to malloc will behave like calls to new,
|
| -// and the std_new_handler will be invoked on failure.
|
| -// Can be set by calling _set_new_mode().
|
| -static int new_mode = 0;
|
| +// Heap functions are stripped from libcmt.lib using the prep_libc.py
|
| +// for each object file stripped, we re-implement them here to allow us to
|
| +// perform additional checks:
|
| +// 1. Enforcing the maximum size that can be allocated to 2Gb.
|
| +// 2. Calling new_handler if malloc fails.
|
| +
|
| +extern "C" {
|
| +// We set this to 1 because part of the CRT uses a check of _crtheap != 0
|
| +// to test whether the CRT has been initialized. Once we've ripped out
|
| +// the allocators from libcmt, we need to provide this definition so that
|
| +// the rest of the CRT is still usable.
|
| +// heapinit.c
|
| +void* _crtheap = reinterpret_cast<void*>(1);
|
| +}
|
|
|
| namespace {
|
|
|
| -// This is a simple allocator based on the windows heap.
|
| const size_t kWindowsPageSize = 4096;
|
| const size_t kMaxWindowsAllocation = INT_MAX - kWindowsPageSize;
|
| -static HANDLE win_heap;
|
| +int new_mode = 0;
|
|
|
| // VS2013 crt uses the process heap as its heap, so we do the same here.
|
| // See heapinit.c in VS CRT sources.
|
| bool win_heap_init() {
|
| - win_heap = GetProcessHeap();
|
| - if (win_heap == NULL)
|
| + // Set the _crtheap global here. THis allows us to offload most of the
|
| + // memory management to the CRT, except the functions we need to shim.
|
| + _crtheap = GetProcessHeap();
|
| + if (_crtheap == NULL)
|
| return false;
|
|
|
| ULONG enable_lfh = 2;
|
| // NOTE: Setting LFH may fail. Vista already has it enabled.
|
| // And under the debugger, it won't use LFH. So we
|
| // ignore any errors.
|
| - HeapSetInformation(win_heap, HeapCompatibilityInformation, &enable_lfh,
|
| + HeapSetInformation(_crtheap, HeapCompatibilityInformation, &enable_lfh,
|
| sizeof(enable_lfh));
|
|
|
| return true;
|
| @@ -44,12 +53,12 @@ bool win_heap_init() {
|
|
|
| void* win_heap_malloc(size_t size) {
|
| if (size < kMaxWindowsAllocation)
|
| - return HeapAlloc(win_heap, 0, size);
|
| + return HeapAlloc(_crtheap, 0, size);
|
| return NULL;
|
| }
|
|
|
| void win_heap_free(void* size) {
|
| - HeapFree(win_heap, 0, size);
|
| + HeapFree(_crtheap, 0, size);
|
| }
|
|
|
| void* win_heap_realloc(void* ptr, size_t size) {
|
| @@ -60,49 +69,14 @@ void* win_heap_realloc(void* ptr, size_t size) {
|
| return NULL;
|
| }
|
| if (size < kMaxWindowsAllocation)
|
| - return HeapReAlloc(win_heap, 0, ptr, size);
|
| + return HeapReAlloc(_crtheap, 0, ptr, size);
|
| return NULL;
|
| }
|
|
|
| -size_t win_heap_msize(void* ptr) {
|
| - return HeapSize(win_heap, 0, ptr);
|
| -}
|
| -
|
| -void* win_heap_memalign(size_t alignment, size_t size) {
|
| - // Reserve enough space to ensure we can align and set aligned_ptr[-1] to the
|
| - // original allocation for use with win_heap_memalign_free() later.
|
| - size_t allocation_size = size + (alignment - 1) + sizeof(void*);
|
| -
|
| - // Check for overflow. Alignment and size are checked in allocator_shim.
|
| - if (size >= allocation_size || alignment >= allocation_size) {
|
| - return NULL;
|
| - }
|
| -
|
| - // Since we're directly calling the allocator function, before OOM handling,
|
| - // we need to NULL check to ensure the allocation succeeded.
|
| - void* ptr = win_heap_malloc(allocation_size);
|
| - if (!ptr)
|
| - return ptr;
|
| -
|
| - char* aligned_ptr = static_cast<char*>(ptr) + sizeof(void*);
|
| - aligned_ptr +=
|
| - alignment - reinterpret_cast<uintptr_t>(aligned_ptr) & (alignment - 1);
|
| -
|
| - reinterpret_cast<void**>(aligned_ptr)[-1] = ptr;
|
| - return aligned_ptr;
|
| -}
|
| -
|
| -void win_heap_memalign_free(void* ptr) {
|
| - if (ptr)
|
| - win_heap_free(static_cast<void**>(ptr)[-1]);
|
| -}
|
| -
|
| void win_heap_term() {
|
| - win_heap = NULL;
|
| + _crtheap = NULL;
|
| }
|
|
|
| -} // namespace
|
| -
|
| // Call the new handler, if one has been set.
|
| // Returns true on successfully calling the handler, false otherwise.
|
| inline bool call_new_handler(bool nothrow, size_t size) {
|
| @@ -120,8 +94,71 @@ inline bool call_new_handler(bool nothrow, size_t size) {
|
| return false;
|
| }
|
|
|
| -extern "C" {
|
| +// Implement a C++ style allocation, which always calls the new_handler
|
| +// on failure.
|
| +inline void* generic_cpp_alloc(size_t size, bool nothrow) {
|
| + void* ptr;
|
| + for (;;) {
|
| + ptr = malloc(size);
|
| + if (ptr)
|
| + return ptr;
|
| + if (!call_new_handler(nothrow, size))
|
| + break;
|
| + }
|
| + return ptr;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// new.cpp
|
| +void* operator new(size_t size) {
|
| + return generic_cpp_alloc(size, false);
|
| +}
|
| +
|
| +// delete.cpp
|
| +void operator delete(void* p) throw() {
|
| + free(p);
|
| +}
|
| +
|
| +// new2.cpp
|
| +void* operator new[](size_t size) {
|
| + return generic_cpp_alloc(size, false);
|
| +}
|
|
|
| +// delete2.cpp
|
| +void operator delete[](void* p) throw() {
|
| + free(p);
|
| +}
|
| +
|
| +// newopnt.cpp
|
| +void* operator new(size_t size, const std::nothrow_t& nt) {
|
| + return generic_cpp_alloc(size, true);
|
| +}
|
| +
|
| +// newaopnt.cpp
|
| +void* operator new[](size_t size, const std::nothrow_t& nt) {
|
| + return generic_cpp_alloc(size, true);
|
| +}
|
| +
|
| +// This function behaves similarly to MSVC's _set_new_mode.
|
| +// If flag is 0 (default), calls to malloc will behave normally.
|
| +// If flag is 1, calls to malloc will behave like calls to new,
|
| +// and the std_new_handler will be invoked on failure.
|
| +// Returns the previous mode.
|
| +// new_mode.cpp
|
| +int _set_new_mode(int flag) throw() {
|
| + int old_mode = new_mode;
|
| + new_mode = flag;
|
| + return old_mode;
|
| +}
|
| +
|
| +// new_mode.cpp
|
| +int _query_new_mode() {
|
| + return new_mode;
|
| +}
|
| +
|
| +extern "C" {
|
| +// malloc.c
|
| void* malloc(size_t size) {
|
| void* ptr;
|
| for (;;) {
|
| @@ -135,11 +172,13 @@ void* malloc(size_t size) {
|
| return ptr;
|
| }
|
|
|
| +// free.c
|
| void free(void* p) {
|
| win_heap_free(p);
|
| return;
|
| }
|
|
|
| +// realloc.c
|
| void* realloc(void* ptr, size_t size) {
|
| // Webkit is brittle for allocators that return NULL for malloc(0). The
|
| // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure
|
| @@ -162,60 +201,56 @@ void* realloc(void* ptr, size_t size) {
|
| return new_ptr;
|
| }
|
|
|
| -
|
| -size_t _msize(void* p) {
|
| - return win_heap_msize(p);
|
| -}
|
| -
|
| +// heapinit.c
|
| intptr_t _get_heap_handle() {
|
| - return reinterpret_cast<intptr_t>(win_heap);
|
| + return reinterpret_cast<intptr_t>(_crtheap);
|
| }
|
|
|
| -// The CRT heap initialization stub.
|
| +// heapinit.c
|
| int _heap_init() {
|
| return win_heap_init() ? 1 : 0;
|
| }
|
|
|
| -// The CRT heap cleanup stub.
|
| +// heapinit.c
|
| void _heap_term() {
|
| win_heap_term();
|
| }
|
|
|
| -// We set this to 1 because part of the CRT uses a check of _crtheap != 0
|
| -// to test whether the CRT has been initialized. Once we've ripped out
|
| -// the allocators from libcmt, we need to provide this definition so that
|
| -// the rest of the CRT is still usable.
|
| -void* _crtheap = reinterpret_cast<void*>(1);
|
| -
|
| -// Provide support for aligned memory through Windows only _aligned_malloc().
|
| -void* _aligned_malloc(size_t size, size_t alignment) {
|
| - // _aligned_malloc guarantees parameter validation, so do so here. These
|
| - // checks are somewhat stricter than _aligned_malloc() since we're effectively
|
| - // using memalign() under the hood.
|
| - if (size == 0U || (alignment & (alignment - 1)) != 0U ||
|
| - (alignment % sizeof(void*)) != 0U)
|
| +// calloc.c
|
| +void* calloc(size_t n, size_t elem_size) {
|
| + // Overflow check.
|
| + const size_t size = n * elem_size;
|
| + if (elem_size != 0 && size / elem_size != n)
|
| return NULL;
|
|
|
| - void* ptr;
|
| - for (;;) {
|
| - ptr = win_heap_memalign(alignment, size);
|
| -
|
| - if (ptr) {
|
| - return ptr;
|
| - }
|
| -
|
| - if (!new_mode || !call_new_handler(true, size))
|
| - break;
|
| + void* result = malloc(size);
|
| + if (result != NULL) {
|
| + memset(result, 0, size);
|
| }
|
| - return ptr;
|
| + return result;
|
| }
|
|
|
| -void _aligned_free(void* p) {
|
| - // Pointers allocated with win_heap_memalign() MUST be freed via
|
| - // win_heap_memalign_free() since the aligned pointer is not the real one.
|
| - win_heap_memalign_free(p);
|
| +// recalloc.c
|
| +void* _recalloc(void* p, size_t n, size_t elem_size) {
|
| + if (!p)
|
| + return calloc(n, elem_size);
|
| +
|
| + // This API is a bit odd.
|
| + // Note: recalloc only guarantees zeroed memory when p is NULL.
|
| + // Generally, calls to malloc() have padding. So a request
|
| + // to malloc N bytes actually malloc's N+x bytes. Later, if
|
| + // that buffer is passed to recalloc, we don't know what N
|
| + // was anymore. We only know what N+x is. As such, there is
|
| + // no way to know what to zero out.
|
| + const size_t size = n * elem_size;
|
| + if (elem_size != 0 && size / elem_size != n)
|
| + return NULL;
|
| + return realloc(p, size);
|
| }
|
|
|
| -#include "generic_allocators.cc"
|
| +// calloc_impl.c
|
| +void* _calloc_impl(size_t n, size_t size) {
|
| + return calloc(n, size);
|
| +}
|
|
|
| } // extern C
|
|
|