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> |
(...skipping 17 matching lines...) Expand all Loading... | |
28 #include <string> | 28 #include <string> |
29 | 29 |
30 #include "base/debug/debugger.h" | 30 #include "base/debug/debugger.h" |
31 #include "base/eintr_wrapper.h" | 31 #include "base/eintr_wrapper.h" |
32 #include "base/file_util.h" | 32 #include "base/file_util.h" |
33 #include "base/hash_tables.h" | 33 #include "base/hash_tables.h" |
34 #include "base/lazy_instance.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/mac/scoped_mach_port.h" | 37 #include "base/mac/scoped_mach_port.h" |
38 #include "base/safe_strerror_posix.h" | |
38 #include "base/string_util.h" | 39 #include "base/string_util.h" |
39 #include "base/sys_info.h" | 40 #include "base/sys_info.h" |
40 #include "base/threading/thread_local.h" | 41 #include "base/threading/thread_local.h" |
41 #include "third_party/apple_apsl/CFBase.h" | 42 #include "third_party/apple_apsl/CFBase.h" |
42 #include "third_party/apple_apsl/malloc.h" | 43 #include "third_party/apple_apsl/malloc.h" |
43 #include "third_party/mach_override/mach_override.h" | 44 #include "third_party/mach_override/mach_override.h" |
44 | 45 |
45 namespace base { | 46 namespace base { |
46 | 47 |
47 void RestoreDefaultExceptionHandler() { | 48 void RestoreDefaultExceptionHandler() { |
(...skipping 535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
583 private: | 584 private: |
584 ThreadLocalBoolean* scoped_tlb_; | 585 ThreadLocalBoolean* scoped_tlb_; |
585 bool original_value_; | 586 bool original_value_; |
586 | 587 |
587 DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset); | 588 DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset); |
588 }; | 589 }; |
589 | 590 |
590 base::LazyInstance<ThreadLocalBoolean>::Leaky | 591 base::LazyInstance<ThreadLocalBoolean>::Leaky |
591 g_unchecked_malloc = LAZY_INSTANCE_INITIALIZER; | 592 g_unchecked_malloc = LAZY_INSTANCE_INITIALIZER; |
592 | 593 |
594 // NOTE(shess): This is called when the malloc library noticed that the heap | |
595 // is fubar. Avoid calls which will re-enter the malloc library. | |
593 void CrMallocErrorBreak() { | 596 void CrMallocErrorBreak() { |
594 g_original_malloc_error_break(); | 597 g_original_malloc_error_break(); |
595 | 598 |
596 // Out of memory is certainly not heap corruption, and not necessarily | 599 // Out of memory is certainly not heap corruption, and not necessarily |
597 // something for which the process should be terminated. Leave that decision | 600 // something for which the process should be terminated. Leave that decision |
598 // to the OOM killer. The EBADF case comes up because the malloc library | 601 // to the OOM killer. The EBADF case comes up because the malloc library |
599 // attempts to log to ASL (syslog) before calling this code, which fails | 602 // attempts to log to ASL (syslog) before calling this code, which fails |
600 // accessing a Unix-domain socket because of sandboxing. | 603 // accessing a Unix-domain socket because of sandboxing. |
601 if (errno == ENOMEM || (errno == EBADF && g_unchecked_malloc.Get().Get())) | 604 if (errno == ENOMEM || (errno == EBADF && g_unchecked_malloc.Get().Get())) |
602 return; | 605 return; |
603 | 606 |
604 // A unit test checks this error message, so it needs to be in release builds. | 607 // A unit test checks this error message, so it needs to be in release builds. |
605 PLOG(ERROR) << | 608 char buf[1024] = |
606 "Terminating process due to a potential for future heap corruption"; | 609 "Terminating process due to a potential for future heap corruption: "; |
610 size_t bufLen = strlen(buf); | |
Mark Mentovai
2012/11/12 22:45:10
Nit: buf_len.
| |
611 safe_strerror_r(errno, buf + bufLen, sizeof(buf) - bufLen); | |
Mark Mentovai
2012/11/12 22:45:10
[safe_]strerror[_r] might wind up entering the all
Scott Hess - ex-Googler
2012/11/12 23:06:43
Seems reasonable.
| |
612 RAW_LOG(ERROR, buf); | |
607 | 613 |
608 // Crash by writing to NULL+errno to allow analyzing errno from | 614 // Crash by writing to NULL+errno to allow analyzing errno from |
609 // crash dump info (setting a breakpad key would re-enter the malloc | 615 // crash dump info (setting a breakpad key would re-enter the malloc |
610 // library). Max documented errno in intro(2) is actually 102, but | 616 // library). Max documented errno in intro(2) is actually 102, but |
611 // it really just needs to be "small" to stay on the right vm page. | 617 // it really just needs to be "small" to stay on the right vm page. |
612 const int kMaxErrno = 256; | 618 const int kMaxErrno = 256; |
613 char* volatile death_ptr = NULL; | 619 char* volatile death_ptr = NULL; |
614 death_ptr += std::min(errno, kMaxErrno); | 620 death_ptr += std::min(errno, kMaxErrno); |
615 *death_ptr = '!'; | 621 *death_ptr = '!'; |
616 } | 622 } |
617 | 623 |
618 } // namespace | 624 } // namespace |
619 | 625 |
620 void EnableTerminationOnHeapCorruption() { | 626 void EnableTerminationOnHeapCorruption() { |
621 #ifdef ADDRESS_SANITIZER | 627 #ifdef ADDRESS_SANITIZER |
622 // Don't do anything special on heap corruption, because it should be handled | 628 // Don't do anything special on heap corruption, because it should be handled |
623 // by AddressSanitizer. | 629 // by AddressSanitizer. |
624 return; | 630 return; |
625 #endif | 631 #endif |
626 malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak(); | 632 malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak(); |
627 if (!malloc_error_break) { | 633 if (!malloc_error_break) { |
628 DLOG(WARNING) << "Could not find malloc_error_break"; | 634 DLOG(WARNING) << "Could not find malloc_error_break"; |
629 return; | 635 return; |
630 } | 636 } |
631 | 637 |
638 // Warm this up so that it doesn't require allocation when | |
639 // |CrMallocErrorBreak()| calls it. | |
640 ignore_result(g_unchecked_malloc.Get().Get()); | |
641 | |
632 mach_error_t err = mach_override_ptr( | 642 mach_error_t err = mach_override_ptr( |
633 (void*)malloc_error_break, | 643 (void*)malloc_error_break, |
634 (void*)&CrMallocErrorBreak, | 644 (void*)&CrMallocErrorBreak, |
635 (void**)&g_original_malloc_error_break); | 645 (void**)&g_original_malloc_error_break); |
636 | 646 |
637 if (err != err_none) | 647 if (err != err_none) |
638 DLOG(WARNING) << "Could not override malloc_error_break; error = " << err; | 648 DLOG(WARNING) << "Could not override malloc_error_break; error = " << err; |
639 } | 649 } |
640 | 650 |
641 // ------------------------------------------------------------------------ | 651 // ------------------------------------------------------------------------ |
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1238 } | 1248 } |
1239 } | 1249 } |
1240 | 1250 |
1241 } // namespace | 1251 } // namespace |
1242 | 1252 |
1243 void EnsureProcessTerminated(ProcessHandle process) { | 1253 void EnsureProcessTerminated(ProcessHandle process) { |
1244 WaitForChildToDie(process, kWaitBeforeKillSeconds); | 1254 WaitForChildToDie(process, kWaitBeforeKillSeconds); |
1245 } | 1255 } |
1246 | 1256 |
1247 } // namespace base | 1257 } // namespace base |
OLD | NEW |