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