diff options
author | MarcoFalke <falke.marco@gmail.com> | 2020-10-12 22:54:15 +0200 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2020-11-24 09:47:29 +0100 |
commit | fac5efe730ab5b8694920547203deefc5252d294 (patch) | |
tree | 66922c7c48887aaa3c611d7315a8b3b5ea517dcc | |
parent | fa861569dcfff9e72686dc5f30b1faa645b4d54e (diff) | |
download | bitcoin-fac5efe730ab5b8694920547203deefc5252d294.tar.xz |
util: Add Assume() identity function
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | doc/developer-notes.md | 27 | ||||
-rw-r--r-- | src/util/check.h | 16 |
3 files changed, 46 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index a512fce83e..b6d7d2f7b0 100644 --- a/configure.ac +++ b/configure.ac @@ -348,6 +348,7 @@ if test "x$enable_debug" = xyes; then AX_CHECK_PREPROC_FLAG([-DDEBUG],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DDEBUG"]],,[[$CXXFLAG_WERROR]]) AX_CHECK_PREPROC_FLAG([-DDEBUG_LOCKORDER],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DDEBUG_LOCKORDER"]],,[[$CXXFLAG_WERROR]]) + AX_CHECK_PREPROC_FLAG([-DABORT_ON_FAILED_ASSUME],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DABORT_ON_FAILED_ASSUME"]],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-ftrapv],[DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -ftrapv"],,[[$CXXFLAG_WERROR]]) fi @@ -1189,6 +1190,8 @@ if test "x$enable_fuzz" = "xyes"; then use_upnp=no use_zmq=no + AX_CHECK_PREPROC_FLAG([-DABORT_ON_FAILED_ASSUME],[[DEBUG_CPPFLAGS="$DEBUG_CPPFLAGS -DABORT_ON_FAILED_ASSUME"]],,[[$CXXFLAG_WERROR]]) + AC_MSG_CHECKING([whether main function is needed]) AX_CHECK_LINK_FLAG( [[-fsanitize=$use_sanitizers]], diff --git a/doc/developer-notes.md b/doc/developer-notes.md index fa188dbcd6..9cb416bb30 100644 --- a/doc/developer-notes.md +++ b/doc/developer-notes.md @@ -276,6 +276,33 @@ configure option adds `-DDEBUG_LOCKORDER` to the compiler flags. This inserts run-time checks to keep track of which locks are held and adds warnings to the `debug.log` file if inconsistencies are detected. +### Assertions and Checks + +The util file `src/util/check.h` offers helpers to protect against coding and +internal logic bugs. They must never be used to validate user, network or any +other input. + +* `assert` or `Assert` should be used to document assumptions when any + violation would mean that it is not safe to continue program execution. The + code is always compiled with assertions enabled. + - For example, a nullptr dereference or any other logic bug in validation + code means the program code is faulty and must terminate immediately. +* `CHECK_NONFATAL` should be used for recoverable internal logic bugs. On + failure, it will throw an exception, which can be caught to recover from the + error. + - For example, a nullptr dereference or any other logic bug in RPC code + means that the RPC code is faulty and can not be executed. However, the + logic bug can be shown to the user and the program can continue to run. +* `Assume` should be used to document assumptions when program execution can + safely continue even if the assumption is violated. In debug builds it + behaves like `Assert`/`assert` to notify developers and testers about + nonfatal errors. In production it doesn't warn or log anything, though the + expression is always evaluated. + - For example it can be assumed that a variable is only initialized once, + but a failed assumption does not result in a fatal bug. A failed + assumption may or may not result in a slightly degraded user experience, + but it is safe to continue program execution. + ### Valgrind suppressions file Valgrind is a programming tool for memory debugging, memory leak detection, and diff --git a/src/util/check.h b/src/util/check.h index aca0c3d9f9..fd65cbf640 100644 --- a/src/util/check.h +++ b/src/util/check.h @@ -56,4 +56,20 @@ T get_pure_r_value(T&& val) /** Identity function. Abort if the value compares equal to zero */ #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); }()) +/** + * Assume is the identity function. + * + * - Should be used to run non-fatal checks. In debug builds it behaves like + * Assert()/assert() to notify developers and testers about non-fatal errors. + * In production it doesn't warn or log anything. + * - For fatal errors, use Assert(). + * - For non-fatal errors in interactive sessions (e.g. RPC or command line + * interfaces), CHECK_NONFATAL() might be more appropriate. + */ +#ifdef ABORT_ON_FAILED_ASSUME +#define Assume(val) Assert(val) +#else +#define Assume(val) ((void)(val)) +#endif + #endif // BITCOIN_UTIL_CHECK_H |