tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

util_bug.h (13906B)


      1 /* Copyright (c) 2003-2004, Roger Dingledine
      2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      4 /* See LICENSE for licensing information */
      5 
      6 /**
      7 * \file util_bug.h
      8 *
      9 * \brief Macros to manage assertions, fatal and non-fatal.
     10 *
     11 * Guidelines: All the different kinds of assertion in this file are for
     12 * bug-checking only. Don't write code that can assert based on bad inputs.
     13 *
     14 * We provide two kinds of assertion here: "fatal" and "nonfatal". Use
     15 * nonfatal assertions for any bug you can reasonably recover from -- and
     16 * please, try to recover!  Many severe bugs in Tor have been caused by using
     17 * a regular assertion when a nonfatal assertion would have been better.
     18 *
     19 * If you need to check a condition with a nonfatal assertion, AND recover
     20 * from that same condition, consider using the BUG() macro inside a
     21 * conditional.  For example:
     22 *
     23 * <code>
     24 *  // wrong -- use tor_assert_nonfatal() if you just want an assertion.
     25 *  BUG(ptr == NULL);
     26 *
     27 *  // okay, but needlessly verbose
     28 *  tor_assert_nonfatal(ptr != NULL);
     29 *  if (ptr == NULL) { ... }
     30 *
     31 *  // this is how we do it:
     32 *  if (BUG(ptr == NULL)) { ... }
     33 * </code>
     34 **/
     35 
     36 #ifndef TOR_UTIL_BUG_H
     37 #define TOR_UTIL_BUG_H
     38 
     39 #include "orconfig.h"
     40 #include "lib/cc/compat_compiler.h"
     41 #include "lib/log/log.h"
     42 #include "lib/smartlist_core/smartlist_core.h"
     43 #include "lib/testsupport/testsupport.h"
     44 
     45 /* Replace assert() with a variant that sends failures to the log before
     46 * calling assert() normally.
     47 */
     48 #ifdef NDEBUG
     49 /* Nobody should ever want to build with NDEBUG set.  99% of our asserts will
     50 * be outside the critical path anyway, so it's silly to disable bug-checking
     51 * throughout the entire program just because a few asserts are slowing you
     52 * down.  Profile, optimize the critical path, and keep debugging on.
     53 *
     54 * And I'm not just saying that because some of our asserts check
     55 * security-critical properties.
     56 */
     57 #error "Sorry; we don't support building with NDEBUG."
     58 #endif /* defined(NDEBUG) */
     59 
     60 #if defined(TOR_UNIT_TESTS) && defined(__GNUC__)
     61 /* We define this GCC macro as a replacement for PREDICT_UNLIKELY() in this
     62 * header, so that in our unit test builds, we'll get compiler warnings about
     63 * stuff like tor_assert(n = 5).
     64 *
     65 * The key here is that (e) is wrapped in exactly one layer of parentheses,
     66 * and then passed right to a conditional.  If you do anything else to the
     67 * expression here, or introduce any more parentheses, the compiler won't
     68 * help you.
     69 *
     70 * We only do this for the unit-test build case because it interferes with
     71 * the likely-branch labeling.  Note below that in the other case, we define
     72 * these macros to just be synonyms for PREDICT_(UN)LIKELY.
     73 */
     74 #define ASSERT_PREDICT_UNLIKELY_(e)             \
     75  ( {                                           \
     76    int tor__assert_tmp_value__;                \
     77    if (e)                                      \
     78      tor__assert_tmp_value__ = 1;              \
     79    else                                        \
     80      tor__assert_tmp_value__ = 0;              \
     81    tor__assert_tmp_value__;                    \
     82  } )
     83 #define ASSERT_PREDICT_LIKELY_(e) ASSERT_PREDICT_UNLIKELY_(e)
     84 #else /* !(defined(TOR_UNIT_TESTS) && defined(__GNUC__)) */
     85 #define ASSERT_PREDICT_UNLIKELY_(e) PREDICT_UNLIKELY(e)
     86 #define ASSERT_PREDICT_LIKELY_(e) PREDICT_LIKELY(e)
     87 #endif /* defined(TOR_UNIT_TESTS) && defined(__GNUC__) */
     88 
     89 /* Sometimes we don't want to use assertions during branch coverage tests; it
     90 * leads to tons of unreached branches which in reality are only assertions we
     91 * didn't hit. */
     92 #if defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
     93 #define tor_assert(a) STMT_BEGIN                                        \
     94  (void)(a);                                                            \
     95  STMT_END
     96 #define tor_assertf(a, fmt, ...) STMT_BEGIN                             \
     97  (void)(a);                                                            \
     98  (void)(fmt);                                                          \
     99  STMT_END
    100 #else /* !(defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_T...)) */
    101 /** Like assert(3), but send assertion failures to the log as well as to
    102 * stderr. */
    103 #define tor_assert(expr) tor_assertf(expr, NULL)
    104 
    105 #define tor_assertf(expr, fmt, ...) STMT_BEGIN                          \
    106  if (ASSERT_PREDICT_LIKELY_(expr)) {                                   \
    107  } else {                                                              \
    108    tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr,      \
    109                          fmt, ##__VA_ARGS__);                          \
    110    tor_abort_();                                                        \
    111  } STMT_END
    112 #endif /* defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) */
    113 
    114 #define tor_assert_unreached()                                  \
    115  STMT_BEGIN {                                                  \
    116    tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__,     \
    117                          "line should be unreached", NULL);    \
    118    tor_abort_();                                               \
    119  } STMT_END
    120 
    121 /* Non-fatal bug assertions. The "unreached" variants mean "this line should
    122 * never be reached." The "once" variants mean "Don't log a warning more than
    123 * once".
    124 *
    125 * The 'BUG' macro checks a boolean condition and logs an error message if it
    126 * is true.  Example usage:
    127 *   if (BUG(x == NULL))
    128 *     return -1;
    129 */
    130 
    131 #ifdef __COVERITY__
    132 #undef BUG
    133 // Coverity defines this in global headers; let's override it.  This is a
    134 // magic coverity-only preprocessor thing.
    135 #ifndef COCCI
    136 #nodef BUG(x) (x)
    137 #endif
    138 #endif /* defined(__COVERITY__) */
    139 
    140 #if defined(__COVERITY__) || defined(__clang_analyzer__)
    141 // We're running with a static analysis tool: let's treat even nonfatal
    142 // assertion failures as something that we need to avoid.
    143 #define ALL_BUGS_ARE_FATAL
    144 #endif
    145 
    146 /** Define ALL_BUGS_ARE_FATAL if you want Tor to crash when any problem comes
    147 * up, so you can get a coredump and track things down. */
    148 #ifdef ALL_BUGS_ARE_FATAL
    149 #define tor_assert_nonfatal_unreached() tor_assert(0)
    150 #define tor_assert_nonfatal(cond) tor_assert((cond))
    151 #define tor_assertf_nonfatal(cond, fmt, ...)    \
    152  tor_assertf(cond, fmt, ##__VA_ARGS__)
    153 #define tor_assert_nonfatal_unreached_once() tor_assert(0)
    154 #define tor_assert_nonfatal_once(cond) tor_assert((cond))
    155 #define BUG(cond)                                                       \
    156  (ASSERT_PREDICT_UNLIKELY_(cond) ?                                     \
    157   (tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",NULL), \
    158    tor_abort_(), 1)                                                    \
    159   : 0)
    160 #ifndef COCCI
    161 #define IF_BUG_ONCE(cond) if (BUG(cond))
    162 #endif
    163 #elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
    164 #define tor_assert_nonfatal_unreached() STMT_NIL
    165 #define tor_assert_nonfatal(cond) ((void)(cond))
    166 #define tor_assertf_nonfatal(cond, fmt, ...) STMT_BEGIN                 \
    167  (void)cond;                                                           \
    168  (void)fmt;                                                            \
    169  STMT_END
    170 #define tor_assert_nonfatal_unreached_once() STMT_NIL
    171 #define tor_assert_nonfatal_once(cond) ((void)(cond))
    172 #define BUG(cond) (ASSERT_PREDICT_UNLIKELY_(cond) ? 1 : 0)
    173 #ifndef COCCI
    174 #define IF_BUG_ONCE(cond) if (BUG(cond))
    175 #endif
    176 #else /* Normal case, !ALL_BUGS_ARE_FATAL, !DISABLE_ASSERTS_IN_UNIT_TESTS */
    177 #define tor_assert_nonfatal_unreached() STMT_BEGIN                      \
    178  tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0, NULL);   \
    179  STMT_END
    180 #define tor_assert_nonfatal(cond) STMT_BEGIN                            \
    181  if (ASSERT_PREDICT_LIKELY_(cond)) {                                   \
    182  } else {                                                              \
    183    tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0, NULL);\
    184  }                                                                     \
    185  STMT_END
    186 #define tor_assertf_nonfatal(cond, fmt, ...) STMT_BEGIN                 \
    187  if (ASSERT_PREDICT_UNLIKELY_(cond)) {                                 \
    188  } else {                                                              \
    189    tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0,        \
    190                      fmt, ##__VA_ARGS__);                               \
    191  }                                                                     \
    192  STMT_END
    193 #define tor_assert_nonfatal_unreached_once() STMT_BEGIN                 \
    194  static int warning_logged__ = 0;                                      \
    195  tor_bug_increment_count_();                                           \
    196  if (!warning_logged__) {                                              \
    197    warning_logged__ = 1;                                               \
    198    tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1, NULL); \
    199  }                                                                     \
    200  STMT_END
    201 #define tor_assert_nonfatal_once(cond) STMT_BEGIN                       \
    202  static int warning_logged__ = 0;                                      \
    203  if (!ASSERT_PREDICT_LIKELY_(cond)) {                                   \
    204    tor_bug_increment_count_();                                         \
    205    if (!warning_logged__) {                                            \
    206      warning_logged__ = 1;                                             \
    207      tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1, NULL);\
    208    }                                                                   \
    209  }                                                                     \
    210  STMT_END
    211 #define BUG(cond)                                                       \
    212  (ASSERT_PREDICT_UNLIKELY_(cond) ?                                     \
    213  (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0,NULL),1) \
    214   : 0)
    215 
    216 #ifndef COCCI
    217 #ifdef __GNUC__
    218 #define IF_BUG_ONCE__(cond,var)                                         \
    219  if (( {                                                               \
    220      static int var = 0;                                               \
    221      int bool_result = !!(cond);                                       \
    222      if (bool_result) {                                                \
    223        tor_bug_increment_count_();                                     \
    224        if (!var) {                                                     \
    225          var = 1;                                                      \
    226          tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__,           \
    227                            ("!("#cond")"), 1, NULL);                   \
    228        }                                                               \
    229      }                                                                 \
    230      bool_result; } ))
    231 #else /* !defined(__GNUC__) */
    232 #define IF_BUG_ONCE__(cond,var)                                         \
    233  static int var = 0;                                                   \
    234  if ((cond) ?                                                          \
    235      (var ? (tor_bug_increment_count_(), 1) :                          \
    236       (var=1,                                                          \
    237        tor_bug_increment_count_(),                                     \
    238        tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__,             \
    239                          ("!("#cond")"), 1, NULL),                     \
    240        1))                                                             \
    241      : 0)
    242 #endif /* defined(__GNUC__) */
    243 #endif /* !defined(COCCI) */
    244 
    245 #define IF_BUG_ONCE_VARNAME_(a)               \
    246  warning_logged_on_ ## a ## __
    247 #define IF_BUG_ONCE_VARNAME__(a)              \
    248  IF_BUG_ONCE_VARNAME_(a)
    249 
    250 /** This macro behaves as 'if (BUG(x))', except that it only logs its
    251 * warning once, no matter how many times it triggers.
    252 */
    253 
    254 #define IF_BUG_ONCE(cond)                                       \
    255  IF_BUG_ONCE__(ASSERT_PREDICT_UNLIKELY_(cond),                 \
    256                IF_BUG_ONCE_VARNAME__(__LINE__))
    257 
    258 #endif /* defined(ALL_BUGS_ARE_FATAL) || ... */
    259 
    260 /**
    261 * Use this macro after a nonfatal assertion, and before a case statement
    262 * where you would want to fall through.
    263 */
    264 #ifdef ALL_BUGS_ARE_FATAL
    265 #define FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL \
    266  abort()
    267 #else
    268 #define FALLTHROUGH_UNLESS_ALL_BUGS_ARE_FATAL FALLTHROUGH
    269 #endif /* defined(ALL_BUGS_ARE_FATAL) */
    270 
    271 /** In older code, we used tor_fragile_assert() to mark optional failure
    272 * points. At these points, we could make some debug builds fail.
    273 * (But release builds would continue.)
    274 *
    275 * To get the same behaviour in recent tor versions, define
    276 * ALL_BUGS_ARE_FATAL, and use any non-fatal assertion or *BUG() macro.
    277 */
    278 #define tor_fragile_assert() tor_assert_nonfatal_unreached_once()
    279 
    280 void tor_assertion_failed_(const char *fname, unsigned int line,
    281                           const char *func, const char *expr,
    282                           const char *fmt, ...)
    283    CHECK_PRINTF(5,6);
    284 void tor_bug_increment_count_(void);
    285 size_t tor_bug_get_count(void);
    286 void tor_bug_occurred_(const char *fname, unsigned int line,
    287                       const char *func, const char *expr,
    288                       int once, const char *fmt, ...)
    289  CHECK_PRINTF(6,7);
    290 
    291 void tor_abort_(void) ATTR_NORETURN;
    292 void tor_bug_init_counter(void);
    293 
    294 #ifdef _WIN32
    295 #define SHORT_FILE__ (tor_fix_source_file(__FILE__))
    296 const char *tor_fix_source_file(const char *fname);
    297 #else
    298 #define SHORT_FILE__ (__FILE__)
    299 #define tor_fix_source_file(s) (s)
    300 #endif /* defined(_WIN32) */
    301 
    302 #ifdef TOR_UNIT_TESTS
    303 void tor_capture_bugs_(int n);
    304 void tor_end_capture_bugs_(void);
    305 const struct smartlist_t *tor_get_captured_bug_log_(void);
    306 void tor_set_failed_assertion_callback(void (*fn)(void));
    307 #endif /* defined(TOR_UNIT_TESTS) */
    308 
    309 #endif /* !defined(TOR_UTIL_BUG_H) */