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. |
575 if (errno == ENOMEM) | 598 if (errno == ENOMEM || (errno == EBADF && g_unchecked_malloc.Get().Get())) |
576 return; | 599 return; |
577 | 600 |
578 // A unit test checks this error message, so it needs to be in release builds. | 601 // A unit test checks this error message, so it needs to be in release builds. |
579 LOG(ERROR) << | 602 PLOG(ERROR) << |
580 "Terminating process due to a potential for future heap corruption"; | 603 "Terminating process due to a potential for future heap corruption"; |
581 int* volatile death_ptr = NULL; | 604 char* volatile death_ptr = NULL; |
582 *death_ptr = 0xf00bad; | 605 death_ptr += errno; |
Mark Mentovai
2012/09/19 20:12:33
Oh, so now you trust errno to not be corrupt?
Scott Hess - ex-Googler
2012/09/19 20:27:51
Done. Though at some point we kind of have to ass
Mark Mentovai
2012/09/19 20:34:06
shess wrote:
| |
606 *death_ptr = '!'; | |
583 } | 607 } |
584 | 608 |
585 } // namespace | 609 } // namespace |
586 | 610 |
587 void EnableTerminationOnHeapCorruption() { | 611 void EnableTerminationOnHeapCorruption() { |
588 #ifdef ADDRESS_SANITIZER | 612 #ifdef ADDRESS_SANITIZER |
589 // Don't do anything special on heap corruption, because it should be handled | 613 // Don't do anything special on heap corruption, because it should be handled |
590 // by AddressSanitizer. | 614 // by AddressSanitizer. |
591 return; | 615 return; |
592 #endif | 616 #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) | 853 id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone) |
830 { | 854 { |
831 id result = g_old_allocWithZone(self, _cmd, zone); | 855 id result = g_old_allocWithZone(self, _cmd, zone); |
832 if (!result) | 856 if (!result) |
833 debug::BreakDebugger(); | 857 debug::BreakDebugger(); |
834 return result; | 858 return result; |
835 } | 859 } |
836 | 860 |
837 } // namespace | 861 } // namespace |
838 | 862 |
839 malloc_zone_t* GetPurgeableZone() { | 863 void* UncheckedMalloc(size_t size) { |
840 // malloc_default_purgeable_zone only exists on >= 10.6. Use dlsym to grab it | 864 if (g_old_malloc) { |
841 // at runtime because it may not be present in the SDK used for compilation. | 865 ScopedClearErrno clear_errno; |
842 typedef malloc_zone_t* (*malloc_default_purgeable_zone_t)(void); | 866 ThreadLocalBooleanAutoReset flag(g_unchecked_malloc.Pointer(), true); |
843 malloc_default_purgeable_zone_t malloc_purgeable_zone = | 867 return g_old_malloc(malloc_default_zone(), size); |
844 reinterpret_cast<malloc_default_purgeable_zone_t>( | 868 } |
845 dlsym(RTLD_DEFAULT, "malloc_default_purgeable_zone")); | 869 return malloc(size); |
846 if (malloc_purgeable_zone) | |
847 return malloc_purgeable_zone(); | |
848 return NULL; | |
849 } | 870 } |
850 | 871 |
851 void EnableTerminationOnOutOfMemory() { | 872 void EnableTerminationOnOutOfMemory() { |
852 if (g_oom_killer_enabled) | 873 if (g_oom_killer_enabled) |
853 return; | 874 return; |
854 | 875 |
855 g_oom_killer_enabled = true; | 876 g_oom_killer_enabled = true; |
856 | 877 |
857 // === C malloc/calloc/valloc/realloc/posix_memalign === | 878 // === C malloc/calloc/valloc/realloc/posix_memalign === |
858 | 879 |
(...skipping 14 matching lines...) Expand all Loading... | |
873 #if !defined(ADDRESS_SANITIZER) | 894 #if !defined(ADDRESS_SANITIZER) |
874 // Don't do anything special on OOM for the malloc zones replaced by | 895 // Don't do anything special on OOM for the malloc zones replaced by |
875 // AddressSanitizer, as modifying or protecting them may not work correctly. | 896 // AddressSanitizer, as modifying or protecting them may not work correctly. |
876 | 897 |
877 // See http://trac.webkit.org/changeset/53362/trunk/Tools/DumpRenderTree/mac | 898 // See http://trac.webkit.org/changeset/53362/trunk/Tools/DumpRenderTree/mac |
878 bool zone_allocators_protected = base::mac::IsOSLionOrLater(); | 899 bool zone_allocators_protected = base::mac::IsOSLionOrLater(); |
879 | 900 |
880 ChromeMallocZone* default_zone = | 901 ChromeMallocZone* default_zone = |
881 reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); | 902 reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); |
882 ChromeMallocZone* purgeable_zone = | 903 ChromeMallocZone* purgeable_zone = |
883 reinterpret_cast<ChromeMallocZone*>(GetPurgeableZone()); | 904 reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone()); |
884 | 905 |
885 vm_address_t page_start_default = 0; | 906 vm_address_t page_start_default = 0; |
886 vm_address_t page_start_purgeable = 0; | 907 vm_address_t page_start_purgeable = 0; |
887 vm_size_t len_default = 0; | 908 vm_size_t len_default = 0; |
888 vm_size_t len_purgeable = 0; | 909 vm_size_t len_purgeable = 0; |
889 if (zone_allocators_protected) { | 910 if (zone_allocators_protected) { |
890 page_start_default = reinterpret_cast<vm_address_t>(default_zone) & | 911 page_start_default = reinterpret_cast<vm_address_t>(default_zone) & |
891 static_cast<vm_size_t>(~(getpagesize() - 1)); | 912 static_cast<vm_size_t>(~(getpagesize() - 1)); |
892 len_default = reinterpret_cast<vm_address_t>(default_zone) - | 913 len_default = reinterpret_cast<vm_address_t>(default_zone) - |
893 page_start_default + sizeof(ChromeMallocZone); | 914 page_start_default + sizeof(ChromeMallocZone); |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1209 } | 1230 } |
1210 } | 1231 } |
1211 | 1232 |
1212 } // namespace | 1233 } // namespace |
1213 | 1234 |
1214 void EnsureProcessTerminated(ProcessHandle process) { | 1235 void EnsureProcessTerminated(ProcessHandle process) { |
1215 WaitForChildToDie(process, kWaitBeforeKillSeconds); | 1236 WaitForChildToDie(process, kWaitBeforeKillSeconds); |
1216 } | 1237 } |
1217 | 1238 |
1218 } // namespace base | 1239 } // namespace base |
OLD | NEW |