Commit 25da2dbf authored by siggi's avatar siggi Committed by Commit bot

Start refactoring Windows allocator shim in prep for hooking in generic allocator shim on Windows.

BUG=550886

Review-Url: https://codereview.chromium.org/2143693003
Cr-Commit-Position: refs/heads/master@{#405984}
parent 1ce44d25
...@@ -1986,6 +1986,7 @@ test("base_unittests") { ...@@ -1986,6 +1986,7 @@ test("base_unittests") {
":base", ":base",
":i18n", ":i18n",
":message_loop_tests", ":message_loop_tests",
"//base/allocator:features",
"//base/test:run_all_unittests", "//base/test:run_all_unittests",
"//base/test:test_support", "//base/test:test_support",
"//base/third_party/dynamic_annotations", "//base/third_party/dynamic_annotations",
......
...@@ -93,6 +93,8 @@ if (win_use_allocator_shim) { ...@@ -93,6 +93,8 @@ if (win_use_allocator_shim) {
sources = [ sources = [
"allocator_shim_win.cc", "allocator_shim_win.cc",
"allocator_shim_win.h", "allocator_shim_win.h",
"winheap_stubs_win.cc",
"winheap_stubs_win.h",
] ]
configs += [ ":allocator_shim_define" ] configs += [ ":allocator_shim_define" ]
} }
...@@ -276,7 +278,10 @@ if (use_allocator == "tcmalloc") { ...@@ -276,7 +278,10 @@ if (use_allocator == "tcmalloc") {
buildflag_header("features") { buildflag_header("features") {
header = "features.h" header = "features.h"
flags = [ "USE_EXPERIMENTAL_ALLOCATOR_SHIM=$use_experimental_allocator_shim" ] flags = [
"USE_EXPERIMENTAL_ALLOCATOR_SHIM=$use_experimental_allocator_shim",
"ENABLE_WIN_ALLOCATOR_SHIM_TESTS=($use_experimental_allocator_shim || $win_use_allocator_shim)",
]
} }
if (use_experimental_allocator_shim) { if (use_experimental_allocator_shim) {
......
...@@ -55,6 +55,8 @@ ...@@ -55,6 +55,8 @@
'sources': [ 'sources': [
'allocator_shim_win.cc', 'allocator_shim_win.cc',
'allocator_shim_win.h', 'allocator_shim_win.h',
'winheap_stubs_win.cc',
'winheap_stubs_win.h',
], ],
'configurations': { 'configurations': {
'Debug_Base': { 'Debug_Base': {
...@@ -387,6 +389,12 @@ ...@@ -387,6 +389,12 @@
'buildflag_flags': [ 'buildflag_flags': [
'USE_EXPERIMENTAL_ALLOCATOR_SHIM=<(use_experimental_allocator_shim)', 'USE_EXPERIMENTAL_ALLOCATOR_SHIM=<(use_experimental_allocator_shim)',
], ],
'conditions': [
['<(use_experimental_allocator_shim) or <(win_use_allocator_shim)',
{'buildflag_flags': [ 'ENABLE_WIN_ALLOCATOR_SHIM_TESTS=1' ],},
{'buildflag_flags': [ 'ENABLE_WIN_ALLOCATOR_SHIM_TESTS=0' ],}
],
],
}, },
}, # 'allocator_features' target. }, # 'allocator_features' target.
], # targets. ], # targets.
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
// This #if is needed as gyp can't have different compile // This #if is needed as gyp can't have different compile
// targets between Debug and Release. // targets between Debug and Release.
// TODO(wfh): Remove this once gyp is dead. // TODO(wfh): Remove this once gyp is dead.
// TODO(siggi): Remove this file once the generic shim sticks.
#if defined(ALLOCATOR_SHIM) #if defined(ALLOCATOR_SHIM)
#include <limits.h> #include <limits.h>
...@@ -14,7 +15,8 @@ ...@@ -14,7 +15,8 @@
#include <windows.h> #include <windows.h>
#include <stddef.h> #include <stddef.h>
#include "allocator_shim_win.h" #include "base/allocator/allocator_shim_win.h"
#include "base/allocator/winheap_stubs_win.h"
// This shim make it possible to perform additional checks on allocations // This shim make it possible to perform additional checks on allocations
// before passing them to the Heap functions. // before passing them to the Heap functions.
...@@ -26,66 +28,16 @@ ...@@ -26,66 +28,16 @@
// See definitions of original functions in ucrt\corecrt_malloc.h in SDK // See definitions of original functions in ucrt\corecrt_malloc.h in SDK
// include directory. // include directory.
namespace base {
namespace allocator {
bool g_is_win_shim_layer_initialized = false;
} // namespace allocator
} // namespace base
namespace { namespace {
const size_t kWindowsPageSize = 4096;
const size_t kMaxWindowsAllocation = INT_MAX - kWindowsPageSize;
int new_mode = 0; int new_mode = 0;
inline HANDLE get_heap_handle() {
return reinterpret_cast<HANDLE>(_get_heap_handle());
}
void* win_heap_malloc(size_t size) {
if (size < kMaxWindowsAllocation)
return HeapAlloc(get_heap_handle(), 0, size);
return nullptr;
}
void win_heap_free(void* size) {
HeapFree(get_heap_handle(), 0, size);
}
void* win_heap_realloc(void* ptr, size_t size) {
if (!ptr)
return win_heap_malloc(size);
if (!size) {
win_heap_free(ptr);
return nullptr;
}
if (size < kMaxWindowsAllocation)
return HeapReAlloc(get_heap_handle(), 0, ptr, size);
return nullptr;
}
// 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) {
// Get the current new handler.
_PNH nh = _query_new_handler();
#if defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
if (!nh)
return false;
// Since exceptions are disabled, we don't really know if new_handler
// failed. Assume it will abort if it fails.
return nh(size) ? true : false;
#else
#error "Exceptions in allocator shim are not supported!"
#endif // defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
}
} // namespace } // namespace
extern "C" { extern "C" {
// Symbol to allow weak linkage to win_heap_malloc from memory_win.cc. // Symbol to allow weak linkage to WinHeapMalloc from allocator_impl_win.cc.
void* (*malloc_unchecked)(size_t) = &win_heap_malloc; void* (*malloc_unchecked)(size_t) = &base::allocator::WinHeapMalloc;
// This function behaves similarly to MSVC's _set_new_mode. // This function behaves similarly to MSVC's _set_new_mode.
// If flag is 0 (default), calls to malloc will behave normally. // If flag is 0 (default), calls to malloc will behave normally.
...@@ -100,6 +52,7 @@ int _set_new_mode(int flag) { ...@@ -100,6 +52,7 @@ int _set_new_mode(int flag) {
base::allocator::g_is_win_shim_layer_initialized = true; base::allocator::g_is_win_shim_layer_initialized = true;
int old_mode = new_mode; int old_mode = new_mode;
new_mode = flag; new_mode = flag;
return old_mode; return old_mode;
} }
...@@ -112,11 +65,11 @@ int _query_new_mode() { ...@@ -112,11 +65,11 @@ int _query_new_mode() {
__declspec(restrict) void* malloc(size_t size) { __declspec(restrict) void* malloc(size_t size) {
void* ptr; void* ptr;
for (;;) { for (;;) {
ptr = win_heap_malloc(size); ptr = base::allocator::WinHeapMalloc(size);
if (ptr) if (ptr)
return ptr; return ptr;
if (!new_mode || !call_new_handler(true, size)) if (!new_mode || base::allocator::WinCallNewHandler(size))
break; break;
} }
return ptr; return ptr;
...@@ -124,7 +77,7 @@ __declspec(restrict) void* malloc(size_t size) { ...@@ -124,7 +77,7 @@ __declspec(restrict) void* malloc(size_t size) {
// Replaces free in ucrt\heap\free.cpp // Replaces free in ucrt\heap\free.cpp
void free(void* p) { void free(void* p) {
win_heap_free(p); base::allocator::WinHeapFree(p);
return; return;
} }
...@@ -138,14 +91,14 @@ __declspec(restrict) void* realloc(void* ptr, size_t size) { ...@@ -138,14 +91,14 @@ __declspec(restrict) void* realloc(void* ptr, size_t size) {
void* new_ptr; void* new_ptr;
for (;;) { for (;;) {
new_ptr = win_heap_realloc(ptr, size); new_ptr = base::allocator::WinHeapRealloc(ptr, size);
// Subtle warning: NULL return does not alwas indicate out-of-memory. If // Subtle warning: NULL return does not alwas indicate out-of-memory. If
// the requested new size is zero, realloc should free the ptr and return // the requested new size is zero, realloc should free the ptr and return
// NULL. // NULL.
if (new_ptr || !size) if (new_ptr || !size)
return new_ptr; return new_ptr;
if (!new_mode || !call_new_handler(true, size)) if (!new_mode || !base::allocator::WinCallNewHandler(size))
break; break;
} }
return new_ptr; return new_ptr;
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This code should move into the default Windows shim once the win-specific
// allocation shim has been removed, and the generic shim has becaome the
// default.
#include "winheap_stubs_win.h"
#include <limits.h>
#include <malloc.h>
#include <new.h>
#include <windows.h>
namespace base {
namespace allocator {
bool g_is_win_shim_layer_initialized = false;
namespace {
const size_t kWindowsPageSize = 4096;
const size_t kMaxWindowsAllocation = INT_MAX - kWindowsPageSize;
inline HANDLE get_heap_handle() {
return reinterpret_cast<HANDLE>(_get_heap_handle());
}
} // namespace
void* WinHeapMalloc(size_t size) {
if (size < kMaxWindowsAllocation)
return HeapAlloc(get_heap_handle(), 0, size);
return nullptr;
}
void WinHeapFree(void* size) {
HeapFree(get_heap_handle(), 0, size);
}
void* WinHeapRealloc(void* ptr, size_t size) {
if (!ptr)
return WinHeapMalloc(size);
if (!size) {
WinHeapFree(ptr);
return nullptr;
}
if (size < kMaxWindowsAllocation)
return HeapReAlloc(get_heap_handle(), 0, ptr, size);
return nullptr;
}
// Call the new handler, if one has been set.
// Returns true on successfully calling the handler, false otherwise.
bool WinCallNewHandler(size_t size) {
#if !defined(_HAS_EXCEPTIONS) || _HAS_EXCEPTIONS
#error "Exceptions in allocator shim are not supported!"
#endif // defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
// Get the current new handler.
_PNH nh = _query_new_handler();
if (!nh)
return false;
// Since exceptions are disabled, we don't really know if new_handler
// failed. Assume it will abort if it fails.
return nh(size) ? true : false;
}
} // namespace allocator
} // namespace base
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Thin allocation wrappers for the windows heap. This file should be deleted
// once the win-specific allocation shim has been removed, and the generic shim
// has becaome the default.
#ifndef BASE_ALLOCATOR_WINHEAP_STUBS_H_
#define BASE_ALLOCATOR_WINHEAP_STUBS_H_
#include <stdint.h>
namespace base {
namespace allocator {
// Set to true if the link-time magic has successfully hooked into the CRT's
// heap initialization.
extern bool g_is_win_shim_layer_initialized;
// Thin wrappers to implement the standard C allocation semantics on the
// CRT's Windows heap.
void* WinHeapMalloc(size_t size);
void WinHeapFree(void* size);
void* WinHeapRealloc(void* ptr, size_t size);
// Call the new handler, if one has been set.
// Returns true on successfully calling the handler, false otherwise.
bool WinCallNewHandler(size_t size);
} // namespace allocator
} // namespace base
#endif // BASE_ALLOCATOR_WINHEAP_STUBS_H_
\ No newline at end of file
...@@ -621,6 +621,7 @@ ...@@ -621,6 +621,7 @@
'<@(trace_event_test_sources)', '<@(trace_event_test_sources)',
], ],
'dependencies': [ 'dependencies': [
'allocator/allocator.gyp:allocator_features#target',
'base', 'base',
'base_i18n', 'base_i18n',
'base_message_loop_tests', 'base_message_loop_tests',
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <limits> #include <limits>
#include "base/allocator/allocator_check.h" #include "base/allocator/allocator_check.h"
#include "base/allocator/features.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/debug/alias.h" #include "base/debug/alias.h"
#include "base/memory/aligned_memory.h" #include "base/memory/aligned_memory.h"
...@@ -86,8 +87,8 @@ TEST(MemoryTest, AllocatorShimWorking) { ...@@ -86,8 +87,8 @@ TEST(MemoryTest, AllocatorShimWorking) {
// Don't test these on ASan/TSan/MSan configurations: only test the real // Don't test these on ASan/TSan/MSan configurations: only test the real
// allocator. // allocator.
// Windows only supports these tests with the allocator shim in place. // Windows only supports these tests with the allocator shim in place.
#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && \ #if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && \
!(defined(OS_WIN) && !defined(ALLOCATOR_SHIM)) && \ BUILDFLAG(ENABLE_WIN_ALLOCATOR_SHIM_TESTS) && \
!defined(MEMORY_TOOL_REPLACES_ALLOCATOR) !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
namespace { namespace {
......
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