Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(345)

Unified Diff: base/allocator/allocator_shim_win.cc

Issue 885443002: Roll Chrome into Mojo. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Rebase to ToT mojo Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/allocator/allocator.gyp ('k') | base/allocator/generic_allocators.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..a1473e5fd29f104f5759ade6982ca40a72848e96 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,119 @@ 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);
+// 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;
-// 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)
+ void* result = malloc(size);
+ if (result != NULL) {
+ memset(result, 0, size);
+ }
+ return result;
+}
+
+// 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);
+}
- void* ptr;
- for (;;) {
- ptr = win_heap_memalign(alignment, size);
+// calloc_impl.c
+void* _calloc_impl(size_t n, size_t size) {
+ return calloc(n, size);
+}
- if (ptr) {
- return ptr;
- }
+#ifndef NDEBUG
+#undef malloc
+#undef free
+#undef calloc
- if (!new_mode || !call_new_handler(true, size))
- break;
+static int error_handler(int reportType) {
+ switch (reportType) {
+ case 0: // _CRT_WARN
+ __debugbreak();
+ return 0;
+
+ case 1: // _CRT_ERROR
+ __debugbreak();
+ return 0;
+
+ case 2: // _CRT_ASSERT
+ __debugbreak();
+ return 0;
}
- return ptr;
+ char* p = NULL;
+ *p = '\0';
+ return 0;
}
-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);
+int _CrtDbgReport(int reportType,
+ const char*,
+ int,
+ const char*,
+ const char*,
+ ...) {
+ return error_handler(reportType);
}
-#include "generic_allocators.cc"
+int _CrtDbgReportW(int reportType,
+ const wchar_t*,
+ int,
+ const wchar_t*,
+ const wchar_t*,
+ ...) {
+ return error_handler(reportType);
+}
+
+int _CrtSetReportMode(int, int) {
+ return 0;
+}
+
+void* _malloc_dbg(size_t size, int, const char*, int) {
+ return malloc(size);
+}
+
+void* _realloc_dbg(void* ptr, size_t size, int, const char*, int) {
+ return realloc(ptr, size);
+}
+
+void _free_dbg(void* ptr, int) {
+ free(ptr);
+}
+
+void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
+ return calloc(n, size);
+}
+#endif // NDEBUG
} // extern C
« no previous file with comments | « base/allocator/allocator.gyp ('k') | base/allocator/generic_allocators.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698