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 |