summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/DEPS1
-rw-r--r--base/base.gypi3
-rw-r--r--base/process_util_linux.cc4
-rw-r--r--base/process_util_mac.mm85
-rw-r--r--base/process_util_posix.cc4
-rw-r--r--base/process_util_unittest.cc15
-rw-r--r--third_party/mach_override/README.chromium3
-rw-r--r--third_party/mach_override/mach_override.c1
8 files changed, 111 insertions, 5 deletions
diff --git a/base/DEPS b/base/DEPS
index 81e9cda..80df202 100644
--- a/base/DEPS
+++ b/base/DEPS
@@ -5,6 +5,7 @@ include_rules = [
"+third_party/libevent",
"+third_party/dmg_fp",
"+third_party/GTM",
+ "+third_party/mach_override",
"+third_party/modp_b64",
"+third_party/tcmalloc",
diff --git a/base/base.gypi b/base/base.gypi
index 642e47f..4363799 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -536,6 +536,9 @@
'$(SDKROOT)/System/Library/Frameworks/Security.framework',
],
},
+ 'dependencies': [
+ '../third_party/mach_override/mach_override.gyp:mach_override',
+ ],
}],
[ 'OS != "win"', {
'dependencies': ['../third_party/libevent/libevent.gyp:libevent'],
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index 1f71f4d..b350517 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -718,6 +718,10 @@ int posix_memalign(void** ptr, size_t alignment, size_t size) {
#endif // !defined(USE_TCMALLOC)
} // extern C
+void EnableTerminationOnHeapCorruption() {
+ // On Linux, there nothing to do AFAIK.
+}
+
void EnableTerminationOnOutOfMemory() {
#if defined(OS_ANDROID)
// Android doesn't support setting a new handler.
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index 7db44d9..ceb4f0a 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -12,6 +12,8 @@
#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>
#include <spawn.h>
@@ -34,6 +36,7 @@
#include "base/time.h"
#include "third_party/apple_apsl/CFBase.h"
#include "third_party/apple_apsl/malloc.h"
+#include "third_party/mach_override/mach_override.h"
namespace base {
@@ -483,6 +486,88 @@ size_t GetSystemCommitCharge() {
return (data.active_count * page_size) / 1024;
}
+namespace {
+
+// Finds the library path for malloc() and thus the libC part of libSystem,
+// which in Lion is in a separate image.
+const char* LookUpLibCPath() {
+ const void* addr = reinterpret_cast<void*>(&malloc);
+
+ Dl_info info;
+ if (dladdr(addr, &info))
+ return info.dli_fname;
+
+ LOG(WARNING) << "Could not find image path for malloc()";
+ return NULL;
+}
+
+typedef void(*malloc_error_break_t)(void);
+malloc_error_break_t g_original_malloc_error_break = NULL;
+
+// Returns the function pointer for malloc_error_break. This symbol is declared
+// as __private_extern__ and cannot be dlsym()ed. Instead, use nlist() to
+// get it.
+malloc_error_break_t LookUpMallocErrorBreak() {
+#if ARCH_CPU_32_BITS
+ const char* lib_c_path = LookUpLibCPath();
+ if (!lib_c_path)
+ return NULL;
+
+ // Only need to look up two symbols, but nlist() requires a NULL-terminated
+ // array and takes no count.
+ struct nlist nl[3];
+ bzero(&nl, sizeof(nl));
+
+ // The symbol to find.
+ nl[0].n_un.n_name = const_cast<char*>("_malloc_error_break");
+
+ // A reference symbol by which the address of the desired symbol will be
+ // calculated.
+ nl[1].n_un.n_name = const_cast<char*>("_malloc");
+
+ int rv = nlist(lib_c_path, nl);
+ if (rv != 0 || nl[0].n_type == N_UNDF || nl[1].n_type == N_UNDF) {
+ return NULL;
+ }
+
+ // nlist() returns addresses as offsets in the image, not the instruction
+ // pointer in memory. Use the known in-memory address of malloc()
+ // to compute the offset for malloc_error_break().
+ uintptr_t reference_addr = reinterpret_cast<uintptr_t>(&malloc);
+ reference_addr -= nl[1].n_value;
+ reference_addr += nl[0].n_value;
+
+ return reinterpret_cast<malloc_error_break_t>(reference_addr);
+#endif // ARCH_CPU_32_BITS
+
+ return NULL;
+}
+
+void CrMallocErrorBreak() {
+ g_original_malloc_error_break();
+ LOG(ERROR) <<
+ "Terminating process due to a potential for future heap corruption";
+ base::debug::BreakDebugger();
+}
+
+} // namespace
+
+void EnableTerminationOnHeapCorruption() {
+ malloc_error_break_t malloc_error_break = LookUpMallocErrorBreak();
+ if (!malloc_error_break) {
+ LOG(WARNING) << "Could not find malloc_error_break";
+ return;
+ }
+
+ mach_error_t err = mach_override_ptr(
+ (void*)malloc_error_break,
+ (void*)&CrMallocErrorBreak,
+ (void**)&g_original_malloc_error_break);
+
+ if (err != err_none)
+ LOG(WARNING) << "Could not override malloc_error_break; error = " << err;
+}
+
// ------------------------------------------------------------------------
namespace {
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index db380bd..a81acbc 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -656,10 +656,6 @@ bool LaunchProcess(const CommandLine& cmdline,
ProcessMetrics::~ProcessMetrics() { }
-void EnableTerminationOnHeapCorruption() {
- // On POSIX, there nothing to do AFAIK.
-}
-
bool EnableInProcessStackDumping() {
// When running in an application, our code typically expects SIGPIPE
// to be ignored. Therefore, when testing that same code, it should run
diff --git a/base/process_util_unittest.cc b/base/process_util_unittest.cc
index 3b05d03..8a653d4 100644
--- a/base/process_util_unittest.cc
+++ b/base/process_util_unittest.cc
@@ -397,6 +397,21 @@ TEST_F(ProcessUtilTest, LaunchAsUser) {
#endif // defined(OS_WIN)
+#if defined(OS_MACOSX)
+
+TEST_F(ProcessUtilTest, MacTerminateOnHeapCorruption) {
+ // Note that base::EnableTerminationOnHeapCorruption() is called as part of
+ // test suite setup and does not need to be done again, else mach_override
+ // will fail.
+
+ char buf[3];
+ ASSERT_DEATH(free(buf), "being freed.*"
+ "\\*\\*\\* set a breakpoint in malloc_error_break to debug.*"
+ "Terminating process due to a potential for future heap corruption");
+}
+
+#endif // defined(OS_MACOSX)
+
#if defined(OS_POSIX)
namespace {
diff --git a/third_party/mach_override/README.chromium b/third_party/mach_override/README.chromium
index 065ade9..75a9938 100644
--- a/third_party/mach_override/README.chromium
+++ b/third_party/mach_override/README.chromium
@@ -19,4 +19,5 @@ implementations at run time.
Local Modifications:
-None. All local changes have been upstreamed.
+Added the instructions to |possibleInstructions| for the very short
+malloc_error_break() on 10.5 so that it can be overriden on that platform.
diff --git a/third_party/mach_override/mach_override.c b/third_party/mach_override/mach_override.c
index 1274133..2d12e43 100644
--- a/third_party/mach_override/mach_override.c
+++ b/third_party/mach_override/mach_override.c
@@ -530,6 +530,7 @@ typedef struct {
#if defined(__i386__)
static AsmInstructionMatch possibleInstructions[] = {
+ { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %ebp; mov %esp,%ebp; leave; ret
{ 0x1, {0xFF}, {0x90} }, // nop
{ 0x1, {0xFF}, {0x55} }, // push %esp
{ 0x2, {0xFF, 0xFF}, {0x89, 0xE5} }, // mov %esp,%ebp