Chromium Code Reviews| Index: base/process_util_mac.mm |
| diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm |
| index 7db44d900530d7d79150ca819194393bdb961b76..ceb4f0a540073bd0b92ff6ba7b23096258407c0e 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() { |
|
Scott Hess - ex-Googler
2011/08/22 19:50:35
Would it be worthwhile to unify this with the comp
Robert Sesek
2011/08/22 19:52:14
We want to explicitly discourage this kind of very
Mark Mentovai
2011/08/22 20:07:23
shess wrote:
|
| +#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 { |