1 // Copyright 2020 The Chromium Authors. All rights reserved.
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 
15 // This header defines the CHECK, DCHECK, and DPCHECK macros.
16 //
17 // CHECK dies with a fatal error if its condition is not true. It is not
18 // controlled by NDEBUG, so the check will be executed regardless of compilation
19 // mode.
20 //
21 // DCHECK, the "debug mode" check, is enabled depending on NDEBUG and
22 // DCHECK_ALWAYS_ON, and its severity depends on DCHECK_IS_CONFIGURABLE.
23 //
24 // (D)PCHECK is like (D)CHECK, but includes the system error code (c.f.
25 // perror(3)).
26 //
27 // Additional information can be streamed to these macros and will be included
28 // in the log output if the condition doesn't hold (you may need to include
29 // <ostream>):
30 //
31 //   CHECK(condition) << "Additional info.";
32 //
33 // The condition is evaluated exactly once. Even in build modes where e.g.
34 // DCHECK is disabled, the condition and any stream arguments are still
35 // referenced to avoid warnings about unused variables and functions.
36 //
37 // For the (D)CHECK_EQ, etc. macros, see base/check_op.h. However, that header
38 // is *significantly* larger than check.h, so try to avoid including it in
39 // header files.
40 
41 namespace logging {
42 
43 // Class used to explicitly ignore an ostream, and optionally a boolean value.
44 class VoidifyStream {
45  public:
46   VoidifyStream() = default;
VoidifyStream(bool ignored)47   explicit VoidifyStream(bool ignored) {}
48 
49   // This operator has lower precedence than << but higher than ?:
50   void operator&(std::ostream&) {}
51 };
52 
53 // Helper macro which avoids evaluating the arguents to a stream if the
54 // condition is false.
55 #define LAZY_CHECK_STREAM(stream, condition) \
56   !(condition) ? (void)0 : ::logging::VoidifyStream() & (stream)
57 
58 // Macro which uses but does not evaluate expr and any stream parameters.
59 #define EAT_CHECK_STREAM_PARAMS(expr) \
60   true ? (void)0                      \
61        : ::logging::VoidifyStream(expr) & (*::logging::g_swallow_stream)
62 BASE_EXPORT extern std::ostream* g_swallow_stream;
63 
64 class CheckOpResult;
65 class LogMessage;
66 
67 // Class used for raising a check error upon destruction.
68 class BASE_EXPORT CheckError {
69  public:
70   static CheckError Check(const char* file, int line, const char* condition);
71   static CheckError CheckOp(const char* file, int line, CheckOpResult* result);
72 
73   static CheckError DCheck(const char* file, int line, const char* condition);
74   static CheckError DCheckOp(const char* file, int line, CheckOpResult* result);
75 
76   static CheckError PCheck(const char* file, int line, const char* condition);
77   static CheckError PCheck(const char* file, int line);
78 
79   static CheckError DPCheck(const char* file, int line, const char* condition);
80 
81   static CheckError NotImplemented(const char* file,
82                                    int line,
83                                    const char* function);
84 
85   // Stream for adding optional details to the error message.
86   std::ostream& stream();
87 
88   ~CheckError();
89 
90   CheckError(const CheckError& other) = delete;
91   CheckError& operator=(const CheckError& other) = delete;
92   CheckError(CheckError&& other) = default;
93   CheckError& operator=(CheckError&& other) = default;
94 
95  private:
96   explicit CheckError(LogMessage* log_message);
97 
98   LogMessage* log_message_;
99 };
100 
101 #if defined(OFFICIAL_BUILD) && defined(NDEBUG)
102 
103 // Discard log strings to reduce code bloat.
104 //
105 // This is not calling BreakDebugger since this is called frequently, and
106 // calling an out-of-line function instead of a noreturn inline macro prevents
107 // compiler optimizations.
108 #define CHECK(condition) \
109   UNLIKELY(!(condition)) ? IMMEDIATE_CRASH() : EAT_CHECK_STREAM_PARAMS()
110 
111 #define PCHECK(condition)                                         \
112   LAZY_CHECK_STREAM(                                              \
113       ::logging::CheckError::PCheck(__FILE__, __LINE__).stream(), \
114       UNLIKELY(!(condition)))
115 
116 #else
117 
118 #define CHECK(condition)                                                     \
119   LAZY_CHECK_STREAM(                                                         \
120       ::logging::CheckError::Check(__FILE__, __LINE__, #condition).stream(), \
121       !ANALYZER_ASSUME_TRUE(condition))
122 
123 #define PCHECK(condition)                                                     \
124   LAZY_CHECK_STREAM(                                                          \
125       ::logging::CheckError::PCheck(__FILE__, __LINE__, #condition).stream(), \
126       !ANALYZER_ASSUME_TRUE(condition))
127 
128 #endif
129 
130 #if DCHECK_IS_ON()
131 
132 #define DCHECK(condition)                                                     \
133   LAZY_CHECK_STREAM(                                                          \
134       ::logging::CheckError::DCheck(__FILE__, __LINE__, #condition).stream(), \
135       !ANALYZER_ASSUME_TRUE(condition))
136 
137 #define DPCHECK(condition)                                                     \
138   LAZY_CHECK_STREAM(                                                           \
139       ::logging::CheckError::DPCheck(__FILE__, __LINE__, #condition).stream(), \
140       !ANALYZER_ASSUME_TRUE(condition))
141 
142 #else
143 
144 #define DCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
145 #define DPCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
146 
147 #endif
148 
149 // Async signal safe checking mechanism.
150 BASE_EXPORT void RawCheck(const char* message);
151 #define RAW_CHECK(condition)                                 \
152   do {                                                       \
153     if (!(condition))                                        \
154       ::logging::RawCheck("Check failed: " #condition "\n"); \
155   } while (0)
156 
157 }  // namespace logging
158 
159 #endif  // BASE_CHECK_H_
160