| Index: base/allocator/allocator_interception_mac.mm
|
| diff --git a/base/allocator/allocator_interception_mac.mm b/base/allocator/allocator_interception_mac.mm
|
| index 687100e1b81d7d62cca0e8fa45371e050f8fb38c..6b01b9112fed739a5ea3c23b1477ca45894443cf 100644
|
| --- a/base/allocator/allocator_interception_mac.mm
|
| +++ b/base/allocator/allocator_interception_mac.mm
|
| @@ -37,6 +37,7 @@
|
| #include "base/scoped_clear_errno.h"
|
| #include "build/build_config.h"
|
| #include "third_party/apple_apsl/CFBase.h"
|
| +#include "third_party/mach_override/mach_override.h"
|
|
|
| namespace base {
|
| namespace allocator {
|
| @@ -302,6 +303,50 @@ void ReplaceZoneFunctions(ChromeMallocZone* zone,
|
| }
|
| }
|
|
|
| +typedef void (*MallocZoneRegisterType)(malloc_zone_t* zone);
|
| +MallocZoneRegisterType g_original_malloc_zone_register = nullptr;
|
| +MallocZoneFunctions g_malloc_zone_functions;
|
| +bool g_update_malloc_zone_during_interception = true;
|
| +
|
| +void ChromeMallocZoneRegister(malloc_zone_t* new_zone) {
|
| + DCHECK(g_original_malloc_zone_register);
|
| + if (!g_update_malloc_zone_during_interception) {
|
| + g_original_malloc_zone_register(new_zone);
|
| + return;
|
| + }
|
| +
|
| + ChromeMallocZone* zone = reinterpret_cast<ChromeMallocZone*>(new_zone);
|
| +
|
| + if (!StoreMallocZone(zone))
|
| + return;
|
| +
|
| + ReplaceZoneFunctions(zone, &g_malloc_zone_functions);
|
| + g_original_malloc_zone_register(new_zone);
|
| +}
|
| +
|
| +typedef struct _malloc_zone_t* (*MallocCreateZoneType)(vm_size_t start_size,
|
| + unsigned flags);
|
| +MallocCreateZoneType g_original_malloc_create_zone = nullptr;
|
| +
|
| +struct _malloc_zone_t* ChromeMallocCreateZone(vm_size_t start_size,
|
| + unsigned flags) {
|
| + DCHECK(g_original_malloc_create_zone);
|
| +
|
| + struct _malloc_zone_t* new_zone =
|
| + g_original_malloc_create_zone(start_size, flags);
|
| + if (!g_update_malloc_zone_during_interception) {
|
| + return new_zone;
|
| + }
|
| +
|
| + ChromeMallocZone* zone = reinterpret_cast<ChromeMallocZone*>(new_zone);
|
| +
|
| + if (!StoreMallocZone(zone))
|
| + return new_zone;
|
| +
|
| + ReplaceZoneFunctions(zone, &g_malloc_zone_functions);
|
| + return new_zone;
|
| +}
|
| +
|
| void UninterceptMallocZoneForTesting(struct _malloc_zone_t* zone) {
|
| ChromeMallocZone* chrome_zone = reinterpret_cast<ChromeMallocZone*>(zone);
|
| if (!IsMallocZoneAlreadyStored(chrome_zone))
|
| @@ -513,6 +558,43 @@ void InterceptAllocationsMac() {
|
| reinterpret_cast<IMP>(oom_killer_allocWithZone));
|
| }
|
|
|
| +void InterceptNewlyRegisteredMallocZones(const MallocZoneFunctions* functions) {
|
| + g_update_malloc_zone_during_interception = true;
|
| +
|
| + // In a typical Chrome build, InterceptNewlyRegisteredMallocZones should only
|
| + // be called once. In a testing environment, it might be called more often.
|
| + if (g_original_malloc_zone_register)
|
| + return;
|
| +
|
| + memcpy(&g_malloc_zone_functions, functions, sizeof(MallocZoneFunctions));
|
| + mach_error_t err = mach_override_ptr(
|
| + reinterpret_cast<void*>(malloc_zone_register),
|
| + reinterpret_cast<void*>(ChromeMallocZoneRegister),
|
| + reinterpret_cast<void**>(&g_original_malloc_zone_register));
|
| + if (err != err_none) {
|
| + DLOG(WARNING) << "mach_override malloc_zone_register: " << err;
|
| + }
|
| +
|
| + // On macOS 10.9, the implementation of malloc_create_zone calls
|
| + // malloc_zone_register_while_locked, a private symbol in libmalloc, so we
|
| + // also need to interpose it. Starting from macOS 10.10.0, libmalloc was open
|
| + // sourced, and the implementation of malloc_create_zone calls
|
| + // malloc_zone_register.
|
| + if (base::mac::IsOS10_9()) {
|
| + err = mach_override_ptr(
|
| + reinterpret_cast<void*>(malloc_create_zone),
|
| + reinterpret_cast<void*>(ChromeMallocCreateZone),
|
| + reinterpret_cast<void**>(&g_original_malloc_create_zone));
|
| + if (err != err_none) {
|
| + DLOG(WARNING) << "mach_override malloc_create_zone: " << err;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void StopMallocZoneRegistrationInterceptionForTesting() {
|
| + g_update_malloc_zone_during_interception = false;
|
| +}
|
| +
|
| void UninterceptMallocZonesForTesting() {
|
| UninterceptMallocZoneForTesting(malloc_default_zone());
|
| vm_address_t* zones;
|
| @@ -525,6 +607,7 @@ void UninterceptMallocZonesForTesting() {
|
| }
|
|
|
| ClearAllMallocZonesForTesting();
|
| + StopMallocZoneRegistrationInterceptionForTesting();
|
| }
|
|
|
| } // namespace allocator
|
|
|