OLD | NEW |
---|---|
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 | 8 |
9 #include <new> | 9 #include <new> |
10 | 10 |
11 #include "base/atomicops.h" | 11 #include "base/atomicops.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "base/process/process_metrics.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) | 18 #if !defined(OS_WIN) |
19 #include <unistd.h> | 19 #include <unistd.h> |
20 #else | 20 #else |
21 #include "base/allocator/winheap_stubs_win.h" | 21 #include "base/allocator/winheap_stubs_win.h" |
22 #endif | 22 #endif |
23 | 23 |
24 #if defined(OS_MACOSX) | |
25 #include <malloc/malloc.h> | |
26 #endif | |
27 | |
24 // No calls to malloc / new in this file. They would would cause re-entrancy of | 28 // No calls to malloc / new in this file. They would would cause re-entrancy of |
25 // the shim, which is hard to deal with. Keep this code as simple as possible | 29 // the shim, which is hard to deal with. Keep this code as simple as possible |
26 // and don't use any external C++ object here, not even //base ones. Even if | 30 // and don't use any external C++ object here, not even //base ones. Even if |
27 // they are safe to use today, in future they might be refactored. | 31 // they are safe to use today, in future they might be refactored. |
28 | 32 |
29 namespace { | 33 namespace { |
30 | 34 |
31 using namespace base; | 35 using namespace base; |
32 | 36 |
33 subtle::AtomicWord g_chain_head = reinterpret_cast<subtle::AtomicWord>( | 37 subtle::AtomicWord g_chain_head = reinterpret_cast<subtle::AtomicWord>( |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
89 | 93 |
90 namespace base { | 94 namespace base { |
91 namespace allocator { | 95 namespace allocator { |
92 | 96 |
93 void SetCallNewHandlerOnMallocFailure(bool value) { | 97 void SetCallNewHandlerOnMallocFailure(bool value) { |
94 g_call_new_handler_on_malloc_failure = value; | 98 g_call_new_handler_on_malloc_failure = value; |
95 } | 99 } |
96 | 100 |
97 void* UncheckedAlloc(size_t size) { | 101 void* UncheckedAlloc(size_t size) { |
98 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 102 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
99 return chain_head->alloc_function(chain_head, size); | 103 return chain_head->alloc_function(chain_head, size, nullptr); |
100 } | 104 } |
101 | 105 |
102 void InsertAllocatorDispatch(AllocatorDispatch* dispatch) { | 106 void InsertAllocatorDispatch(AllocatorDispatch* dispatch) { |
103 // Loop in case of (an unlikely) race on setting the list head. | 107 // Loop in case of (an unlikely) race on setting the list head. |
104 size_t kMaxRetries = 7; | 108 size_t kMaxRetries = 7; |
105 for (size_t i = 0; i < kMaxRetries; ++i) { | 109 for (size_t i = 0; i < kMaxRetries; ++i) { |
106 const AllocatorDispatch* chain_head = GetChainHead(); | 110 const AllocatorDispatch* chain_head = GetChainHead(); |
107 dispatch->next = chain_head; | 111 dispatch->next = chain_head; |
108 | 112 |
109 // This function guarantees to be thread-safe w.r.t. concurrent | 113 // This function guarantees to be thread-safe w.r.t. concurrent |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
151 // - If the std::new_handler is NOT set just return nullptr. | 155 // - If the std::new_handler is NOT set just return nullptr. |
152 // - If the std::new_handler is set: | 156 // - If the std::new_handler is set: |
153 // - Assume it will abort() if it fails (very likely the new_handler will | 157 // - Assume it will abort() if it fails (very likely the new_handler will |
154 // just suicide priting a message). | 158 // just suicide priting a message). |
155 // - Assume it did succeed if it returns, in which case reattempt the alloc. | 159 // - Assume it did succeed if it returns, in which case reattempt the alloc. |
156 | 160 |
157 void* ShimCppNew(size_t size) { | 161 void* ShimCppNew(size_t size) { |
158 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 162 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
159 void* ptr; | 163 void* ptr; |
160 do { | 164 do { |
161 ptr = chain_head->alloc_function(chain_head, size); | 165 void* context = nullptr; |
166 #if defined(OS_MACOSX) | |
167 context = malloc_default_zone(); | |
168 #endif | |
169 ptr = chain_head->alloc_function(chain_head, size, context); | |
162 } while (!ptr && CallNewHandler(size)); | 170 } while (!ptr && CallNewHandler(size)); |
163 return ptr; | 171 return ptr; |
164 } | 172 } |
165 | 173 |
166 void ShimCppDelete(void* address) { | 174 void ShimCppDelete(void* address) { |
175 void* context = nullptr; | |
176 #if defined(OS_MACOSX) | |
177 context = malloc_default_zone(); | |
178 #endif | |
167 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 179 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
168 return chain_head->free_function(chain_head, address); | 180 return chain_head->free_function(chain_head, address, context); |
169 } | 181 } |
170 | 182 |
171 void* ShimMalloc(size_t size) { | 183 void* ShimMalloc(size_t size, void* context) { |
172 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 184 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
173 void* ptr; | 185 void* ptr; |
174 do { | 186 do { |
175 ptr = chain_head->alloc_function(chain_head, size); | 187 ptr = chain_head->alloc_function(chain_head, size, context); |
176 } while (!ptr && g_call_new_handler_on_malloc_failure && | 188 } while (!ptr && g_call_new_handler_on_malloc_failure && |
177 CallNewHandler(size)); | 189 CallNewHandler(size)); |
178 return ptr; | 190 return ptr; |
179 } | 191 } |
180 | 192 |
181 void* ShimCalloc(size_t n, size_t size) { | 193 void* ShimCalloc(size_t n, size_t size, void* context) { |
182 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 194 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
183 void* ptr; | 195 void* ptr; |
184 do { | 196 do { |
185 ptr = chain_head->alloc_zero_initialized_function(chain_head, n, size); | 197 ptr = chain_head->alloc_zero_initialized_function(chain_head, n, size, |
198 context); | |
186 } while (!ptr && g_call_new_handler_on_malloc_failure && | 199 } while (!ptr && g_call_new_handler_on_malloc_failure && |
187 CallNewHandler(size)); | 200 CallNewHandler(size)); |
188 return ptr; | 201 return ptr; |
189 } | 202 } |
190 | 203 |
191 void* ShimRealloc(void* address, size_t size) { | 204 void* ShimRealloc(void* address, size_t size, void* context) { |
192 // realloc(size == 0) means free() and might return a nullptr. We should | 205 // realloc(size == 0) means free() and might return a nullptr. We should |
193 // not call the std::new_handler in that case, though. | 206 // not call the std::new_handler in that case, though. |
194 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 207 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
195 void* ptr; | 208 void* ptr; |
196 do { | 209 do { |
197 ptr = chain_head->realloc_function(chain_head, address, size); | 210 ptr = chain_head->realloc_function(chain_head, address, size, context); |
198 } while (!ptr && size && g_call_new_handler_on_malloc_failure && | 211 } while (!ptr && size && g_call_new_handler_on_malloc_failure && |
199 CallNewHandler(size)); | 212 CallNewHandler(size)); |
200 return ptr; | 213 return ptr; |
201 } | 214 } |
202 | 215 |
203 void* ShimMemalign(size_t alignment, size_t size) { | 216 void* ShimMemalign(size_t alignment, size_t size, void* context) { |
204 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 217 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
205 void* ptr; | 218 void* ptr; |
206 do { | 219 do { |
207 ptr = chain_head->alloc_aligned_function(chain_head, alignment, size); | 220 ptr = chain_head->alloc_aligned_function(chain_head, alignment, size, |
221 context); | |
208 } while (!ptr && g_call_new_handler_on_malloc_failure && | 222 } while (!ptr && g_call_new_handler_on_malloc_failure && |
209 CallNewHandler(size)); | 223 CallNewHandler(size)); |
210 return ptr; | 224 return ptr; |
211 } | 225 } |
212 | 226 |
213 int ShimPosixMemalign(void** res, size_t alignment, size_t size) { | 227 int ShimPosixMemalign(void** res, size_t alignment, size_t size) { |
214 // posix_memalign is supposed to check the arguments. See tc_posix_memalign() | 228 // posix_memalign is supposed to check the arguments. See tc_posix_memalign() |
215 // in tc_malloc.cc. | 229 // in tc_malloc.cc. |
216 if (((alignment % sizeof(void*)) != 0) || | 230 if (((alignment % sizeof(void*)) != 0) || |
217 ((alignment & (alignment - 1)) != 0) || (alignment == 0)) { | 231 ((alignment & (alignment - 1)) != 0) || (alignment == 0)) { |
218 return EINVAL; | 232 return EINVAL; |
219 } | 233 } |
220 void* ptr = ShimMemalign(alignment, size); | 234 void* ptr = ShimMemalign(alignment, size, nullptr); |
221 *res = ptr; | 235 *res = ptr; |
222 return ptr ? 0 : ENOMEM; | 236 return ptr ? 0 : ENOMEM; |
223 } | 237 } |
224 | 238 |
225 void* ShimValloc(size_t size) { | 239 void* ShimValloc(size_t size, void* context) { |
226 return ShimMemalign(GetCachedPageSize(), size); | 240 return ShimMemalign(GetCachedPageSize(), size, context); |
227 } | 241 } |
228 | 242 |
229 void* ShimPvalloc(size_t size) { | 243 void* ShimPvalloc(size_t size) { |
230 // pvalloc(0) should allocate one page, according to its man page. | 244 // pvalloc(0) should allocate one page, according to its man page. |
231 if (size == 0) { | 245 if (size == 0) { |
232 size = GetCachedPageSize(); | 246 size = GetCachedPageSize(); |
233 } else { | 247 } else { |
234 size = (size + GetCachedPageSize() - 1) & ~(GetCachedPageSize() - 1); | 248 size = (size + GetCachedPageSize() - 1) & ~(GetCachedPageSize() - 1); |
235 } | 249 } |
236 return ShimMemalign(GetCachedPageSize(), size); | 250 return ShimMemalign(GetCachedPageSize(), size, nullptr); |
Primiano Tucci (use gerrit)
2017/02/20 10:33:05
add a comment saying that this is nullptr because
| |
237 } | 251 } |
238 | 252 |
239 void ShimFree(void* address) { | 253 void ShimFree(void* address, void* context) { |
240 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 254 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
241 return chain_head->free_function(chain_head, address); | 255 return chain_head->free_function(chain_head, address, context); |
242 } | 256 } |
243 | 257 |
244 size_t ShimGetSizeEstimate(const void* address) { | 258 size_t ShimGetSizeEstimate(const void* address, void* context) { |
245 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 259 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
246 return chain_head->get_size_estimate_function(chain_head, | 260 return chain_head->get_size_estimate_function( |
247 const_cast<void*>(address)); | 261 chain_head, const_cast<void*>(address), context); |
248 } | 262 } |
249 | 263 |
250 unsigned ShimBatchMalloc(size_t size, void** results, unsigned num_requested) { | 264 unsigned ShimBatchMalloc(size_t size, |
265 void** results, | |
266 unsigned num_requested, | |
267 void* context) { | |
251 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 268 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
252 return chain_head->batch_malloc_function(chain_head, size, results, | 269 return chain_head->batch_malloc_function(chain_head, size, results, |
253 num_requested); | 270 num_requested, context); |
254 } | 271 } |
255 | 272 |
256 void ShimBatchFree(void** to_be_freed, unsigned num_to_be_freed) { | 273 void ShimBatchFree(void** to_be_freed, |
274 unsigned num_to_be_freed, | |
275 void* context) { | |
257 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 276 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
258 return chain_head->batch_free_function(chain_head, to_be_freed, | 277 return chain_head->batch_free_function(chain_head, to_be_freed, |
259 num_to_be_freed); | 278 num_to_be_freed, context); |
260 } | 279 } |
261 | 280 |
262 void ShimFreeDefiniteSize(void* ptr, size_t size) { | 281 void ShimFreeDefiniteSize(void* ptr, size_t size, void* context) { |
263 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 282 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
264 return chain_head->free_definite_size_function(chain_head, ptr, size); | 283 return chain_head->free_definite_size_function(chain_head, ptr, size, |
284 context); | |
265 } | 285 } |
266 | 286 |
267 } // extern "C" | 287 } // extern "C" |
268 | 288 |
269 #if !defined(OS_WIN) && !defined(OS_MACOSX) | 289 #if !defined(OS_WIN) && !defined(OS_MACOSX) |
270 // Cpp symbols (new / delete) should always be routed through the shim layer | 290 // Cpp symbols (new / delete) should always be routed through the shim layer |
271 // except on Windows and macOS where the malloc intercept is deep enough that it | 291 // except on Windows and macOS where the malloc intercept is deep enough that it |
272 // also catches the cpp calls. | 292 // also catches the cpp calls. |
273 #include "base/allocator/allocator_shim_override_cpp_symbols.h" | 293 #include "base/allocator/allocator_shim_override_cpp_symbols.h" |
274 #endif | 294 #endif |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
313 // Cross-checks. | 333 // Cross-checks. |
314 | 334 |
315 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 335 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
316 #error The allocator shim should not be compiled when building for memory tools. | 336 #error The allocator shim should not be compiled when building for memory tools. |
317 #endif | 337 #endif |
318 | 338 |
319 #if (defined(__GNUC__) && defined(__EXCEPTIONS)) || \ | 339 #if (defined(__GNUC__) && defined(__EXCEPTIONS)) || \ |
320 (defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS) | 340 (defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS) |
321 #error This code cannot be used when exceptions are turned on. | 341 #error This code cannot be used when exceptions are turned on. |
322 #endif | 342 #endif |
OLD | NEW |