tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

check_op.h (10988B)


      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&>::value &&
     74        !std::is_function_v<typename std::remove_pointer<T>::type>,
     75    char*>
     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<
     99    !base::internal::SupportsOstreamOperator<const T&>::value &&
    100        base::internal::SupportsToString<const T&>::value,
    101                        char*>
    102 CheckOpValueStr(const T& v) {
    103  // .ToString() may not return a std::string, e.g. blink::WTF::String.
    104  return CheckOpValueStr(v.ToString());
    105 }
    106 
    107 // Provide an overload for functions and function pointers. Function pointers
    108 // don't implicitly convert to void* but do implicitly convert to bool, so
    109 // without this function pointers are always printed as 1 or 0. (MSVC isn't
    110 // standards-conforming here and converts function pointers to regular
    111 // pointers, so this is a no-op for MSVC.)
    112 template <typename T>
    113 inline std::enable_if_t<
    114    std::is_function_v<typename std::remove_pointer<T>::type>,
    115    char*>
    116 CheckOpValueStr(const T& v) {
    117  return CheckOpValueStr(reinterpret_cast<const void*>(v));
    118 }
    119 
    120 // We need overloads for enums that don't support operator<<.
    121 // (i.e. scoped enums where no operator<< overload was declared).
    122 template <typename T>
    123 inline std::enable_if_t<
    124    !base::internal::SupportsOstreamOperator<const T&>::value &&
    125        std::is_enum_v<T>,
    126                        char*>
    127 CheckOpValueStr(const T& v) {
    128  return CheckOpValueStr(
    129      static_cast<typename std::underlying_type<T>::type>(v));
    130 }
    131 
    132 // Takes ownership of `v1_str` and `v2_str`, destroying them with free(). For
    133 // use with CheckOpValueStr() which allocates these strings using strdup().
    134 // Returns allocated string (with strdup) for passing into
    135 // ::logging::CheckError::(D)CheckOp methods.
    136 // TODO(pbos): Annotate this ABSL_ATTRIBUTE_RETURNS_NONNULL after solving
    137 // compile failure.
    138 BASE_EXPORT char* CreateCheckOpLogMessageString(const char* expr_str,
    139                                                char* v1_str,
    140                                                char* v2_str);
    141 
    142 // Helper macro for binary operators.
    143 // The 'switch' is used to prevent the 'else' from being ambiguous when the
    144 // macro is used in an 'if' clause such as:
    145 // if (a == 1)
    146 //   CHECK_EQ(2, a);
    147 #define CHECK_OP_FUNCTION_IMPL(check_failure_function, name, op, val1, val2) \
    148  switch (0)                                                                 \
    149  case 0:                                                                    \
    150  default:                                                                   \
    151    if (char* const message_on_fail = ::logging::Check##name##Impl(          \
    152            (val1), (val2), #val1 " " #op " " #val2);                        \
    153        !message_on_fail)                                                    \
    154      ;                                                                      \
    155    else                                                                     \
    156      check_failure_function(message_on_fail)
    157 
    158 #if !CHECK_WILL_STREAM()
    159 
    160 // Discard log strings to reduce code bloat.
    161 #define CHECK_OP(name, op, val1, val2) CHECK((val1)op(val2))
    162 
    163 #else
    164 
    165 #define CHECK_OP(name, op, val1, val2) \
    166  CHECK_OP_FUNCTION_IMPL(::logging::CheckError::CheckOp, name, op, val1, val2)
    167 
    168 #endif
    169 
    170 // The second overload avoids address-taking of static members for
    171 // fundamental types.
    172 #define DEFINE_CHECK_OP_IMPL(name, op)                                         \
    173  template <                                                                   \
    174      typename T, typename U,                                                  \
    175      std::enable_if_t<!std::is_fundamental_v<T> || !std::is_fundamental_v<U>, \
    176                       int> = 0>                                               \
    177  constexpr char* Check##name##Impl(const T& v1, const U& v2,                  \
    178                                    const char* expr_str) {                    \
    179    if (LIKELY(ANALYZER_ASSUME_TRUE(v1 op v2)))                                \
    180      return nullptr;                                                          \
    181    return CreateCheckOpLogMessageString(expr_str, CheckOpValueStr(v1),        \
    182                                         CheckOpValueStr(v2));                 \
    183  }                                                                            \
    184  template <                                                                   \
    185      typename T, typename U,                                                  \
    186      std::enable_if_t<std::is_fundamental_v<T> && std::is_fundamental_v<U>,   \
    187                       int> = 0>                                               \
    188  constexpr char* Check##name##Impl(T v1, U v2, const char* expr_str) {        \
    189    if (LIKELY(ANALYZER_ASSUME_TRUE(v1 op v2)))                                \
    190      return nullptr;                                                          \
    191    return CreateCheckOpLogMessageString(expr_str, CheckOpValueStr(v1),        \
    192                                         CheckOpValueStr(v2));                 \
    193  }
    194 
    195 // clang-format off
    196 DEFINE_CHECK_OP_IMPL(EQ, ==)
    197 DEFINE_CHECK_OP_IMPL(NE, !=)
    198 DEFINE_CHECK_OP_IMPL(LE, <=)
    199 DEFINE_CHECK_OP_IMPL(LT, < )
    200 DEFINE_CHECK_OP_IMPL(GE, >=)
    201 DEFINE_CHECK_OP_IMPL(GT, > )
    202 #undef DEFINE_CHECK_OP_IMPL
    203 #define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
    204 #define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
    205 #define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
    206 #define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
    207 #define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
    208 #define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
    209 // clang-format on
    210 
    211 #if DCHECK_IS_ON()
    212 
    213 #define DCHECK_OP(name, op, val1, val2) \
    214  CHECK_OP_FUNCTION_IMPL(::logging::CheckError::DCheckOp, name, op, val1, val2)
    215 
    216 #else
    217 
    218 // Don't do any evaluation but still reference the same stuff as when enabled.
    219 #define DCHECK_OP(name, op, val1, val2)                      \
    220  EAT_CHECK_STREAM_PARAMS((::logging::CheckOpValueStr(val1), \
    221                           ::logging::CheckOpValueStr(val2), (val1)op(val2)))
    222 
    223 #endif
    224 
    225 // clang-format off
    226 #define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
    227 #define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
    228 #define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
    229 #define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
    230 #define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
    231 #define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
    232 // clang-format on
    233 
    234 #define DUMP_WILL_BE_CHECK_OP(name, op, val1, val2)                          \
    235  CHECK_OP_FUNCTION_IMPL(::logging::CheckError::DumpWillBeCheckOp, name, op, \
    236                         val1, val2)
    237 
    238 #define DUMP_WILL_BE_CHECK_EQ(val1, val2) \
    239  DUMP_WILL_BE_CHECK_OP(EQ, ==, val1, val2)
    240 #define DUMP_WILL_BE_CHECK_NE(val1, val2) \
    241  DUMP_WILL_BE_CHECK_OP(NE, !=, val1, val2)
    242 #define DUMP_WILL_BE_CHECK_LE(val1, val2) \
    243  DUMP_WILL_BE_CHECK_OP(LE, <=, val1, val2)
    244 #define DUMP_WILL_BE_CHECK_LT(val1, val2) \
    245  DUMP_WILL_BE_CHECK_OP(LT, <, val1, val2)
    246 #define DUMP_WILL_BE_CHECK_GE(val1, val2) \
    247  DUMP_WILL_BE_CHECK_OP(GE, >=, val1, val2)
    248 #define DUMP_WILL_BE_CHECK_GT(val1, val2) \
    249  DUMP_WILL_BE_CHECK_OP(GT, >, val1, val2)
    250 
    251 }  // namespace logging
    252 
    253 #endif  // BASE_CHECK_OP_H_