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