1 /* Copyright (c) 2003, 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 */
11 #include "lib/log/util_bug.h"
12 #include "lib/log/log.h"
13 #include "lib/err/backtrace.h"
14 #include "lib/err/torerr.h"
16 #include "lib/smartlist_core/smartlist_core.h"
17 #include "lib/smartlist_core/smartlist_foreach.h"
19 #include "lib/malloc/malloc.h"
20 #include "lib/string/printf.h"
26 static void (*failed_assertion_cb
)(void) = NULL
;
27 static int n_bugs_to_capture
= 0;
28 static smartlist_t
*bug_messages
= NULL
;
29 #define capturing_bugs() (bug_messages != NULL && n_bugs_to_capture)
31 tor_capture_bugs_(int n
)
33 tor_end_capture_bugs_();
34 bug_messages
= smartlist_new();
35 n_bugs_to_capture
= n
;
38 tor_end_capture_bugs_(void)
40 n_bugs_to_capture
= 0;
43 SMARTLIST_FOREACH(bug_messages
, char *, cp
, tor_free(cp
));
44 smartlist_free(bug_messages
);
48 tor_get_captured_bug_log_(void)
53 add_captured_bug(const char *s
)
56 smartlist_add_strdup(bug_messages
, s
);
58 /** Set a callback to be invoked when we get any tor_bug_occurred_
59 * invocation. We use this in the unit tests so that a nonfatal
60 * assertion failure can also count as a test failure.
63 tor_set_failed_assertion_callback(void (*fn
)(void))
65 failed_assertion_cb
= fn
;
67 #else /* !defined(TOR_UNIT_TESTS) */
68 #define capturing_bugs() (0)
69 #define add_captured_bug(s) do { } while (0)
70 #endif /* defined(TOR_UNIT_TESTS) */
72 /** Helper for tor_assert: report the assertion failure. */
74 tor_assertion_failed_(const char *fname
, unsigned int line
,
75 const char *func
, const char *expr
,
83 #pragma clang diagnostic push
84 #pragma clang diagnostic ignored "-Wformat-nonliteral"
88 tor_vasprintf(&extra
, fmt
, ap
);
92 #pragma clang diagnostic pop
95 log_err(LD_BUG
, "%s:%u: %s: Assertion %s failed; aborting.",
96 fname
, line
, func
, expr
);
97 tor_asprintf(&buf
, "Assertion %s failed in %s at %s:%u: %s",
98 expr
, func
, fname
, line
, extra
? extra
: "");
100 log_backtrace(LOG_ERR
, LD_BUG
, buf
);
104 /** Helper for tor_assert_nonfatal: report the assertion failure. */
106 tor_bug_occurred_(const char *fname
, unsigned int line
,
107 const char *func
, const char *expr
,
108 int once
, const char *fmt
, ...)
111 const char *once_str
= once
?
112 " (Future instances of this warning will be silenced.)": "";
114 if (capturing_bugs()) {
115 add_captured_bug("This line should not have been reached.");
118 log_warn(LD_BUG
, "%s:%u: %s: This line should not have been reached.%s",
119 fname
, line
, func
, once_str
);
121 "Line unexpectedly reached at %s at %s:%u",
124 if (capturing_bugs()) {
125 add_captured_bug(expr
);
133 #pragma clang diagnostic push
134 #pragma clang diagnostic ignored "-Wformat-nonliteral"
138 tor_vasprintf(&extra
, fmt
, ap
);
142 #pragma clang diagnostic pop
145 log_warn(LD_BUG
, "%s:%u: %s: Non-fatal assertion %s failed.%s",
146 fname
, line
, func
, expr
, once_str
);
147 tor_asprintf(&buf
, "Non-fatal assertion %s failed in %s at %s:%u%s%s",
148 expr
, func
, fname
, line
, fmt
? " : " : "",
152 log_backtrace(LOG_WARN
, LD_BUG
, buf
);
155 #ifdef TOR_UNIT_TESTS
156 if (failed_assertion_cb
) {
157 failed_assertion_cb();
163 * Call the tor_raw_abort_() function to close raw logs, then kill the current
164 * process with a fatal error. But first, close the file-based log file
165 * descriptors, so error messages are written before process termination.
167 * (This is a separate function so that we declare it in util_bug.h without
168 * including torerr.h in all the users of util_bug.h)
173 logs_flush_sigsafe();
178 /** Take a filename and return a pointer to its final element. This
179 * function is called on __FILE__ to fix a MSVC nit where __FILE__
180 * contains the full path to the file. This is bad, because it
181 * confuses users to find the home directory of the person who
182 * compiled the binary in their warning messages.
185 tor_fix_source_file(const char *fname
)
187 const char *cp1
, *cp2
, *r
;
188 cp1
= strrchr(fname
, '/');
189 cp2
= strrchr(fname
, '\\');
191 r
= (cp1
<cp2
)?(cp2
+1):(cp1
+1);
201 #endif /* defined(_WIN32) */