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