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