rephist: Introduce a fraction and period for overload onionskin
[tor.git] / src / lib / log / util_bug.c
blob34b41324afac7dbc7f4ce5358264bb4dc7c301ff
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 */
6 /**
7 * \file util_bug.c
8 **/
10 #include "orconfig.h"
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"
15 #ifdef TOR_UNIT_TESTS
16 #include "lib/smartlist_core/smartlist_core.h"
17 #include "lib/smartlist_core/smartlist_foreach.h"
18 #endif
19 #include "lib/malloc/malloc.h"
20 #include "lib/string/printf.h"
22 #include <string.h>
23 #include <stdlib.h>
25 #ifdef TOR_UNIT_TESTS
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)
30 void
31 tor_capture_bugs_(int n)
33 tor_end_capture_bugs_();
34 bug_messages = smartlist_new();
35 n_bugs_to_capture = n;
37 void
38 tor_end_capture_bugs_(void)
40 n_bugs_to_capture = 0;
41 if (!bug_messages)
42 return;
43 SMARTLIST_FOREACH(bug_messages, char *, cp, tor_free(cp));
44 smartlist_free(bug_messages);
45 bug_messages = NULL;
47 const smartlist_t *
48 tor_get_captured_bug_log_(void)
50 return bug_messages;
52 static void
53 add_captured_bug(const char *s)
55 --n_bugs_to_capture;
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.
62 void
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. */
73 void
74 tor_assertion_failed_(const char *fname, unsigned int line,
75 const char *func, const char *expr,
76 const char *fmt, ...)
78 char *buf = NULL;
79 char *extra = NULL;
80 va_list ap;
82 #ifdef __clang__
83 #pragma clang diagnostic push
84 #pragma clang diagnostic ignored "-Wformat-nonliteral"
85 #endif
86 if (fmt) {
87 va_start(ap,fmt);
88 tor_vasprintf(&extra, fmt, ap);
89 va_end(ap);
91 #ifdef __clang__
92 #pragma clang diagnostic pop
93 #endif
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 : "");
99 tor_free(extra);
100 log_backtrace(LOG_ERR, LD_BUG, buf);
101 tor_free(buf);
104 /** Helper for tor_assert_nonfatal: report the assertion failure. */
105 void
106 tor_bug_occurred_(const char *fname, unsigned int line,
107 const char *func, const char *expr,
108 int once, const char *fmt, ...)
110 char *buf = NULL;
111 const char *once_str = once ?
112 " (Future instances of this warning will be silenced.)": "";
113 if (! expr) {
114 if (capturing_bugs()) {
115 add_captured_bug("This line should not have been reached.");
116 return;
118 log_warn(LD_BUG, "%s:%u: %s: This line should not have been reached.%s",
119 fname, line, func, once_str);
120 tor_asprintf(&buf,
121 "Line unexpectedly reached at %s at %s:%u",
122 func, fname, line);
123 } else {
124 if (capturing_bugs()) {
125 add_captured_bug(expr);
126 return;
129 va_list ap;
130 char *extra = NULL;
132 #ifdef __clang__
133 #pragma clang diagnostic push
134 #pragma clang diagnostic ignored "-Wformat-nonliteral"
135 #endif
136 if (fmt) {
137 va_start(ap,fmt);
138 tor_vasprintf(&extra, fmt, ap);
139 va_end(ap);
141 #ifdef __clang__
142 #pragma clang diagnostic pop
143 #endif
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 ? " : " : "",
149 extra ? extra : "");
150 tor_free(extra);
152 log_backtrace(LOG_WARN, LD_BUG, buf);
153 tor_free(buf);
155 #ifdef TOR_UNIT_TESTS
156 if (failed_assertion_cb) {
157 failed_assertion_cb();
159 #endif
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)
170 void
171 tor_abort_(void)
173 logs_flush_sigsafe();
174 tor_raw_abort_();
177 #ifdef _WIN32
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.
184 const char *
185 tor_fix_source_file(const char *fname)
187 const char *cp1, *cp2, *r;
188 cp1 = strrchr(fname, '/');
189 cp2 = strrchr(fname, '\\');
190 if (cp1 && cp2) {
191 r = (cp1<cp2)?(cp2+1):(cp1+1);
192 } else if (cp1) {
193 r = cp1+1;
194 } else if (cp2) {
195 r = cp2+1;
196 } else {
197 r = fname;
199 return r;
201 #endif /* defined(_WIN32) */