• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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_PARTITION_ALLOC_CONFIG_H_
6 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CONFIG_H_
7 
8 #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
9 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
10 #include "build/build_config.h"
11 
12 // PA_CONFIG() uses a similar trick as BUILDFLAG() to allow the compiler catch
13 // typos or a missing #include.
14 //
15 // -----------------------------------------------------------------------------
16 // Housekeeping Rules
17 // -----------------------------------------------------------------------------
18 // 1. Prefix all config macros in this file with PA_CONFIG_ and define them in
19 //    a function-like manner, e.g. PA_CONFIG_MY_SETTING().
20 // 2. Both positive and negative cases must be defined.
21 // 3. Don't use PA_CONFIG_MY_SETTING() directly outside of this file, use
22 //    PA_CONFIG(flag-without-PA_CONFIG_) instead, e.g. PA_CONFIG(MY_SETTING).
23 // 4. Do not use PA_CONFIG() when defining config macros, or it will lead to
24 //    recursion. Either use #if/#else, or PA_CONFIG_MY_SETTING() directly.
25 // 5. Try to use constexpr instead of macros wherever possible.
26 // TODO(bartekn): Convert macros to constexpr or BUILDFLAG as much as possible.
27 #define PA_CONFIG(flag) (PA_CONFIG_##flag())
28 
29 // Assert that the heuristic in partition_alloc.gni is accurate on supported
30 // configurations.
31 #if BUILDFLAG(HAS_64_BIT_POINTERS)
32 static_assert(sizeof(void*) == 8, "");
33 #else
34 static_assert(sizeof(void*) != 8, "");
35 #endif  // PA_CONFIG(HAS_64_BITS_POINTERS)
36 
37 #if BUILDFLAG(HAS_64_BIT_POINTERS) && \
38     (defined(__ARM_NEON) || defined(__ARM_NEON__)) && defined(__ARM_FP)
39 #define PA_CONFIG_STARSCAN_NEON_SUPPORTED() 1
40 #else
41 #define PA_CONFIG_STARSCAN_NEON_SUPPORTED() 0
42 #endif
43 
44 #if BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(IS_IOS)
45 // Allow PA to select an alternate pool size at run-time before initialization,
46 // rather than using a single constexpr value.
47 //
48 // This is needed on iOS because iOS test processes can't handle large pools
49 // (see crbug.com/1250788).
50 //
51 // This setting is specific to 64-bit, as 32-bit has a different implementation.
52 #define PA_CONFIG_DYNAMICALLY_SELECT_POOL_SIZE() 1
53 #else
54 #define PA_CONFIG_DYNAMICALLY_SELECT_POOL_SIZE() 0
55 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(IS_IOS)
56 
57 // Puts the regular and BRP pools right next to each other, so that we can
58 // check "belongs to one of the two pools" with a single bitmask operation.
59 //
60 // This setting is specific to 64-bit, as 32-bit has a different implementation.
61 #if BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(GLUE_CORE_POOLS)
62 #define PA_CONFIG_GLUE_CORE_POOLS() 1
63 #else
64 #define PA_CONFIG_GLUE_CORE_POOLS() 0
65 #endif
66 
67 #if BUILDFLAG(HAS_64_BIT_POINTERS) && \
68     (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID))
69 #include <linux/version.h>
70 // TODO(bikineev): Enable for ChromeOS.
71 #define PA_CONFIG_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED() \
72   (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0))
73 #else
74 #define PA_CONFIG_STARSCAN_UFFD_WRITE_PROTECTOR_SUPPORTED() 0
75 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS) &&
76         // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID))
77 
78 #if BUILDFLAG(USE_STARSCAN)
79 // Use card table to avoid races for PCScan configuration without safepoints.
80 // The card table provides the guaranteee that for a marked card the underling
81 // super-page is fully initialized.
82 #define PA_CONFIG_STARSCAN_USE_CARD_TABLE() 1
83 #else
84 // The card table is permanently disabled for 32-bit.
85 #define PA_CONFIG_STARSCAN_USE_CARD_TABLE() 0
86 #endif  // BUILDFLAG(USE_STARSCAN)
87 
88 // Use batched freeing when sweeping pages. This builds up a freelist in the
89 // scanner thread and appends to the slot-span's freelist only once.
90 #define PA_CONFIG_STARSCAN_BATCHED_FREE() 1
91 
92 // TODO(bikineev): Temporarily disable inlining in *Scan to get clearer
93 // stacktraces.
94 #define PA_CONFIG_STARSCAN_NOINLINE_SCAN_FUNCTIONS() 1
95 
96 // TODO(bikineev): Temporarily disable *Scan in MemoryReclaimer as it seems to
97 // cause significant jank.
98 #define PA_CONFIG_STARSCAN_ENABLE_STARSCAN_ON_RECLAIM() 0
99 
100 // Double free detection comes with expensive cmpxchg (with the loop around it).
101 // We currently disable it to improve the runtime.
102 #define PA_CONFIG_STARSCAN_EAGER_DOUBLE_FREE_DETECTION_ENABLED() 0
103 
104 // POSIX is not only UNIX, e.g. macOS and other OSes. We do use Linux-specific
105 // features such as futex(2).
106 #define PA_CONFIG_HAS_LINUX_KERNEL() \
107   (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID))
108 
109 // On some platforms, we implement locking by spinning in userspace, then going
110 // into the kernel only if there is contention. This requires platform support,
111 // namely:
112 // - On Linux, futex(2)
113 // - On Windows, a fast userspace "try" operation which is available
114 //   with SRWLock
115 // - On macOS, pthread_mutex_trylock() is fast by default starting with macOS
116 //   10.14. Chromium targets an earlier version, so it cannot be known at
117 //   compile-time. So we use something different.
118 // - Otherwise, on POSIX we assume that a fast userspace pthread_mutex_trylock()
119 //   is available.
120 //
121 // Otherwise, a userspace spinlock implementation is used.
122 #if PA_CONFIG(HAS_LINUX_KERNEL) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_APPLE) || \
123     BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
124 #define PA_CONFIG_HAS_FAST_MUTEX() 1
125 #else
126 #define PA_CONFIG_HAS_FAST_MUTEX() 0
127 #endif
128 
129 // If defined, enables zeroing memory on Free() with roughly 1% probability.
130 // This applies only to normal buckets, as direct-map allocations are always
131 // decommitted.
132 // TODO(bartekn): Re-enable once PartitionAlloc-Everywhere evaluation is done.
133 #define PA_CONFIG_ZERO_RANDOMLY_ON_FREE() 0
134 
135 // Need TLS support.
136 #define PA_CONFIG_THREAD_CACHE_SUPPORTED() \
137   (BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_FUCHSIA))
138 
139 // Too expensive for official builds, as it adds cache misses to all
140 // allocations. On the other hand, we want wide metrics coverage to get
141 // realistic profiles.
142 #define PA_CONFIG_THREAD_CACHE_ALLOC_STATS() \
143   (BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && !defined(OFFICIAL_BUILD))
144 
145 // Optional statistics collection. Lightweight, contrary to the ones above,
146 // hence enabled by default.
147 #define PA_CONFIG_THREAD_CACHE_ENABLE_STATISTICS() 1
148 
149 // Enable free list shadow entry to strengthen hardening as much as possible.
150 // The shadow entry is an inversion (bitwise-NOT) of the encoded `next` pointer.
151 //
152 // Disabled when ref-count is placed in the previous slot, as it will overlap
153 // with the shadow for the smallest slots.
154 //
155 // Disabled on Big Endian CPUs, because encoding is also a bitwise-NOT there,
156 // making the shadow entry equal to the original, valid pointer to the next
157 // slot. In case Use-after-Free happens, we'd rather not hand out a valid,
158 // ready-to-use pointer.
159 #define PA_CONFIG_HAS_FREELIST_SHADOW_ENTRY()    \
160   (!BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT) && \
161    defined(ARCH_CPU_LITTLE_ENDIAN))
162 
163 #define PA_CONFIG_HAS_MEMORY_TAGGING()              \
164   (defined(ARCH_CPU_ARM64) && defined(__clang__) && \
165    (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)))
166 
167 #if PA_CONFIG(HAS_MEMORY_TAGGING)
168 static_assert(sizeof(void*) == 8);
169 #endif
170 
171 // Specifies whether allocation extras need to be added.
172 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
173 #define PA_CONFIG_EXTRAS_REQUIRED() 1
174 #else
175 #define PA_CONFIG_EXTRAS_REQUIRED() 0
176 #endif
177 
178 // Count and total wall clock time spent in memory related system calls. This
179 // doesn't cover all system calls, in particular the ones related to locking.
180 //
181 // Not enabled by default, as it has a runtime cost, and causes issues with some
182 // builds (e.g. Windows).
183 // However the total count is collected on all platforms.
184 #define PA_CONFIG_COUNT_SYSCALL_TIME() 0
185 
186 // On Windows, |thread_local| variables cannot be marked "dllexport", see
187 // compiler error C2492 at
188 // https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2492?view=msvc-160.
189 // Don't use it there.
190 //
191 // On macOS and iOS:
192 // - With PartitionAlloc-Everywhere, thread_local allocates, reentering the
193 //   allocator.
194 // - Component builds triggered a clang bug: crbug.com/1243375
195 //
196 // Regardless, the "normal" TLS access is fast on x86_64 (see partition_tls.h),
197 // so don't bother with thread_local anywhere.
198 #define PA_CONFIG_THREAD_LOCAL_TLS() \
199   (!(BUILDFLAG(IS_WIN) && defined(COMPONENT_BUILD)) && !BUILDFLAG(IS_APPLE))
200 
201 // When PartitionAlloc is malloc(), detect malloc() becoming re-entrant by
202 // calling malloc() again.
203 //
204 // Limitations:
205 // - BUILDFLAG(PA_DCHECK_IS_ON) due to runtime cost
206 // - thread_local TLS to simplify the implementation
207 // - Not on Android due to bot failures
208 #if BUILDFLAG(PA_DCHECK_IS_ON) && BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
209     PA_CONFIG(THREAD_LOCAL_TLS) && !BUILDFLAG(IS_ANDROID)
210 #define PA_CONFIG_HAS_ALLOCATION_GUARD() 1
211 #else
212 #define PA_CONFIG_HAS_ALLOCATION_GUARD() 0
213 #endif
214 
215 // On Android, we have to go through emutls, since this is always a shared
216 // library, so don't bother.
217 #if PA_CONFIG(THREAD_LOCAL_TLS) && !BUILDFLAG(IS_ANDROID)
218 #define PA_CONFIG_THREAD_CACHE_FAST_TLS() 1
219 #else
220 #define PA_CONFIG_THREAD_CACHE_FAST_TLS() 0
221 #endif
222 
223 // Lazy commit should only be enabled on Windows, because commit charge is
224 // only meaningful and limited on Windows. It affects performance on other
225 // platforms and is simply not needed there due to OS supporting overcommit.
226 #if BUILDFLAG(IS_WIN)
227 constexpr bool kUseLazyCommit = true;
228 #else
229 constexpr bool kUseLazyCommit = false;
230 #endif
231 
232 // On these platforms, lock all the partitions before fork(), and unlock after.
233 // This may be required on more platforms in the future.
234 #define PA_CONFIG_HAS_ATFORK_HANDLER() \
235   (BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
236 
237 // PartitionAlloc uses PartitionRootEnumerator to acquire all
238 // PartitionRoots at BeforeFork and to release at AfterFork.
239 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && PA_CONFIG(HAS_ATFORK_HANDLER)
240 #define PA_CONFIG_USE_PARTITION_ROOT_ENUMERATOR() 1
241 #else
242 #define PA_CONFIG_USE_PARTITION_ROOT_ENUMERATOR() 0
243 #endif
244 
245 // Due to potential conflict with the free list pointer in the "previous slot"
246 // mode in the smallest bucket, we can't check both the cookie and the dangling
247 // raw_ptr at the same time.
248 #define PA_CONFIG_REF_COUNT_CHECK_COOKIE()         \
249   (!(BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS) &&  \
250      BUILDFLAG(PUT_REF_COUNT_IN_PREVIOUS_SLOT)) && \
251    (BUILDFLAG(PA_DCHECK_IS_ON) ||                  \
252     BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)))
253 
254 // Use available space in the reference count to store the initially requested
255 // size from the application. This is used for debugging. On mac, it is used to
256 // workaround a bug. (crbug.com/1378822)
257 #if BUILDFLAG(IS_MAC) && !PA_CONFIG(REF_COUNT_CHECK_COOKIE) && \
258     !BUILDFLAG(ENABLE_DANGLING_RAW_PTR_CHECKS)
259 #define PA_CONFIG_REF_COUNT_STORE_REQUESTED_SIZE() 1
260 #else
261 #define PA_CONFIG_REF_COUNT_STORE_REQUESTED_SIZE() 0
262 #endif
263 
264 #if PA_CONFIG(REF_COUNT_STORE_REQUESTED_SIZE) && \
265     PA_CONFIG(REF_COUNT_CHECK_COOKIE)
266 #error "Cannot use a cookie *and* store the allocation size"
267 #endif
268 
269 // Prefer smaller slot spans.
270 //
271 // Smaller slot spans may improve dirty memory fragmentation, but may also
272 // increase address space usage.
273 //
274 // This is intended to roll out more broadly, but only enabled on Linux for now
275 // to get performance bot and real-world data pre-A/B experiment.
276 //
277 // Also enabled on ARM64 macOS, as the 16kiB pages on this platform lead to
278 // larger slot spans.
279 #define PA_CONFIG_PREFER_SMALLER_SLOT_SPANS() \
280   (BUILDFLAG(IS_LINUX) || (BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)))
281 
282 // Enable shadow metadata.
283 //
284 // With this flag, shadow pools will be mapped, on which writable shadow
285 // metadatas are placed, and the real metadatas are set to read-only instead.
286 // This feature is only enabled with 64-bit environment because pools work
287 // differently with 32-bits pointers (see glossary).
288 #if BUILDFLAG(ENABLE_SHADOW_METADATA_FOR_64_BITS_POINTERS) && \
289     BUILDFLAG(HAS_64_BIT_POINTERS)
290 #define PA_CONFIG_ENABLE_SHADOW_METADATA() 1
291 #else
292 #define PA_CONFIG_ENABLE_SHADOW_METADATA() 0
293 #endif
294 
295 // According to crbug.com/1349955#c24, macOS 11 has a bug where they asset that
296 // malloc_size() of an allocation is equal to the requested size. This is
297 // generally not true. The assert passed only because it happened to be true for
298 // the sizes they requested. BRP changes that, hence can't be deployed without a
299 // workaround.
300 //
301 // The bug has been fixed in macOS 12. Here we can only check the platform, and
302 // the version is checked dynamically later.
303 #define PA_CONFIG_ENABLE_MAC11_MALLOC_SIZE_HACK() \
304   (BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT) && BUILDFLAG(IS_MAC))
305 
306 // Enables compressed (4-byte) pointers that can point within the core pools
307 // (Regular + BRP).
308 #if BUILDFLAG(HAS_64_BIT_POINTERS) && BUILDFLAG(ENABLE_POINTER_COMPRESSION)
309 #define PA_CONFIG_POINTER_COMPRESSION() 1
310 
311 #if !PA_CONFIG(GLUE_CORE_POOLS)
312 #error "Pointer compression works only with contiguous pools"
313 #endif
314 #if PA_CONFIG(DYNAMICALLY_SELECT_POOL_SIZE)
315 #error "Dynamically selected pool size is currently not supported"
316 #endif
317 #if PA_CONFIG(HAS_MEMORY_TAGGING)
318 // TODO(1376980): Address MTE once it's enabled.
319 #error "Compressed pointers don't support tag in the upper bits"
320 #endif
321 #else  // BUILDFLAG(HAS_64_BIT_POINTERS) &&
322        // BUILDFLAG(ENABLE_POINTER_COMPRESSION)
323 #define PA_CONFIG_POINTER_COMPRESSION() 0
324 #endif
325 
326 // PA_CONFIG(IS_NONCLANG_MSVC): mimics the compound condition used by
327 // Chromium's `//base/compiler_specific.h` to detect true (non-Clang)
328 // MSVC.
329 #if defined(COMPILER_MSVC) && !defined(__clang__)
330 #define PA_CONFIG_IS_NONCLANG_MSVC() 1
331 #else
332 #define PA_CONFIG_IS_NONCLANG_MSVC() 0
333 #endif
334 
335 #endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_CONFIG_H_
336