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 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
583 private: | 583 private: |
584 ThreadLocalBoolean* scoped_tlb_; | 584 ThreadLocalBoolean* scoped_tlb_; |
585 bool original_value_; | 585 bool original_value_; |
586 | 586 |
587 DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset); | 587 DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset); |
588 }; | 588 }; |
589 | 589 |
590 base::LazyInstance<ThreadLocalBoolean>::Leaky | 590 base::LazyInstance<ThreadLocalBoolean>::Leaky |
591 g_unchecked_malloc = LAZY_INSTANCE_INITIALIZER; | 591 g_unchecked_malloc = LAZY_INSTANCE_INITIALIZER; |
592 | 592 |
| 593 // NOTE(shess): This is called when the malloc library noticed that the heap |
| 594 // is fubar. Avoid calls which will re-enter the malloc library. |
593 void CrMallocErrorBreak() { | 595 void CrMallocErrorBreak() { |
594 g_original_malloc_error_break(); | 596 g_original_malloc_error_break(); |
595 | 597 |
596 // Out of memory is certainly not heap corruption, and not necessarily | 598 // Out of memory is certainly not heap corruption, and not necessarily |
597 // something for which the process should be terminated. Leave that decision | 599 // 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 | 600 // 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 | 601 // attempts to log to ASL (syslog) before calling this code, which fails |
600 // accessing a Unix-domain socket because of sandboxing. | 602 // accessing a Unix-domain socket because of sandboxing. |
601 if (errno == ENOMEM || (errno == EBADF && g_unchecked_malloc.Get().Get())) | 603 if (errno == ENOMEM || (errno == EBADF && g_unchecked_malloc.Get().Get())) |
602 return; | 604 return; |
603 | 605 |
604 // A unit test checks this error message, so it needs to be in release builds. | 606 // A unit test checks this error message, so it needs to be in release builds. |
605 PLOG(ERROR) << | 607 char buf[1024] = |
606 "Terminating process due to a potential for future heap corruption"; | 608 "Terminating process due to a potential for future heap corruption: " |
| 609 "errno="; |
| 610 char errnobuf[] = { |
| 611 '0' + ((errno / 100) % 10), |
| 612 '0' + ((errno / 10) % 10), |
| 613 '0' + (errno % 10), |
| 614 '\000' |
| 615 }; |
| 616 COMPILE_ASSERT(ELAST <= 999, errno_too_large_to_encode); |
| 617 strlcat(buf, errnobuf, sizeof(buf)); |
| 618 RAW_LOG(ERROR, buf); |
607 | 619 |
608 // Crash by writing to NULL+errno to allow analyzing errno from | 620 // Crash by writing to NULL+errno to allow analyzing errno from |
609 // crash dump info (setting a breakpad key would re-enter the malloc | 621 // crash dump info (setting a breakpad key would re-enter the malloc |
610 // library). Max documented errno in intro(2) is actually 102, but | 622 // 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. | 623 // it really just needs to be "small" to stay on the right vm page. |
612 const int kMaxErrno = 256; | 624 const int kMaxErrno = 256; |
613 char* volatile death_ptr = NULL; | 625 char* volatile death_ptr = NULL; |
614 death_ptr += std::min(errno, kMaxErrno); | 626 death_ptr += std::min(errno, kMaxErrno); |
615 *death_ptr = '!'; | 627 *death_ptr = '!'; |
616 } | 628 } |
617 | 629 |
618 } // namespace | 630 } // namespace |
619 | 631 |
620 void EnableTerminationOnHeapCorruption() { | 632 void EnableTerminationOnHeapCorruption() { |
621 #ifdef ADDRESS_SANITIZER | 633 #ifdef ADDRESS_SANITIZER |
622 // Don't do anything special on heap corruption, because it should be handled | 634 // Don't do anything special on heap corruption, because it should be handled |
623 // by AddressSanitizer. | 635 // by AddressSanitizer. |
624 return; | 636 return; |
625 #endif | 637 #endif |
626 malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak(); | 638 malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak(); |
627 if (!malloc_error_break) { | 639 if (!malloc_error_break) { |
628 DLOG(WARNING) << "Could not find malloc_error_break"; | 640 DLOG(WARNING) << "Could not find malloc_error_break"; |
629 return; | 641 return; |
630 } | 642 } |
631 | 643 |
| 644 // Warm this up so that it doesn't require allocation when |
| 645 // |CrMallocErrorBreak()| calls it. |
| 646 ignore_result(g_unchecked_malloc.Get().Get()); |
| 647 |
632 mach_error_t err = mach_override_ptr( | 648 mach_error_t err = mach_override_ptr( |
633 (void*)malloc_error_break, | 649 (void*)malloc_error_break, |
634 (void*)&CrMallocErrorBreak, | 650 (void*)&CrMallocErrorBreak, |
635 (void**)&g_original_malloc_error_break); | 651 (void**)&g_original_malloc_error_break); |
636 | 652 |
637 if (err != err_none) | 653 if (err != err_none) |
638 DLOG(WARNING) << "Could not override malloc_error_break; error = " << err; | 654 DLOG(WARNING) << "Could not override malloc_error_break; error = " << err; |
639 } | 655 } |
640 | 656 |
641 // ------------------------------------------------------------------------ | 657 // ------------------------------------------------------------------------ |
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1238 } | 1254 } |
1239 } | 1255 } |
1240 | 1256 |
1241 } // namespace | 1257 } // namespace |
1242 | 1258 |
1243 void EnsureProcessTerminated(ProcessHandle process) { | 1259 void EnsureProcessTerminated(ProcessHandle process) { |
1244 WaitForChildToDie(process, kWaitBeforeKillSeconds); | 1260 WaitForChildToDie(process, kWaitBeforeKillSeconds); |
1245 } | 1261 } |
1246 | 1262 |
1247 } // namespace base | 1263 } // namespace base |
OLD | NEW |