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