OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_util.h" | 5 #include "base/process_util.h" |
6 | 6 |
7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
8 #include <crt_externs.h> | 8 #include <crt_externs.h> |
9 #include <dlfcn.h> | 9 #include <dlfcn.h> |
10 #include <errno.h> | 10 #include <errno.h> |
11 #include <mach/mach.h> | 11 #include <mach/mach.h> |
12 #include <mach/mach_init.h> | 12 #include <mach/mach_init.h> |
13 #include <mach/mach_vm.h> | 13 #include <mach/mach_vm.h> |
14 #include <mach/shared_region.h> | 14 #include <mach/shared_region.h> |
15 #include <mach/task.h> | 15 #include <mach/task.h> |
16 #include <mach-o/dyld.h> | |
17 #include <mach-o/nlist.h> | 16 #include <mach-o/nlist.h> |
18 #include <malloc/malloc.h> | 17 #include <malloc/malloc.h> |
19 #import <objc/runtime.h> | 18 #import <objc/runtime.h> |
20 #include <signal.h> | 19 #include <signal.h> |
21 #include <spawn.h> | 20 #include <spawn.h> |
22 #include <sys/event.h> | 21 #include <sys/event.h> |
23 #include <sys/mman.h> | 22 #include <sys/mman.h> |
24 #include <sys/sysctl.h> | 23 #include <sys/sysctl.h> |
25 #include <sys/types.h> | 24 #include <sys/types.h> |
26 #include <sys/wait.h> | 25 #include <sys/wait.h> |
27 | 26 |
28 #include <new> | 27 #include <new> |
29 #include <string> | 28 #include <string> |
30 | 29 |
31 #include "base/debug/debugger.h" | 30 #include "base/debug/debugger.h" |
32 #include "base/eintr_wrapper.h" | 31 #include "base/eintr_wrapper.h" |
33 #include "base/file_util.h" | 32 #include "base/file_util.h" |
34 #include "base/hash_tables.h" | 33 #include "base/hash_tables.h" |
| 34 #include "base/lazy_instance.h" |
35 #include "base/logging.h" | 35 #include "base/logging.h" |
36 #include "base/mac/mac_util.h" | 36 #include "base/mac/mac_util.h" |
37 #include "base/string_util.h" | 37 #include "base/string_util.h" |
38 #include "base/sys_info.h" | 38 #include "base/sys_info.h" |
39 #include "base/sys_string_conversions.h" | 39 #include "base/threading/thread_local.h" |
40 #include "base/time.h" | |
41 #include "third_party/apple_apsl/CFBase.h" | 40 #include "third_party/apple_apsl/CFBase.h" |
42 #include "third_party/apple_apsl/malloc.h" | 41 #include "third_party/apple_apsl/malloc.h" |
43 #include "third_party/mach_override/mach_override.h" | 42 #include "third_party/mach_override/mach_override.h" |
44 | 43 |
45 namespace base { | 44 namespace base { |
46 | 45 |
47 void RestoreDefaultExceptionHandler() { | 46 void RestoreDefaultExceptionHandler() { |
48 // This function is tailored to remove the Breakpad exception handler. | 47 // This function is tailored to remove the Breakpad exception handler. |
49 // exception_mask matches s_exception_mask in | 48 // exception_mask matches s_exception_mask in |
50 // breakpad/src/client/mac/handler/exception_handler.cc | 49 // breakpad/src/client/mac/handler/exception_handler.cc |
(...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
559 if (errno == 0) | 558 if (errno == 0) |
560 errno = old_errno_; | 559 errno = old_errno_; |
561 } | 560 } |
562 | 561 |
563 private: | 562 private: |
564 int old_errno_; | 563 int old_errno_; |
565 | 564 |
566 DISALLOW_COPY_AND_ASSIGN(ScopedClearErrno); | 565 DISALLOW_COPY_AND_ASSIGN(ScopedClearErrno); |
567 }; | 566 }; |
568 | 567 |
| 568 // Combines ThreadLocalBoolean with AutoReset. It would be convenient |
| 569 // to compose ThreadLocalPointer<bool> with AutoReset<bool>, but that |
| 570 // would require allocating some storage for the bool. |
| 571 class ThreadLocalBooleanAutoReset { |
| 572 public: |
| 573 ThreadLocalBooleanAutoReset(ThreadLocalBoolean* tlb, bool new_value) |
| 574 : scoped_tlb_(tlb), |
| 575 original_value_(tlb->Get()) { |
| 576 scoped_tlb_->Set(new_value); |
| 577 } |
| 578 ~ThreadLocalBooleanAutoReset() { |
| 579 scoped_tlb_->Set(original_value_); |
| 580 } |
| 581 |
| 582 private: |
| 583 ThreadLocalBoolean* scoped_tlb_; |
| 584 bool original_value_; |
| 585 |
| 586 DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset); |
| 587 }; |
| 588 |
| 589 base::LazyInstance<ThreadLocalBoolean>::Leaky |
| 590 g_unchecked_malloc = LAZY_INSTANCE_INITIALIZER; |
| 591 |
569 void CrMallocErrorBreak() { | 592 void CrMallocErrorBreak() { |
570 g_original_malloc_error_break(); | 593 g_original_malloc_error_break(); |
571 | 594 |
572 // Out of memory is certainly not heap corruption, and not necessarily | 595 // Out of memory is certainly not heap corruption, and not necessarily |
573 // something for which the process should be terminated. Leave that decision | 596 // something for which the process should be terminated. Leave that decision |
574 // to the OOM killer. | 597 // to the OOM killer. The EBADF case comes up because the malloc library |
575 if (errno == ENOMEM) | 598 // attempts to log to ASL (syslog) before calling this code, which fails |
| 599 // accessing a Unix-domain socket because of sandboxing. |
| 600 if (errno == ENOMEM || (errno == EBADF && g_unchecked_malloc.Get().Get())) |
576 return; | 601 return; |
577 | 602 |
578 // A unit test checks this error message, so it needs to be in release builds. | 603 // A unit test checks this error message, so it needs to be in release builds. |
579 LOG(ERROR) << | 604 PLOG(ERROR) << |
580 "Terminating process due to a potential for future heap corruption"; | 605 "Terminating process due to a potential for future heap corruption"; |
581 int* volatile death_ptr = NULL; | 606 |
582 *death_ptr = 0xf00bad; | 607 // Crash by writing to NULL+errno to allow analyzing errno from |
| 608 // crash dump info (setting a breakpad key would re-enter the malloc |
| 609 // library). Max documented errno in intro(2) is actually 102, but |
| 610 // it really just needs to be "small" to stay on the right vm page. |
| 611 const int kMaxErrno = 256; |
| 612 char* volatile death_ptr = NULL; |
| 613 death_ptr += std::min(errno, kMaxErrno); |
| 614 *death_ptr = '!'; |
583 } | 615 } |
584 | 616 |
585 } // namespace | 617 } // namespace |
586 | 618 |
587 void EnableTerminationOnHeapCorruption() { | 619 void EnableTerminationOnHeapCorruption() { |
588 #ifdef ADDRESS_SANITIZER | 620 #ifdef ADDRESS_SANITIZER |
589 // Don't do anything special on heap corruption, because it should be handled | 621 // Don't do anything special on heap corruption, because it should be handled |
590 // by AddressSanitizer. | 622 // by AddressSanitizer. |
591 return; | 623 return; |
592 #endif | 624 #endif |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
829 id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone) | 861 id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone) |
830 { | 862 { |
831 id result = g_old_allocWithZone(self, _cmd, zone); | 863 id result = g_old_allocWithZone(self, _cmd, zone); |
832 if (!result) | 864 if (!result) |
833 debug::BreakDebugger(); | 865 debug::BreakDebugger(); |
834 return result; | 866 return result; |
835 } | 867 } |
836 | 868 |
837 } // namespace | 869 } // namespace |
838 | 870 |
839 malloc_zone_t* GetPurgeableZone() { | 871 void* UncheckedMalloc(size_t size) { |
840 // malloc_default_purgeable_zone only exists on >= 10.6. Use dlsym to grab it | 872 if (g_old_malloc) { |
841 // at runtime because it may not be present in the SDK used for compilation. | 873 ScopedClearErrno clear_errno; |
842 typedef malloc_zone_t* (*malloc_default_purgeable_zone_t)(void); | 874 ThreadLocalBooleanAutoReset flag(g_unchecked_malloc.Pointer(), true); |
843 malloc_default_purgeable_zone_t malloc_purgeable_zone = | 875 return g_old_malloc(malloc_default_zone(), size); |
844 reinterpret_cast<malloc_default_purgeable_zone_t>( | 876 } |
845 dlsym(RTLD_DEFAULT, "malloc_default_purgeable_zone")); | 877 return malloc(size); |
846 if (malloc_purgeable_zone) | |
847 return malloc_purgeable_zone(); | |
848 return NULL; | |
849 } | 878 } |
850 | 879 |
851 void EnableTerminationOnOutOfMemory() { | 880 void EnableTerminationOnOutOfMemory() { |
852 if (g_oom_killer_enabled) | 881 if (g_oom_killer_enabled) |
853 return; | 882 return; |
854 | 883 |
855 g_oom_killer_enabled = true; | 884 g_oom_killer_enabled = true; |
856 | 885 |
857 // === C malloc/calloc/valloc/realloc/posix_memalign === | 886 // === C malloc/calloc/valloc/realloc/posix_memalign === |
858 | 887 |
(...skipping 14 matching lines...) Expand all Loading... |
873 #if !defined(ADDRESS_SANITIZER) | 902 #if !defined(ADDRESS_SANITIZER) |
874 // Don't do anything special on OOM for the malloc zones replaced by | 903 // Don't do anything special on OOM for the malloc zones replaced by |
875 // AddressSanitizer, as modifying or protecting them may not work correctly. | 904 // AddressSanitizer, as modifying or protecting them may not work correctly. |
876 | 905 |
877 // See http://trac.webkit.org/changeset/53362/trunk/Tools/DumpRenderTree/mac | 906 // See http://trac.webkit.org/changeset/53362/trunk/Tools/DumpRenderTree/mac |
878 bool zone_allocators_protected = base::mac::IsOSLionOrLater(); | 907 bool zone_allocators_protected = base::mac::IsOSLionOrLater(); |
879 | 908 |
880 ChromeMallocZone* default_zone = | 909 ChromeMallocZone* default_zone = |
881 reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); | 910 reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); |
882 ChromeMallocZone* purgeable_zone = | 911 ChromeMallocZone* purgeable_zone = |
883 reinterpret_cast<ChromeMallocZone*>(GetPurgeableZone()); | 912 reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone()); |
884 | 913 |
885 vm_address_t page_start_default = 0; | 914 vm_address_t page_start_default = 0; |
886 vm_address_t page_start_purgeable = 0; | 915 vm_address_t page_start_purgeable = 0; |
887 vm_size_t len_default = 0; | 916 vm_size_t len_default = 0; |
888 vm_size_t len_purgeable = 0; | 917 vm_size_t len_purgeable = 0; |
889 if (zone_allocators_protected) { | 918 if (zone_allocators_protected) { |
890 page_start_default = reinterpret_cast<vm_address_t>(default_zone) & | 919 page_start_default = reinterpret_cast<vm_address_t>(default_zone) & |
891 static_cast<vm_size_t>(~(getpagesize() - 1)); | 920 static_cast<vm_size_t>(~(getpagesize() - 1)); |
892 len_default = reinterpret_cast<vm_address_t>(default_zone) - | 921 len_default = reinterpret_cast<vm_address_t>(default_zone) - |
893 page_start_default + sizeof(ChromeMallocZone); | 922 page_start_default + sizeof(ChromeMallocZone); |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1209 } | 1238 } |
1210 } | 1239 } |
1211 | 1240 |
1212 } // namespace | 1241 } // namespace |
1213 | 1242 |
1214 void EnsureProcessTerminated(ProcessHandle process) { | 1243 void EnsureProcessTerminated(ProcessHandle process) { |
1215 WaitForChildToDie(process, kWaitBeforeKillSeconds); | 1244 WaitForChildToDie(process, kWaitBeforeKillSeconds); |
1216 } | 1245 } |
1217 | 1246 |
1218 } // namespace base | 1247 } // namespace base |
OLD | NEW |