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 #ifndef PARTITION_ALLOC_PARTITION_ALLOC_HOOKS_H_
6 #define PARTITION_ALLOC_PARTITION_ALLOC_HOOKS_H_
7 
8 #include <atomic>
9 #include <cstddef>
10 
11 #include "partition_alloc/partition_alloc_base/compiler_specific.h"
12 #include "partition_alloc/partition_alloc_base/component_export.h"
13 #include "partition_alloc/partition_alloc_constants.h"
14 
15 namespace partition_alloc {
16 
17 class AllocationNotificationData;
18 class FreeNotificationData;
19 
20 // PartitionAlloc supports setting hooks to observe allocations/frees as they
21 // occur as well as 'override' hooks that allow overriding those operations.
PA_COMPONENT_EXPORT(PARTITION_ALLOC)22 class PA_COMPONENT_EXPORT(PARTITION_ALLOC) PartitionAllocHooks {
23  public:
24   // Log allocation and free events.
25   typedef void AllocationObserverHook(
26       const AllocationNotificationData& notification_data);
27   typedef void FreeObserverHook(const FreeNotificationData& notification_data);
28 
29   // If it returns true, the allocation has been overridden with the pointer in
30   // *out.
31   typedef bool AllocationOverrideHook(void** out,
32                                       AllocFlags flags,
33                                       size_t size,
34                                       const char* type_name);
35   // If it returns true, then the allocation was overridden and has been freed.
36   typedef bool FreeOverrideHook(void* address);
37   // If it returns true, the underlying allocation is overridden and *out holds
38   // the size of the underlying allocation.
39   typedef bool ReallocOverrideHook(size_t* out, void* address);
40 
41   // Special hook type, independent of the rest. Triggered when `free()` detects
42   // outstanding references to the allocation.
43   // IMPORTANT: Make sure the hook always overwrites `[address, address + size)`
44   // with a bit pattern that cannot be interpreted as a valid memory address.
45   typedef void QuarantineOverrideHook(void* address, size_t size);
46 
47   // To unhook, call Set*Hooks with nullptrs.
48   static void SetObserverHooks(AllocationObserverHook* alloc_hook,
49                                FreeObserverHook* free_hook);
50   static void SetOverrideHooks(AllocationOverrideHook* alloc_hook,
51                                FreeOverrideHook* free_hook,
52                                ReallocOverrideHook realloc_hook);
53 
54   // Helper method to check whether hooks are enabled. This is an optimization
55   // so that if a function needs to call observer and override hooks in two
56   // different places this value can be cached and only loaded once.
57   static bool AreHooksEnabled() {
58     return hooks_enabled_.load(std::memory_order_relaxed);
59   }
60 
61   static void AllocationObserverHookIfEnabled(
62       const partition_alloc::AllocationNotificationData& notification_data);
63   static bool AllocationOverrideHookIfEnabled(void** out,
64                                               AllocFlags flags,
65                                               size_t size,
66                                               const char* type_name);
67 
68   static void FreeObserverHookIfEnabled(
69       const FreeNotificationData& notification_data);
70   static bool FreeOverrideHookIfEnabled(void* address);
71 
72   static void ReallocObserverHookIfEnabled(
73       const FreeNotificationData& free_notification_data,
74       const AllocationNotificationData& allocation_notification_data);
75   static bool ReallocOverrideHookIfEnabled(size_t* out, void* address);
76 
77   PA_ALWAYS_INLINE static QuarantineOverrideHook* GetQuarantineOverrideHook() {
78     return quarantine_override_hook_.load(std::memory_order_acquire);
79   }
80 
81   static void SetQuarantineOverrideHook(QuarantineOverrideHook* hook);
82 
83  private:
84   // Single bool that is used to indicate whether observer or allocation hooks
85   // are set to reduce the numbers of loads required to check whether hooking is
86   // enabled.
87   static std::atomic<bool> hooks_enabled_;
88 
89   // Lock used to synchronize Set*Hooks calls.
90   static std::atomic<AllocationObserverHook*> allocation_observer_hook_;
91   static std::atomic<FreeObserverHook*> free_observer_hook_;
92 
93   static std::atomic<AllocationOverrideHook*> allocation_override_hook_;
94   static std::atomic<FreeOverrideHook*> free_override_hook_;
95   static std::atomic<ReallocOverrideHook*> realloc_override_hook_;
96 
97   static std::atomic<QuarantineOverrideHook*> quarantine_override_hook_;
98 };
99 
100 }  // namespace partition_alloc
101 
102 #endif  // PARTITION_ALLOC_PARTITION_ALLOC_HOOKS_H_
103