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