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