check.h
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