tor-browser

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

check.h (10931B)


      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_H_
      6 #define BASE_CHECK_H_
      7 
      8 #include <iosfwd>
      9 
     10 #include "base/base_export.h"
     11 #include "base/compiler_specific.h"
     12 #include "base/dcheck_is_on.h"
     13 #include "base/immediate_crash.h"
     14 #include "base/location.h"
     15 
     16 // This header defines the CHECK, DCHECK, and DPCHECK macros.
     17 //
     18 // CHECK dies with a fatal error if its condition is not true. It is not
     19 // controlled by NDEBUG, so the check will be executed regardless of compilation
     20 // mode.
     21 //
     22 // DCHECK, the "debug mode" check, is enabled depending on NDEBUG and
     23 // DCHECK_ALWAYS_ON, and its severity depends on DCHECK_IS_CONFIGURABLE.
     24 //
     25 // (D)PCHECK is like (D)CHECK, but includes the system error code (c.f.
     26 // perror(3)).
     27 //
     28 // Additional information can be streamed to these macros and will be included
     29 // in the log output if the condition doesn't hold (you may need to include
     30 // <ostream>):
     31 //
     32 //   CHECK(condition) << "Additional info.";
     33 //
     34 // The condition is evaluated exactly once. Even in build modes where e.g.
     35 // DCHECK is disabled, the condition and any stream arguments are still
     36 // referenced to avoid warnings about unused variables and functions.
     37 //
     38 // For the (D)CHECK_EQ, etc. macros, see base/check_op.h. However, that header
     39 // is *significantly* larger than check.h, so try to avoid including it in
     40 // header files.
     41 
     42 namespace logging {
     43 
     44 // Class used to explicitly ignore an ostream, and optionally a boolean value.
     45 class VoidifyStream {
     46 public:
     47  VoidifyStream() = default;
     48  explicit VoidifyStream(bool) {}
     49 
     50  // This operator has lower precedence than << but higher than ?:
     51  void operator&(std::ostream&) {}
     52 };
     53 
     54 // Macro which uses but does not evaluate expr and any stream parameters.
     55 #define EAT_CHECK_STREAM_PARAMS(expr) \
     56  true ? (void)0                      \
     57       : ::logging::VoidifyStream(expr) & (*::logging::g_swallow_stream)
     58 BASE_EXPORT extern std::ostream* g_swallow_stream;
     59 
     60 class LogMessage;
     61 
     62 // Class used for raising a check error upon destruction.
     63 class BASE_EXPORT CheckError {
     64 public:
     65  static CheckError Check(
     66      const char* condition,
     67      const base::Location& location = base::Location::Current());
     68  // Takes ownership over (free()s after using) `log_message_str`, for use with
     69  // CHECK_op macros.
     70  static CheckError CheckOp(
     71      char* log_message_str,
     72      const base::Location& location = base::Location::Current());
     73 
     74  static CheckError DCheck(
     75      const char* condition,
     76      const base::Location& location = base::Location::Current());
     77  // Takes ownership over (free()s after using) `log_message_str`, for use with
     78  // DCHECK_op macros.
     79  static CheckError DCheckOp(
     80      char* log_message_str,
     81      const base::Location& location = base::Location::Current());
     82 
     83  static CheckError DumpWillBeCheck(
     84      const char* condition,
     85      const base::Location& location = base::Location::Current());
     86  // Takes ownership over (free()s after using) `log_message_str`, for use with
     87  // DUMP_WILL_BE_CHECK_op macros.
     88  static CheckError DumpWillBeCheckOp(
     89      char* log_message_str,
     90      const base::Location& location = base::Location::Current());
     91 
     92  static CheckError PCheck(
     93      const char* condition,
     94      const base::Location& location = base::Location::Current());
     95  static CheckError PCheck(
     96      const base::Location& location = base::Location::Current());
     97 
     98  static CheckError DPCheck(
     99      const char* condition,
    100      const base::Location& location = base::Location::Current());
    101 
    102  static CheckError DumpWillBeNotReachedNoreturn(
    103      const base::Location& location = base::Location::Current());
    104 
    105  static CheckError NotImplemented(
    106      const char* function,
    107      const base::Location& location = base::Location::Current());
    108 
    109  // Stream for adding optional details to the error message.
    110  std::ostream& stream();
    111 
    112  // Try really hard to get the call site and callee as separate stack frames in
    113  // crash reports.
    114  NOMERGE NOINLINE NOT_TAIL_CALLED ~CheckError();
    115 
    116  CheckError(const CheckError&) = delete;
    117  CheckError& operator=(const CheckError&) = delete;
    118 
    119  template <typename T>
    120  std::ostream& operator<<(T&& streamed_type) {
    121    return stream() << streamed_type;
    122  }
    123 
    124 protected:
    125  // Takes ownership of `log_message`.
    126  explicit CheckError(LogMessage* log_message) : log_message_(log_message) {}
    127 
    128  LogMessage* const log_message_;
    129 };
    130 
    131 class BASE_EXPORT NotReachedError : public CheckError {
    132 public:
    133  static NotReachedError NotReached(
    134      const base::Location& location = base::Location::Current());
    135 
    136  // Used to trigger a NOTREACHED() without providing file or line while also
    137  // discarding log-stream arguments. See base/notreached.h.
    138  NOMERGE NOINLINE NOT_TAIL_CALLED static void TriggerNotReached();
    139 
    140  // TODO(crbug.com/851128): Mark [[noreturn]] once this is CHECK-fatal on all
    141  // builds.
    142  NOMERGE NOINLINE NOT_TAIL_CALLED ~NotReachedError();
    143 
    144 private:
    145  using CheckError::CheckError;
    146 };
    147 
    148 // TODO(crbug.com/851128): This should take the name of the above class once all
    149 // callers of NOTREACHED() have migrated to the CHECK-fatal version.
    150 class BASE_EXPORT NotReachedNoreturnError : public CheckError {
    151 public:
    152  explicit NotReachedNoreturnError(
    153      const base::Location& location = base::Location::Current());
    154 
    155  [[noreturn]] NOMERGE NOINLINE NOT_TAIL_CALLED ~NotReachedNoreturnError();
    156 };
    157 
    158 // A helper macro for checks that log to streams that makes it easier for the
    159 // compiler to identify and warn about dead code, e.g.:
    160 //
    161 //   return 2;
    162 //   NOTREACHED();
    163 //
    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(Foo());
    168 //
    169 // TODO(crbug.com/1380930): Remove the const bool when the blink-gc plugin has
    170 // been updated to accept `if (LIKELY(!field_))` as well as `if (!field_)`.
    171 #define LOGGING_CHECK_FUNCTION_IMPL(check_stream, condition)              \
    172  switch (0)                                                              \
    173  case 0:                                                                 \
    174  default:                                                                \
    175    /* Hint to the optimizer that `condition` is unlikely to be false. */ \
    176    /* The optimizer can use this as a hint to place the failure path */  \
    177    /* out-of-line, e.g. at the tail of the function. */                  \
    178    if (const bool probably_true = static_cast<bool>(condition);          \
    179        LIKELY(ANALYZER_ASSUME_TRUE(probably_true)))                      \
    180      ;                                                                   \
    181    else                                                                  \
    182      (check_stream)
    183 
    184 #if defined(OFFICIAL_BUILD) && !defined(NDEBUG)
    185 #error "Debug builds are not expected to be optimized as official builds."
    186 #endif  // defined(OFFICIAL_BUILD) && !defined(NDEBUG)
    187 
    188 #if defined(OFFICIAL_BUILD) && !DCHECK_IS_ON()
    189 // Note that this uses IMMEDIATE_CRASH_ALWAYS_INLINE to force-inline in debug
    190 // mode as well. See LoggingTest.CheckCausesDistinctBreakpoints.
    191 [[noreturn]] IMMEDIATE_CRASH_ALWAYS_INLINE void CheckFailure() {
    192  base::ImmediateCrash();
    193 }
    194 
    195 // Discard log strings to reduce code bloat.
    196 //
    197 // This is not calling BreakDebugger since this is called frequently, and
    198 // calling an out-of-line function instead of a noreturn inline macro prevents
    199 // compiler optimizations. Unlike the other check macros, this one does not use
    200 // LOGGING_CHECK_FUNCTION_IMPL(), since it is incompatible with
    201 // EAT_CHECK_STREAM_PARAMETERS().
    202 #define CHECK(condition) \
    203  UNLIKELY(!(condition)) ? logging::CheckFailure() : EAT_CHECK_STREAM_PARAMS()
    204 
    205 #define CHECK_WILL_STREAM() false
    206 
    207 // Strip the conditional string from official builds.
    208 #define PCHECK(condition) \
    209  LOGGING_CHECK_FUNCTION_IMPL(::logging::CheckError::PCheck(), condition)
    210 
    211 #else
    212 
    213 #define CHECK_WILL_STREAM() true
    214 
    215 #define CHECK(condition)                                                \
    216  LOGGING_CHECK_FUNCTION_IMPL(::logging::CheckError::Check(#condition), \
    217                              condition)
    218 
    219 #define PCHECK(condition)                                                \
    220  LOGGING_CHECK_FUNCTION_IMPL(::logging::CheckError::PCheck(#condition), \
    221                              condition)
    222 
    223 #endif
    224 
    225 #if DCHECK_IS_ON()
    226 
    227 #define DCHECK(condition)                                                \
    228  LOGGING_CHECK_FUNCTION_IMPL(::logging::CheckError::DCheck(#condition), \
    229                              condition)
    230 #define DPCHECK(condition)                                                \
    231  LOGGING_CHECK_FUNCTION_IMPL(::logging::CheckError::DPCheck(#condition), \
    232                              condition)
    233 
    234 #else
    235 
    236 #define DCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
    237 #define DPCHECK(condition) EAT_CHECK_STREAM_PARAMS(!(condition))
    238 
    239 #endif  // DCHECK_IS_ON()
    240 
    241 // The DUMP_WILL_BE_CHECK() macro provides a convenient way to non-fatally dump
    242 // in official builds if a condition is false. This is used to more cautiously
    243 // roll out a new CHECK() (or upgrade a DCHECK) where the caller isn't entirely
    244 // sure that something holds true in practice (but asserts that it should). This
    245 // is especially useful for platforms that have a low pre-stable population and
    246 // code areas that are rarely exercised.
    247 //
    248 // On DCHECK builds this macro matches DCHECK behavior.
    249 //
    250 // This macro isn't optimized (preserves filename, line number and log messages
    251 // in official builds), as they are expected to be in product temporarily. When
    252 // using this macro, leave a TODO(crbug.com/nnnn) entry referring to a bug
    253 // related to its rollout. Then put a NextAction on the bug to come back and
    254 // clean this up (replace with a CHECK). A DUMP_WILL_BE_CHECK() that's been left
    255 // untouched for a long time without bug updates suggests that issues that
    256 // would've prevented enabling this CHECK have either not been discovered or
    257 // have been resolved.
    258 //
    259 // Using this macro is preferred over direct base::debug::DumpWithoutCrashing()
    260 // invocations as it communicates intent to eventually end up as a CHECK. It
    261 // also preserves the log message so setting crash keys to get additional debug
    262 // info isn't required as often.
    263 #define DUMP_WILL_BE_CHECK(condition) \
    264  LOGGING_CHECK_FUNCTION_IMPL(        \
    265      ::logging::CheckError::DumpWillBeCheck(#condition), condition)
    266 
    267 // Async signal safe checking mechanism.
    268 [[noreturn]] BASE_EXPORT void RawCheckFailure(const char* message);
    269 #define RAW_CHECK(condition)                                        \
    270  do {                                                              \
    271    if (UNLIKELY(!(condition))) {                                   \
    272      ::logging::RawCheckFailure("Check failed: " #condition "\n"); \
    273    }                                                               \
    274  } while (0)
    275 
    276 }  // namespace logging
    277 
    278 #endif  // BASE_CHECK_H_