| 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 |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 void RemoveAllocatorDispatchForTesting(AllocatorDispatch* dispatch) { | 135 void RemoveAllocatorDispatchForTesting(AllocatorDispatch* dispatch) { |
| 136 DCHECK_EQ(GetChainHead(), dispatch); | 136 DCHECK_EQ(GetChainHead(), dispatch); |
| 137 subtle::NoBarrier_Store(&g_chain_head, | 137 subtle::NoBarrier_Store(&g_chain_head, |
| 138 reinterpret_cast<subtle::AtomicWord>(dispatch->next)); | 138 reinterpret_cast<subtle::AtomicWord>(dispatch->next)); |
| 139 } | 139 } |
| 140 | 140 |
| 141 } // namespace allocator | 141 } // namespace allocator |
| 142 } // namespace base | 142 } // namespace base |
| 143 | 143 |
| 144 // The Shim* functions below are the entry-points into the shim-layer and | 144 // The Shim* functions below are the entry-points into the shim-layer and |
| 145 // are supposed to be invoked / aliased by the allocator_shim_override_* | 145 // are supposed to be invoked by the allocator_shim_override_* |
| 146 // headers to route the malloc / new symbols through the shim layer. | 146 // headers to route the malloc / new symbols through the shim layer. |
| 147 // They are defined as ALWAYS_INLINE in order to remove a level of indirection |
| 148 // between the system-defined entry points and the shim implementations. |
| 147 extern "C" { | 149 extern "C" { |
| 148 | 150 |
| 149 // The general pattern for allocations is: | 151 // The general pattern for allocations is: |
| 150 // - Try to allocate, if succeded return the pointer. | 152 // - Try to allocate, if succeded return the pointer. |
| 151 // - If the allocation failed: | 153 // - If the allocation failed: |
| 152 // - Call the std::new_handler if it was a C++ allocation. | 154 // - Call the std::new_handler if it was a C++ allocation. |
| 153 // - Call the std::new_handler if it was a malloc() (or calloc() or similar) | 155 // - Call the std::new_handler if it was a malloc() (or calloc() or similar) |
| 154 // AND SetCallNewHandlerOnMallocFailure(true). | 156 // AND SetCallNewHandlerOnMallocFailure(true). |
| 155 // - If the std::new_handler is NOT set just return nullptr. | 157 // - If the std::new_handler is NOT set just return nullptr. |
| 156 // - If the std::new_handler is set: | 158 // - If the std::new_handler is set: |
| 157 // - Assume it will abort() if it fails (very likely the new_handler will | 159 // - Assume it will abort() if it fails (very likely the new_handler will |
| 158 // just suicide priting a message). | 160 // just suicide priting a message). |
| 159 // - Assume it did succeed if it returns, in which case reattempt the alloc. | 161 // - Assume it did succeed if it returns, in which case reattempt the alloc. |
| 160 | 162 |
| 161 void* ShimCppNew(size_t size) { | 163 ALWAYS_INLINE void* ShimCppNew(size_t size) { |
| 162 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 164 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 163 void* ptr; | 165 void* ptr; |
| 164 do { | 166 do { |
| 165 void* context = nullptr; | 167 void* context = nullptr; |
| 166 #if defined(OS_MACOSX) | 168 #if defined(OS_MACOSX) |
| 167 context = malloc_default_zone(); | 169 context = malloc_default_zone(); |
| 168 #endif | 170 #endif |
| 169 ptr = chain_head->alloc_function(chain_head, size, context); | 171 ptr = chain_head->alloc_function(chain_head, size, context); |
| 170 } while (!ptr && CallNewHandler(size)); | 172 } while (!ptr && CallNewHandler(size)); |
| 171 return ptr; | 173 return ptr; |
| 172 } | 174 } |
| 173 | 175 |
| 174 void ShimCppDelete(void* address) { | 176 ALWAYS_INLINE void ShimCppDelete(void* address) { |
| 175 void* context = nullptr; | 177 void* context = nullptr; |
| 176 #if defined(OS_MACOSX) | 178 #if defined(OS_MACOSX) |
| 177 context = malloc_default_zone(); | 179 context = malloc_default_zone(); |
| 178 #endif | 180 #endif |
| 179 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 181 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 180 return chain_head->free_function(chain_head, address, context); | 182 return chain_head->free_function(chain_head, address, context); |
| 181 } | 183 } |
| 182 | 184 |
| 183 void* ShimMalloc(size_t size, void* context) { | 185 ALWAYS_INLINE void* ShimMalloc(size_t size, void* context) { |
| 184 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 186 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 185 void* ptr; | 187 void* ptr; |
| 186 do { | 188 do { |
| 187 ptr = chain_head->alloc_function(chain_head, size, context); | 189 ptr = chain_head->alloc_function(chain_head, size, context); |
| 188 } while (!ptr && g_call_new_handler_on_malloc_failure && | 190 } while (!ptr && g_call_new_handler_on_malloc_failure && |
| 189 CallNewHandler(size)); | 191 CallNewHandler(size)); |
| 190 return ptr; | 192 return ptr; |
| 191 } | 193 } |
| 192 | 194 |
| 193 void* ShimCalloc(size_t n, size_t size, void* context) { | 195 ALWAYS_INLINE void* ShimCalloc(size_t n, size_t size, void* context) { |
| 194 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 196 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 195 void* ptr; | 197 void* ptr; |
| 196 do { | 198 do { |
| 197 ptr = chain_head->alloc_zero_initialized_function(chain_head, n, size, | 199 ptr = chain_head->alloc_zero_initialized_function(chain_head, n, size, |
| 198 context); | 200 context); |
| 199 } while (!ptr && g_call_new_handler_on_malloc_failure && | 201 } while (!ptr && g_call_new_handler_on_malloc_failure && |
| 200 CallNewHandler(size)); | 202 CallNewHandler(size)); |
| 201 return ptr; | 203 return ptr; |
| 202 } | 204 } |
| 203 | 205 |
| 204 void* ShimRealloc(void* address, size_t size, void* context) { | 206 ALWAYS_INLINE void* ShimRealloc(void* address, size_t size, void* context) { |
| 205 // realloc(size == 0) means free() and might return a nullptr. We should | 207 // realloc(size == 0) means free() and might return a nullptr. We should |
| 206 // not call the std::new_handler in that case, though. | 208 // not call the std::new_handler in that case, though. |
| 207 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 209 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 208 void* ptr; | 210 void* ptr; |
| 209 do { | 211 do { |
| 210 ptr = chain_head->realloc_function(chain_head, address, size, context); | 212 ptr = chain_head->realloc_function(chain_head, address, size, context); |
| 211 } while (!ptr && size && g_call_new_handler_on_malloc_failure && | 213 } while (!ptr && size && g_call_new_handler_on_malloc_failure && |
| 212 CallNewHandler(size)); | 214 CallNewHandler(size)); |
| 213 return ptr; | 215 return ptr; |
| 214 } | 216 } |
| 215 | 217 |
| 216 void* ShimMemalign(size_t alignment, size_t size, void* context) { | 218 ALWAYS_INLINE void* ShimMemalign(size_t alignment, size_t size, void* context) { |
| 217 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 219 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 218 void* ptr; | 220 void* ptr; |
| 219 do { | 221 do { |
| 220 ptr = chain_head->alloc_aligned_function(chain_head, alignment, size, | 222 ptr = chain_head->alloc_aligned_function(chain_head, alignment, size, |
| 221 context); | 223 context); |
| 222 } while (!ptr && g_call_new_handler_on_malloc_failure && | 224 } while (!ptr && g_call_new_handler_on_malloc_failure && |
| 223 CallNewHandler(size)); | 225 CallNewHandler(size)); |
| 224 return ptr; | 226 return ptr; |
| 225 } | 227 } |
| 226 | 228 |
| 227 int ShimPosixMemalign(void** res, size_t alignment, size_t size) { | 229 ALWAYS_INLINE int ShimPosixMemalign(void** res, size_t alignment, size_t size) { |
| 228 // posix_memalign is supposed to check the arguments. See tc_posix_memalign() | 230 // posix_memalign is supposed to check the arguments. See tc_posix_memalign() |
| 229 // in tc_malloc.cc. | 231 // in tc_malloc.cc. |
| 230 if (((alignment % sizeof(void*)) != 0) || | 232 if (((alignment % sizeof(void*)) != 0) || |
| 231 ((alignment & (alignment - 1)) != 0) || (alignment == 0)) { | 233 ((alignment & (alignment - 1)) != 0) || (alignment == 0)) { |
| 232 return EINVAL; | 234 return EINVAL; |
| 233 } | 235 } |
| 234 void* ptr = ShimMemalign(alignment, size, nullptr); | 236 void* ptr = ShimMemalign(alignment, size, nullptr); |
| 235 *res = ptr; | 237 *res = ptr; |
| 236 return ptr ? 0 : ENOMEM; | 238 return ptr ? 0 : ENOMEM; |
| 237 } | 239 } |
| 238 | 240 |
| 239 void* ShimValloc(size_t size, void* context) { | 241 ALWAYS_INLINE void* ShimValloc(size_t size, void* context) { |
| 240 return ShimMemalign(GetCachedPageSize(), size, context); | 242 return ShimMemalign(GetCachedPageSize(), size, context); |
| 241 } | 243 } |
| 242 | 244 |
| 243 void* ShimPvalloc(size_t size) { | 245 ALWAYS_INLINE void* ShimPvalloc(size_t size) { |
| 244 // pvalloc(0) should allocate one page, according to its man page. | 246 // pvalloc(0) should allocate one page, according to its man page. |
| 245 if (size == 0) { | 247 if (size == 0) { |
| 246 size = GetCachedPageSize(); | 248 size = GetCachedPageSize(); |
| 247 } else { | 249 } else { |
| 248 size = (size + GetCachedPageSize() - 1) & ~(GetCachedPageSize() - 1); | 250 size = (size + GetCachedPageSize() - 1) & ~(GetCachedPageSize() - 1); |
| 249 } | 251 } |
| 250 // The third argument is nullptr because pvalloc is glibc only and does not | 252 // The third argument is nullptr because pvalloc is glibc only and does not |
| 251 // exist on OSX/BSD systems. | 253 // exist on OSX/BSD systems. |
| 252 return ShimMemalign(GetCachedPageSize(), size, nullptr); | 254 return ShimMemalign(GetCachedPageSize(), size, nullptr); |
| 253 } | 255 } |
| 254 | 256 |
| 255 void ShimFree(void* address, void* context) { | 257 ALWAYS_INLINE void ShimFree(void* address, void* context) { |
| 256 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 258 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 257 return chain_head->free_function(chain_head, address, context); | 259 return chain_head->free_function(chain_head, address, context); |
| 258 } | 260 } |
| 259 | 261 |
| 260 size_t ShimGetSizeEstimate(const void* address, void* context) { | 262 ALWAYS_INLINE size_t ShimGetSizeEstimate(const void* address, void* context) { |
| 261 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 263 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 262 return chain_head->get_size_estimate_function( | 264 return chain_head->get_size_estimate_function( |
| 263 chain_head, const_cast<void*>(address), context); | 265 chain_head, const_cast<void*>(address), context); |
| 264 } | 266 } |
| 265 | 267 |
| 266 unsigned ShimBatchMalloc(size_t size, | 268 ALWAYS_INLINE unsigned ShimBatchMalloc(size_t size, |
| 267 void** results, | 269 void** results, |
| 268 unsigned num_requested, | 270 unsigned num_requested, |
| 269 void* context) { | 271 void* context) { |
| 270 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 272 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 271 return chain_head->batch_malloc_function(chain_head, size, results, | 273 return chain_head->batch_malloc_function(chain_head, size, results, |
| 272 num_requested, context); | 274 num_requested, context); |
| 273 } | 275 } |
| 274 | 276 |
| 275 void ShimBatchFree(void** to_be_freed, | 277 ALWAYS_INLINE void ShimBatchFree(void** to_be_freed, |
| 276 unsigned num_to_be_freed, | 278 unsigned num_to_be_freed, |
| 277 void* context) { | 279 void* context) { |
| 278 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 280 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 279 return chain_head->batch_free_function(chain_head, to_be_freed, | 281 return chain_head->batch_free_function(chain_head, to_be_freed, |
| 280 num_to_be_freed, context); | 282 num_to_be_freed, context); |
| 281 } | 283 } |
| 282 | 284 |
| 283 void ShimFreeDefiniteSize(void* ptr, size_t size, void* context) { | 285 ALWAYS_INLINE void ShimFreeDefiniteSize(void* ptr, size_t size, void* context) { |
| 284 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); | 286 const allocator::AllocatorDispatch* const chain_head = GetChainHead(); |
| 285 return chain_head->free_definite_size_function(chain_head, ptr, size, | 287 return chain_head->free_definite_size_function(chain_head, ptr, size, |
| 286 context); | 288 context); |
| 287 } | 289 } |
| 288 | 290 |
| 289 } // extern "C" | 291 } // extern "C" |
| 290 | 292 |
| 291 #if !defined(OS_WIN) && !defined(OS_MACOSX) | 293 #if !defined(OS_WIN) && !defined(OS_MACOSX) |
| 292 // Cpp symbols (new / delete) should always be routed through the shim layer | 294 // Cpp symbols (new / delete) should always be routed through the shim layer |
| 293 // except on Windows and macOS where the malloc intercept is deep enough that it | 295 // except on Windows and macOS where the malloc intercept is deep enough that it |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 // Cross-checks. | 337 // Cross-checks. |
| 336 | 338 |
| 337 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) | 339 #if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) |
| 338 #error The allocator shim should not be compiled when building for memory tools. | 340 #error The allocator shim should not be compiled when building for memory tools. |
| 339 #endif | 341 #endif |
| 340 | 342 |
| 341 #if (defined(__GNUC__) && defined(__EXCEPTIONS)) || \ | 343 #if (defined(__GNUC__) && defined(__EXCEPTIONS)) || \ |
| 342 (defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS) | 344 (defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS) |
| 343 #error This code cannot be used when exceptions are turned on. | 345 #error This code cannot be used when exceptions are turned on. |
| 344 #endif | 346 #endif |
| OLD | NEW |