Chromium Code Reviews| 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 |