check.h (10931B)
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 BASE_CHECK_H_ 6 #define BASE_CHECK_H_ 7 8 #include <iosfwd> 9 10 #include "base/base_export.h" 11 #include "base/compiler_specific.h" 12 #include "base/dcheck_is_on.h" 13 #include "base/immediate_crash.h" 14 #include "base/location.h" 15 16 // This header defines the CHECK, DCHECK, and DPCHECK macros. 17 // 18 // CHECK dies with a fatal error if its condition is not true. It is not 19 // controlled by NDEBUG, so the check will be executed regardless of compilation 20 // mode. 21 // 22 // DCHECK, the "debug mode" check, is enabled depending on NDEBUG and 23 // DCHECK_ALWAYS_ON, and its severity depends on DCHECK_IS_CONFIGURABLE. 24 // 25 // (D)PCHECK is like (D)CHECK, but includes the system error code (c.f. 26 // perror(3)). 27 // 28 // Additional information can be streamed to these macros and will be included 29 // in the log output if the condition doesn't hold (you may need to include 30 // <ostream>): 31 // 32 // CHECK(condition) << "Additional info."; 33 // 34 // The condition is evaluated exactly once. Even in build modes where e.g. 35 // DCHECK is disabled, the condition and any stream arguments are still 36 // referenced to avoid warnings about unused variables and functions. 37 // 38 // For the (D)CHECK_EQ, etc. macros, see base/check_op.h. However, that header 39 // is *significantly* larger than check.h, so try to avoid including it in 40 // header files. 41 42 namespace logging { 43 44 // Class used to explicitly ignore an ostream, and optionally a boolean value. 45 class VoidifyStream { 46 public: 47 VoidifyStream() = default; 48 explicit VoidifyStream(bool) {} 49 50 // This operator has lower precedence than << but higher than ?: 51 void operator&(std::ostream&) {} 52 }; 53 54 // Macro which uses but does not evaluate expr and any stream parameters. 55 #define EAT_CHECK_STREAM_PARAMS(expr) \ 56 true ? (void)0 \ 57 : ::logging::VoidifyStream(expr) & (*::logging::g_swallow_stream) 58 BASE_EXPORT extern std::ostream* g_swallow_stream; 59 60 class LogMessage; 61 62 // Class used for raising a check error upon destruction. 63 class BASE_EXPORT CheckError { 64 public: 65 static CheckError Check( 66 const char* condition, 67 const base::Location& location = base::Location::Current()); 68 // Takes ownership over (free()s after using) `log_message_str`, for use with 69 // CHECK_op macros. 70 static CheckError CheckOp( 71 char* log_message_str, 72 const base::Location& location = base::Location::Current()); 73 74 static CheckError DCheck( 75 const char* condition, 76 const base::Location& location = base::Location::Current()); 77 // Takes ownership over (free()s after using) `log_message_str`, for use with 78 // DCHECK_op macros. 79 static CheckError DCheckOp( 80 char* log_message_str, 81 const base::Location& location = base::Location::Current()); 82 83 static CheckError DumpWillBeCheck( 84 const char* condition, 85 const base::Location& location = base::Location::Current()); 86 // Takes ownership over (free()s after using) `log_message_str`, for use with 87 // DUMP_WILL_BE_CHECK_op macros. 88 static CheckError DumpWillBeCheckOp( 89 char* log_message_str, 90 const base::Location& location = base::Location::Current()); 91 92 static CheckError PCheck( 93 const char* condition, 94 const base::Location& location = base::Location::Current()); 95 static CheckError PCheck( 96 const base::Location& location = base::Location::Current()); 97 98 static CheckError DPCheck( 99 const char* condition, 100 const base::Location& location = base::Location::Current()); 101 102 static CheckError DumpWillBeNotReachedNoreturn( 103 const base::Location& location = base::Location::Current()); 104 105 static CheckError NotImplemented( 106 const char* function, 107 const base::Location& location = base::Location::Current()); 108 109 // Stream for adding optional details to the error message. 110 std::ostream& stream(); 111 112 // Try really hard to get the call site and callee as separate stack frames in 113 // crash reports. 114 NOMERGE NOINLINE NOT_TAIL_CALLED ~CheckError(); 115 116 CheckError(const CheckError&) = delete; 117 CheckError& operator=(const CheckError&) = delete; 118 119 template <typename T> 120 std::ostream& operator<<(T&& streamed_type) { 121 return stream() << streamed_type; 122 } 123 124 protected: 125 // Takes ownership of `log_message`. 126 explicit CheckError(LogMessage* log_message) : log_message_(log_message) {} 127 128 LogMessage* const log_message_; 129 }; 130 131 class BASE_EXPORT NotReachedError : public CheckError { 132 public: 133 static NotReachedError NotReached( 134 const base::Location& location = base::Location::Current()); 135 136 // Used to trigger a NOTREACHED() without providing file or line while also 137 // discarding log-stream arguments. See base/notreached.h. 138 NOMERGE NOINLINE NOT_TAIL_CALLED static void TriggerNotReached(); 139 140 // TODO(crbug.com/851128): Mark [[noreturn]] once this is CHECK-fatal on all 141 // builds. 142 NOMERGE NOINLINE NOT_TAIL_CALLED ~NotReachedError(); 143 144 private: 145 using CheckError::CheckError; 146 }; 147 148 // TODO(crbug.com/851128): This should take the name of the above class once all 149 // callers of NOTREACHED() have migrated to the CHECK-fatal version. 150 class BASE_EXPORT NotReachedNoreturnError : public CheckError { 151 public: 152 explicit NotReachedNoreturnError( 153 const base::Location& location = base::Location::Current()); 154 155 [[noreturn]] NOMERGE NOINLINE NOT_TAIL_CALLED ~NotReachedNoreturnError(); 156 }; 157 158 // A helper macro for checks that log to streams that makes it easier for the 159 // compiler to identify and warn about dead code, e.g.: 160 // 161 // return 2; 162 // NOTREACHED(); 163 // 164 // The 'switch' is used to prevent the 'else' from being ambiguous when the 165 // macro is used in an 'if' clause such as: 166 // if (a == 1) 167 // CHECK(Foo()); 168 // 169 // TODO(crbug.com/1380930): Remove the const bool when the blink-gc plugin has 170 // been updated to accept `if (LIKELY(!field_))` as well as `if (!field_)`. 171 #define LOGGING_CHECK_FUNCTION_IMPL(check_stream, condition) \ 172 switch (0) \ 173 case 0: \ 174 default: \ 175 /* Hint to the optimizer that `condition` is unlikely to be false. */ \ 176 /* The optimizer can use this as a hint to place the failure path */ \ 177 /* out-of-line, e.g. at the tail of the function. */ \ 178 if (const bool probably_true = static_cast<bool>(condition); \ 179 LIKELY(ANALYZER_ASSUME_TRUE(probably_true))) \ 180 ; \ 181 else \ 182 (check_stream) 183 184 #if defined(OFFICIAL_BUILD) && !defined(NDEBUG) 185 #error "Debug builds are not expected to be optimized as official builds." 186 #endif // defined(OFFICIAL_BUILD) && !defined(NDEBUG) 187 188 #if defined(OFFICIAL_BUILD) && !DCHECK_IS_ON() 189 // Note that this uses IMMEDIATE_CRASH_ALWAYS_INLINE to force-inline in debug 190 // mode as well. See LoggingTest.CheckCausesDistinctBreakpoints. 191 [[noreturn]] IMMEDIATE_CRASH_ALWAYS_INLINE void CheckFailure() { 192 base::ImmediateCrash(); 193 } 194 195 // Discard log strings to reduce code bloat. 196 // 197 // This is not calling BreakDebugger since this is called frequently, and 198 // calling an out-of-line function instead of a noreturn inline macro prevents 199 // compiler optimizations. Unlike the other check macros, this one does not use 200 // LOGGING_CHECK_FUNCTION_IMPL(), since it is incompatible with 201 // EAT_CHECK_STREAM_PARAMETERS(). 202 #define CHECK(condition) \ 203 UNLIKELY(!(condition)) ? logging::CheckFailure() : EAT_CHECK_STREAM_PARAMS() 204 205 #define CHECK_WILL_STREAM() false 206 207 // Strip the conditional string from official builds. 208 #define PCHECK(condition) \ 209 LOGGING_CHECK_FUNCTION_IMPL(::logging::CheckError::PCheck(), condition) 210 211 #else 212 213 #define CHECK_WILL_STREAM() true 214 215 #define CHECK(condition) \ 216 LOGGING_CHECK_FUNCTION_IMPL(::logging::CheckError::Check(#condition), \ 217 condition) 218 219 #define PCHECK(condition) \ 220 LOGGING_CHECK_FUNCTION_IMPL(::logging::CheckError::PCheck(#condition), \ 221 condition) 222 223 #endif 224 225 #if DCHECK_IS_ON() 226 227 #define DCHECK(condition) \ 228 LOGGING_CHECK_FUNCTION_IMPL(::logging::CheckError::DCheck(#condition), \ 229 condition) 230 #define DPCHECK(condition) \ 231 LOGGING_CHECK_FUNCTION_IMPL(::logging::CheckError::DPCheck(#condition), \ 232 condition) 233 234 #else 235 236 #define DCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition)) 237 #define DPCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition)) 238 239 #endif // DCHECK_IS_ON() 240 241 // The DUMP_WILL_BE_CHECK() macro provides a convenient way to non-fatally dump 242 // in official builds if a condition is false. This is used to more cautiously 243 // roll out a new CHECK() (or upgrade a DCHECK) where the caller isn't entirely 244 // sure that something holds true in practice (but asserts that it should). This 245 // is especially useful for platforms that have a low pre-stable population and 246 // code areas that are rarely exercised. 247 // 248 // On DCHECK builds this macro matches DCHECK behavior. 249 // 250 // This macro isn't optimized (preserves filename, line number and log messages 251 // in official builds), as they are expected to be in product temporarily. When 252 // using this macro, leave a TODO(crbug.com/nnnn) entry referring to a bug 253 // related to its rollout. Then put a NextAction on the bug to come back and 254 // clean this up (replace with a CHECK). A DUMP_WILL_BE_CHECK() that's been left 255 // untouched for a long time without bug updates suggests that issues that 256 // would've prevented enabling this CHECK have either not been discovered or 257 // have been resolved. 258 // 259 // Using this macro is preferred over direct base::debug::DumpWithoutCrashing() 260 // invocations as it communicates intent to eventually end up as a CHECK. It 261 // also preserves the log message so setting crash keys to get additional debug 262 // info isn't required as often. 263 #define DUMP_WILL_BE_CHECK(condition) \ 264 LOGGING_CHECK_FUNCTION_IMPL( \ 265 ::logging::CheckError::DumpWillBeCheck(#condition), condition) 266 267 // Async signal safe checking mechanism. 268 [[noreturn]] BASE_EXPORT void RawCheckFailure(const char* message); 269 #define RAW_CHECK(condition) \ 270 do { \ 271 if (UNLIKELY(!(condition))) { \ 272 ::logging::RawCheckFailure("Check failed: " #condition "\n"); \ 273 } \ 274 } while (0) 275 276 } // namespace logging 277 278 #endif // BASE_CHECK_H_