Chromium Code Reviews| 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 |