diff options
Diffstat (limited to 'base/process_util_mac.mm')
-rw-r--r-- | base/process_util_mac.mm | 67 |
1 files changed, 48 insertions, 19 deletions
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm index b257021..4885e4b 100644 --- a/base/process_util_mac.mm +++ b/base/process_util_mac.mm @@ -13,7 +13,6 @@ #include <mach/mach_vm.h> #include <mach/shared_region.h> #include <mach/task.h> -#include <mach-o/dyld.h> #include <mach-o/nlist.h> #include <malloc/malloc.h> #import <objc/runtime.h> @@ -32,12 +31,12 @@ #include "base/eintr_wrapper.h" #include "base/file_util.h" #include "base/hash_tables.h" +#include "base/lazy_instance.h" #include "base/logging.h" #include "base/mac/mac_util.h" #include "base/string_util.h" #include "base/sys_info.h" -#include "base/sys_string_conversions.h" -#include "base/time.h" +#include "base/threading/thread_local.h" #include "third_party/apple_apsl/CFBase.h" #include "third_party/apple_apsl/malloc.h" #include "third_party/mach_override/mach_override.h" @@ -566,20 +565,53 @@ class ScopedClearErrno { DISALLOW_COPY_AND_ASSIGN(ScopedClearErrno); }; +// Combines ThreadLocalBoolean with AutoReset. It would be convenient +// to compose ThreadLocalPointer<bool> with AutoReset<bool>, but that +// would require allocating some storage for the bool. +class ThreadLocalBooleanAutoReset { + public: + ThreadLocalBooleanAutoReset(ThreadLocalBoolean* tlb, bool new_value) + : scoped_tlb_(tlb), + original_value_(tlb->Get()) { + scoped_tlb_->Set(new_value); + } + ~ThreadLocalBooleanAutoReset() { + scoped_tlb_->Set(original_value_); + } + + private: + ThreadLocalBoolean* scoped_tlb_; + bool original_value_; + + DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanAutoReset); +}; + +base::LazyInstance<ThreadLocalBoolean>::Leaky + g_unchecked_malloc = LAZY_INSTANCE_INITIALIZER; + void CrMallocErrorBreak() { g_original_malloc_error_break(); // Out of memory is certainly not heap corruption, and not necessarily // something for which the process should be terminated. Leave that decision - // to the OOM killer. - if (errno == ENOMEM) + // to the OOM killer. The EBADF case comes up because the malloc library + // attempts to log to ASL (syslog) before calling this code, which fails + // accessing a Unix-domain socket because of sandboxing. + if (errno == ENOMEM || (errno == EBADF && g_unchecked_malloc.Get().Get())) return; // A unit test checks this error message, so it needs to be in release builds. - LOG(ERROR) << + PLOG(ERROR) << "Terminating process due to a potential for future heap corruption"; - int* volatile death_ptr = NULL; - *death_ptr = 0xf00bad; + + // Crash by writing to NULL+errno to allow analyzing errno from + // crash dump info (setting a breakpad key would re-enter the malloc + // library). Max documented errno in intro(2) is actually 102, but + // it really just needs to be "small" to stay on the right vm page. + const int kMaxErrno = 256; + char* volatile death_ptr = NULL; + death_ptr += std::min(errno, kMaxErrno); + *death_ptr = '!'; } } // namespace @@ -836,16 +868,13 @@ id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone) } // namespace -malloc_zone_t* GetPurgeableZone() { - // malloc_default_purgeable_zone only exists on >= 10.6. Use dlsym to grab it - // at runtime because it may not be present in the SDK used for compilation. - typedef malloc_zone_t* (*malloc_default_purgeable_zone_t)(void); - malloc_default_purgeable_zone_t malloc_purgeable_zone = - reinterpret_cast<malloc_default_purgeable_zone_t>( - dlsym(RTLD_DEFAULT, "malloc_default_purgeable_zone")); - if (malloc_purgeable_zone) - return malloc_purgeable_zone(); - return NULL; +void* UncheckedMalloc(size_t size) { + if (g_old_malloc) { + ScopedClearErrno clear_errno; + ThreadLocalBooleanAutoReset flag(g_unchecked_malloc.Pointer(), true); + return g_old_malloc(malloc_default_zone(), size); + } + return malloc(size); } void EnableTerminationOnOutOfMemory() { @@ -880,7 +909,7 @@ void EnableTerminationOnOutOfMemory() { ChromeMallocZone* default_zone = reinterpret_cast<ChromeMallocZone*>(malloc_default_zone()); ChromeMallocZone* purgeable_zone = - reinterpret_cast<ChromeMallocZone*>(GetPurgeableZone()); + reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone()); vm_address_t page_start_default = 0; vm_address_t page_start_purgeable = 0; |