• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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