• 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_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_CHECK_H_
6 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_CHECK_H_
7 
8 #include <iosfwd>
9 
10 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
11 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
12 #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
13 #include "base/allocator/partition_allocator/partition_alloc_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 partition_alloc::internal::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 arguments to a stream if the
54 // condition is false.
55 #define PA_LAZY_CHECK_STREAM(stream, condition) \
56   !(condition)                                  \
57       ? (void)0                                 \
58       : ::partition_alloc::internal::logging::VoidifyStream() & (stream)
59 
60 // Macro which uses but does not evaluate expr and any stream parameters.
61 #define PA_EAT_CHECK_STREAM_PARAMS(expr)                             \
62   true ? (void)0                                                     \
63        : ::partition_alloc::internal::logging::VoidifyStream(expr) & \
64              (*::partition_alloc::internal::logging::g_swallow_stream)
65 PA_COMPONENT_EXPORT(PARTITION_ALLOC) extern std::ostream* g_swallow_stream;
66 
67 class LogMessage;
68 
69 // Class used for raising a check error upon destruction.
PA_COMPONENT_EXPORT(PARTITION_ALLOC)70 class PA_COMPONENT_EXPORT(PARTITION_ALLOC) CheckError {
71  public:
72   static CheckError Check(const char* file, int line, const char* condition);
73 
74   static CheckError DCheck(const char* file, int line, const char* condition);
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   PA_NOMERGE ~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 #error "Debug builds are not expected to be optimized as official builds."
103 #endif  // defined(OFFICIAL_BUILD) && !defined(NDEBUG)
104 
105 #if defined(OFFICIAL_BUILD) && !BUILDFLAG(PA_DCHECK_IS_ON)
106 
107 // Discard log strings to reduce code bloat.
108 //
109 // This is not calling BreakDebugger since this is called frequently, and
110 // calling an out-of-line function instead of a noreturn inline macro prevents
111 // compiler optimizations.
112 #define PA_BASE_CHECK(condition)                   \
113   PA_UNLIKELY(!(condition)) ? PA_IMMEDIATE_CRASH() \
114                             : PA_EAT_CHECK_STREAM_PARAMS()
115 
116 // TODO(1151236): base/test/gtest_util.h uses CHECK_WILL_STREAM(). After
117 // copying (or removing) gtest_util.h and removing gtest_uti.h from partition
118 // allocator's DEPS, rename or remove CHECK_WILL_STREAM().
119 #define CHECK_WILL_STREAM() false
120 
121 #define PA_BASE_PCHECK(condition)                                        \
122   PA_LAZY_CHECK_STREAM(                                                  \
123       ::partition_alloc::internal::logging::CheckError::PCheck(__FILE__, \
124                                                                __LINE__) \
125           .stream(),                                                     \
126       PA_UNLIKELY(!(condition)))
127 
128 #else
129 
130 #define PA_BASE_CHECK(condition)                               \
131   PA_LAZY_CHECK_STREAM(                                        \
132       ::partition_alloc::internal::logging::CheckError::Check( \
133           __FILE__, __LINE__, #condition)                      \
134           .stream(),                                           \
135       !PA_ANALYZER_ASSUME_TRUE(condition))
136 
137 #define CHECK_WILL_STREAM() true
138 
139 #define PA_BASE_PCHECK(condition)                               \
140   PA_LAZY_CHECK_STREAM(                                         \
141       ::partition_alloc::internal::logging::CheckError::PCheck( \
142           __FILE__, __LINE__, #condition)                       \
143           .stream(),                                            \
144       !PA_ANALYZER_ASSUME_TRUE(condition))
145 
146 #endif
147 
148 #if BUILDFLAG(PA_DCHECK_IS_ON)
149 
150 #define PA_BASE_DCHECK(condition)                               \
151   PA_LAZY_CHECK_STREAM(                                         \
152       ::partition_alloc::internal::logging::CheckError::DCheck( \
153           __FILE__, __LINE__, #condition)                       \
154           .stream(),                                            \
155       !PA_ANALYZER_ASSUME_TRUE(condition))
156 
157 #define PA_BASE_DPCHECK(condition)                               \
158   PA_LAZY_CHECK_STREAM(                                          \
159       ::partition_alloc::internal::logging::CheckError::DPCheck( \
160           __FILE__, __LINE__, #condition)                        \
161           .stream(),                                             \
162       !PA_ANALYZER_ASSUME_TRUE(condition))
163 
164 #else
165 
166 #define PA_BASE_DCHECK(condition) PA_EAT_CHECK_STREAM_PARAMS(!(condition))
167 #define PA_BASE_DPCHECK(condition) PA_EAT_CHECK_STREAM_PARAMS(!(condition))
168 
169 #endif
170 
171 // Async signal safe checking mechanism.
172 PA_COMPONENT_EXPORT(PARTITION_ALLOC) void RawCheck(const char* message);
173 PA_COMPONENT_EXPORT(PARTITION_ALLOC) void RawError(const char* message);
174 #define PA_RAW_CHECK(condition)                       \
175   do {                                                \
176     if (!(condition))                                 \
177       ::partition_alloc::internal::logging::RawCheck( \
178           "Check failed: " #condition "\n");          \
179   } while (0)
180 
181 }  // namespace partition_alloc::internal::logging
182 
183 #endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_PARTITION_ALLOC_BASE_CHECK_H_
184