1 // Copyright (c) 2019 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 #if defined(HAVE_CONFIG_H)
9 #include <config/bitcoin-config.h>
10 #endif
11 
12 #include <tinyformat.h>
13 
14 #include <stdexcept>
15 
16 class NonFatalCheckError : public std::runtime_error
17 {
18     using std::runtime_error::runtime_error;
19 };
20 
21 /**
22  * Throw a NonFatalCheckError when the condition evaluates to false
23  *
24  * This should only be used
25  * - where the condition is assumed to be true, not for error handling or validating user input
26  * - where a failure to fulfill the condition is recoverable and does not abort the program
27  *
28  * For example in RPC code, where it is undesirable to crash the whole program, this can be generally used to replace
29  * asserts or recoverable logic errors. A NonFatalCheckError in RPC code is caught and passed as a string to the RPC
30  * caller, which can then report the issue to the developers.
31  */
32 #define CHECK_NONFATAL(condition)                                 \
33     do {                                                          \
34         if (!(condition)) {                                       \
35             throw NonFatalCheckError(                             \
36                 strprintf("%s:%d (%s)\n"                          \
37                           "Internal bug detected: '%s'\n"         \
38                           "You may report this issue here: %s\n", \
39                     __FILE__, __LINE__, __func__,                 \
40                     (#condition),                                 \
41                     PACKAGE_BUGREPORT));                          \
42         }                                                         \
43     } while (false)
44 
45 #if defined(NDEBUG)
46 #error "Cannot compile without assertions!"
47 #endif
48 
49 /** Helper for Assert(). TODO remove in C++14 and replace `decltype(get_pure_r_value(val))` with `T` (templated lambda) */
50 template <typename T>
get_pure_r_value(T && val)51 T get_pure_r_value(T&& val)
52 {
53     return std::forward<T>(val);
54 }
55 
56 /** Identity function. Abort if the value compares equal to zero */
57 #define Assert(val) [&]() -> decltype(get_pure_r_value(val)) { auto&& check = (val); assert(#val && check); return std::forward<decltype(get_pure_r_value(val))>(check); }()
58 
59 #endif // BITCOIN_UTIL_CHECK_H
60