1 // Copyright 2016 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 BASE_ALLOCATOR_PARTITION_ALLOCATOR_SRC_PARTITION_ALLOC_SHIM_ALLOCATOR_SHIM_H_ 6 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_SRC_PARTITION_ALLOC_SHIM_ALLOCATOR_SHIM_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include "partition_alloc/partition_alloc_buildflags.h" 12 13 #if BUILDFLAG(USE_ALLOCATOR_SHIM) 14 #include "build/build_config.h" 15 #include "partition_alloc/partition_alloc_base/component_export.h" 16 #include "partition_alloc/partition_alloc_base/types/strong_alias.h" 17 #include "partition_alloc/tagging.h" 18 19 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN) 20 #include "partition_alloc/starscan/pcscan.h" 21 #endif 22 23 namespace allocator_shim { 24 25 // Allocator Shim API. Allows to: 26 // - Configure the behavior of the allocator (what to do on OOM failures). 27 // - Install new hooks (AllocatorDispatch) in the allocator chain. 28 29 // When this shim layer is enabled, the route of an allocation is as-follows: 30 // 31 // [allocator_shim_override_*.h] Intercept malloc() / operator new calls: 32 // The override_* headers define the symbols required to intercept calls to 33 // malloc() and operator new (if not overridden by specific C++ classes). 34 // 35 // [allocator_shim.cc] Routing allocation calls to the shim: 36 // The headers above route the calls to the internal ShimMalloc(), ShimFree(), 37 // ShimCppNew() etc. methods defined in allocator_shim.cc. 38 // These methods will: (1) forward the allocation call to the front of the 39 // AllocatorDispatch chain. (2) perform security hardenings (e.g., might 40 // call std::new_handler on OOM failure). 41 // 42 // [allocator_shim_default_dispatch_to_*.cc] The AllocatorDispatch chain: 43 // It is a singly linked list where each element is a struct with function 44 // pointers (|malloc_function|, |free_function|, etc). Normally the chain 45 // consists of a single AllocatorDispatch element, herein called 46 // the "default dispatch", which is statically defined at build time and 47 // ultimately routes the calls to the actual allocator defined by the build 48 // config (glibc, ...). 49 // 50 // It is possible to dynamically insert further AllocatorDispatch stages 51 // to the front of the chain, for debugging / profiling purposes. 52 // 53 // All the functions must be thread safe. The shim does not enforce any 54 // serialization. This is to route to thread-aware allocators without 55 // introducing unnecessary perf hits. 56 57 struct AllocatorDispatch { 58 using AllocFn = void*(const AllocatorDispatch* self, 59 size_t size, 60 void* context); 61 using AllocUncheckedFn = void*(const AllocatorDispatch* self, 62 size_t size, 63 void* context); 64 using AllocZeroInitializedFn = void*(const AllocatorDispatch* self, 65 size_t n, 66 size_t size, 67 void* context); 68 using AllocAlignedFn = void*(const AllocatorDispatch* self, 69 size_t alignment, 70 size_t size, 71 void* context); 72 using ReallocFn = void*(const AllocatorDispatch* self, 73 void* address, 74 size_t size, 75 void* context); 76 using FreeFn = void(const AllocatorDispatch* self, 77 void* address, 78 void* context); 79 // Returns the allocated size of user data (not including heap overhead). 80 // Can be larger than the requested size. 81 using GetSizeEstimateFn = size_t(const AllocatorDispatch* self, 82 void* address, 83 void* context); 84 using GoodSizeFn = size_t(const AllocatorDispatch* self, 85 size_t size, 86 void* context); 87 using ClaimedAddressFn = bool(const AllocatorDispatch* self, 88 void* address, 89 void* context); 90 using BatchMallocFn = unsigned(const AllocatorDispatch* self, 91 size_t size, 92 void** results, 93 unsigned num_requested, 94 void* context); 95 using BatchFreeFn = void(const AllocatorDispatch* self, 96 void** to_be_freed, 97 unsigned num_to_be_freed, 98 void* context); 99 using FreeDefiniteSizeFn = void(const AllocatorDispatch* self, 100 void* ptr, 101 size_t size, 102 void* context); 103 using TryFreeDefaultFn = void(const AllocatorDispatch* self, 104 void* ptr, 105 void* context); 106 using AlignedMallocFn = void*(const AllocatorDispatch* self, 107 size_t size, 108 size_t alignment, 109 void* context); 110 using AlignedReallocFn = void*(const AllocatorDispatch* self, 111 void* address, 112 size_t size, 113 size_t alignment, 114 void* context); 115 using AlignedFreeFn = void(const AllocatorDispatch* self, 116 void* address, 117 void* context); 118 119 AllocFn* const alloc_function; 120 AllocUncheckedFn* const alloc_unchecked_function; 121 AllocZeroInitializedFn* const alloc_zero_initialized_function; 122 AllocAlignedFn* const alloc_aligned_function; 123 ReallocFn* const realloc_function; 124 FreeFn* const free_function; 125 GetSizeEstimateFn* const get_size_estimate_function; 126 GoodSizeFn* const good_size_function; 127 // claimed_address, batch_malloc, batch_free, free_definite_size and 128 // try_free_default are specific to the OSX and iOS allocators. 129 ClaimedAddressFn* const claimed_address_function; 130 BatchMallocFn* const batch_malloc_function; 131 BatchFreeFn* const batch_free_function; 132 FreeDefiniteSizeFn* const free_definite_size_function; 133 TryFreeDefaultFn* const try_free_default_function; 134 // _aligned_malloc, _aligned_realloc, and _aligned_free are specific to the 135 // Windows allocator. 136 AlignedMallocFn* const aligned_malloc_function; 137 AlignedReallocFn* const aligned_realloc_function; 138 AlignedFreeFn* const aligned_free_function; 139 140 const AllocatorDispatch* next; 141 142 // |default_dispatch| is statically defined by one (and only one) of the 143 // allocator_shim_default_dispatch_to_*.cc files, depending on the build 144 // configuration. 145 static const AllocatorDispatch default_dispatch; 146 }; 147 148 // When true makes malloc behave like new, w.r.t calling the new_handler if 149 // the allocation fails (see set_new_mode() in Windows). 150 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) 151 void SetCallNewHandlerOnMallocFailure(bool value); 152 153 // Allocates |size| bytes or returns nullptr. It does NOT call the new_handler, 154 // regardless of SetCallNewHandlerOnMallocFailure(). 155 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) void* UncheckedAlloc(size_t size); 156 157 // Frees memory allocated with UncheckedAlloc(). 158 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) void UncheckedFree(void* ptr); 159 160 // Inserts |dispatch| in front of the allocator chain. This method is 161 // thread-safe w.r.t concurrent invocations of InsertAllocatorDispatch(). 162 // The callers have responsibility for inserting a single dispatch no more 163 // than once. 164 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) 165 void InsertAllocatorDispatch(AllocatorDispatch* dispatch); 166 167 // Test-only. Rationale: (1) lack of use cases; (2) dealing safely with a 168 // removal of arbitrary elements from a singly linked list would require a lock 169 // in malloc(), which we really don't want. 170 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) 171 void RemoveAllocatorDispatchForTesting(AllocatorDispatch* dispatch); 172 173 #if BUILDFLAG(IS_APPLE) 174 // The fallback function to be called when try_free_default_function receives a 175 // pointer which doesn't belong to the allocator. 176 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) 177 void TryFreeDefaultFallbackToFindZoneAndFree(void* ptr); 178 #endif // BUILDFLAG(IS_APPLE) 179 180 #if BUILDFLAG(IS_APPLE) 181 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) 182 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) 183 void InitializeDefaultAllocatorPartitionRoot(); 184 bool IsDefaultAllocatorPartitionRootInitialized(); 185 #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) 186 // On macOS, the allocator shim needs to be turned on during runtime. 187 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) void InitializeAllocatorShim(); 188 #endif // BUILDFLAG(IS_APPLE) 189 190 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) 191 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) void EnablePartitionAllocMemoryReclaimer(); 192 193 using EnableBrp = 194 partition_alloc::internal::base::StrongAlias<class EnableBrpTag, bool>; 195 using EnableMemoryTagging = 196 partition_alloc::internal::base::StrongAlias<class EnableMemoryTaggingTag, 197 bool>; 198 using SplitMainPartition = 199 partition_alloc::internal::base::StrongAlias<class SplitMainPartitionTag, 200 bool>; 201 using UseDedicatedAlignedPartition = partition_alloc::internal::base:: 202 StrongAlias<class UseDedicatedAlignedPartitionTag, bool>; 203 enum class BucketDistribution : uint8_t { kNeutral, kDenser }; 204 using ZappingByFreeFlags = 205 partition_alloc::internal::base::StrongAlias<class ZappingByFreeFlagsTag, 206 bool>; 207 208 // If |thread_cache_on_non_quarantinable_partition| is specified, the 209 // thread-cache will be enabled on the non-quarantinable partition. The 210 // thread-cache on the main (malloc) partition will be disabled. 211 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) 212 void ConfigurePartitions( 213 EnableBrp enable_brp, 214 EnableMemoryTagging enable_memory_tagging, 215 partition_alloc::TagViolationReportingMode memory_tagging_reporting_mode, 216 SplitMainPartition split_main_partition, 217 UseDedicatedAlignedPartition use_dedicated_aligned_partition, 218 size_t ref_count_size, 219 BucketDistribution distribution, 220 size_t scheduler_loop_quarantine_capacity_in_bytes, 221 ZappingByFreeFlags zapping_by_free_flags); 222 223 // If |thread_cache_on_non_quarantinable_partition| is specified, the 224 // thread-cache will be enabled on the non-quarantinable partition. The 225 // thread-cache on the main (malloc) partition will be disabled. 226 // This is the deprecated version of ConfigurePartitions, kept for compatibility 227 // with pdfium's test setup, see 228 // third_party/pdfium/testing/allocator_shim_config.cpp. 229 // TODO(crbug.com/1137393): Remove this functions once pdfium has switched to 230 // the new version. 231 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) 232 void ConfigurePartitions( 233 EnableBrp enable_brp, 234 EnableMemoryTagging enable_memory_tagging, 235 SplitMainPartition split_main_partition, 236 UseDedicatedAlignedPartition use_dedicated_aligned_partition, 237 size_t ref_count_size, 238 BucketDistribution distribution); 239 240 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) uint32_t GetMainPartitionRootExtrasSize(); 241 242 #if BUILDFLAG(USE_STARSCAN) 243 PA_COMPONENT_EXPORT(ALLOCATOR_SHIM) 244 void EnablePCScan(partition_alloc::internal::PCScan::InitConfig); 245 #endif 246 #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) 247 248 } // namespace allocator_shim 249 250 #endif // BUILDFLAG(USE_ALLOCATOR_SHIM) 251 252 #endif // BASE_ALLOCATOR_PARTITION_ALLOCATOR_SRC_PARTITION_ALLOC_SHIM_ALLOCATOR_SHIM_H_ 253