| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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/memory.h" | 5 #include "base/process/memory.h" |
| 6 | 6 |
| 7 #include <CoreFoundation/CoreFoundation.h> | 7 #include <CoreFoundation/CoreFoundation.h> |
| 8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <mach/mach.h> | 9 #include <mach/mach.h> |
| 10 #include <mach/mach_vm.h> | 10 #include <mach/mach_vm.h> |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 } | 101 } |
| 102 | 102 |
| 103 private: | 103 private: |
| 104 ThreadLocalBoolean* scoped_tlb_; | 104 ThreadLocalBoolean* scoped_tlb_; |
| 105 bool original_value_; | 105 bool original_value_; |
| 106 | 106 |
| 107 DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset); | 107 DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset); |
| 108 }; | 108 }; |
| 109 | 109 |
| 110 base::LazyInstance<ThreadLocalBoolean>::Leaky | 110 base::LazyInstance<ThreadLocalBoolean>::Leaky |
| 111 g_unchecked_malloc = LAZY_INSTANCE_INITIALIZER; | 111 g_unchecked_alloc = LAZY_INSTANCE_INITIALIZER; |
| 112 | 112 |
| 113 // NOTE(shess): This is called when the malloc library noticed that the heap | 113 // NOTE(shess): This is called when the malloc library noticed that the heap |
| 114 // is fubar. Avoid calls which will re-enter the malloc library. | 114 // is fubar. Avoid calls which will re-enter the malloc library. |
| 115 void CrMallocErrorBreak() { | 115 void CrMallocErrorBreak() { |
| 116 g_original_malloc_error_break(); | 116 g_original_malloc_error_break(); |
| 117 | 117 |
| 118 // Out of memory is certainly not heap corruption, and not necessarily | 118 // Out of memory is certainly not heap corruption, and not necessarily |
| 119 // something for which the process should be terminated. Leave that decision | 119 // something for which the process should be terminated. Leave that decision |
| 120 // to the OOM killer. The EBADF case comes up because the malloc library | 120 // to the OOM killer. The EBADF case comes up because the malloc library |
| 121 // attempts to log to ASL (syslog) before calling this code, which fails | 121 // attempts to log to ASL (syslog) before calling this code, which fails |
| 122 // accessing a Unix-domain socket because of sandboxing. | 122 // accessing a Unix-domain socket because of sandboxing. |
| 123 if (errno == ENOMEM || (errno == EBADF && g_unchecked_malloc.Get().Get())) | 123 if (errno == ENOMEM || (errno == EBADF && g_unchecked_alloc.Get().Get())) |
| 124 return; | 124 return; |
| 125 | 125 |
| 126 // A unit test checks this error message, so it needs to be in release builds. | 126 // A unit test checks this error message, so it needs to be in release builds. |
| 127 char buf[1024] = | 127 char buf[1024] = |
| 128 "Terminating process due to a potential for future heap corruption: " | 128 "Terminating process due to a potential for future heap corruption: " |
| 129 "errno="; | 129 "errno="; |
| 130 char errnobuf[] = { | 130 char errnobuf[] = { |
| 131 '0' + ((errno / 100) % 10), | 131 '0' + ((errno / 100) % 10), |
| 132 '0' + ((errno / 10) % 10), | 132 '0' + ((errno / 10) % 10), |
| 133 '0' + (errno % 10), | 133 '0' + (errno % 10), |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 486 debug::BreakDebugger(); | 486 debug::BreakDebugger(); |
| 487 return result; | 487 return result; |
| 488 } | 488 } |
| 489 | 489 |
| 490 } // namespace | 490 } // namespace |
| 491 | 491 |
| 492 void* UncheckedMalloc(size_t size) { | 492 void* UncheckedMalloc(size_t size) { |
| 493 if (g_old_malloc) { | 493 if (g_old_malloc) { |
| 494 #if ARCH_CPU_32_BITS | 494 #if ARCH_CPU_32_BITS |
| 495 ScopedClearErrno clear_errno; | 495 ScopedClearErrno clear_errno; |
| 496 ThreadLocalBooleanAutoReset flag(g_unchecked_malloc.Pointer(), true); | 496 ThreadLocalBooleanAutoReset flag(g_unchecked_alloc.Pointer(), true); |
| 497 #endif // ARCH_CPU_32_BITS | 497 #endif // ARCH_CPU_32_BITS |
| 498 return g_old_malloc(malloc_default_zone(), size); | 498 return g_old_malloc(malloc_default_zone(), size); |
| 499 } | 499 } |
| 500 return malloc(size); | 500 return malloc(size); |
| 501 } | 501 } |
| 502 | 502 |
| 503 void* UncheckedCalloc(size_t num_items, size_t size) { |
| 504 if (g_old_calloc) { |
| 505 #if ARCH_CPU_32_BITS |
| 506 ScopedClearErrno clear_errno; |
| 507 ThreadLocalBooleanAutoReset flag(g_unchecked_alloc.Pointer(), true); |
| 508 #endif // ARCH_CPU_32_BITS |
| 509 return g_old_calloc(malloc_default_zone(), num_items, size); |
| 510 } |
| 511 return calloc(num_items, size); |
| 512 } |
| 513 |
| 503 void EnableTerminationOnOutOfMemory() { | 514 void EnableTerminationOnOutOfMemory() { |
| 504 if (g_oom_killer_enabled) | 515 if (g_oom_killer_enabled) |
| 505 return; | 516 return; |
| 506 | 517 |
| 507 g_oom_killer_enabled = true; | 518 g_oom_killer_enabled = true; |
| 508 | 519 |
| 509 // === C malloc/calloc/valloc/realloc/posix_memalign === | 520 // === C malloc/calloc/valloc/realloc/posix_memalign === |
| 510 | 521 |
| 511 // This approach is not perfect, as requests for amounts of memory larger than | 522 // This approach is not perfect, as requests for amounts of memory larger than |
| 512 // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will | 523 // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 697 @selector(allocWithZone:)); | 708 @selector(allocWithZone:)); |
| 698 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( | 709 g_old_allocWithZone = reinterpret_cast<allocWithZone_t>( |
| 699 method_getImplementation(orig_method)); | 710 method_getImplementation(orig_method)); |
| 700 CHECK(g_old_allocWithZone) | 711 CHECK(g_old_allocWithZone) |
| 701 << "Failed to get allocWithZone allocation function."; | 712 << "Failed to get allocWithZone allocation function."; |
| 702 method_setImplementation(orig_method, | 713 method_setImplementation(orig_method, |
| 703 reinterpret_cast<IMP>(oom_killer_allocWithZone)); | 714 reinterpret_cast<IMP>(oom_killer_allocWithZone)); |
| 704 } | 715 } |
| 705 | 716 |
| 706 } // namespace base | 717 } // namespace base |
| OLD | NEW |