Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(189)

Side by Side Diff: base/allocator/allocator_interception_mac.mm

Issue 2712363002: Use mach_override to intercept all newly registered malloc zones.
Patch Set: compile error. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // This file contains all the logic necessary to intercept allocations on 5 // This file contains all the logic necessary to intercept allocations on
6 // macOS. "malloc zones" are an abstraction that allows the process to intercept 6 // macOS. "malloc zones" are an abstraction that allows the process to intercept
7 // all malloc-related functions. There is no good mechanism [short of 7 // all malloc-related functions. There is no good mechanism [short of
8 // interposition] to determine new malloc zones are added, so there's no clean 8 // interposition] to determine new malloc zones are added, so there's no clean
9 // mechanism to intercept all malloc zones. This file contains logic to 9 // mechanism to intercept all malloc zones. This file contains logic to
10 // intercept the default and purgeable zones, which always exist. A cursory 10 // intercept the default and purgeable zones, which always exist. A cursory
(...skipping 19 matching lines...) Expand all
30 #include "base/allocator/allocator_shim.h" 30 #include "base/allocator/allocator_shim.h"
31 #include "base/allocator/features.h" 31 #include "base/allocator/features.h"
32 #include "base/allocator/malloc_zone_functions_mac.h" 32 #include "base/allocator/malloc_zone_functions_mac.h"
33 #include "base/logging.h" 33 #include "base/logging.h"
34 #include "base/mac/mac_util.h" 34 #include "base/mac/mac_util.h"
35 #include "base/mac/mach_logging.h" 35 #include "base/mac/mach_logging.h"
36 #include "base/process/memory.h" 36 #include "base/process/memory.h"
37 #include "base/scoped_clear_errno.h" 37 #include "base/scoped_clear_errno.h"
38 #include "build/build_config.h" 38 #include "build/build_config.h"
39 #include "third_party/apple_apsl/CFBase.h" 39 #include "third_party/apple_apsl/CFBase.h"
40 #include "third_party/mach_override/mach_override.h"
40 41
41 namespace base { 42 namespace base {
42 namespace allocator { 43 namespace allocator {
43 44
44 bool g_replaced_default_zone = false; 45 bool g_replaced_default_zone = false;
45 46
46 namespace { 47 namespace {
47 48
48 bool g_oom_killer_enabled; 49 bool g_oom_killer_enabled;
49 50
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 296
296 // Restore protection if it was active. 297 // Restore protection if it was active.
297 if (reprotection_start) { 298 if (reprotection_start) {
298 kern_return_t result = 299 kern_return_t result =
299 mach_vm_protect(mach_task_self(), reprotection_start, 300 mach_vm_protect(mach_task_self(), reprotection_start,
300 reprotection_length, false, reprotection_value); 301 reprotection_length, false, reprotection_value);
301 MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect"; 302 MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
302 } 303 }
303 } 304 }
304 305
306 typedef void (*MallocZoneRegisterType)(malloc_zone_t* zone);
307 MallocZoneRegisterType g_original_malloc_zone_register = nullptr;
308 MallocZoneFunctions g_malloc_zone_functions;
309 bool g_update_malloc_zone_during_interception = true;
310
311 void ChromeMallocZoneRegister(malloc_zone_t* new_zone) {
312 DCHECK(g_original_malloc_zone_register);
313 if (!g_update_malloc_zone_during_interception) {
314 g_original_malloc_zone_register(new_zone);
315 return;
316 }
317
318 ChromeMallocZone* zone = reinterpret_cast<ChromeMallocZone*>(new_zone);
319
320 if (!StoreMallocZone(zone))
321 return;
322
323 ReplaceZoneFunctions(zone, &g_malloc_zone_functions);
324 g_original_malloc_zone_register(new_zone);
325 }
326
327 typedef struct _malloc_zone_t* (*MallocCreateZoneType)(vm_size_t start_size,
328 unsigned flags);
329 MallocCreateZoneType g_original_malloc_create_zone = nullptr;
330
331 struct _malloc_zone_t* ChromeMallocCreateZone(vm_size_t start_size,
332 unsigned flags) {
333 DCHECK(g_original_malloc_create_zone);
334
335 struct _malloc_zone_t* new_zone =
336 g_original_malloc_create_zone(start_size, flags);
337 if (!g_update_malloc_zone_during_interception) {
338 return new_zone;
339 }
340
341 ChromeMallocZone* zone = reinterpret_cast<ChromeMallocZone*>(new_zone);
342
343 if (!StoreMallocZone(zone))
344 return new_zone;
345
346 ReplaceZoneFunctions(zone, &g_malloc_zone_functions);
347 return new_zone;
348 }
349
305 void UninterceptMallocZoneForTesting(struct _malloc_zone_t* zone) { 350 void UninterceptMallocZoneForTesting(struct _malloc_zone_t* zone) {
306 ChromeMallocZone* chrome_zone = reinterpret_cast<ChromeMallocZone*>(zone); 351 ChromeMallocZone* chrome_zone = reinterpret_cast<ChromeMallocZone*>(zone);
307 if (!IsMallocZoneAlreadyStored(chrome_zone)) 352 if (!IsMallocZoneAlreadyStored(chrome_zone))
308 return; 353 return;
309 MallocZoneFunctions& functions = GetFunctionsForZone(zone); 354 MallocZoneFunctions& functions = GetFunctionsForZone(zone);
310 ReplaceZoneFunctions(chrome_zone, &functions); 355 ReplaceZoneFunctions(chrome_zone, &functions);
311 } 356 }
312 357
313 } // namespace 358 } // namespace
314 359
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 Method orig_method = 551 Method orig_method =
507 class_getClassMethod(nsobject_class, @selector(allocWithZone:)); 552 class_getClassMethod(nsobject_class, @selector(allocWithZone:));
508 g_old_allocWithZone = 553 g_old_allocWithZone =
509 reinterpret_cast<allocWithZone_t>(method_getImplementation(orig_method)); 554 reinterpret_cast<allocWithZone_t>(method_getImplementation(orig_method));
510 CHECK(g_old_allocWithZone) 555 CHECK(g_old_allocWithZone)
511 << "Failed to get allocWithZone allocation function."; 556 << "Failed to get allocWithZone allocation function.";
512 method_setImplementation(orig_method, 557 method_setImplementation(orig_method,
513 reinterpret_cast<IMP>(oom_killer_allocWithZone)); 558 reinterpret_cast<IMP>(oom_killer_allocWithZone));
514 } 559 }
515 560
561 void InterceptNewlyRegisteredMallocZones(const MallocZoneFunctions* functions) {
562 g_update_malloc_zone_during_interception = true;
563
564 // In a typical Chrome build, InterceptNewlyRegisteredMallocZones should only
565 // be called once. In a testing environment, it might be called more often.
566 if (g_original_malloc_zone_register)
567 return;
568
569 memcpy(&g_malloc_zone_functions, functions, sizeof(MallocZoneFunctions));
570 mach_error_t err = mach_override_ptr(
571 reinterpret_cast<void*>(malloc_zone_register),
572 reinterpret_cast<void*>(ChromeMallocZoneRegister),
573 reinterpret_cast<void**>(&g_original_malloc_zone_register));
574 if (err != err_none) {
575 DLOG(WARNING) << "mach_override malloc_zone_register: " << err;
576 }
577
578 // On macOS 10.9, the implementation of malloc_create_zone calls
579 // malloc_zone_register_while_locked, a private symbol in libmalloc, so we
580 // also need to interpose it. Starting from macOS 10.10.0, libmalloc was open
581 // sourced, and the implementation of malloc_create_zone calls
582 // malloc_zone_register.
583 if (base::mac::IsOS10_9()) {
584 err = mach_override_ptr(
585 reinterpret_cast<void*>(malloc_create_zone),
586 reinterpret_cast<void*>(ChromeMallocCreateZone),
587 reinterpret_cast<void**>(&g_original_malloc_create_zone));
588 if (err != err_none) {
589 DLOG(WARNING) << "mach_override malloc_create_zone: " << err;
590 }
591 }
592 }
593
594 void StopMallocZoneRegistrationInterceptionForTesting() {
595 g_update_malloc_zone_during_interception = false;
596 }
597
516 void UninterceptMallocZonesForTesting() { 598 void UninterceptMallocZonesForTesting() {
517 UninterceptMallocZoneForTesting(malloc_default_zone()); 599 UninterceptMallocZoneForTesting(malloc_default_zone());
518 vm_address_t* zones; 600 vm_address_t* zones;
519 unsigned int count; 601 unsigned int count;
520 kern_return_t kr = malloc_get_all_zones(mach_task_self(), 0, &zones, &count); 602 kern_return_t kr = malloc_get_all_zones(mach_task_self(), 0, &zones, &count);
521 CHECK(kr == KERN_SUCCESS); 603 CHECK(kr == KERN_SUCCESS);
522 for (unsigned int i = 0; i < count; ++i) { 604 for (unsigned int i = 0; i < count; ++i) {
523 UninterceptMallocZoneForTesting( 605 UninterceptMallocZoneForTesting(
524 reinterpret_cast<struct _malloc_zone_t*>(zones[i])); 606 reinterpret_cast<struct _malloc_zone_t*>(zones[i]));
525 } 607 }
526 608
527 ClearAllMallocZonesForTesting(); 609 ClearAllMallocZonesForTesting();
610 StopMallocZoneRegistrationInterceptionForTesting();
528 } 611 }
529 612
530 } // namespace allocator 613 } // namespace allocator
531 } // namespace base 614 } // namespace base
OLDNEW
« no previous file with comments | « base/allocator/allocator_interception_mac.h ('k') | base/allocator/allocator_interception_mac_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698