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

Side by Side Diff: base/allocator/allocator_shim.cc

Issue 2138173002: Hookup the generic heap intercept for Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Squash the use_experimental_allocator_shim for NaCL as per Brett's suggestion. Created 4 years, 5 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 unified diff | Download patch
« no previous file with comments | « base/allocator/BUILD.gn ('k') | base/allocator/allocator_shim_default_dispatch_to_winheap.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/allocator/allocator_shim.h" 5 #include "base/allocator/allocator_shim.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <unistd.h>
9 8
10 #include <new> 9 #include <new>
11 10
12 #include "base/atomicops.h" 11 #include "base/atomicops.h"
13 #include "base/logging.h" 12 #include "base/logging.h"
14 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/process/process_metrics.h"
15 #include "base/threading/platform_thread.h" 15 #include "base/threading/platform_thread.h"
16 #include "build/build_config.h" 16 #include "build/build_config.h"
17 17
18 #if !defined(OS_WIN)
19 #include <unistd.h>
20 #else
21 #include "base/allocator/winheap_stubs_win.h"
22 #endif
23
18 // No calls to malloc / new in this file. They would would cause re-entrancy of 24 // No calls to malloc / new in this file. They would would cause re-entrancy of
19 // the shim, which is hard to deal with. Keep this code as simple as possible 25 // the shim, which is hard to deal with. Keep this code as simple as possible
20 // and don't use any external C++ object here, not even //base ones. Even if 26 // and don't use any external C++ object here, not even //base ones. Even if
21 // they are safe to use today, in future they might be refactored. 27 // they are safe to use today, in future they might be refactored.
22 28
23 namespace { 29 namespace {
24 30
25 using namespace base; 31 using namespace base;
26 32
27 subtle::AtomicWord g_chain_head = reinterpret_cast<subtle::AtomicWord>( 33 subtle::AtomicWord g_chain_head = reinterpret_cast<subtle::AtomicWord>(
28 &allocator::AllocatorDispatch::default_dispatch); 34 &allocator::AllocatorDispatch::default_dispatch);
29 35
30 bool g_call_new_handler_on_malloc_failure = false; 36 bool g_call_new_handler_on_malloc_failure = false;
31 subtle::Atomic32 g_new_handler_lock = 0; 37 subtle::Atomic32 g_new_handler_lock = 0;
32 38
33 // In theory this should be just base::ThreadChecker. But we can't afford 39 // In theory this should be just base::ThreadChecker. But we can't afford
34 // the luxury of a LazyInstance<ThreadChecker> here as it would cause a new(). 40 // the luxury of a LazyInstance<ThreadChecker> here as it would cause a new().
35 bool CalledOnValidThread() { 41 bool CalledOnValidThread() {
36 using subtle::Atomic32; 42 using subtle::Atomic32;
37 const Atomic32 kInvalidTID = static_cast<Atomic32>(kInvalidThreadId); 43 const Atomic32 kInvalidTID = static_cast<Atomic32>(kInvalidThreadId);
38 static Atomic32 g_tid = kInvalidTID; 44 static Atomic32 g_tid = kInvalidTID;
39 Atomic32 cur_tid = static_cast<Atomic32>(PlatformThread::CurrentId()); 45 Atomic32 cur_tid = static_cast<Atomic32>(PlatformThread::CurrentId());
40 Atomic32 prev_tid = 46 Atomic32 prev_tid =
41 subtle::NoBarrier_CompareAndSwap(&g_tid, kInvalidTID, cur_tid); 47 subtle::NoBarrier_CompareAndSwap(&g_tid, kInvalidTID, cur_tid);
42 return prev_tid == kInvalidTID || prev_tid == cur_tid; 48 return prev_tid == kInvalidTID || prev_tid == cur_tid;
43 } 49 }
44 50
45 inline size_t GetPageSize() { 51 inline size_t GetCachedPageSize() {
46 static size_t pagesize = 0; 52 static size_t pagesize = 0;
47 if (!pagesize) 53 if (!pagesize)
48 pagesize = sysconf(_SC_PAGESIZE); 54 pagesize = base::GetPageSize();
49 return pagesize; 55 return pagesize;
50 } 56 }
51 57
52 // Calls the std::new handler thread-safely. Returns true if a new_handler was 58 // Calls the std::new handler thread-safely. Returns true if a new_handler was
53 // set and called, false if no new_handler was set. 59 // set and called, false if no new_handler was set.
54 bool CallNewHandler() { 60 bool CallNewHandler(size_t size) {
61 #if defined(OS_WIN)
62 return base::allocator::WinCallNewHandler(size);
63 #else
55 // TODO(primiano): C++11 has introduced ::get_new_handler() which is supposed 64 // TODO(primiano): C++11 has introduced ::get_new_handler() which is supposed
56 // to be thread safe and would avoid the spinlock boilerplate here. However 65 // to be thread safe and would avoid the spinlock boilerplate here. However
57 // it doesn't seem to be available yet in the Linux chroot headers yet. 66 // it doesn't seem to be available yet in the Linux chroot headers yet.
58 std::new_handler nh; 67 std::new_handler nh;
59 { 68 {
60 while (subtle::Acquire_CompareAndSwap(&g_new_handler_lock, 0, 1)) 69 while (subtle::Acquire_CompareAndSwap(&g_new_handler_lock, 0, 1))
61 PlatformThread::YieldCurrentThread(); 70 PlatformThread::YieldCurrentThread();
62 nh = std::set_new_handler(0); 71 nh = std::set_new_handler(0);
63 ignore_result(std::set_new_handler(nh)); 72 ignore_result(std::set_new_handler(nh));
64 subtle::Release_Store(&g_new_handler_lock, 0); 73 subtle::Release_Store(&g_new_handler_lock, 0);
65 } 74 }
66 if (!nh) 75 if (!nh)
67 return false; 76 return false;
68 (*nh)(); 77 (*nh)();
69 // Assume the new_handler will abort if it fails. Exception are disabled and 78 // Assume the new_handler will abort if it fails. Exception are disabled and
70 // we don't support the case of a new_handler throwing std::bad_balloc. 79 // we don't support the case of a new_handler throwing std::bad_balloc.
71 return true; 80 return true;
81 #endif
72 } 82 }
73 83
74 inline const allocator::AllocatorDispatch* GetChainHead() { 84 inline const allocator::AllocatorDispatch* GetChainHead() {
75 // TODO(primiano): Just use NoBarrier_Load once crbug.com/593344 is fixed. 85 // TODO(primiano): Just use NoBarrier_Load once crbug.com/593344 is fixed.
76 // Unfortunately due to that bug NoBarrier_Load() is mistakenly fully 86 // Unfortunately due to that bug NoBarrier_Load() is mistakenly fully
77 // barriered on Linux+Clang, and that causes visible perf regressons. 87 // barriered on Linux+Clang, and that causes visible perf regressons.
78 return reinterpret_cast<const allocator::AllocatorDispatch*>( 88 return reinterpret_cast<const allocator::AllocatorDispatch*>(
79 #if defined(OS_LINUX) && defined(__clang__) 89 #if defined(OS_LINUX) && defined(__clang__)
80 *static_cast<const volatile subtle::AtomicWord*>(&g_chain_head) 90 *static_cast<const volatile subtle::AtomicWord*>(&g_chain_head)
81 #else 91 #else
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 // - If the std::new_handler is set: 151 // - If the std::new_handler is set:
142 // - Assume it will abort() if it fails (very likely the new_handler will 152 // - Assume it will abort() if it fails (very likely the new_handler will
143 // just suicide priting a message). 153 // just suicide priting a message).
144 // - Assume it did succeed if it returns, in which case reattempt the alloc. 154 // - Assume it did succeed if it returns, in which case reattempt the alloc.
145 155
146 void* ShimCppNew(size_t size) { 156 void* ShimCppNew(size_t size) {
147 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); 157 const allocator::AllocatorDispatch* const chain_head = GetChainHead();
148 void* ptr; 158 void* ptr;
149 do { 159 do {
150 ptr = chain_head->alloc_function(chain_head, size); 160 ptr = chain_head->alloc_function(chain_head, size);
151 } while (!ptr && CallNewHandler()); 161 } while (!ptr && CallNewHandler(size));
152 return ptr; 162 return ptr;
153 } 163 }
154 164
155 void ShimCppDelete(void* address) { 165 void ShimCppDelete(void* address) {
156 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); 166 const allocator::AllocatorDispatch* const chain_head = GetChainHead();
157 return chain_head->free_function(chain_head, address); 167 return chain_head->free_function(chain_head, address);
158 } 168 }
159 169
160 void* ShimMalloc(size_t size) { 170 void* ShimMalloc(size_t size) {
161 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); 171 const allocator::AllocatorDispatch* const chain_head = GetChainHead();
162 void* ptr; 172 void* ptr;
163 do { 173 do {
164 ptr = chain_head->alloc_function(chain_head, size); 174 ptr = chain_head->alloc_function(chain_head, size);
165 } while (!ptr && g_call_new_handler_on_malloc_failure && CallNewHandler()); 175 } while (!ptr && g_call_new_handler_on_malloc_failure &&
176 CallNewHandler(size));
166 return ptr; 177 return ptr;
167 } 178 }
168 179
169 void* ShimCalloc(size_t n, size_t size) { 180 void* ShimCalloc(size_t n, size_t size) {
170 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); 181 const allocator::AllocatorDispatch* const chain_head = GetChainHead();
171 void* ptr; 182 void* ptr;
172 do { 183 do {
173 ptr = chain_head->alloc_zero_initialized_function(chain_head, n, size); 184 ptr = chain_head->alloc_zero_initialized_function(chain_head, n, size);
174 } while (!ptr && g_call_new_handler_on_malloc_failure && CallNewHandler()); 185 } while (!ptr && g_call_new_handler_on_malloc_failure &&
186 CallNewHandler(size));
175 return ptr; 187 return ptr;
176 } 188 }
177 189
178 void* ShimRealloc(void* address, size_t size) { 190 void* ShimRealloc(void* address, size_t size) {
179 // realloc(size == 0) means free() and might return a nullptr. We should 191 // realloc(size == 0) means free() and might return a nullptr. We should
180 // not call the std::new_handler in that case, though. 192 // not call the std::new_handler in that case, though.
181 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); 193 const allocator::AllocatorDispatch* const chain_head = GetChainHead();
182 void* ptr; 194 void* ptr;
183 do { 195 do {
184 ptr = chain_head->realloc_function(chain_head, address, size); 196 ptr = chain_head->realloc_function(chain_head, address, size);
185 } while (!ptr && size && g_call_new_handler_on_malloc_failure && 197 } while (!ptr && size && g_call_new_handler_on_malloc_failure &&
186 CallNewHandler()); 198 CallNewHandler(size));
187 return ptr; 199 return ptr;
188 } 200 }
189 201
190 void* ShimMemalign(size_t alignment, size_t size) { 202 void* ShimMemalign(size_t alignment, size_t size) {
191 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); 203 const allocator::AllocatorDispatch* const chain_head = GetChainHead();
192 void* ptr; 204 void* ptr;
193 do { 205 do {
194 ptr = chain_head->alloc_aligned_function(chain_head, alignment, size); 206 ptr = chain_head->alloc_aligned_function(chain_head, alignment, size);
195 } while (!ptr && g_call_new_handler_on_malloc_failure && CallNewHandler()); 207 } while (!ptr && g_call_new_handler_on_malloc_failure &&
208 CallNewHandler(size));
196 return ptr; 209 return ptr;
197 } 210 }
198 211
199 int ShimPosixMemalign(void** res, size_t alignment, size_t size) { 212 int ShimPosixMemalign(void** res, size_t alignment, size_t size) {
200 // posix_memalign is supposed to check the arguments. See tc_posix_memalign() 213 // posix_memalign is supposed to check the arguments. See tc_posix_memalign()
201 // in tc_malloc.cc. 214 // in tc_malloc.cc.
202 if (((alignment % sizeof(void*)) != 0) || 215 if (((alignment % sizeof(void*)) != 0) ||
203 ((alignment & (alignment - 1)) != 0) || (alignment == 0)) { 216 ((alignment & (alignment - 1)) != 0) || (alignment == 0)) {
204 return EINVAL; 217 return EINVAL;
205 } 218 }
206 void* ptr = ShimMemalign(alignment, size); 219 void* ptr = ShimMemalign(alignment, size);
207 *res = ptr; 220 *res = ptr;
208 return ptr ? 0 : ENOMEM; 221 return ptr ? 0 : ENOMEM;
209 } 222 }
210 223
211 void* ShimValloc(size_t size) { 224 void* ShimValloc(size_t size) {
212 return ShimMemalign(GetPageSize(), size); 225 return ShimMemalign(GetCachedPageSize(), size);
213 } 226 }
214 227
215 void* ShimPvalloc(size_t size) { 228 void* ShimPvalloc(size_t size) {
216 // pvalloc(0) should allocate one page, according to its man page. 229 // pvalloc(0) should allocate one page, according to its man page.
217 if (size == 0) { 230 if (size == 0) {
218 size = GetPageSize(); 231 size = GetCachedPageSize();
219 } else { 232 } else {
220 size = (size + GetPageSize() - 1) & ~(GetPageSize() - 1); 233 size = (size + GetCachedPageSize() - 1) & ~(GetCachedPageSize() - 1);
221 } 234 }
222 return ShimMemalign(GetPageSize(), size); 235 return ShimMemalign(GetCachedPageSize(), size);
223 } 236 }
224 237
225 void ShimFree(void* address) { 238 void ShimFree(void* address) {
226 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); 239 const allocator::AllocatorDispatch* const chain_head = GetChainHead();
227 return chain_head->free_function(chain_head, address); 240 return chain_head->free_function(chain_head, address);
228 } 241 }
229 242
230 } // extern "C" 243 } // extern "C"
231 244
232 // Cpp symbols (new / delete) should always be routed through the shim layer. 245 #if !defined(OS_WIN)
246 // Cpp symbols (new / delete) should always be routed through the shim layer
247 // except on Windows where the malloc intercept is deep enough that it also
248 // catches the cpp calls.
233 #include "base/allocator/allocator_shim_override_cpp_symbols.h" 249 #include "base/allocator/allocator_shim_override_cpp_symbols.h"
250 #endif
234 251
252 #if defined(OS_ANDROID)
235 // Android does not support symbol interposition. The way malloc symbols are 253 // Android does not support symbol interposition. The way malloc symbols are
236 // intercepted on Android is by using link-time -wrap flags. 254 // intercepted on Android is by using link-time -wrap flags.
237 #if !defined(OS_ANDROID) 255 #include "base/allocator/allocator_shim_override_linker_wrapped_symbols.h"
238 // Ditto for plain malloc() / calloc() / free() etc. symbols. 256 #elif defined(OS_WIN)
257 // On Windows we use plain link-time overriding of the CRT symbols.
258 #include "base/allocator/allocator_shim_override_ucrt_symbols_win.h"
259 #else
239 #include "base/allocator/allocator_shim_override_libc_symbols.h" 260 #include "base/allocator/allocator_shim_override_libc_symbols.h"
240 #else
241 #include "base/allocator/allocator_shim_override_linker_wrapped_symbols.h"
242 #endif 261 #endif
243 262
244 // In the case of tcmalloc we also want to plumb into the glibc hooks 263 // In the case of tcmalloc we also want to plumb into the glibc hooks
245 // to avoid that allocations made in glibc itself (e.g., strdup()) get 264 // to avoid that allocations made in glibc itself (e.g., strdup()) get
246 // accidentally performed on the glibc heap instead of the tcmalloc one. 265 // accidentally performed on the glibc heap instead of the tcmalloc one.
247 #if defined(USE_TCMALLOC) 266 #if defined(USE_TCMALLOC)
248 #include "base/allocator/allocator_shim_override_glibc_weak_symbols.h" 267 #include "base/allocator/allocator_shim_override_glibc_weak_symbols.h"
249 #endif 268 #endif
250 269
251 // Cross-checks. 270 // Cross-checks.
252 271
253 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) 272 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
254 #error The allocator shim should not be compiled when building for memory tools. 273 #error The allocator shim should not be compiled when building for memory tools.
255 #endif 274 #endif
256 275
257 #if (defined(__GNUC__) && defined(__EXCEPTIONS)) || \ 276 #if (defined(__GNUC__) && defined(__EXCEPTIONS)) || \
258 (defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS) 277 (defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS)
259 #error This code cannot be used when exceptions are turned on. 278 #error This code cannot be used when exceptions are turned on.
260 #endif 279 #endif
OLDNEW
« no previous file with comments | « base/allocator/BUILD.gn ('k') | base/allocator/allocator_shim_default_dispatch_to_winheap.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698