tor  0.4.2.0-alpha-dev
util_bug.h
Go to the documentation of this file.
1 /* Copyright (c) 2003-2004, Roger Dingledine
2  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3  * Copyright (c) 2007-2019, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
5 
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"
43 
44 /* Replace assert() with a variant that sends failures to the log before
45  * calling assert() normally.
46  */
47 #ifdef NDEBUG
48 /* Nobody should ever want to build with NDEBUG set. 99% of our asserts will
49  * be outside the critical path anyway, so it's silly to disable bug-checking
50  * throughout the entire program just because a few asserts are slowing you
51  * down. Profile, optimize the critical path, and keep debugging on.
52  *
53  * And I'm not just saying that because some of our asserts check
54  * security-critical properties.
55  */
56 #error "Sorry; we don't support building with NDEBUG."
57 #endif /* defined(NDEBUG) */
58 
59 #if defined(TOR_UNIT_TESTS) && defined(__GNUC__)
60 /* We define this GCC macro as a replacement for PREDICT_UNLIKELY() in this
61  * header, so that in our unit test builds, we'll get compiler warnings about
62  * stuff like tor_assert(n = 5).
63  *
64  * The key here is that (e) is wrapped in exactly one layer of parentheses,
65  * and then passed right to a conditional. If you do anything else to the
66  * expression here, or introduce any more parentheses, the compiler won't
67  * help you.
68  *
69  * We only do this for the unit-test build case because it interferes with
70  * the likely-branch labeling. Note below that in the other case, we define
71  * these macros to just be synonyms for PREDICT_(UN)LIKELY.
72  */
73 #define ASSERT_PREDICT_UNLIKELY_(e) \
74  ( { \
75  int tor__assert_tmp_value__; \
76  if (e) \
77  tor__assert_tmp_value__ = 1; \
78  else \
79  tor__assert_tmp_value__ = 0; \
80  tor__assert_tmp_value__; \
81  } )
82 #define ASSERT_PREDICT_LIKELY_(e) ASSERT_PREDICT_UNLIKELY_(e)
83 #else /* !(defined(TOR_UNIT_TESTS) && defined(__GNUC__)) */
84 #define ASSERT_PREDICT_UNLIKELY_(e) PREDICT_UNLIKELY(e)
85 #define ASSERT_PREDICT_LIKELY_(e) PREDICT_LIKELY(e)
86 #endif /* defined(TOR_UNIT_TESTS) && defined(__GNUC__) */
87 
88 /* Sometimes we don't want to use assertions during branch coverage tests; it
89  * leads to tons of unreached branches which in reality are only assertions we
90  * didn't hit. */
91 #if defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
92 #define tor_assert(a) STMT_BEGIN \
93  (void)(a); \
94  STMT_END
95 #define tor_assertf(a, fmt, ...) STMT_BEGIN \
96  (void)(a); \
97  (void)(fmt); \
98  STMT_END
99 #else /* !(defined(TOR_UNIT_TESTS) && ... */
100 
102 #define tor_assert(expr) tor_assertf(expr, NULL)
103 
104 #define tor_assertf(expr, fmt, ...) STMT_BEGIN \
105  if (ASSERT_PREDICT_LIKELY_(expr)) { \
106  } else { \
107  tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr, \
108  fmt, ##__VA_ARGS__); \
109  tor_abort_(); \
110  } STMT_END
111 #endif /* defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS) */
112 
113 #define tor_assert_unreached() \
114  STMT_BEGIN { \
115  tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, \
116  "line should be unreached", NULL); \
117  tor_abort_(); \
118  } STMT_END
119 
120 /* Non-fatal bug assertions. The "unreached" variants mean "this line should
121  * never be reached." The "once" variants mean "Don't log a warning more than
122  * once".
123  *
124  * The 'BUG' macro checks a boolean condition and logs an error message if it
125  * is true. Example usage:
126  * if (BUG(x == NULL))
127  * return -1;
128  */
129 
130 #ifdef __COVERITY__
131 #undef BUG
132 // Coverity defines this in global headers; let's override it. This is a
133 // magic coverity-only preprocessor thing.
134 #nodef BUG(x) (x)
135 #endif /* defined(__COVERITY__) */
136 
137 #if defined(__COVERITY__) || defined(__clang_analyzer__)
138 // We're running with a static analysis tool: let's treat even nonfatal
139 // assertion failures as something that we need to avoid.
140 #define ALL_BUGS_ARE_FATAL
141 #endif
142 
143 #ifdef ALL_BUGS_ARE_FATAL
144 #define tor_assert_nonfatal_unreached() tor_assert(0)
145 #define tor_assert_nonfatal(cond) tor_assert((cond))
146 #define tor_assertf_nonfatal(cond, fmt, ...) \
147  tor_assertf(cond, fmt, ##__VA_ARGS__)
148 #define tor_assert_nonfatal_unreached_once() tor_assert(0)
149 #define tor_assert_nonfatal_once(cond) tor_assert((cond))
150 #define BUG(cond) \
151  (ASSERT_PREDICT_UNLIKELY_(cond) ? \
152  (tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",NULL), \
153  tor_abort_(), 1) \
154  : 0)
155 #elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
156 #define tor_assert_nonfatal_unreached() STMT_NIL
157 #define tor_assert_nonfatal(cond) ((void)(cond))
158 #define tor_assertf_nonfatal(cond, fmt, ...) STMT_BEGIN \
159  (void)cond; \
160  (void)fmt; \
161  STMT_END
162 #define tor_assert_nonfatal_unreached_once() STMT_NIL
163 #define tor_assert_nonfatal_once(cond) ((void)(cond))
164 #define BUG(cond) (ASSERT_PREDICT_UNLIKELY_(cond) ? 1 : 0)
165 #else /* Normal case, !ALL_BUGS_ARE_FATAL, !DISABLE_ASSERTS_IN_UNIT_TESTS */
166 #define tor_assert_nonfatal_unreached() STMT_BEGIN \
167  tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0, NULL); \
168  STMT_END
169 #define tor_assert_nonfatal(cond) STMT_BEGIN \
170  if (ASSERT_PREDICT_LIKELY_(cond)) { \
171  } else { \
172  tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0, NULL);\
173  } \
174  STMT_END
175 #define tor_assertf_nonfatal(cond, fmt, ...) STMT_BEGIN \
176  if (ASSERT_PREDICT_UNLIKELY_(cond)) { \
177  } else { \
178  tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0, \
179  fmt, ##__VA_ARGS__); \
180  } \
181  STMT_END
182 #define tor_assert_nonfatal_unreached_once() STMT_BEGIN \
183  static int warning_logged__ = 0; \
184  if (!warning_logged__) { \
185  warning_logged__ = 1; \
186  tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1, NULL); \
187  } \
188  STMT_END
189 #define tor_assert_nonfatal_once(cond) STMT_BEGIN \
190  static int warning_logged__ = 0; \
191  if (ASSERT_PREDICT_LIKELY_(cond)) { \
192  } else if (!warning_logged__) { \
193  warning_logged__ = 1; \
194  tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1, NULL);\
195  } \
196  STMT_END
197 #define BUG(cond) \
198  (ASSERT_PREDICT_UNLIKELY_(cond) ? \
199  (tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",1,NULL),1) \
200  : 0)
201 #endif /* defined(ALL_BUGS_ARE_FATAL) || ... */
202 
203 #ifdef __GNUC__
204 #define IF_BUG_ONCE__(cond,var) \
205  if (( { \
206  static int var = 0; \
207  int bool_result = !!(cond); \
208  if (bool_result && !var) { \
209  var = 1; \
210  tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \
211  "!("#cond")", 1, NULL); \
212  } \
213  bool_result; } ))
214 #else /* !(defined(__GNUC__)) */
215 #define IF_BUG_ONCE__(cond,var) \
216  static int var = 0; \
217  if ((cond) ? \
218  (var ? 1 : \
219  (var=1, \
220  tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \
221  "!("#cond")", 1, NULL), \
222  1)) \
223  : 0)
224 #endif /* defined(__GNUC__) */
225 #define IF_BUG_ONCE_VARNAME_(a) \
226  warning_logged_on_ ## a ## __
227 #define IF_BUG_ONCE_VARNAME__(a) \
228  IF_BUG_ONCE_VARNAME_(a)
229 
234 #define IF_BUG_ONCE(cond) \
235  IF_BUG_ONCE__(ASSERT_PREDICT_UNLIKELY_(cond), \
236  IF_BUG_ONCE_VARNAME__(__LINE__))
237 
240 // #define tor_fragile_assert() tor_assert_unreached(0)
241 #define tor_fragile_assert() tor_assert_nonfatal_unreached_once()
242 
243 void tor_assertion_failed_(const char *fname, unsigned int line,
244  const char *func, const char *expr,
245  const char *fmt, ...);
246 void tor_bug_occurred_(const char *fname, unsigned int line,
247  const char *func, const char *expr,
248  int once, const char *fmt, ...);
249 
250 void tor_abort_(void) ATTR_NORETURN;
251 
252 #ifdef _WIN32
253 #define SHORT_FILE__ (tor_fix_source_file(__FILE__))
254 const char *tor_fix_source_file(const char *fname);
255 #else
256 #define SHORT_FILE__ (__FILE__)
257 #define tor_fix_source_file(s) (s)
258 #endif /* defined(_WIN32) */
259 
260 #ifdef TOR_UNIT_TESTS
261 void tor_capture_bugs_(int n);
262 void tor_end_capture_bugs_(void);
263 const struct smartlist_t *tor_get_captured_bug_log_(void);
264 void tor_set_failed_assertion_callback(void (*fn)(void));
265 #endif /* defined(TOR_UNIT_TESTS) */
266 
267 #endif /* !defined(TOR_UTIL_BUG_H) */
void tor_abort_(void) ATTR_NORETURN
Definition: util_bug.c:171
Utility macros to handle different features and behavior in different compilers.
void tor_bug_occurred_(const char *fname, unsigned int line, const char *func, const char *expr, int once, const char *fmt,...)
Definition: util_bug.c:107
Macros to implement mocking and selective exposure for the test code.
Headers for log.c.
void tor_assertion_failed_(const char *fname, unsigned int line, const char *func, const char *expr, const char *fmt,...)
Definition: util_bug.c:74