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/debug/debugging_buildflags.h"
14 #include "base/immediate_crash.h"
15 #include "base/location.h"
16
17 // This header defines the CHECK, DCHECK, and DPCHECK macros.
18 //
19 // CHECK dies with a fatal error if its condition is not true. It is not
20 // controlled by NDEBUG, so the check will be executed regardless of compilation
21 // mode.
22 //
23 // DCHECK, the "debug mode" check, is enabled depending on NDEBUG and
24 // DCHECK_ALWAYS_ON, and its severity depends on DCHECK_IS_CONFIGURABLE.
25 //
26 // (D)PCHECK is like (D)CHECK, but includes the system error code (c.f.
27 // perror(3)).
28 //
29 // Additional information can be streamed to these macros and will be included
30 // in the log output if the condition doesn't hold (you may need to include
31 // <ostream>):
32 //
33 // CHECK(condition) << "Additional info.";
34 //
35 // The condition is evaluated exactly once. Even in build modes where e.g.
36 // DCHECK is disabled, the condition and any stream arguments are still
37 // referenced to avoid warnings about unused variables and functions.
38 //
39 // For the (D)CHECK_EQ, etc. macros, see base/check_op.h. However, that header
40 // is *significantly* larger than check.h, so try to avoid including it in
41 // header files.
42
43 namespace logging {
44
45 // Class used to explicitly ignore an ostream, and optionally a boolean value.
46 class VoidifyStream {
47 public:
48 VoidifyStream() = default;
VoidifyStream(bool)49 explicit VoidifyStream(bool) {}
50
51 // This operator has lower precedence than << but higher than ?:
52 void operator&(std::ostream&) {}
53 };
54
55 // Macro which uses but does not evaluate expr and any stream parameters.
56 #define EAT_CHECK_STREAM_PARAMS(expr) \
57 true ? (void)0 \
58 : ::logging::VoidifyStream(expr) & (*::logging::g_swallow_stream)
59 BASE_EXPORT extern std::ostream* g_swallow_stream;
60
61 class LogMessage;
62
63 // Class used for raising a check error upon destruction.
64 class BASE_EXPORT CheckError {
65 public:
66 // Used by CheckOp. Takes ownership of `log_message`.
CheckError(LogMessage * log_message)67 explicit CheckError(LogMessage* log_message) : log_message_(log_message) {}
68
69 static CheckError Check(const char* file, int line, const char* condition);
70
71 static CheckError DCheck(
72 const char* condition,
73 const base::Location& location = base::Location::Current());
74
75 static CheckError PCheck(const char* file, int line, const char* condition);
76 static CheckError PCheck(const char* file, int line);
77
78 static CheckError DPCheck(
79 const char* condition,
80 const base::Location& location = base::Location::Current());
81
82 static CheckError NotImplemented(const char* file,
83 int line,
84 const char* function);
85
86 // Stream for adding optional details to the error message.
87 std::ostream& stream();
88
89 // Try really hard to get the call site and callee as separate stack frames in
90 // crash reports.
91 NOMERGE NOINLINE NOT_TAIL_CALLED ~CheckError();
92
93 CheckError(const CheckError&) = delete;
94 CheckError& operator=(const CheckError&) = delete;
95
96 template <typename T>
97 std::ostream& operator<<(T&& streamed_type) {
98 return stream() << streamed_type;
99 }
100
101 protected:
102 LogMessage* const log_message_;
103 };
104
105 class BASE_EXPORT NotReachedError : public CheckError {
106 public:
107 static NotReachedError NotReached(
108 const base::Location& location = base::Location::Current());
109
110 // Used to trigger a NOTREACHED() without providing file or line while also
111 // discarding log-stream arguments. See base/notreached.h.
112 NOMERGE NOINLINE NOT_TAIL_CALLED static void TriggerNotReached();
113
114 // TODO(crbug.com/851128): Mark [[noreturn]] once this is CHECK-fatal on all
115 // builds.
116 NOMERGE NOINLINE NOT_TAIL_CALLED ~NotReachedError();
117
118 private:
119 using CheckError::CheckError;
120 };
121
122 // TODO(crbug.com/851128): This should take the name of the above class once all
123 // callers of NOTREACHED() have migrated to the CHECK-fatal version.
124 class BASE_EXPORT NotReachedNoreturnError : public CheckError {
125 public:
126 NotReachedNoreturnError(const char* file, int line);
127
128 [[noreturn]] NOMERGE NOINLINE NOT_TAIL_CALLED ~NotReachedNoreturnError();
129 };
130
131 // The 'switch' is used to prevent the 'else' from being ambiguous when the
132 // macro is used in an 'if' clause such as:
133 // if (a == 1)
134 // CHECK(Foo());
135 //
136 // TODO(crbug.com/1380930): Remove the const bool when the blink-gc plugin has
137 // been updated to accept `if (LIKELY(!field_))` as well as `if (!field_)`.
138 #define CHECK_FUNCTION_IMPL(check_failure_invocation, condition) \
139 switch (0) \
140 case 0: \
141 default: \
142 if (const bool checky_bool_lol = static_cast<bool>(condition); \
143 LIKELY(ANALYZER_ASSUME_TRUE(checky_bool_lol))) \
144 ; \
145 else \
146 check_failure_invocation
147
148 #if defined(OFFICIAL_BUILD) && !defined(NDEBUG)
149 #error "Debug builds are not expected to be optimized as official builds."
150 #endif // defined(OFFICIAL_BUILD) && !defined(NDEBUG)
151
152 #if defined(OFFICIAL_BUILD) && !DCHECK_IS_ON()
153 // Note that this uses IMMEDIATE_CRASH_ALWAYS_INLINE to force-inline in debug
154 // mode as well. See LoggingTest.CheckCausesDistinctBreakpoints.
CheckFailure()155 [[noreturn]] IMMEDIATE_CRASH_ALWAYS_INLINE void CheckFailure() {
156 base::ImmediateCrash();
157 }
158
159 // Discard log strings to reduce code bloat.
160 //
161 // This is not calling BreakDebugger since this is called frequently, and
162 // calling an out-of-line function instead of a noreturn inline macro prevents
163 // compiler optimizations.
164 #define CHECK(condition) \
165 UNLIKELY(!(condition)) ? logging::CheckFailure() : EAT_CHECK_STREAM_PARAMS()
166
167 #define CHECK_WILL_STREAM() false
168
169 // Strip the conditional string from official builds.
170 #define PCHECK(condition) \
171 CHECK_FUNCTION_IMPL(::logging::CheckError::PCheck(__FILE__, __LINE__), \
172 condition)
173
174 #else
175
176 #define CHECK_WILL_STREAM() true
177
178 #define CHECK(condition) \
179 CHECK_FUNCTION_IMPL( \
180 ::logging::CheckError::Check(__FILE__, __LINE__, #condition), condition)
181
182 #define PCHECK(condition) \
183 CHECK_FUNCTION_IMPL( \
184 ::logging::CheckError::PCheck(__FILE__, __LINE__, #condition), \
185 condition)
186
187 #endif
188
189 #if DCHECK_IS_ON()
190
191 #define DCHECK(condition) \
192 CHECK_FUNCTION_IMPL(::logging::CheckError::DCheck(#condition), condition)
193 #define DPCHECK(condition) \
194 CHECK_FUNCTION_IMPL(::logging::CheckError::DPCheck(#condition), condition)
195
196 #else
197
198 #define DCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
199 #define DPCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
200
201 #endif
202
203 // Async signal safe checking mechanism.
204 BASE_EXPORT void RawCheck(const char* message);
205 BASE_EXPORT void RawError(const char* message);
206 #define RAW_CHECK(condition) \
207 do { \
208 if (UNLIKELY(!(condition))) { \
209 ::logging::RawCheck("Check failed: " #condition "\n"); \
210 } \
211 } while (0)
212
213 } // namespace logging
214
215 #endif // BASE_CHECK_H_
216