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