| Index: base/process_util_mac.mm
|
| diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
|
| index b257021401726975aa33eb3fc7cc96b140964141..4885e4b18c6135ea08b1311eca24c1b0919ebd88 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;
|
|
|