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