#ifndef TOR_UTIL_BUG_H
#define TOR_UTIL_BUG_H
#include "orconfig.h"
#include "lib/cc/compat_compiler.h"
#include "lib/log/log.h"
#include "lib/testsupport/testsupport.h"
#ifdef NDEBUG
#error "Sorry; we don't support building with NDEBUG."
#endif
#if defined(TOR_UNIT_TESTS) && defined(__GNUC__)
#define ASSERT_PREDICT_UNLIKELY_(e) \
( { \
int tor__assert_tmp_value__; \
if (e) \
tor__assert_tmp_value__ = 1; \
else \
tor__assert_tmp_value__ = 0; \
tor__assert_tmp_value__; \
} )
#define ASSERT_PREDICT_LIKELY_(e) ASSERT_PREDICT_UNLIKELY_(e)
#else
#define ASSERT_PREDICT_UNLIKELY_(e) PREDICT_UNLIKELY(e)
#define ASSERT_PREDICT_LIKELY_(e) PREDICT_LIKELY(e)
#endif
#if defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
#define tor_assert(a) STMT_BEGIN \
(void)(a); \
STMT_END
#define tor_assertf(a, fmt, ...) STMT_BEGIN \
(void)(a); \
(void)(fmt); \
STMT_END
#else
#define tor_assert(expr) tor_assertf(expr, NULL)
#define tor_assertf(expr, fmt, ...) STMT_BEGIN \
if (ASSERT_PREDICT_LIKELY_(expr)) { \
} else { \
tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr, \
fmt, ##__VA_ARGS__); \
tor_abort_(); \
} STMT_END
#endif
#define tor_assert_unreached() \
STMT_BEGIN { \
tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, \
"line should be unreached", NULL); \
tor_abort_(); \
} STMT_END
#ifdef __COVERITY__
#undef BUG
#ifndef COCCI
#nodef BUG(x) (x)
#endif
#endif
#if defined(__COVERITY__) || defined(__clang_analyzer__)
#define ALL_BUGS_ARE_FATAL
#endif
#ifdef ALL_BUGS_ARE_FATAL
#define tor_assert_nonfatal_unreached() tor_assert(0)
#define tor_assert_nonfatal(cond) tor_assert((cond))
#define tor_assertf_nonfatal(cond, fmt, ...) \
tor_assertf(cond, fmt, ##__VA_ARGS__)
#define tor_assert_nonfatal_unreached_once() tor_assert(0)
#define tor_assert_nonfatal_once(cond) tor_assert((cond))
#define BUG(cond) \
(ASSERT_PREDICT_UNLIKELY_(cond) ? \
(tor_assertion_failed_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",NULL), \
tor_abort_(), 1) \
: 0)
#ifndef COCCI
#define IF_BUG_ONCE(cond) if (BUG(cond))
#endif
#elif defined(TOR_UNIT_TESTS) && defined(DISABLE_ASSERTS_IN_UNIT_TESTS)
#define tor_assert_nonfatal_unreached() STMT_NIL
#define tor_assert_nonfatal(cond) ((void)(cond))
#define tor_assertf_nonfatal(cond, fmt, ...) STMT_BEGIN \
(void)cond; \
(void)fmt; \
STMT_END
#define tor_assert_nonfatal_unreached_once() STMT_NIL
#define tor_assert_nonfatal_once(cond) ((void)(cond))
#define BUG(cond) (ASSERT_PREDICT_UNLIKELY_(cond) ? 1 : 0)
#ifndef COCCI
#define IF_BUG_ONCE(cond) if (BUG(cond))
#endif
#else
#define tor_assert_nonfatal_unreached() STMT_BEGIN \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 0, NULL); \
STMT_END
#define tor_assert_nonfatal(cond) STMT_BEGIN \
if (ASSERT_PREDICT_LIKELY_(cond)) { \
} else { \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0, NULL);\
} \
STMT_END
#define tor_assertf_nonfatal(cond, fmt, ...) STMT_BEGIN \
if (ASSERT_PREDICT_UNLIKELY_(cond)) { \
} else { \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 0, \
fmt, ##__VA_ARGS__); \
} \
STMT_END
#define tor_assert_nonfatal_unreached_once() STMT_BEGIN \
static int warning_logged__ = 0; \
if (!warning_logged__) { \
warning_logged__ = 1; \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1, NULL); \
} \
STMT_END
#define tor_assert_nonfatal_once(cond) STMT_BEGIN \
static int warning_logged__ = 0; \
if (ASSERT_PREDICT_LIKELY_(cond)) { \
} else if (!warning_logged__) { \
warning_logged__ = 1; \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1, NULL);\
} \
STMT_END
#define BUG(cond) \
(ASSERT_PREDICT_UNLIKELY_(cond) ? \
(tor_bug_occurred_(SHORT_FILE__,__LINE__,__func__,"!("#cond")",0,NULL),1) \
: 0)
#ifndef COCCI
#ifdef __GNUC__
#define IF_BUG_ONCE__(cond,var) \
if (( { \
static int var = 0; \
int bool_result = !!(cond); \
if (bool_result && !var) { \
var = 1; \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \
("!("#cond")"), 1, NULL); \
} \
bool_result; } ))
#else
#define IF_BUG_ONCE__(cond,var) \
static int var = 0; \
if ((cond) ? \
(var ? 1 : \
(var=1, \
tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \
("!("#cond")"), 1, NULL), \
1)) \
: 0)
#endif
#endif
#define IF_BUG_ONCE_VARNAME_(a) \
warning_logged_on_ ## a ## __
#define IF_BUG_ONCE_VARNAME__(a) \
IF_BUG_ONCE_VARNAME_(a)
#define IF_BUG_ONCE(cond) \
IF_BUG_ONCE__(ASSERT_PREDICT_UNLIKELY_(cond), \
IF_BUG_ONCE_VARNAME__(__LINE__))
#endif
#define tor_fragile_assert() tor_assert_nonfatal_unreached_once()
void tor_assertion_failed_(const char *fname, unsigned int line,
const char *func, const char *expr,
const char *fmt, ...)
CHECK_PRINTF(5,6);
void tor_bug_occurred_(const char *fname, unsigned int line,
const char *func, const char *expr,
int once, const char *fmt, ...)
CHECK_PRINTF(6,7);
void tor_abort_(void) ATTR_NORETURN;
#ifdef _WIN32
#define SHORT_FILE__ (tor_fix_source_file(__FILE__))
const char *tor_fix_source_file(const char *fname);
#else
#define SHORT_FILE__ (__FILE__)
#define tor_fix_source_file(s) (s)
#endif
#ifdef TOR_UNIT_TESTS
void tor_capture_bugs_(int n);
void tor_end_capture_bugs_(void);
const struct smartlist_t *tor_get_captured_bug_log_(void);
void tor_set_failed_assertion_callback(void (*fn)(void));
#endif
#endif