1 // Copyright 2020 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_CHECK_H_ 6 #define PARTITION_ALLOC_PARTITION_ALLOC_CHECK_H_ 7 8 #include <cstdint> 9 10 #include "build/build_config.h" 11 #include "partition_alloc/page_allocator_constants.h" 12 #include "partition_alloc/partition_alloc_base/check.h" 13 #include "partition_alloc/partition_alloc_base/compiler_specific.h" 14 #include "partition_alloc/partition_alloc_base/debug/alias.h" 15 #include "partition_alloc/partition_alloc_base/debug/debugging_buildflags.h" 16 #include "partition_alloc/partition_alloc_base/immediate_crash.h" 17 #include "partition_alloc/partition_alloc_buildflags.h" 18 19 // When PartitionAlloc is used as the default allocator, we cannot use the 20 // regular (D)CHECK() macros, as they allocate internally. When an assertion is 21 // triggered, they format strings, leading to reentrancy in the code, which none 22 // of PartitionAlloc is designed to support (and especially not for error 23 // paths). 24 // 25 // As a consequence: 26 // - When PartitionAlloc is not malloc(), use the regular macros 27 // - Otherwise, crash immediately. This provides worse error messages though. 28 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && !PA_BASE_CHECK_WILL_STREAM() 29 30 // For official build discard log strings to reduce binary bloat. 31 // See base/check.h for implementation details. 32 #define PA_CHECK(condition) \ 33 PA_UNLIKELY(!(condition)) ? PA_IMMEDIATE_CRASH() \ 34 : PA_EAT_CHECK_STREAM_PARAMS() 35 36 #if BUILDFLAG(PA_DCHECK_IS_ON) 37 #define PA_DCHECK(condition) PA_CHECK(condition) 38 #else 39 #define PA_DCHECK(condition) PA_EAT_CHECK_STREAM_PARAMS(!(condition)) 40 #endif // BUILDFLAG(PA_DCHECK_IS_ON) 41 42 #define PA_PCHECK(condition) \ 43 if (!(condition)) { \ 44 int error = errno; \ 45 ::partition_alloc::internal::base::debug::Alias(&error); \ 46 PA_IMMEDIATE_CRASH(); \ 47 } \ 48 static_assert(true) 49 50 #if BUILDFLAG(PA_DCHECK_IS_ON) 51 #define PA_DPCHECK(condition) PA_PCHECK(condition) 52 #else 53 #define PA_DPCHECK(condition) PA_EAT_CHECK_STREAM_PARAMS(!(condition)) 54 #endif // BUILDFLAG(PA_DCHECK_IS_ON) 55 56 #else // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && 57 // !PA_BASE_CHECK_WILL_STREAM() 58 #define PA_CHECK(condition) PA_BASE_CHECK(condition) 59 #define PA_DCHECK(condition) PA_BASE_DCHECK(condition) 60 #define PA_PCHECK(condition) PA_BASE_PCHECK(condition) 61 #define PA_DPCHECK(condition) PA_BASE_DPCHECK(condition) 62 #endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && 63 // !PA_BASE_CHECK_WILL_STREAM() 64 65 // Expensive dchecks that run within *Scan. These checks are only enabled in 66 // debug builds with dchecks enabled. 67 #if !defined(NDEBUG) 68 #define PA_SCAN_DCHECK_IS_ON() BUILDFLAG(PA_DCHECK_IS_ON) 69 #else 70 #define PA_SCAN_DCHECK_IS_ON() 0 71 #endif 72 73 #if PA_SCAN_DCHECK_IS_ON() 74 #define PA_SCAN_DCHECK(expr) PA_DCHECK(expr) 75 #else 76 #define PA_SCAN_DCHECK(expr) PA_EAT_CHECK_STREAM_PARAMS(!(expr)) 77 #endif 78 79 #if defined(PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR) 80 81 // Use this macro to assert on things that are conditionally constexpr as 82 // determined by PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR or 83 // PAGE_ALLOCATOR_CONSTANTS_DECLARE_CONSTEXPR. Where fixed at compile time, this 84 // is a static_assert. Where determined at run time, this is a PA_CHECK. 85 // Therefore, this macro must only be used where both a static_assert and a 86 // PA_CHECK would be viable, that is, within a function, and ideally a function 87 // that executes only once, early in the program, such as during initialization. 88 #define STATIC_ASSERT_OR_PA_CHECK(condition, message) \ 89 static_assert(condition, message) 90 91 #else 92 93 #define STATIC_ASSERT_OR_PA_CHECK(condition, message) \ 94 do { \ 95 PA_CHECK(condition) << (message); \ 96 } while (false) 97 98 #endif 99 100 // alignas(16) DebugKv causes breakpad_unittests and sandbox_linux_unittests 101 // failures on android-marshmallow-x86-rel because of SIGSEGV. 102 #if BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_X86_FAMILY) && \ 103 defined(ARCH_CPU_32_BITS) 104 #define PA_DEBUGKV_ALIGN alignas(8) 105 #else 106 #define PA_DEBUGKV_ALIGN alignas(16) 107 #endif 108 109 namespace partition_alloc::internal { 110 111 static constexpr size_t kDebugKeyMaxLength = 8ull; 112 113 // Used for PA_DEBUG_DATA_ON_STACK, below. 114 struct PA_DEBUGKV_ALIGN DebugKv { 115 // 16 bytes object aligned on 16 bytes, to make it easier to see in crash 116 // reports. 117 char k[kDebugKeyMaxLength] = {}; // Not necessarily 0-terminated. 118 uint64_t v = 0; 119 DebugKvDebugKv120 DebugKv(const char* key, uint64_t value) : v(value) { 121 // Fill with ' ', so that the stack dump is nicer to read. Not using 122 // memset() on purpose, this header is included from *many* places. 123 for (size_t index = 0; index < sizeof k; index++) { 124 k[index] = ' '; 125 } 126 127 for (size_t index = 0; index < sizeof k; index++) { 128 k[index] = key[index]; 129 if (key[index] == '\0') { 130 break; 131 } 132 } 133 } 134 }; 135 136 } // namespace partition_alloc::internal 137 138 #define PA_CONCAT(x, y) x##y 139 #define PA_CONCAT2(x, y) PA_CONCAT(x, y) 140 #define PA_DEBUG_UNIQUE_NAME PA_CONCAT2(kv, __LINE__) 141 142 // Puts a key-value pair on the stack for debugging. `base::debug::Alias()` 143 // makes sure a local variable is saved on the stack, but the variables can be 144 // hard to find in crash reports, particularly if the frame pointer is not 145 // present / invalid. 146 // 147 // This puts a key right before the value on the stack. The key has to be a C 148 // string, which gets truncated if it's longer than 8 characters. 149 // Example use: 150 // PA_DEBUG_DATA_ON_STACK("size", 0x42) 151 // 152 // Sample output in lldb: 153 // (lldb) x 0x00007fffffffd0d0 0x00007fffffffd0f0 154 // 0x7fffffffd0d0: 73 69 7a 65 00 00 00 00 42 00 00 00 00 00 00 00 155 // size............ 156 // 157 // With gdb, one can use: 158 // x/8g <STACK_POINTER> 159 // to see the data. With lldb, "x <STACK_POINTER> <FRAME_POJNTER>" can be used. 160 #define PA_DEBUG_DATA_ON_STACK(name, value) \ 161 static_assert(sizeof name <= \ 162 ::partition_alloc::internal::kDebugKeyMaxLength + 1); \ 163 ::partition_alloc::internal::DebugKv PA_DEBUG_UNIQUE_NAME{name, value}; \ 164 ::partition_alloc::internal::base::debug::Alias(&PA_DEBUG_UNIQUE_NAME) 165 166 #endif // PARTITION_ALLOC_PARTITION_ALLOC_CHECK_H_ 167