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=="; | |
Mark Mentovai
2012/11/12 23:19:32
One = too many?
Scott Hess - ex-Googler
2012/11/12 23:39:53
Done. I was thinking C-style is-equal-to, but a b
| |
610 char errnobuf[4] = { | |
Mark Mentovai
2012/11/12 23:19:32
No [4], just [].
Scott Hess - ex-Googler
2012/11/12 23:39:53
Done.
| |
611 '0' + ((errno / 100) % 10), | |
612 '0' + ((errno / 10) % 10), | |
613 '0' + (errno % 10), | |
614 '\000' | |
615 }; | |
Mark Mentovai
2012/11/12 23:19:32
Ha!
Do you want to COMPILE_ASSERT that ELAST <= 9
Scott Hess - ex-Googler
2012/11/12 23:39:53
Honestly, I kind of questioned even the third digi
| |
616 strlcat(buf, errnobuf, sizeof(buf)); | |
Mark Mentovai
2012/11/12 23:19:32
I can think of a way to avoid the copy, but that’s
Scott Hess - ex-Googler
2012/11/12 23:39:53
There are dozens of ways to skin this cat, and the
| |
617 RAW_LOG(ERROR, buf); | |
607 | 618 |
608 // Crash by writing to NULL+errno to allow analyzing errno from | 619 // Crash by writing to NULL+errno to allow analyzing errno from |
609 // crash dump info (setting a breakpad key would re-enter the malloc | 620 // crash dump info (setting a breakpad key would re-enter the malloc |
610 // library). Max documented errno in intro(2) is actually 102, but | 621 // 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. | 622 // it really just needs to be "small" to stay on the right vm page. |
612 const int kMaxErrno = 256; | 623 const int kMaxErrno = 256; |
613 char* volatile death_ptr = NULL; | 624 char* volatile death_ptr = NULL; |
614 death_ptr += std::min(errno, kMaxErrno); | 625 death_ptr += std::min(errno, kMaxErrno); |
615 *death_ptr = '!'; | 626 *death_ptr = '!'; |
616 } | 627 } |
617 | 628 |
618 } // namespace | 629 } // namespace |
619 | 630 |
620 void EnableTerminationOnHeapCorruption() { | 631 void EnableTerminationOnHeapCorruption() { |
621 #ifdef ADDRESS_SANITIZER | 632 #ifdef ADDRESS_SANITIZER |
622 // Don't do anything special on heap corruption, because it should be handled | 633 // Don't do anything special on heap corruption, because it should be handled |
623 // by AddressSanitizer. | 634 // by AddressSanitizer. |
624 return; | 635 return; |
625 #endif | 636 #endif |
626 malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak(); | 637 malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak(); |
627 if (!malloc_error_break) { | 638 if (!malloc_error_break) { |
628 DLOG(WARNING) << "Could not find malloc_error_break"; | 639 DLOG(WARNING) << "Could not find malloc_error_break"; |
629 return; | 640 return; |
630 } | 641 } |
631 | 642 |
643 // Warm this up so that it doesn't require allocation when | |
644 // |CrMallocErrorBreak()| calls it. | |
645 ignore_result(g_unchecked_malloc.Get().Get()); | |
646 | |
632 mach_error_t err = mach_override_ptr( | 647 mach_error_t err = mach_override_ptr( |
633 (void*)malloc_error_break, | 648 (void*)malloc_error_break, |
634 (void*)&CrMallocErrorBreak, | 649 (void*)&CrMallocErrorBreak, |
635 (void**)&g_original_malloc_error_break); | 650 (void**)&g_original_malloc_error_break); |
636 | 651 |
637 if (err != err_none) | 652 if (err != err_none) |
638 DLOG(WARNING) << "Could not override malloc_error_break; error = " << err; | 653 DLOG(WARNING) << "Could not override malloc_error_break; error = " << err; |
639 } | 654 } |
640 | 655 |
641 // ------------------------------------------------------------------------ | 656 // ------------------------------------------------------------------------ |
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1238 } | 1253 } |
1239 } | 1254 } |
1240 | 1255 |
1241 } // namespace | 1256 } // namespace |
1242 | 1257 |
1243 void EnsureProcessTerminated(ProcessHandle process) { | 1258 void EnsureProcessTerminated(ProcessHandle process) { |
1244 WaitForChildToDie(process, kWaitBeforeKillSeconds); | 1259 WaitForChildToDie(process, kWaitBeforeKillSeconds); |
1245 } | 1260 } |
1246 | 1261 |
1247 } // namespace base | 1262 } // namespace base |
OLD | NEW |