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_OP_H_
6 #define BASE_CHECK_OP_H_
7
8 #include <cstddef>
9 #include <string>
10 #include <string_view>
11 #include <type_traits>
12
13 #include "base/base_export.h"
14 #include "base/check.h"
15 #include "base/dcheck_is_on.h"
16 #include "base/memory/raw_ptr_exclusion.h"
17 #include "base/strings/to_string.h"
18 #include "base/types/supports_ostream_operator.h"
19
20 // This header defines the (DP)CHECK_EQ etc. macros.
21 //
22 // (DP)CHECK_EQ(x, y) is similar to (DP)CHECK(x == y) but will also log the
23 // values of x and y if the condition doesn't hold. This works for basic types
24 // and types with an operator<< or .ToString() method.
25 //
26 // The operands are evaluated exactly once, and even in build modes where e.g.
27 // DCHECK is disabled, the operands and their stringification methods are still
28 // referenced to avoid warnings about unused variables or functions.
29 //
30 // Like (D)CHECK (D)CHECK_EQ also supports an optional base::NotFatalUntil
31 // parameter. See base/check.h.
32 //
33 // To support the stringification of the check operands, this header is
34 // *significantly* larger than base/check.h, so it should be avoided in common
35 // headers.
36 //
37 // This header also provides the (DP)CHECK macros (by including check.h), so if
38 // you use e.g. both CHECK_EQ and CHECK, including this header is enough. If you
39 // only use CHECK however, please include the smaller check.h instead.
40
41 namespace logging {
42
43 // Functions for turning check operand values into NUL-terminated C strings.
44 // Caller takes ownership of the result and must release it with `free`.
45 // This would normally be defined by <ostream>, but this header tries to avoid
46 // including <ostream> to reduce compile-time. See https://crrev.com/c/2128112.
47 BASE_EXPORT char* CheckOpValueStr(int v);
48 BASE_EXPORT char* CheckOpValueStr(unsigned v);
49 BASE_EXPORT char* CheckOpValueStr(long v);
50 BASE_EXPORT char* CheckOpValueStr(unsigned long v);
51 BASE_EXPORT char* CheckOpValueStr(long long v);
52 BASE_EXPORT char* CheckOpValueStr(unsigned long long v);
53 BASE_EXPORT char* CheckOpValueStr(const void* v);
54 BASE_EXPORT char* CheckOpValueStr(std::nullptr_t v);
55 BASE_EXPORT char* CheckOpValueStr(double v);
56 // Although the standard defines operator<< for std::string and std::string_view
57 // in their respective headers, libc++ requires <ostream> for them. See
58 // https://github.com/llvm/llvm-project/issues/61070. So we define non-<ostream>
59 // versions here too.
60 BASE_EXPORT char* CheckOpValueStr(const std::string& v);
61 BASE_EXPORT char* CheckOpValueStr(std::string_view v);
62
63 // Convert a streamable value to string out-of-line to avoid <sstream>.
64 BASE_EXPORT char* StreamValToStr(const void* v,
65 void (*stream_func)(std::ostream&,
66 const void*));
67
68 #ifdef __has_builtin
69 #define SUPPORTS_BUILTIN_ADDRESSOF (__has_builtin(__builtin_addressof))
70 #else
71 #define SUPPORTS_BUILTIN_ADDRESSOF 0
72 #endif
73
74 template <typename T>
75 requires(base::internal::SupportsOstreamOperator<const T&> &&
76 !std::is_function_v<std::remove_pointer_t<T>>)
CheckOpValueStr(const T & v)77 inline char* CheckOpValueStr(const T& v) {
78 auto f = [](std::ostream& s, const void* p) {
79 s << *reinterpret_cast<const T*>(p);
80 };
81
82 // operator& might be overloaded, so do the std::addressof dance.
83 // __builtin_addressof is preferred since it also handles Obj-C ARC pointers.
84 // Some casting is still needed, because T might be volatile.
85 #if SUPPORTS_BUILTIN_ADDRESSOF
86 const void* vp = const_cast<const void*>(
87 reinterpret_cast<const volatile void*>(__builtin_addressof(v)));
88 #else
89 const void* vp = reinterpret_cast<const void*>(
90 const_cast<const char*>(&reinterpret_cast<const volatile char&>(v)));
91 #endif
92 return StreamValToStr(vp, f);
93 }
94
95 #undef SUPPORTS_BUILTIN_ADDRESSOF
96
97 // Overload for types that have no operator<< but do have .ToString() defined.
98 template <typename T>
99 requires(!base::internal::SupportsOstreamOperator<const T&> &&
100 base::internal::SupportsToString<const T&>)
CheckOpValueStr(const T & v)101 inline char* CheckOpValueStr(const T& v) {
102 // .ToString() may not return a std::string, e.g. blink::WTF::String.
103 return CheckOpValueStr(v.ToString());
104 }
105
106 // Provide an overload for functions and function pointers. Function pointers
107 // don't implicitly convert to void* but do implicitly convert to bool, so
108 // without this function pointers are always printed as 1 or 0. (MSVC isn't
109 // standards-conforming here and converts function pointers to regular
110 // pointers, so this is a no-op for MSVC.)
111 template <typename T>
requires(std::is_function_v<std::remove_pointer_t<T>>)112 requires(std::is_function_v<std::remove_pointer_t<T>>)
113 inline char* CheckOpValueStr(const T& v) {
114 return CheckOpValueStr(reinterpret_cast<const void*>(v));
115 }
116
117 // We need overloads for enums that don't support operator<<.
118 // (i.e. scoped enums where no operator<< overload was declared).
119 template <typename T>
120 requires(!base::internal::SupportsOstreamOperator<const T&> &&
121 std::is_enum_v<T>)
CheckOpValueStr(const T & v)122 inline char* CheckOpValueStr(const T& v) {
123 return CheckOpValueStr(static_cast<std::underlying_type_t<T>>(v));
124 }
125
126 // Takes ownership of `v1_str` and `v2_str`, destroying them with free(). For
127 // use with CheckOpValueStr() which allocates these strings using strdup().
128 // Returns allocated string (with strdup) for passing into
129 // ::logging::CheckError::(D)CheckOp methods.
130 // TODO(pbos): Annotate this ABSL_ATTRIBUTE_RETURNS_NONNULL after solving
131 // compile failure.
132 BASE_EXPORT char* CreateCheckOpLogMessageString(const char* expr_str,
133 char* v1_str,
134 char* v2_str);
135
136 // Helper macro for binary operators.
137 // The 'switch' is used to prevent the 'else' from being ambiguous when the
138 // macro is used in an 'if' clause such as:
139 // if (a == 1)
140 // CHECK_EQ(2, a);
141 #define CHECK_OP_FUNCTION_IMPL(check_failure_function, name, op, val1, val2, \
142 ...) \
143 switch (0) \
144 case 0: \
145 default: \
146 if (char* const message_on_fail = ::logging::Check##name##Impl( \
147 (val1), (val2), #val1 " " #op " " #val2); \
148 !message_on_fail) \
149 ; \
150 else \
151 check_failure_function(message_on_fail __VA_OPT__(, ) __VA_ARGS__)
152
153 #if !CHECK_WILL_STREAM()
154
155 // Discard log strings to reduce code bloat.
156 #define CHECK_OP(name, op, val1, val2, ...) \
157 BASE_IF(BASE_IS_EMPTY(__VA_ARGS__), CHECK((val1)op(val2)), \
158 CHECK_OP_FUNCTION_IMPL(::logging::CheckError::CheckOp, name, op, \
159 val1, val2, __VA_ARGS__))
160
161 #else
162
163 #define CHECK_OP(name, op, val1, val2, ...) \
164 CHECK_OP_FUNCTION_IMPL(::logging::CheckError::CheckOp, name, op, val1, \
165 val2 __VA_OPT__(, ) __VA_ARGS__)
166
167 #endif
168
169 // The second overload avoids address-taking of static members for
170 // fundamental types.
171 #define DEFINE_CHECK_OP_IMPL(name, op) \
172 template <typename T, typename U> \
173 requires(!std::is_fundamental_v<T> || !std::is_fundamental_v<U>) \
174 constexpr char* Check##name##Impl(const T& v1, const U& v2, \
175 const char* expr_str) { \
176 if (LIKELY(ANALYZER_ASSUME_TRUE(v1 op v2))) \
177 return nullptr; \
178 return CreateCheckOpLogMessageString(expr_str, CheckOpValueStr(v1), \
179 CheckOpValueStr(v2)); \
180 } \
181 template <typename T, typename U> \
182 requires(std::is_fundamental_v<T> && std::is_fundamental_v<U>) \
183 constexpr char* Check##name##Impl(T v1, U v2, const char* expr_str) { \
184 if (LIKELY(ANALYZER_ASSUME_TRUE(v1 op v2))) \
185 return nullptr; \
186 return CreateCheckOpLogMessageString(expr_str, CheckOpValueStr(v1), \
187 CheckOpValueStr(v2)); \
188 }
189
190 // clang-format off
191 DEFINE_CHECK_OP_IMPL(EQ, ==)
192 DEFINE_CHECK_OP_IMPL(NE, !=)
193 DEFINE_CHECK_OP_IMPL(LE, <=)
194 DEFINE_CHECK_OP_IMPL(LT, < )
195 DEFINE_CHECK_OP_IMPL(GE, >=)
196 DEFINE_CHECK_OP_IMPL(GT, > )
197 #undef DEFINE_CHECK_OP_IMPL
198 #define CHECK_EQ(val1, val2, ...) \
199 CHECK_OP(EQ, ==, val1, val2 __VA_OPT__(, ) __VA_ARGS__)
200 #define CHECK_NE(val1, val2, ...) \
201 CHECK_OP(NE, !=, val1, val2 __VA_OPT__(, ) __VA_ARGS__)
202 #define CHECK_LE(val1, val2, ...) \
203 CHECK_OP(LE, <=, val1, val2 __VA_OPT__(, ) __VA_ARGS__)
204 #define CHECK_LT(val1, val2, ...) \
205 CHECK_OP(LT, < , val1, val2 __VA_OPT__(, ) __VA_ARGS__)
206 #define CHECK_GE(val1, val2, ...) \
207 CHECK_OP(GE, >=, val1, val2 __VA_OPT__(, ) __VA_ARGS__)
208 #define CHECK_GT(val1, val2, ...) \
209 CHECK_OP(GT, > , val1, val2 __VA_OPT__(, ) __VA_ARGS__)
210 // clang-format on
211
212 #if DCHECK_IS_ON()
213
214 #define DCHECK_OP(name, op, val1, val2) \
215 CHECK_OP_FUNCTION_IMPL(::logging::CheckError::DCheckOp, name, op, val1, val2)
216
217 #else
218
219 // Don't do any evaluation but still reference the same stuff as when enabled.
220 #define DCHECK_OP(name, op, val1, val2) \
221 EAT_CHECK_STREAM_PARAMS((::logging::CheckOpValueStr(val1), \
222 ::logging::CheckOpValueStr(val2), (val1)op(val2)))
223
224 #endif
225
226 // clang-format off
227 #define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
228 #define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
229 #define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
230 #define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
231 #define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
232 #define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
233 // clang-format on
234
235 #define DUMP_WILL_BE_CHECK_OP(name, op, val1, val2) \
236 CHECK_OP_FUNCTION_IMPL(::logging::CheckError::DumpWillBeCheckOp, name, op, \
237 val1, val2)
238
239 #define DUMP_WILL_BE_CHECK_EQ(val1, val2) \
240 DUMP_WILL_BE_CHECK_OP(EQ, ==, val1, val2)
241 #define DUMP_WILL_BE_CHECK_NE(val1, val2) \
242 DUMP_WILL_BE_CHECK_OP(NE, !=, val1, val2)
243 #define DUMP_WILL_BE_CHECK_LE(val1, val2) \
244 DUMP_WILL_BE_CHECK_OP(LE, <=, val1, val2)
245 #define DUMP_WILL_BE_CHECK_LT(val1, val2) \
246 DUMP_WILL_BE_CHECK_OP(LT, <, val1, val2)
247 #define DUMP_WILL_BE_CHECK_GE(val1, val2) \
248 DUMP_WILL_BE_CHECK_OP(GE, >=, val1, val2)
249 #define DUMP_WILL_BE_CHECK_GT(val1, val2) \
250 DUMP_WILL_BE_CHECK_OP(GT, >, val1, val2)
251
252 } // namespace logging
253
254 #endif // BASE_CHECK_OP_H_
255