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; |