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