aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcoFalke <falke.marco@gmail.com>2020-10-12 22:54:15 +0200
committerMarcoFalke <falke.marco@gmail.com>2020-11-24 09:47:29 +0100
commitfac5efe730ab5b8694920547203deefc5252d294 (patch)
tree66922c7c48887aaa3c611d7315a8b3b5ea517dcc
parentfa861569dcfff9e72686dc5f30b1faa645b4d54e (diff)
downloadbitcoin-fac5efe730ab5b8694920547203deefc5252d294.tar.xz
util: Add Assume() identity function
-rw-r--r--configure.ac3
-rw-r--r--doc/developer-notes.md27
-rw-r--r--src/util/check.h16
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