check.h raw

   1  // Copyright (c) 2019-present The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #ifndef BITCOIN_UTIL_CHECK_H
   6  #define BITCOIN_UTIL_CHECK_H
   7  
   8  #include <attributes.h>
   9  
  10  #include <atomic>
  11  // We use `util/check.h` to provide the `assert()` macro
  12  // to ensure that `NDEBUG` is not defined.
  13  #include <cassert> // IWYU pragma: export
  14  #include <source_location>
  15  #include <stdexcept>
  16  #include <string>
  17  #include <string_view>
  18  #include <type_traits>
  19  #include <utility>
  20  
  21  constexpr bool G_FUZZING_BUILD{
  22  #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
  23      true
  24  #else
  25      false
  26  #endif
  27  };
  28  constexpr bool G_ABORT_ON_FAILED_ASSUME{G_FUZZING_BUILD ||
  29  #ifdef ABORT_ON_FAILED_ASSUME
  30      true
  31  #else
  32      false
  33  #endif
  34  };
  35  
  36  extern std::atomic<bool> g_enable_dynamic_fuzz_determinism;
  37  
  38  inline bool EnableFuzzDeterminism()
  39  {
  40      if constexpr (G_FUZZING_BUILD) {
  41          return true;
  42      } else if constexpr (!G_ABORT_ON_FAILED_ASSUME) {
  43          // Running fuzz tests is always disabled if Assume() doesn't abort
  44          // (ie, non-fuzz non-debug builds), as otherwise tests which
  45          // should fail due to a failing Assume may still pass. As such,
  46          // we also statically disable fuzz determinism in that case.
  47          return false;
  48      } else {
  49          return g_enable_dynamic_fuzz_determinism;
  50      }
  51  }
  52  
  53  extern bool g_detail_test_only_CheckFailuresAreExceptionsNotAborts;
  54  struct test_only_CheckFailuresAreExceptionsNotAborts {
  55      test_only_CheckFailuresAreExceptionsNotAborts() { g_detail_test_only_CheckFailuresAreExceptionsNotAborts = true; };
  56      ~test_only_CheckFailuresAreExceptionsNotAborts() { g_detail_test_only_CheckFailuresAreExceptionsNotAborts = false; };
  57  };
  58  
  59  std::string StrFormatInternalBug(std::string_view msg, const std::source_location& loc);
  60  
  61  class NonFatalCheckError : public std::runtime_error
  62  {
  63  public:
  64      NonFatalCheckError(std::string_view msg, const std::source_location& loc);
  65  };
  66  
  67  /** Internal helper */
  68  void assertion_fail(const std::source_location& loc, std::string_view assertion);
  69  
  70  /** Helper for CHECK_NONFATAL() */
  71  template <typename T>
  72  T&& inline_check_non_fatal(LIFETIMEBOUND T&& val, const std::source_location& loc, std::string_view assertion)
  73  {
  74      if (!val) {
  75          if constexpr (G_ABORT_ON_FAILED_ASSUME) {
  76              assertion_fail(loc, assertion);
  77          }
  78          throw NonFatalCheckError{assertion, loc};
  79      }
  80      return std::forward<T>(val);
  81  }
  82  
  83  #if defined(NDEBUG)
  84  #error "Cannot compile without assertions!"
  85  #endif
  86  
  87  /** Helper for Assert()/Assume() */
  88  template <bool IS_ASSERT, typename T>
  89  constexpr T&& inline_assertion_check(LIFETIMEBOUND T&& val, [[maybe_unused]] const std::source_location& loc, [[maybe_unused]] std::string_view assertion)
  90  {
  91      if (IS_ASSERT || std::is_constant_evaluated() || G_ABORT_ON_FAILED_ASSUME) {
  92          if (!val) {
  93              assertion_fail(loc, assertion);
  94          }
  95      }
  96      return std::forward<T>(val);
  97  }
  98  
  99  #define STR_INTERNAL_BUG(msg) StrFormatInternalBug((msg), std::source_location::current())
 100  
 101  /**
 102   * Identity function. Throw a NonFatalCheckError when the condition evaluates to false
 103   *
 104   * This should only be used
 105   * - where the condition is assumed to be true, not for error handling or validating user input
 106   * - where a failure to fulfill the condition is recoverable and does not abort the program
 107   *
 108   * For example in RPC code, where it is undesirable to crash the whole program, this can be generally used to replace
 109   * asserts or recoverable logic errors. A NonFatalCheckError in RPC code is caught and passed as a string to the RPC
 110   * caller, which can then report the issue to the developers.
 111   */
 112  #define CHECK_NONFATAL(condition) \
 113      inline_check_non_fatal(condition, std::source_location::current(), #condition)
 114  
 115  /** Identity function. Abort if the value compares equal to zero */
 116  #define Assert(val) inline_assertion_check<true>(val, std::source_location::current(), #val)
 117  
 118  /**
 119   * Assume is the identity function.
 120   *
 121   * - Should be used to run non-fatal checks. In debug builds it behaves like
 122   *   Assert()/assert() to notify developers and testers about non-fatal errors.
 123   *   In production it doesn't warn or log anything.
 124   * - For fatal errors, use Assert().
 125   * - For non-fatal errors in interactive sessions (e.g. RPC or command line
 126   *   interfaces), CHECK_NONFATAL() might be more appropriate.
 127   */
 128  #define Assume(val) inline_assertion_check<false>(val, std::source_location::current(), #val)
 129  
 130  /**
 131   * NONFATAL_UNREACHABLE() is a macro that is used to mark unreachable code. It throws a NonFatalCheckError.
 132   */
 133  #define NONFATAL_UNREACHABLE() \
 134      throw NonFatalCheckError { "Unreachable code reached (non-fatal)", std::source_location::current() }
 135  
 136  #if defined(__has_feature)
 137  #    if __has_feature(address_sanitizer)
 138  #       include <sanitizer/asan_interface.h>
 139  #    endif
 140  #endif
 141  
 142  #ifndef ASAN_POISON_MEMORY_REGION
 143  #   define ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
 144  #   define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
 145  #endif
 146  
 147  #endif // BITCOIN_UTIL_CHECK_H
 148