| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/process/memory.h" | 5 #include "base/process/memory.h" |
| 6 | 6 |
| 7 // AddressSanitizer handles heap corruption, and on 64 bit Macs, the malloc |
| 8 // system automatically abort()s on heap corruption. |
| 9 #if !defined(ADDRESS_SANITIZER) && ARCH_CPU_32_BITS |
| 10 #define HANDLE_MEMORY_CORRUPTION_MANUALLY |
| 11 #endif |
| 12 |
| 7 #include <CoreFoundation/CoreFoundation.h> | 13 #include <CoreFoundation/CoreFoundation.h> |
| 8 #include <errno.h> | 14 #include <errno.h> |
| 9 #include <mach/mach.h> | 15 #include <mach/mach.h> |
| 10 #include <mach/mach_vm.h> | 16 #include <mach/mach_vm.h> |
| 11 #include <malloc/malloc.h> | 17 #include <malloc/malloc.h> |
| 12 #import <objc/runtime.h> | 18 #import <objc/runtime.h> |
| 13 | 19 |
| 14 #include <new> | 20 #include <new> |
| 15 | 21 |
| 16 #include "base/lazy_instance.h" | 22 #include "base/lazy_instance.h" |
| 17 #include "base/logging.h" | 23 #include "base/logging.h" |
| 18 #include "base/mac/mac_util.h" | 24 #include "base/mac/mac_util.h" |
| 19 #include "base/mac/mach_logging.h" | 25 #include "base/mac/mach_logging.h" |
| 20 #include "base/scoped_clear_errno.h" | 26 #include "base/scoped_clear_errno.h" |
| 21 #include "third_party/apple_apsl/CFBase.h" | 27 #include "third_party/apple_apsl/CFBase.h" |
| 22 #include "third_party/apple_apsl/malloc.h" | 28 #include "third_party/apple_apsl/malloc.h" |
| 23 | 29 |
| 24 #if ARCH_CPU_32_BITS | 30 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 25 #include <dlfcn.h> | 31 #include <dlfcn.h> |
| 26 #include <mach-o/nlist.h> | 32 #include <mach-o/nlist.h> |
| 27 | 33 |
| 28 #include "base/threading/thread_local.h" | 34 #include "base/threading/thread_local.h" |
| 29 #include "third_party/mach_override/mach_override.h" | 35 #include "third_party/mach_override/mach_override.h" |
| 30 #endif // ARCH_CPU_32_BITS | 36 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 31 | 37 |
| 32 namespace base { | 38 namespace base { |
| 33 | 39 |
| 34 // These are helpers for EnableTerminationOnHeapCorruption, which is a no-op | 40 // These are helpers for EnableTerminationOnHeapCorruption, which is a no-op |
| 35 // on 64 bit Macs. | 41 // on 64 bit Macs. |
| 36 #if ARCH_CPU_32_BITS | 42 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 37 namespace { | 43 namespace { |
| 38 | 44 |
| 39 // Finds the library path for malloc() and thus the libC part of libSystem, | 45 // Finds the library path for malloc() and thus the libC part of libSystem, |
| 40 // which in Lion is in a separate image. | 46 // which in Lion is in a separate image. |
| 41 const char* LookUpLibCPath() { | 47 const char* LookUpLibCPath() { |
| 42 const void* addr = reinterpret_cast<void*>(&malloc); | 48 const void* addr = reinterpret_cast<void*>(&malloc); |
| 43 | 49 |
| 44 Dl_info info; | 50 Dl_info info; |
| 45 if (dladdr(addr, &info)) | 51 if (dladdr(addr, &info)) |
| 46 return info.dli_fname; | 52 return info.dli_fname; |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 // crash dump info (setting a breakpad key would re-enter the malloc | 161 // crash dump info (setting a breakpad key would re-enter the malloc |
| 156 // library). Max documented errno in intro(2) is actually 102, but | 162 // library). Max documented errno in intro(2) is actually 102, but |
| 157 // it really just needs to be "small" to stay on the right vm page. | 163 // it really just needs to be "small" to stay on the right vm page. |
| 158 const int kMaxErrno = 256; | 164 const int kMaxErrno = 256; |
| 159 char* volatile death_ptr = NULL; | 165 char* volatile death_ptr = NULL; |
| 160 death_ptr += std::min(errno, kMaxErrno); | 166 death_ptr += std::min(errno, kMaxErrno); |
| 161 *death_ptr = '!'; | 167 *death_ptr = '!'; |
| 162 } | 168 } |
| 163 | 169 |
| 164 } // namespace | 170 } // namespace |
| 165 #endif // ARCH_CPU_32_BITS | 171 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 166 | 172 |
| 167 void EnableTerminationOnHeapCorruption() { | 173 void EnableTerminationOnHeapCorruption() { |
| 168 #if defined(ADDRESS_SANITIZER) || ARCH_CPU_64_BITS | 174 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 169 // AddressSanitizer handles heap corruption, and on 64 bit Macs, the malloc | |
| 170 // system automatically abort()s on heap corruption. | |
| 171 return; | |
| 172 #else | |
| 173 // Only override once, otherwise CrMallocErrorBreak() will recurse | 175 // Only override once, otherwise CrMallocErrorBreak() will recurse |
| 174 // to itself. | 176 // to itself. |
| 175 if (g_original_malloc_error_break) | 177 if (g_original_malloc_error_break) |
| 176 return; | 178 return; |
| 177 | 179 |
| 178 malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak(); | 180 malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak(); |
| 179 if (!malloc_error_break) { | 181 if (!malloc_error_break) { |
| 180 DLOG(WARNING) << "Could not find malloc_error_break"; | 182 DLOG(WARNING) << "Could not find malloc_error_break"; |
| 181 return; | 183 return; |
| 182 } | 184 } |
| 183 | 185 |
| 184 mach_error_t err = mach_override_ptr( | 186 mach_error_t err = mach_override_ptr( |
| 185 (void*)malloc_error_break, | 187 (void*)malloc_error_break, |
| 186 (void*)&CrMallocErrorBreak, | 188 (void*)&CrMallocErrorBreak, |
| 187 (void**)&g_original_malloc_error_break); | 189 (void**)&g_original_malloc_error_break); |
| 188 | 190 |
| 189 if (err != err_none) | 191 if (err != err_none) |
| 190 DLOG(WARNING) << "Could not override malloc_error_break; error = " << err; | 192 DLOG(WARNING) << "Could not override malloc_error_break; error = " << err; |
| 191 #endif // defined(ADDRESS_SANITIZER) || ARCH_CPU_64_BITS | 193 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 192 } | 194 } |
| 193 | 195 |
| 194 // ------------------------------------------------------------------------ | 196 // ------------------------------------------------------------------------ |
| 195 | 197 |
| 196 namespace { | 198 namespace { |
| 197 | 199 |
| 198 bool g_oom_killer_enabled; | 200 bool g_oom_killer_enabled; |
| 199 | 201 |
| 202 #if !defined(ADDRESS_SANITIZER) |
| 203 |
| 200 // Starting with Mac OS X 10.7, the zone allocators set up by the system are | 204 // Starting with Mac OS X 10.7, the zone allocators set up by the system are |
| 201 // read-only, to prevent them from being overwritten in an attack. However, | 205 // read-only, to prevent them from being overwritten in an attack. However, |
| 202 // blindly unprotecting and reprotecting the zone allocators fails with | 206 // blindly unprotecting and reprotecting the zone allocators fails with |
| 203 // GuardMalloc because GuardMalloc sets up its zone allocator using a block of | 207 // GuardMalloc because GuardMalloc sets up its zone allocator using a block of |
| 204 // memory in its bss. Explicit saving/restoring of the protection is required. | 208 // memory in its bss. Explicit saving/restoring of the protection is required. |
| 205 // | 209 // |
| 206 // This function takes a pointer to a malloc zone, de-protects it if necessary, | 210 // This function takes a pointer to a malloc zone, de-protects it if necessary, |
| 207 // and returns (in the out parameters) a region of memory (if any) to be | 211 // and returns (in the out parameters) a region of memory (if any) to be |
| 208 // re-protected when modifications are complete. This approach assumes that | 212 // re-protected when modifications are complete. This approach assumes that |
| 209 // there is no contention for the protection of this memory. | 213 // there is no contention for the protection of this memory. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 | 286 |
| 283 malloc_type g_old_malloc_purgeable; | 287 malloc_type g_old_malloc_purgeable; |
| 284 calloc_type g_old_calloc_purgeable; | 288 calloc_type g_old_calloc_purgeable; |
| 285 valloc_type g_old_valloc_purgeable; | 289 valloc_type g_old_valloc_purgeable; |
| 286 free_type g_old_free_purgeable; | 290 free_type g_old_free_purgeable; |
| 287 realloc_type g_old_realloc_purgeable; | 291 realloc_type g_old_realloc_purgeable; |
| 288 memalign_type g_old_memalign_purgeable; | 292 memalign_type g_old_memalign_purgeable; |
| 289 | 293 |
| 290 void* oom_killer_malloc(struct _malloc_zone_t* zone, | 294 void* oom_killer_malloc(struct _malloc_zone_t* zone, |
| 291 size_t size) { | 295 size_t size) { |
| 292 #if ARCH_CPU_32_BITS | 296 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 293 ScopedClearErrno clear_errno; | 297 ScopedClearErrno clear_errno; |
| 294 #endif // ARCH_CPU_32_BITS | 298 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 295 void* result = g_old_malloc(zone, size); | 299 void* result = g_old_malloc(zone, size); |
| 296 if (!result && size) | 300 if (!result && size) |
| 297 debug::BreakDebugger(); | 301 debug::BreakDebugger(); |
| 298 return result; | 302 return result; |
| 299 } | 303 } |
| 300 | 304 |
| 301 void* oom_killer_calloc(struct _malloc_zone_t* zone, | 305 void* oom_killer_calloc(struct _malloc_zone_t* zone, |
| 302 size_t num_items, | 306 size_t num_items, |
| 303 size_t size) { | 307 size_t size) { |
| 304 #if ARCH_CPU_32_BITS | 308 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 305 ScopedClearErrno clear_errno; | 309 ScopedClearErrno clear_errno; |
| 306 #endif // ARCH_CPU_32_BITS | 310 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 307 void* result = g_old_calloc(zone, num_items, size); | 311 void* result = g_old_calloc(zone, num_items, size); |
| 308 if (!result && num_items && size) | 312 if (!result && num_items && size) |
| 309 debug::BreakDebugger(); | 313 debug::BreakDebugger(); |
| 310 return result; | 314 return result; |
| 311 } | 315 } |
| 312 | 316 |
| 313 void* oom_killer_valloc(struct _malloc_zone_t* zone, | 317 void* oom_killer_valloc(struct _malloc_zone_t* zone, |
| 314 size_t size) { | 318 size_t size) { |
| 315 #if ARCH_CPU_32_BITS | 319 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 316 ScopedClearErrno clear_errno; | 320 ScopedClearErrno clear_errno; |
| 317 #endif // ARCH_CPU_32_BITS | 321 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 318 void* result = g_old_valloc(zone, size); | 322 void* result = g_old_valloc(zone, size); |
| 319 if (!result && size) | 323 if (!result && size) |
| 320 debug::BreakDebugger(); | 324 debug::BreakDebugger(); |
| 321 return result; | 325 return result; |
| 322 } | 326 } |
| 323 | 327 |
| 324 void oom_killer_free(struct _malloc_zone_t* zone, | 328 void oom_killer_free(struct _malloc_zone_t* zone, |
| 325 void* ptr) { | 329 void* ptr) { |
| 326 #if ARCH_CPU_32_BITS | 330 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 327 ScopedClearErrno clear_errno; | 331 ScopedClearErrno clear_errno; |
| 328 #endif // ARCH_CPU_32_BITS | 332 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 329 g_old_free(zone, ptr); | 333 g_old_free(zone, ptr); |
| 330 } | 334 } |
| 331 | 335 |
| 332 void* oom_killer_realloc(struct _malloc_zone_t* zone, | 336 void* oom_killer_realloc(struct _malloc_zone_t* zone, |
| 333 void* ptr, | 337 void* ptr, |
| 334 size_t size) { | 338 size_t size) { |
| 335 #if ARCH_CPU_32_BITS | 339 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 336 ScopedClearErrno clear_errno; | 340 ScopedClearErrno clear_errno; |
| 337 #endif // ARCH_CPU_32_BITS | 341 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 338 void* result = g_old_realloc(zone, ptr, size); | 342 void* result = g_old_realloc(zone, ptr, size); |
| 339 if (!result && size) | 343 if (!result && size) |
| 340 debug::BreakDebugger(); | 344 debug::BreakDebugger(); |
| 341 return result; | 345 return result; |
| 342 } | 346 } |
| 343 | 347 |
| 344 void* oom_killer_memalign(struct _malloc_zone_t* zone, | 348 void* oom_killer_memalign(struct _malloc_zone_t* zone, |
| 345 size_t alignment, | 349 size_t alignment, |
| 346 size_t size) { | 350 size_t size) { |
| 347 #if ARCH_CPU_32_BITS | 351 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 348 ScopedClearErrno clear_errno; | 352 ScopedClearErrno clear_errno; |
| 349 #endif // ARCH_CPU_32_BITS | 353 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 350 void* result = g_old_memalign(zone, alignment, size); | 354 void* result = g_old_memalign(zone, alignment, size); |
| 351 // Only die if posix_memalign would have returned ENOMEM, since there are | 355 // Only die if posix_memalign would have returned ENOMEM, since there are |
| 352 // other reasons why NULL might be returned (see | 356 // other reasons why NULL might be returned (see |
| 353 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ). | 357 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ). |
| 354 if (!result && size && alignment >= sizeof(void*) | 358 if (!result && size && alignment >= sizeof(void*) |
| 355 && (alignment & (alignment - 1)) == 0) { | 359 && (alignment & (alignment - 1)) == 0) { |
| 356 debug::BreakDebugger(); | 360 debug::BreakDebugger(); |
| 357 } | 361 } |
| 358 return result; | 362 return result; |
| 359 } | 363 } |
| 360 | 364 |
| 361 void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone, | 365 void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone, |
| 362 size_t size) { | 366 size_t size) { |
| 363 #if ARCH_CPU_32_BITS | 367 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 364 ScopedClearErrno clear_errno; | 368 ScopedClearErrno clear_errno; |
| 365 #endif // ARCH_CPU_32_BITS | 369 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 366 void* result = g_old_malloc_purgeable(zone, size); | 370 void* result = g_old_malloc_purgeable(zone, size); |
| 367 if (!result && size) | 371 if (!result && size) |
| 368 debug::BreakDebugger(); | 372 debug::BreakDebugger(); |
| 369 return result; | 373 return result; |
| 370 } | 374 } |
| 371 | 375 |
| 372 void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone, | 376 void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone, |
| 373 size_t num_items, | 377 size_t num_items, |
| 374 size_t size) { | 378 size_t size) { |
| 375 #if ARCH_CPU_32_BITS | 379 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 376 ScopedClearErrno clear_errno; | 380 ScopedClearErrno clear_errno; |
| 377 #endif // ARCH_CPU_32_BITS | 381 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 378 void* result = g_old_calloc_purgeable(zone, num_items, size); | 382 void* result = g_old_calloc_purgeable(zone, num_items, size); |
| 379 if (!result && num_items && size) | 383 if (!result && num_items && size) |
| 380 debug::BreakDebugger(); | 384 debug::BreakDebugger(); |
| 381 return result; | 385 return result; |
| 382 } | 386 } |
| 383 | 387 |
| 384 void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone, | 388 void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone, |
| 385 size_t size) { | 389 size_t size) { |
| 386 #if ARCH_CPU_32_BITS | 390 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 387 ScopedClearErrno clear_errno; | 391 ScopedClearErrno clear_errno; |
| 388 #endif // ARCH_CPU_32_BITS | 392 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 389 void* result = g_old_valloc_purgeable(zone, size); | 393 void* result = g_old_valloc_purgeable(zone, size); |
| 390 if (!result && size) | 394 if (!result && size) |
| 391 debug::BreakDebugger(); | 395 debug::BreakDebugger(); |
| 392 return result; | 396 return result; |
| 393 } | 397 } |
| 394 | 398 |
| 395 void oom_killer_free_purgeable(struct _malloc_zone_t* zone, | 399 void oom_killer_free_purgeable(struct _malloc_zone_t* zone, |
| 396 void* ptr) { | 400 void* ptr) { |
| 397 #if ARCH_CPU_32_BITS | 401 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 398 ScopedClearErrno clear_errno; | 402 ScopedClearErrno clear_errno; |
| 399 #endif // ARCH_CPU_32_BITS | 403 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 400 g_old_free_purgeable(zone, ptr); | 404 g_old_free_purgeable(zone, ptr); |
| 401 } | 405 } |
| 402 | 406 |
| 403 void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone, | 407 void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone, |
| 404 void* ptr, | 408 void* ptr, |
| 405 size_t size) { | 409 size_t size) { |
| 406 #if ARCH_CPU_32_BITS | 410 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 407 ScopedClearErrno clear_errno; | 411 ScopedClearErrno clear_errno; |
| 408 #endif // ARCH_CPU_32_BITS | 412 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 409 void* result = g_old_realloc_purgeable(zone, ptr, size); | 413 void* result = g_old_realloc_purgeable(zone, ptr, size); |
| 410 if (!result && size) | 414 if (!result && size) |
| 411 debug::BreakDebugger(); | 415 debug::BreakDebugger(); |
| 412 return result; | 416 return result; |
| 413 } | 417 } |
| 414 | 418 |
| 415 void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone, | 419 void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone, |
| 416 size_t alignment, | 420 size_t alignment, |
| 417 size_t size) { | 421 size_t size) { |
| 418 #if ARCH_CPU_32_BITS | 422 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 419 ScopedClearErrno clear_errno; | 423 ScopedClearErrno clear_errno; |
| 420 #endif // ARCH_CPU_32_BITS | 424 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 421 void* result = g_old_memalign_purgeable(zone, alignment, size); | 425 void* result = g_old_memalign_purgeable(zone, alignment, size); |
| 422 // Only die if posix_memalign would have returned ENOMEM, since there are | 426 // Only die if posix_memalign would have returned ENOMEM, since there are |
| 423 // other reasons why NULL might be returned (see | 427 // other reasons why NULL might be returned (see |
| 424 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ). | 428 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ). |
| 425 if (!result && size && alignment >= sizeof(void*) | 429 if (!result && size && alignment >= sizeof(void*) |
| 426 && (alignment & (alignment - 1)) == 0) { | 430 && (alignment & (alignment - 1)) == 0) { |
| 427 debug::BreakDebugger(); | 431 debug::BreakDebugger(); |
| 428 } | 432 } |
| 429 return result; | 433 return result; |
| 430 } | 434 } |
| 431 | 435 |
| 436 #endif // !defined(ADDRESS_SANITIZER) |
| 437 |
| 432 // === C++ operator new === | 438 // === C++ operator new === |
| 433 | 439 |
| 434 void oom_killer_new() { | 440 void oom_killer_new() { |
| 435 debug::BreakDebugger(); | 441 debug::BreakDebugger(); |
| 436 } | 442 } |
| 437 | 443 |
| 444 #if !defined(ADDRESS_SANITIZER) |
| 445 |
| 438 // === Core Foundation CFAllocators === | 446 // === Core Foundation CFAllocators === |
| 439 | 447 |
| 440 bool CanGetContextForCFAllocator() { | 448 bool CanGetContextForCFAllocator() { |
| 441 return !base::mac::IsOSLaterThanYosemite_DontCallThis(); | 449 return !base::mac::IsOSLaterThanYosemite_DontCallThis(); |
| 442 } | 450 } |
| 443 | 451 |
| 444 CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) { | 452 CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) { |
| 445 if (base::mac::IsOSSnowLeopard()) { | 453 if (base::mac::IsOSSnowLeopard()) { |
| 446 ChromeCFAllocatorLeopards* our_allocator = | 454 ChromeCFAllocatorLeopards* our_allocator = |
| 447 const_cast<ChromeCFAllocatorLeopards*>( | 455 const_cast<ChromeCFAllocatorLeopards*>( |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 | 492 |
| 485 void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size, | 493 void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size, |
| 486 CFOptionFlags hint, | 494 CFOptionFlags hint, |
| 487 void* info) { | 495 void* info) { |
| 488 void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info); | 496 void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info); |
| 489 if (!result) | 497 if (!result) |
| 490 debug::BreakDebugger(); | 498 debug::BreakDebugger(); |
| 491 return result; | 499 return result; |
| 492 } | 500 } |
| 493 | 501 |
| 502 #endif // !defined(ADDRESS_SANITIZER) |
| 503 |
| 494 // === Cocoa NSObject allocation === | 504 // === Cocoa NSObject allocation === |
| 495 | 505 |
| 496 typedef id (*allocWithZone_t)(id, SEL, NSZone*); | 506 typedef id (*allocWithZone_t)(id, SEL, NSZone*); |
| 497 allocWithZone_t g_old_allocWithZone; | 507 allocWithZone_t g_old_allocWithZone; |
| 498 | 508 |
| 499 id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone) | 509 id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone) |
| 500 { | 510 { |
| 501 id result = g_old_allocWithZone(self, _cmd, zone); | 511 id result = g_old_allocWithZone(self, _cmd, zone); |
| 502 if (!result) | 512 if (!result) |
| 503 debug::BreakDebugger(); | 513 debug::BreakDebugger(); |
| 504 return result; | 514 return result; |
| 505 } | 515 } |
| 506 | 516 |
| 507 } // namespace | 517 } // namespace |
| 508 | 518 |
| 509 bool UncheckedMalloc(size_t size, void** result) { | 519 bool UncheckedMalloc(size_t size, void** result) { |
| 520 #if defined(ADDRESS_SANITIZER) |
| 521 *result = malloc(size); |
| 522 #else |
| 510 if (g_old_malloc) { | 523 if (g_old_malloc) { |
| 511 #if ARCH_CPU_32_BITS | 524 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 512 ScopedClearErrno clear_errno; | 525 ScopedClearErrno clear_errno; |
| 513 ThreadLocalBooleanAutoReset flag(g_unchecked_alloc.Pointer(), true); | 526 ThreadLocalBooleanAutoReset flag(g_unchecked_alloc.Pointer(), true); |
| 514 #endif // ARCH_CPU_32_BITS | 527 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 515 *result = g_old_malloc(malloc_default_zone(), size); | 528 *result = g_old_malloc(malloc_default_zone(), size); |
| 516 } else { | 529 } else { |
| 517 *result = malloc(size); | 530 *result = malloc(size); |
| 518 } | 531 } |
| 532 #endif // defined(ADDRESS_SANITIZER) |
| 519 | 533 |
| 520 return *result != NULL; | 534 return *result != NULL; |
| 521 } | 535 } |
| 522 | 536 |
| 523 bool UncheckedCalloc(size_t num_items, size_t size, void** result) { | 537 bool UncheckedCalloc(size_t num_items, size_t size, void** result) { |
| 538 #if defined(ADDRESS_SANITIZER) |
| 539 *result = calloc(num_items, size); |
| 540 #else |
| 524 if (g_old_calloc) { | 541 if (g_old_calloc) { |
| 525 #if ARCH_CPU_32_BITS | 542 #if defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 526 ScopedClearErrno clear_errno; | 543 ScopedClearErrno clear_errno; |
| 527 ThreadLocalBooleanAutoReset flag(g_unchecked_alloc.Pointer(), true); | 544 ThreadLocalBooleanAutoReset flag(g_unchecked_alloc.Pointer(), true); |
| 528 #endif // ARCH_CPU_32_BITS | 545 #endif // defined(HANDLE_MEMORY_CORRUPTION_MANUALLY) |
| 529 *result = g_old_calloc(malloc_default_zone(), num_items, size); | 546 *result = g_old_calloc(malloc_default_zone(), num_items, size); |
| 530 } else { | 547 } else { |
| 531 *result = calloc(num_items, size); | 548 *result = calloc(num_items, size); |
| 532 } | 549 } |
| 550 #endif // defined(ADDRESS_SANITIZER) |
| 533 | 551 |
| 534 return *result != NULL; | 552 return *result != NULL; |
| 535 } | 553 } |
| 536 | 554 |
| 537 void* UncheckedMalloc(size_t size) { | 555 void* UncheckedMalloc(size_t size) { |
| 538 void* address; | 556 void* address; |
| 539 return UncheckedMalloc(size, &address) ? address : NULL; | 557 return UncheckedMalloc(size, &address) ? address : NULL; |
| 540 } | 558 } |
| 541 | 559 |
| 542 void* UncheckedCalloc(size_t num_items, size_t size) { | 560 void* UncheckedCalloc(size_t num_items, size_t size) { |
| 543 void* address; | 561 void* address; |
| 544 return UncheckedCalloc(num_items, size, &address) ? address : NULL; | 562 return UncheckedCalloc(num_items, size, &address) ? address : NULL; |
| 545 } | 563 } |
| 546 | 564 |
| 547 void EnableTerminationOnOutOfMemory() { | 565 void EnableTerminationOnOutOfMemory() { |
| 548 if (g_oom_killer_enabled) | 566 if (g_oom_killer_enabled) |
| 549 return; | 567 return; |
| 550 | 568 |
| 551 g_oom_killer_enabled = true; | 569 g_oom_killer_enabled = true; |
| 552 | 570 |
| 553 // === C malloc/calloc/valloc/realloc/posix_memalign === | 571 // === C malloc/calloc/valloc/realloc/posix_memalign === |
| 554 | 572 |
| 555 // This approach is not perfect, as requests for amounts of memory larger than | 573 // This approach is not perfect, as requests for amounts of memory larger than |
| 556 // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will | 574 // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will |
| 557 // still fail with a NULL rather than dying (see | 575 // still fail with a NULL rather than dying (see |
| 558 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c for details). | 576 // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c for details). |
| 559 // Unfortunately, it's the best we can do. Also note that this does not affect | 577 // Unfortunately, it's the best we can do. Also note that this does not affect |
| 560 // allocations from non-default zones. | 578 // allocations from non-default zones. |
| 561 | 579 |
| 580 #if !defined(ADDRESS_SANITIZER) |
| 581 // Don't do anything special on OOM for the malloc zones replaced by |
| 582 // AddressSanitizer, as modifying or protecting them may not work correctly. |
| 583 |
| 562 CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc && | 584 CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc && |
| 563 !g_old_memalign) << "Old allocators unexpectedly non-null"; | 585 !g_old_memalign) << "Old allocators unexpectedly non-null"; |
| 564 | 586 |
| 565 CHECK(!g_old_malloc_purgeable && !g_old_calloc_purgeable && | 587 CHECK(!g_old_malloc_purgeable && !g_old_calloc_purgeable && |
| 566 !g_old_valloc_purgeable && !g_old_realloc_purgeable && | 588 !g_old_valloc_purgeable && !g_old_realloc_purgeable && |
| 567 !g_old_memalign_purgeable) << "Old allocators unexpectedly non-null"; | 589 !g_old_memalign_purgeable) << "Old allocators unexpectedly non-null"; |
| 568 | 590 |
| 569 #if !defined(ADDRESS_SANITIZER) | |
| 570 // Don't do anything special on OOM for the malloc zones replaced by | |
| 571 // AddressSanitizer, as modifying or protecting them may not work correctly. | |
| 572 | |
| 573 ChromeMallocZone* default_zone = | 591 ChromeMallocZone* default_zone = |
| 574 reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); | 592 reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); |
| 575 ChromeMallocZone* purgeable_zone = | 593 ChromeMallocZone* purgeable_zone = |
| 576 reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone()); | 594 reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone()); |
| 577 | 595 |
| 578 mach_vm_address_t default_reprotection_start = 0; | 596 mach_vm_address_t default_reprotection_start = 0; |
| 579 mach_vm_size_t default_reprotection_length = 0; | 597 mach_vm_size_t default_reprotection_length = 0; |
| 580 vm_prot_t default_reprotection_value = VM_PROT_NONE; | 598 vm_prot_t default_reprotection_value = VM_PROT_NONE; |
| 581 DeprotectMallocZone(default_zone, | 599 DeprotectMallocZone(default_zone, |
| 582 &default_reprotection_start, | 600 &default_reprotection_start, |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 742 @selector(allocWithZone:)); | 760 @selector(allocWithZone:)); |
| 743 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( | 761 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( |
| 744 method_getImplementation(orig_method)); | 762 method_getImplementation(orig_method)); |
| 745 CHECK(g_old_allocWithZone) | 763 CHECK(g_old_allocWithZone) |
| 746 << "Failed to get allocWithZone allocation function."; | 764 << "Failed to get allocWithZone allocation function."; |
| 747 method_setImplementation(orig_method, | 765 method_setImplementation(orig_method, |
| 748 reinterpret_cast<IMP>(oom_killer_allocWithZone)); | 766 reinterpret_cast<IMP>(oom_killer_allocWithZone)); |
| 749 } | 767 } |
| 750 | 768 |
| 751 } // namespace base | 769 } // namespace base |
| OLD | NEW |