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..9bd394fe34a5a179e2440ad0acc94bbe9fda809f 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,85 @@ size_t GetSystemCommitCharge() { |
| return (data.active_count * page_size) / 1024; |
| } |
| +namespace { |
| + |
| +typedef void(*malloc_error_break_t)(void); |
|
Mark Mentovai
2011/08/17 16:44:55
Move the typedef and declaration down so that they
|
| +malloc_error_break_t g_original_malloc_error_break = NULL; |
| + |
| +// Finds the library path for malloc() and thus libSystem, or at least a part |
| +// of it. libSystem was split into parts on Lion. |
| +const char* LookupLibSystemPath() { |
|
Mark Mentovai
2011/08/17 16:44:55
Since the “part of libSystem” is what Apple calls
|
| + 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; |
| +} |
| + |
| +// 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. |
|
Mark Mentovai
2011/08/17 16:44:55
I think I’ll have to (or someone else will have to
|
| +malloc_error_break_t LookupMallocErrorBreak() { |
|
Mark Mentovai
2011/08/17 16:44:55
LookUp (as above).
|
| +#if ARCH_CPU_32_BITS |
| + const char* lib_system_path = LookupLibSystemPath(); |
|
Mark Mentovai
2011/08/17 16:44:55
Rename the variable if you rename the function.
|
| + if (!lib_system_path) |
| + return NULL; |
| + |
| + // Only need to lookup two symbols, but nlist() requires a NULL-terminated |
|
Mark Mentovai
2011/08/17 16:44:55
Look up should be two words here too.
|
| + // array and takes no count. So do that. |
|
Mark Mentovai
2011/08/17 16:44:55
Nix “So do that.”
|
| + struct nlist nl[3]; |
| + bzero(&nl, sizeof(nl)); |
| + |
| + // The symbol to find. |
| + nl[0].n_un.n_name = const_cast<char*>("_malloc_error_break"); |
|
Mark Mentovai
2011/08/17 16:44:55
Wow, what a terrible interface.
|
| + |
| + // 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_system_path, nl); |
| + if (rv < 0 || nl[0].n_type == N_UNDF || nl[1].n_type == N_UNDF) { |
|
Mark Mentovai
2011/08/17 16:44:55
Shouldn’t you explicitly test |rv == 0| here?
|
| + 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(); |
| + base::debug::BreakDebugger(); |
| +} |
| + |
| +} // namespace |
| + |
| +void EnableTerminationOnHeapCorruption() { |
| + malloc_error_break_t error_break = LookupMallocErrorBreak(); |
|
Mark Mentovai
2011/08/17 16:44:55
I’d call this malloc_error_break.
|
| + if (!error_break) { |
| + LOG(WARNING) << "Could not find malloc_error_break"; |
| + return; |
| + } |
| + |
| + mach_error_t err = mach_override_ptr( |
| + (void*)error_break, |
| + (void*)&CrMallocErrorBreak, |
| + (void**)&g_original_malloc_error_break); |
| + |
| + if (err != err_none) |
| + LOG(WARNING) << "Could not override malloc_error_break; error = " << err; |
|
Mark Mentovai
2011/08/17 16:44:55
bpoop has a custom set of logging streams to handl
|
| +} |
| // ------------------------------------------------------------------------ |
| namespace { |