blob: 99db3eba1856a332ee36366ad59aedad4d12593e [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2020 The Chromium Authors
Hans Wennborg12aea3e2020-04-14 15:29:002// 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"
Hans Wennborg944479f2020-06-25 21:39:2512#include "base/dcheck_is_on.h"
Peter Boström88d58882022-08-18 18:32:4313#include "base/debug/debugging_buildflags.h"
Hans Wennborg12aea3e2020-04-14 15:29:0014#include "base/immediate_crash.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
42namespace logging {
43
Peter Boströmc9dda6492022-11-03 22:27:2644// Class used to explicitly ignore an ostream, and optionally a boolean value.
45class VoidifyStream {
46 public:
47 VoidifyStream() = default;
Brett Brothertonf161a06a2022-11-11 18:20:2448 explicit VoidifyStream(bool) {}
Peter Boströmc9dda6492022-11-03 22:27:2649
50 // This operator has lower precedence than << but higher than ?:
51 void operator&(std::ostream&) {}
52};
Hans Wennborg12aea3e2020-04-14 15:29:0053
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)
58BASE_EXPORT extern std::ostream* g_swallow_stream;
59
Hans Wennborg12aea3e2020-04-14 15:29:0060class LogMessage;
61
62// Class used for raising a check error upon destruction.
63class BASE_EXPORT CheckError {
64 public:
Peter Boströmf01d8262022-11-16 19:35:3865 // Used by CheckOp. Takes ownership of `log_message`.
66 explicit CheckError(LogMessage* log_message) : log_message_(log_message) {}
67
Hans Wennborg12aea3e2020-04-14 15:29:0068 static CheckError Check(const char* file, int line, const char* condition);
Hans Wennborg12aea3e2020-04-14 15:29:0069
70 static CheckError DCheck(const char* file, int line, const char* condition);
Hans Wennborg12aea3e2020-04-14 15:29:0071
72 static CheckError PCheck(const char* file, int line, const char* condition);
73 static CheckError PCheck(const char* file, int line);
74
75 static CheckError DPCheck(const char* file, int line, const char* condition);
76
Hans Wennborg0472f8c2020-04-23 19:27:2777 static CheckError NotImplemented(const char* file,
78 int line,
79 const char* function);
80
Hans Wennborg12aea3e2020-04-14 15:29:0081 // Stream for adding optional details to the error message.
82 std::ostream& stream();
83
Peter Boströma1021e12023-01-19 04:02:4084 // Try really hard to get the call site and callee as separate stack frames in
85 // crash reports.
86 NOMERGE NOINLINE NOT_TAIL_CALLED ~CheckError();
Hans Wennborg12aea3e2020-04-14 15:29:0087
Peter Boström67c8f16d2022-06-23 21:58:2988 CheckError(const CheckError&) = delete;
89 CheckError& operator=(const CheckError&) = delete;
Hans Wennborg12aea3e2020-04-14 15:29:0090
Peter Boström2b2875bb2022-10-28 23:50:1591 template <typename T>
92 std::ostream& operator<<(T&& streamed_type) {
93 return stream() << streamed_type;
94 }
95
Hans Wennborg12aea3e2020-04-14 15:29:0096 private:
Peter Boström67c8f16d2022-06-23 21:58:2997 LogMessage* const log_message_;
Hans Wennborg12aea3e2020-04-14 15:29:0098};
99
Peter Boströmd7df6242022-12-13 18:05:40100class BASE_EXPORT NotReachedError : public CheckError {
101 public:
102 static NotReachedError NotReached(const char* file, int line);
103
Peter Boströmb41ff6d2023-01-06 19:51:45104 // Used to trigger a NOTREACHED() without providing file or line while also
105 // discarding log-stream arguments. See base/notreached.h.
Peter Boströma1021e12023-01-19 04:02:40106 NOMERGE NOINLINE NOT_TAIL_CALLED static void TriggerNotReached();
Peter Boströmb41ff6d2023-01-06 19:51:45107
Peter Boströmd7df6242022-12-13 18:05:40108 // TODO(crbug.com/851128): Mark [[noreturn]] once this is CHECK-fatal on all
109 // builds.
Peter Boströma1021e12023-01-19 04:02:40110 NOMERGE NOINLINE NOT_TAIL_CALLED ~NotReachedError();
Peter Boströmd7df6242022-12-13 18:05:40111
112 private:
113 using CheckError::CheckError;
114};
115
Peter Boströmc9dda6492022-11-03 22:27:26116// The 'switch' is used to prevent the 'else' from being ambiguous when the
117// macro is used in an 'if' clause such as:
118// if (a == 1)
119// CHECK(Foo());
120//
121// TODO(crbug.com/1380930): Remove the const bool when the blink-gc plugin has
122// been updated to accept `if (LIKELY(!field_))` as well as `if (!field_)`.
123#define CHECK_FUNCTION_IMPL(check_failure_invocation, condition) \
124 switch (0) \
125 case 0: \
126 default: \
127 if (const bool checky_bool_lol = static_cast<bool>(condition); \
128 LIKELY(ANALYZER_ASSUME_TRUE(checky_bool_lol))) \
129 ; \
130 else \
131 check_failure_invocation
Peter Boström2f8318f2022-10-12 03:28:29132
Peter Boströmd0a383c2022-10-29 04:09:12133#if defined(OFFICIAL_BUILD) && !defined(NDEBUG)
134#error "Debug builds are not expected to be optimized as official builds."
135#endif // defined(OFFICIAL_BUILD) && !defined(NDEBUG)
Hans Wennborg12aea3e2020-04-14 15:29:00136
Peter Boströmd0a383c2022-10-29 04:09:12137#if defined(OFFICIAL_BUILD) && !DCHECK_IS_ON()
Peter Boströmb30544d2022-10-21 00:17:58138// Note that this uses IMMEDIATE_CRASH_ALWAYS_INLINE to force-inline in debug
139// mode as well. See LoggingTest.CheckCausesDistinctBreakpoints.
140[[noreturn]] IMMEDIATE_CRASH_ALWAYS_INLINE void CheckFailure() {
Peter Boström25c6ec72022-11-02 23:25:19141 base::ImmediateCrash();
Peter Boströmb30544d2022-10-21 00:17:58142}
143
Hans Wennborg12aea3e2020-04-14 15:29:00144// Discard log strings to reduce code bloat.
145//
146// This is not calling BreakDebugger since this is called frequently, and
147// calling an out-of-line function instead of a noreturn inline macro prevents
148// compiler optimizations.
149#define CHECK(condition) \
Peter Boströmb30544d2022-10-21 00:17:58150 UNLIKELY(!(condition)) ? logging::CheckFailure() : EAT_CHECK_STREAM_PARAMS()
Hans Wennborg12aea3e2020-04-14 15:29:00151
Gabriel Charettefe051042022-01-19 09:27:29152#define CHECK_WILL_STREAM() false
153
Peter Boströmc9dda6492022-11-03 22:27:26154// Strip the conditional string from official builds.
155#define PCHECK(condition) \
156 CHECK_FUNCTION_IMPL(::logging::CheckError::PCheck(__FILE__, __LINE__), \
157 condition)
Hans Wennborg12aea3e2020-04-14 15:29:00158
159#else
160
Gabriel Charettefe051042022-01-19 09:27:29161#define CHECK_WILL_STREAM() true
162
Peter Boström2f8318f2022-10-12 03:28:29163#define CHECK(condition) \
Peter Boströmc9dda6492022-11-03 22:27:26164 CHECK_FUNCTION_IMPL( \
165 ::logging::CheckError::Check(__FILE__, __LINE__, #condition), condition)
Peter Boström2f8318f2022-10-12 03:28:29166
Peter Boströmc9dda6492022-11-03 22:27:26167#define PCHECK(condition) \
168 CHECK_FUNCTION_IMPL( \
169 ::logging::CheckError::PCheck(__FILE__, __LINE__, #condition), \
170 condition)
Hans Wennborg12aea3e2020-04-14 15:29:00171
172#endif
173
Hans Wennborg12aea3e2020-04-14 15:29:00174#if DCHECK_IS_ON()
175
Peter Boströmc9dda6492022-11-03 22:27:26176#define DCHECK(condition) \
177 CHECK_FUNCTION_IMPL( \
178 ::logging::CheckError::DCheck(__FILE__, __LINE__, #condition), \
179 condition)
180#define DPCHECK(condition) \
181 CHECK_FUNCTION_IMPL( \
182 ::logging::CheckError::DPCheck(__FILE__, __LINE__, #condition), \
183 condition)
Hans Wennborg12aea3e2020-04-14 15:29:00184
185#else
186
187#define DCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
188#define DPCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
189
190#endif
191
192// Async signal safe checking mechanism.
193BASE_EXPORT void RawCheck(const char* message);
Takashi Sakamoto05c5e732021-09-09 03:18:27194BASE_EXPORT void RawError(const char* message);
Hans Wennborg12aea3e2020-04-14 15:29:00195#define RAW_CHECK(condition) \
196 do { \
197 if (!(condition)) \
198 ::logging::RawCheck("Check failed: " #condition "\n"); \
199 } while (0)
200
201} // namespace logging
202
203#endif // BASE_CHECK_H_