| OLD | NEW |
| 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2008 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 | 5 |
| 6 #include "base/process_util.h" | 6 #include "base/process_util.h" |
| 7 | 7 |
| 8 #import <Cocoa/Cocoa.h> | 8 #import <Cocoa/Cocoa.h> |
| 9 #include <crt_externs.h> | 9 #include <crt_externs.h> |
| 10 #include <dlfcn.h> | 10 #include <dlfcn.h> |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 #include <new> | 23 #include <new> |
| 24 #include <string> | 24 #include <string> |
| 25 | 25 |
| 26 #include "base/debug_util.h" | 26 #include "base/debug_util.h" |
| 27 #include "base/eintr_wrapper.h" | 27 #include "base/eintr_wrapper.h" |
| 28 #include "base/logging.h" | 28 #include "base/logging.h" |
| 29 #include "base/string_util.h" | 29 #include "base/string_util.h" |
| 30 #include "base/sys_info.h" | 30 #include "base/sys_info.h" |
| 31 #include "base/sys_string_conversions.h" | 31 #include "base/sys_string_conversions.h" |
| 32 #include "base/time.h" | 32 #include "base/time.h" |
| 33 #include "third_party/apple_apsl/CFBase.h" |
| 34 #include "third_party/apple_apsl/malloc.h" |
| 33 | 35 |
| 34 namespace base { | 36 namespace base { |
| 35 | 37 |
| 36 void RestoreDefaultExceptionHandler() { | 38 void RestoreDefaultExceptionHandler() { |
| 37 // This function is tailored to remove the Breakpad exception handler. | 39 // This function is tailored to remove the Breakpad exception handler. |
| 38 // exception_mask matches s_exception_mask in | 40 // exception_mask matches s_exception_mask in |
| 39 // breakpad/src/client/mac/handler/exception_handler.cc | 41 // breakpad/src/client/mac/handler/exception_handler.cc |
| 40 const exception_mask_t exception_mask = EXC_MASK_BAD_ACCESS | | 42 const exception_mask_t exception_mask = EXC_MASK_BAD_ACCESS | |
| 41 EXC_MASK_BAD_INSTRUCTION | | 43 EXC_MASK_BAD_INSTRUCTION | |
| 42 EXC_MASK_ARITHMETIC | | 44 EXC_MASK_ARITHMETIC | |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 } | 365 } |
| 364 | 366 |
| 365 // ------------------------------------------------------------------------ | 367 // ------------------------------------------------------------------------ |
| 366 | 368 |
| 367 namespace { | 369 namespace { |
| 368 | 370 |
| 369 bool g_oom_killer_enabled; | 371 bool g_oom_killer_enabled; |
| 370 | 372 |
| 371 // === C malloc/calloc/valloc/realloc/posix_memalign === | 373 // === C malloc/calloc/valloc/realloc/posix_memalign === |
| 372 | 374 |
| 373 // The extended version of malloc_zone_t from the 10.6 SDK's <malloc/malloc.h>, | |
| 374 // included here to allow for compilation in 10.5. (10.5 has version 3 zone | |
| 375 // allocators, while 10.6 has version 6 allocators.) | |
| 376 struct ChromeMallocZone { | |
| 377 void* reserved1; | |
| 378 void* reserved2; | |
| 379 size_t (*size)(struct _malloc_zone_t* zone, const void* ptr); | |
| 380 void* (*malloc)(struct _malloc_zone_t* zone, size_t size); | |
| 381 void* (*calloc)(struct _malloc_zone_t* zone, size_t num_items, size_t size); | |
| 382 void* (*valloc)(struct _malloc_zone_t* zone, size_t size); | |
| 383 void (*free)(struct _malloc_zone_t* zone, void* ptr); | |
| 384 void* (*realloc)(struct _malloc_zone_t* zone, void* ptr, size_t size); | |
| 385 void (*destroy)(struct _malloc_zone_t* zone); | |
| 386 const char* zone_name; | |
| 387 unsigned (*batch_malloc)(struct _malloc_zone_t* zone, size_t size, | |
| 388 void** results, unsigned num_requested); | |
| 389 void (*batch_free)(struct _malloc_zone_t* zone, void** to_be_freed, | |
| 390 unsigned num_to_be_freed); | |
| 391 struct malloc_introspection_t* introspect; | |
| 392 unsigned version; | |
| 393 void* (*memalign)(struct _malloc_zone_t* zone, size_t alignment, | |
| 394 size_t size); // version >= 5 | |
| 395 void (*free_definite_size)(struct _malloc_zone_t* zone, void* ptr, | |
| 396 size_t size); // version >= 6 | |
| 397 }; | |
| 398 | |
| 399 typedef void* (*malloc_type)(struct _malloc_zone_t* zone, | 375 typedef void* (*malloc_type)(struct _malloc_zone_t* zone, |
| 400 size_t size); | 376 size_t size); |
| 401 typedef void* (*calloc_type)(struct _malloc_zone_t* zone, | 377 typedef void* (*calloc_type)(struct _malloc_zone_t* zone, |
| 402 size_t num_items, | 378 size_t num_items, |
| 403 size_t size); | 379 size_t size); |
| 404 typedef void* (*valloc_type)(struct _malloc_zone_t* zone, | 380 typedef void* (*valloc_type)(struct _malloc_zone_t* zone, |
| 405 size_t size); | 381 size_t size); |
| 406 typedef void* (*realloc_type)(struct _malloc_zone_t* zone, | 382 typedef void* (*realloc_type)(struct _malloc_zone_t* zone, |
| 407 void* ptr, | 383 void* ptr, |
| 408 size_t size); | 384 size_t size); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 } | 495 } |
| 520 | 496 |
| 521 // === C++ operator new === | 497 // === C++ operator new === |
| 522 | 498 |
| 523 void oom_killer_new() { | 499 void oom_killer_new() { |
| 524 DebugUtil::BreakDebugger(); | 500 DebugUtil::BreakDebugger(); |
| 525 } | 501 } |
| 526 | 502 |
| 527 // === Core Foundation CFAllocators === | 503 // === Core Foundation CFAllocators === |
| 528 | 504 |
| 529 // This is the real structure of a CFAllocatorRef behind the scenes. See | |
| 530 // http://opensource.apple.com/source/CF/CF-476.19/CFBase.c (10.5.8) and | |
| 531 // http://opensource.apple.com/source/CF/CF-550/CFBase.c (10.6) for details. | |
| 532 struct ChromeCFRuntimeBase { | |
| 533 uintptr_t _cfisa; | |
| 534 uint8_t _cfinfo[4]; | |
| 535 #if __LP64__ | |
| 536 uint32_t _rc; | |
| 537 #endif | |
| 538 }; | |
| 539 | |
| 540 struct ChromeCFAllocator { | |
| 541 ChromeCFRuntimeBase cf_runtime_base; | |
| 542 size_t (*size)(struct _malloc_zone_t* zone, const void* ptr); | |
| 543 void* (*malloc)(struct _malloc_zone_t* zone, size_t size); | |
| 544 void* (*calloc)(struct _malloc_zone_t* zone, size_t num_items, size_t size); | |
| 545 void* (*valloc)(struct _malloc_zone_t* zone, size_t size); | |
| 546 void (*free)(struct _malloc_zone_t* zone, void* ptr); | |
| 547 void* (*realloc)(struct _malloc_zone_t* zone, void* ptr, size_t size); | |
| 548 void (*destroy)(struct _malloc_zone_t* zone); | |
| 549 const char* zone_name; | |
| 550 unsigned (*batch_malloc)(struct _malloc_zone_t* zone, size_t size, | |
| 551 void** results, unsigned num_requested); | |
| 552 void (*batch_free)(struct _malloc_zone_t* zone, void** to_be_freed, | |
| 553 unsigned num_to_be_freed); | |
| 554 struct malloc_introspection_t* introspect; | |
| 555 void* reserved5; | |
| 556 | |
| 557 void* allocator; | |
| 558 CFAllocatorContext context; | |
| 559 }; | |
| 560 typedef ChromeCFAllocator* ChromeCFAllocatorRef; | 505 typedef ChromeCFAllocator* ChromeCFAllocatorRef; |
| 561 | 506 |
| 562 CFAllocatorAllocateCallBack g_old_cfallocator_system_default; | 507 CFAllocatorAllocateCallBack g_old_cfallocator_system_default; |
| 563 CFAllocatorAllocateCallBack g_old_cfallocator_malloc; | 508 CFAllocatorAllocateCallBack g_old_cfallocator_malloc; |
| 564 CFAllocatorAllocateCallBack g_old_cfallocator_malloc_zone; | 509 CFAllocatorAllocateCallBack g_old_cfallocator_malloc_zone; |
| 565 | 510 |
| 566 void* oom_killer_cfallocator_system_default(CFIndex alloc_size, | 511 void* oom_killer_cfallocator_system_default(CFIndex alloc_size, |
| 567 CFOptionFlags hint, | 512 CFOptionFlags hint, |
| 568 void* info) { | 513 void* info) { |
| 569 void* result = g_old_cfallocator_system_default(alloc_size, hint, info); | 514 void* result = g_old_cfallocator_system_default(alloc_size, hint, info); |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 766 CHECK(!g_old_cfallocator_system_default && !g_old_cfallocator_malloc && | 711 CHECK(!g_old_cfallocator_system_default && !g_old_cfallocator_malloc && |
| 767 !g_old_cfallocator_malloc_zone) | 712 !g_old_cfallocator_malloc_zone) |
| 768 << "Old allocators unexpectedly non-null"; | 713 << "Old allocators unexpectedly non-null"; |
| 769 | 714 |
| 770 bool cf_allocator_internals_known = | 715 bool cf_allocator_internals_known = |
| 771 darwin_version == 9 || darwin_version == 10; | 716 darwin_version == 9 || darwin_version == 10; |
| 772 | 717 |
| 773 if (cf_allocator_internals_known) { | 718 if (cf_allocator_internals_known) { |
| 774 ChromeCFAllocatorRef allocator = const_cast<ChromeCFAllocatorRef>( | 719 ChromeCFAllocatorRef allocator = const_cast<ChromeCFAllocatorRef>( |
| 775 reinterpret_cast<const ChromeCFAllocator*>(kCFAllocatorSystemDefault)); | 720 reinterpret_cast<const ChromeCFAllocator*>(kCFAllocatorSystemDefault)); |
| 776 g_old_cfallocator_system_default = allocator->context.allocate; | 721 g_old_cfallocator_system_default = allocator->_context.allocate; |
| 777 CHECK(g_old_cfallocator_system_default) | 722 CHECK(g_old_cfallocator_system_default) |
| 778 << "Failed to get kCFAllocatorSystemDefault allocation function."; | 723 << "Failed to get kCFAllocatorSystemDefault allocation function."; |
| 779 allocator->context.allocate = oom_killer_cfallocator_system_default; | 724 allocator->_context.allocate = oom_killer_cfallocator_system_default; |
| 780 | 725 |
| 781 allocator = const_cast<ChromeCFAllocatorRef>( | 726 allocator = const_cast<ChromeCFAllocatorRef>( |
| 782 reinterpret_cast<const ChromeCFAllocator*>(kCFAllocatorMalloc)); | 727 reinterpret_cast<const ChromeCFAllocator*>(kCFAllocatorMalloc)); |
| 783 g_old_cfallocator_malloc = allocator->context.allocate; | 728 g_old_cfallocator_malloc = allocator->_context.allocate; |
| 784 CHECK(g_old_cfallocator_malloc) | 729 CHECK(g_old_cfallocator_malloc) |
| 785 << "Failed to get kCFAllocatorMalloc allocation function."; | 730 << "Failed to get kCFAllocatorMalloc allocation function."; |
| 786 allocator->context.allocate = oom_killer_cfallocator_malloc; | 731 allocator->_context.allocate = oom_killer_cfallocator_malloc; |
| 787 | 732 |
| 788 allocator = const_cast<ChromeCFAllocatorRef>( | 733 allocator = const_cast<ChromeCFAllocatorRef>( |
| 789 reinterpret_cast<const ChromeCFAllocator*>(kCFAllocatorMallocZone)); | 734 reinterpret_cast<const ChromeCFAllocator*>(kCFAllocatorMallocZone)); |
| 790 g_old_cfallocator_malloc_zone = allocator->context.allocate; | 735 g_old_cfallocator_malloc_zone = allocator->_context.allocate; |
| 791 CHECK(g_old_cfallocator_malloc_zone) | 736 CHECK(g_old_cfallocator_malloc_zone) |
| 792 << "Failed to get kCFAllocatorMallocZone allocation function."; | 737 << "Failed to get kCFAllocatorMallocZone allocation function."; |
| 793 allocator->context.allocate = oom_killer_cfallocator_malloc_zone; | 738 allocator->_context.allocate = oom_killer_cfallocator_malloc_zone; |
| 794 } else { | 739 } else { |
| 795 NSLog(@"Internals of CFAllocator not known; out-of-memory failures via " | 740 NSLog(@"Internals of CFAllocator not known; out-of-memory failures via " |
| 796 "CFAllocator will not result in termination. http://crbug.com/45650"); | 741 "CFAllocator will not result in termination. http://crbug.com/45650"); |
| 797 } | 742 } |
| 798 | 743 |
| 799 // === Cocoa NSObject allocation === | 744 // === Cocoa NSObject allocation === |
| 800 | 745 |
| 801 // Note that both +[NSObject new] and +[NSObject alloc] call through to | 746 // Note that both +[NSObject new] and +[NSObject alloc] call through to |
| 802 // +[NSObject allocWithZone:]. | 747 // +[NSObject allocWithZone:]. |
| 803 | 748 |
| 804 CHECK(!g_old_allocWithZone) | 749 CHECK(!g_old_allocWithZone) |
| 805 << "Old allocator unexpectedly non-null"; | 750 << "Old allocator unexpectedly non-null"; |
| 806 | 751 |
| 807 Class nsobject_class = [NSObject class]; | 752 Class nsobject_class = [NSObject class]; |
| 808 Method orig_method = class_getClassMethod(nsobject_class, | 753 Method orig_method = class_getClassMethod(nsobject_class, |
| 809 @selector(allocWithZone:)); | 754 @selector(allocWithZone:)); |
| 810 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( | 755 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( |
| 811 method_getImplementation(orig_method)); | 756 method_getImplementation(orig_method)); |
| 812 CHECK(g_old_allocWithZone) | 757 CHECK(g_old_allocWithZone) |
| 813 << "Failed to get allocWithZone allocation function."; | 758 << "Failed to get allocWithZone allocation function."; |
| 814 method_setImplementation(orig_method, | 759 method_setImplementation(orig_method, |
| 815 reinterpret_cast<IMP>(oom_killer_allocWithZone)); | 760 reinterpret_cast<IMP>(oom_killer_allocWithZone)); |
| 816 } | 761 } |
| 817 | 762 |
| 818 } // namespace base | 763 } // namespace base |
| OLD | NEW |