• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/allocator/partition_allocator/partition_alloc_hooks.h"
6 
7 #include <ostream>
8 
9 #include "base/allocator/partition_allocator/partition_alloc_check.h"
10 #include "base/allocator/partition_allocator/partition_lock.h"
11 
12 namespace partition_alloc {
13 
14 namespace {
15 
16 internal::Lock g_hook_lock;
17 
GetHooksLock()18 internal::Lock& GetHooksLock() {
19   return g_hook_lock;
20 }
21 
22 }  // namespace
23 
24 std::atomic<bool> PartitionAllocHooks::hooks_enabled_(false);
25 std::atomic<PartitionAllocHooks::AllocationObserverHook*>
26     PartitionAllocHooks::allocation_observer_hook_(nullptr);
27 std::atomic<PartitionAllocHooks::FreeObserverHook*>
28     PartitionAllocHooks::free_observer_hook_(nullptr);
29 std::atomic<PartitionAllocHooks::AllocationOverrideHook*>
30     PartitionAllocHooks::allocation_override_hook_(nullptr);
31 std::atomic<PartitionAllocHooks::FreeOverrideHook*>
32     PartitionAllocHooks::free_override_hook_(nullptr);
33 std::atomic<PartitionAllocHooks::ReallocOverrideHook*>
34     PartitionAllocHooks::realloc_override_hook_(nullptr);
35 std::atomic<PartitionAllocHooks::QuarantineOverrideHook*>
36     PartitionAllocHooks::quarantine_override_hook_(nullptr);
37 
SetObserverHooks(AllocationObserverHook * alloc_hook,FreeObserverHook * free_hook)38 void PartitionAllocHooks::SetObserverHooks(AllocationObserverHook* alloc_hook,
39                                            FreeObserverHook* free_hook) {
40   internal::ScopedGuard guard(GetHooksLock());
41 
42   // Chained hooks are not supported. Registering a non-null hook when a
43   // non-null hook is already registered indicates somebody is trying to
44   // overwrite a hook.
45   PA_CHECK((!allocation_observer_hook_ && !free_observer_hook_) ||
46            (!alloc_hook && !free_hook))
47       << "Overwriting already set observer hooks";
48   allocation_observer_hook_ = alloc_hook;
49   free_observer_hook_ = free_hook;
50 
51   hooks_enabled_ = allocation_observer_hook_ || allocation_override_hook_;
52 }
53 
SetOverrideHooks(AllocationOverrideHook * alloc_hook,FreeOverrideHook * free_hook,ReallocOverrideHook realloc_hook)54 void PartitionAllocHooks::SetOverrideHooks(AllocationOverrideHook* alloc_hook,
55                                            FreeOverrideHook* free_hook,
56                                            ReallocOverrideHook realloc_hook) {
57   internal::ScopedGuard guard(GetHooksLock());
58 
59   PA_CHECK((!allocation_override_hook_ && !free_override_hook_ &&
60             !realloc_override_hook_) ||
61            (!alloc_hook && !free_hook && !realloc_hook))
62       << "Overwriting already set override hooks";
63   allocation_override_hook_ = alloc_hook;
64   free_override_hook_ = free_hook;
65   realloc_override_hook_ = realloc_hook;
66 
67   hooks_enabled_ = allocation_observer_hook_ || allocation_override_hook_;
68 }
69 
AllocationObserverHookIfEnabled(void * address,size_t size,const char * type_name)70 void PartitionAllocHooks::AllocationObserverHookIfEnabled(
71     void* address,
72     size_t size,
73     const char* type_name) {
74   if (auto* hook = allocation_observer_hook_.load(std::memory_order_relaxed)) {
75     hook(address, size, type_name);
76   }
77 }
78 
AllocationOverrideHookIfEnabled(void ** out,unsigned int flags,size_t size,const char * type_name)79 bool PartitionAllocHooks::AllocationOverrideHookIfEnabled(
80     void** out,
81     unsigned int flags,
82     size_t size,
83     const char* type_name) {
84   if (auto* hook = allocation_override_hook_.load(std::memory_order_relaxed)) {
85     return hook(out, flags, size, type_name);
86   }
87   return false;
88 }
89 
FreeObserverHookIfEnabled(void * address)90 void PartitionAllocHooks::FreeObserverHookIfEnabled(void* address) {
91   if (auto* hook = free_observer_hook_.load(std::memory_order_relaxed)) {
92     hook(address);
93   }
94 }
95 
FreeOverrideHookIfEnabled(void * address)96 bool PartitionAllocHooks::FreeOverrideHookIfEnabled(void* address) {
97   if (auto* hook = free_override_hook_.load(std::memory_order_relaxed)) {
98     return hook(address);
99   }
100   return false;
101 }
102 
ReallocObserverHookIfEnabled(void * old_address,void * new_address,size_t size,const char * type_name)103 void PartitionAllocHooks::ReallocObserverHookIfEnabled(void* old_address,
104                                                        void* new_address,
105                                                        size_t size,
106                                                        const char* type_name) {
107   // Report a reallocation as a free followed by an allocation.
108   AllocationObserverHook* allocation_hook =
109       allocation_observer_hook_.load(std::memory_order_relaxed);
110   FreeObserverHook* free_hook =
111       free_observer_hook_.load(std::memory_order_relaxed);
112   if (allocation_hook && free_hook) {
113     free_hook(old_address);
114     allocation_hook(new_address, size, type_name);
115   }
116 }
117 
ReallocOverrideHookIfEnabled(size_t * out,void * address)118 bool PartitionAllocHooks::ReallocOverrideHookIfEnabled(size_t* out,
119                                                        void* address) {
120   if (ReallocOverrideHook* hook =
121           realloc_override_hook_.load(std::memory_order_relaxed)) {
122     return hook(out, address);
123   }
124   return false;
125 }
126 
127 // Do not unset the hook if there are remaining quarantined slots
128 // not to break checks on unquarantining.
SetQuarantineOverrideHook(QuarantineOverrideHook * hook)129 void PartitionAllocHooks::SetQuarantineOverrideHook(
130     QuarantineOverrideHook* hook) {
131   quarantine_override_hook_.store(hook, std::memory_order_release);
132 }
133 
134 }  // namespace partition_alloc
135