1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
base / allocator / partition_allocator / src / partition_alloc / partition_alloc_base / check.h [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PARTITION_ALLOC_PARTITION_ALLOC_BASE_CHECK_H_
#define PARTITION_ALLOC_PARTITION_ALLOC_BASE_CHECK_H_
#include <iosfwd>
#include "partition_alloc/buildflags.h"
#include "partition_alloc/partition_alloc_base/compiler_specific.h"
#include "partition_alloc/partition_alloc_base/component_export.h"
#include "partition_alloc/partition_alloc_base/immediate_crash.h"
#include "partition_alloc/partition_alloc_base/log_message.h"
#include "partition_alloc/partition_alloc_base/strings/cstring_builder.h"
#define PA_STRINGIFY_IMPL(s) #s
#define PA_STRINGIFY(s) PA_STRINGIFY_IMPL(s)
// This header defines the CHECK, DCHECK, and DPCHECK macros.
//
// CHECK dies with a fatal error if its condition is not true. It is not
// controlled by NDEBUG, so the check will be executed regardless of compilation
// mode.
//
// DCHECK, the "debug mode" check, is enabled depending on NDEBUG and
// DCHECK_ALWAYS_ON, and its severity depends on DCHECK_IS_CONFIGURABLE.
//
// (D)PCHECK is like (D)CHECK, but includes the system error code (c.f.
// perror(3)).
//
// Additional information can be streamed to these macros and will be included
// in the log output if the condition doesn't hold (you may need to include
// <ostream>):
//
// CHECK(condition) << "Additional info.";
//
// The condition is evaluated exactly once. Even in build modes where e.g.
// DCHECK is disabled, the condition and any stream arguments are still
// referenced to avoid warnings about unused variables and functions.
//
// For the (D)CHECK_EQ, etc. macros, see base/check_op.h. However, that header
// is *significantly* larger than check.h, so try to avoid including it in
// header files.
namespace partition_alloc::internal::logging {
// Class used to explicitly ignore an ostream, and optionally a boolean value.
class VoidifyStream {
public:
VoidifyStream() = default;
explicit VoidifyStream(bool ignored) {}
// This operator has lower precedence than << but higher than ?:
void operator&(base::strings::CStringBuilder&) {}
};
// Helper macro which avoids evaluating the arguments to a stream if the
// condition is false.
#define PA_LAZY_CHECK_STREAM(stream, condition) \
!(condition) \
? (void)0 \
: ::partition_alloc::internal::logging::VoidifyStream() & (stream)
// Macro which uses but does not evaluate expr and any stream parameters.
#define PA_EAT_CHECK_STREAM_PARAMS(expr) \
true ? (void)0 \
: ::partition_alloc::internal::logging::VoidifyStream(expr) & \
(*::partition_alloc::internal::logging::g_swallow_stream)
PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE)
extern base::strings::CStringBuilder* g_swallow_stream;
class LogMessage;
// Class used for raising a check error upon destruction.
class PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) CheckError {
public:
// Stream for adding optional details to the error message.
base::strings::CStringBuilder& stream();
PA_NOMERGE ~CheckError();
protected:
CheckError(const char* file,
int line,
LogSeverity severity,
const char* condition);
CheckError(const char* file, int line, LogSeverity severity);
CheckError(const char* file,
int line,
LogSeverity severity,
const char* condition,
SystemErrorCode err_code);
union {
LogMessage log_message_;
#if PA_BUILDFLAG(IS_WIN)
Win32ErrorLogMessage errno_log_message_;
#else
ErrnoLogMessage errno_log_message_;
#endif
};
// |has_errno| describes which union member is used, |log_message_| or
// |errno_log_message_|. If |has_errno| is true, CheckError initializes
// |errno_log_message_| at its constructor and destroys at its destructor.
// (This also means the CheckError is an instance of the parent class of
// PCheck or DPCheck.)
// If false, CheckError initializes and destroys |log_message_|.
const bool has_errno = false;
};
namespace check_error {
// Class used for raising a check error upon destruction.
class PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) Check : public CheckError {
public:
Check(const char* file, int line, const char* condition);
};
class PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) DCheck : public CheckError {
public:
DCheck(const char* file, int line, const char* condition);
};
class PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) PCheck : public CheckError {
public:
PCheck(const char* file, int line, const char* condition);
PCheck(const char* file, int line);
};
class PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) DPCheck : public CheckError {
public:
DPCheck(const char* file, int line, const char* condition);
};
class PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) NotImplemented
: public CheckError {
public:
NotImplemented(const char* file, int line, const char* function);
};
} // namespace check_error
#if defined(OFFICIAL_BUILD) && !defined(NDEBUG)
#error "Debug builds are not expected to be optimized as official builds."
#endif // defined(OFFICIAL_BUILD) && !defined(NDEBUG)
#if defined(OFFICIAL_BUILD) && !PA_BUILDFLAG(DCHECKS_ARE_ON)
// TODO(crbug.com/357081797): Use `[[unlikely]]` instead when there's a way to
// switch the expression below to a statement without breaking
// -Wthread-safety-analysis.
#if PA_HAS_BUILTIN(__builtin_expect)
#define PA_BASE_INTERNAL_EXPECT_FALSE(cond) __builtin_expect(!(cond), 0)
#else
#define PA_BASE_INTERNAL_EXPECT_FALSE(cond) !(cond)
#endif
// Discard log strings to reduce code bloat.
//
// This is not calling BreakDebugger since this is called frequently, and
// calling an out-of-line function instead of a noreturn inline macro prevents
// compiler optimizations.
#define PA_BASE_CHECK(cond) \
PA_BASE_INTERNAL_EXPECT_FALSE(cond) ? PA_IMMEDIATE_CRASH() \
: PA_EAT_CHECK_STREAM_PARAMS()
#define PA_BASE_CHECK_WILL_STREAM() false
#define PA_BASE_PCHECK(cond) \
PA_LAZY_CHECK_STREAM( \
::partition_alloc::internal::logging::check_error::PCheck(__FILE__, \
__LINE__) \
.stream(), \
PA_BASE_INTERNAL_EXPECT_FALSE(cond))
#else
#define PA_BASE_CHECK(condition) \
PA_LAZY_CHECK_STREAM( \
::partition_alloc::internal::logging::check_error::Check( \
__FILE__, __LINE__, #condition) \
.stream(), \
!PA_ANALYZER_ASSUME_TRUE(condition))
#define PA_BASE_CHECK_WILL_STREAM() true
#define PA_BASE_PCHECK(condition) \
PA_LAZY_CHECK_STREAM( \
::partition_alloc::internal::logging::check_error::PCheck( \
__FILE__, __LINE__, #condition) \
.stream(), \
!PA_ANALYZER_ASSUME_TRUE(condition))
#endif
#if PA_BUILDFLAG(DCHECKS_ARE_ON)
#define PA_BASE_DCHECK(condition) \
PA_LAZY_CHECK_STREAM( \
::partition_alloc::internal::logging::check_error::DCheck( \
__FILE__, __LINE__, #condition) \
.stream(), \
!PA_ANALYZER_ASSUME_TRUE(condition))
#define PA_BASE_DPCHECK(condition) \
PA_LAZY_CHECK_STREAM( \
::partition_alloc::internal::logging::check_error::DPCheck( \
__FILE__, __LINE__, #condition) \
.stream(), \
!PA_ANALYZER_ASSUME_TRUE(condition))
#else
#define PA_BASE_DCHECK(condition) PA_EAT_CHECK_STREAM_PARAMS(!(condition))
#define PA_BASE_DPCHECK(condition) PA_EAT_CHECK_STREAM_PARAMS(!(condition))
#endif
// Async signal safe checking mechanism.
[[noreturn]] PA_COMPONENT_EXPORT(PARTITION_ALLOC_BASE) void RawCheckFailure(
const char* message);
#define PA_RAW_CHECK(condition) \
do { \
if (!(condition)) \
::partition_alloc::internal::logging::RawCheckFailure( \
"Check failed: " #condition "\n"); \
} while (0)
} // namespace partition_alloc::internal::logging
#endif // PARTITION_ALLOC_PARTITION_ALLOC_BASE_CHECK_H_