Tor 0.4.9.0-alpha-dev
util_bug.c
Go to the documentation of this file.
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 */
5
6/**
7 * \file util_bug.c
8 **/
9
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
18#endif
19#include "lib/malloc/malloc.h"
20#include "lib/string/printf.h"
21#include "lib/thread/threads.h"
22
23#include <string.h>
24#include <stdlib.h>
25
26#ifdef TOR_UNIT_TESTS
27static void (*failed_assertion_cb)(void) = NULL;
28static int n_bugs_to_capture = 0;
29static smartlist_t *bug_messages = NULL;
30#define capturing_bugs() (bug_messages != NULL && n_bugs_to_capture)
31void
32tor_capture_bugs_(int n)
33{
34 tor_end_capture_bugs_();
35 bug_messages = smartlist_new();
36 n_bugs_to_capture = n;
37}
38void
39tor_end_capture_bugs_(void)
40{
41 n_bugs_to_capture = 0;
42 if (!bug_messages)
43 return;
44 SMARTLIST_FOREACH(bug_messages, char *, cp, tor_free(cp));
45 smartlist_free(bug_messages);
46 bug_messages = NULL;
47}
48const smartlist_t *
49tor_get_captured_bug_log_(void)
50{
51 return bug_messages;
52}
53static void
54add_captured_bug(const char *s)
55{
56 --n_bugs_to_capture;
57 smartlist_add_strdup(bug_messages, s);
58}
59/** Set a callback to be invoked when we get any tor_bug_occurred_
60 * invocation. We use this in the unit tests so that a nonfatal
61 * assertion failure can also count as a test failure.
62 */
63void
64tor_set_failed_assertion_callback(void (*fn)(void))
65{
66 failed_assertion_cb = fn;
67}
68#else /* !defined(TOR_UNIT_TESTS) */
69#define capturing_bugs() (0)
70#define add_captured_bug(s) do { } while (0)
71#endif /* defined(TOR_UNIT_TESTS) */
72
73/** Helper for tor_assert: report the assertion failure. */
74void
75tor_assertion_failed_(const char *fname, unsigned int line,
76 const char *func, const char *expr,
77 const char *fmt, ...)
78{
79 char *buf = NULL;
80 char *extra = NULL;
81 va_list ap;
82
83#ifdef __clang__
84#pragma clang diagnostic push
85#pragma clang diagnostic ignored "-Wformat-nonliteral"
86#endif
87 if (fmt) {
88 va_start(ap,fmt);
89 tor_vasprintf(&extra, fmt, ap);
90 va_end(ap);
91 }
92#ifdef __clang__
93#pragma clang diagnostic pop
94#endif
95
96 log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.",
97 fname, line, func, expr);
98 tor_asprintf(&buf, "Assertion %s failed in %s at %s:%u: %s",
99 expr, func, fname, line, extra ? extra : "");
100 tor_free(extra);
101 log_backtrace(LOG_ERR, LD_BUG, buf);
102 tor_free(buf);
103}
104
105static atomic_counter_t total_bug_reached;
106
107void
108tor_bug_init_counter(void)
109{
110 atomic_counter_init(&total_bug_reached);
111}
112
113/** Helper to update BUG count in metrics. */
114void
116{
117 atomic_counter_add(&total_bug_reached, 1);
118}
119
120size_t
121tor_bug_get_count(void)
122{
123 return atomic_counter_get(&total_bug_reached);
124}
125
126/** Helper for tor_assert_nonfatal: report the assertion failure. */
127void
128tor_bug_occurred_(const char *fname, unsigned int line,
129 const char *func, const char *expr,
130 int once, const char *fmt, ...)
131{
132 char *buf = NULL;
133 const char *once_str = once ?
134 " (Future instances of this warning will be silenced.)": "";
135 if (! once) {
136 // _once assertions count from the macro directly so we count them as many
137 // time as they are reached, and not just once.
139 }
140 if (! expr) {
141 if (capturing_bugs()) {
142 add_captured_bug("This line should not have been reached.");
143 return;
144 }
145 log_warn(LD_BUG, "%s:%u: %s: This line should not have been reached.%s",
146 fname, line, func, once_str);
147 tor_asprintf(&buf,
148 "Line unexpectedly reached at %s at %s:%u",
149 func, fname, line);
150 } else {
151 if (capturing_bugs()) {
152 add_captured_bug(expr);
153 return;
154 }
155
156 va_list ap;
157 char *extra = NULL;
158
159#ifdef __clang__
160#pragma clang diagnostic push
161#pragma clang diagnostic ignored "-Wformat-nonliteral"
162#endif
163 if (fmt) {
164 va_start(ap,fmt);
165 tor_vasprintf(&extra, fmt, ap);
166 va_end(ap);
167 }
168#ifdef __clang__
169#pragma clang diagnostic pop
170#endif
171
172 log_warn(LD_BUG, "%s:%u: %s: Non-fatal assertion %s failed.%s",
173 fname, line, func, expr, once_str);
174 tor_asprintf(&buf, "Non-fatal assertion %s failed in %s at %s:%u%s%s",
175 expr, func, fname, line, fmt ? " : " : "",
176 extra ? extra : "");
177 tor_free(extra);
178 }
179 log_backtrace(LOG_WARN, LD_BUG, buf);
180 tor_free(buf);
181
182#ifdef TOR_UNIT_TESTS
183 if (failed_assertion_cb) {
184 failed_assertion_cb();
185 }
186#endif
187}
188
189/**
190 * Call the tor_raw_abort_() function to close raw logs, then kill the current
191 * process with a fatal error. But first, close the file-based log file
192 * descriptors, so error messages are written before process termination.
193 *
194 * (This is a separate function so that we declare it in util_bug.h without
195 * including torerr.h in all the users of util_bug.h)
196 **/
197void
199{
202}
203
204#ifdef _WIN32
205/** Take a filename and return a pointer to its final element. This
206 * function is called on __FILE__ to fix a MSVC nit where __FILE__
207 * contains the full path to the file. This is bad, because it
208 * confuses users to find the home directory of the person who
209 * compiled the binary in their warning messages.
210 */
211const char *
212tor_fix_source_file(const char *fname)
213{
214 const char *cp1, *cp2, *r;
215 cp1 = strrchr(fname, '/');
216 cp2 = strrchr(fname, '\\');
217 if (cp1 && cp2) {
218 r = (cp1<cp2)?(cp2+1):(cp1+1);
219 } else if (cp1) {
220 r = cp1+1;
221 } else if (cp2) {
222 r = cp2+1;
223 } else {
224 r = fname;
225 }
226 return r;
227}
228#endif /* defined(_WIN32) */
Header for backtrace.c.
void atomic_counter_init(atomic_counter_t *counter)
void atomic_counter_add(atomic_counter_t *counter, size_t add)
size_t atomic_counter_get(atomic_counter_t *counter)
void logs_flush_sigsafe(void)
Definition: log.c:796
Headers for log.c.
#define LOG_ERR
Definition: log.h:56
#define LD_BUG
Definition: log.h:86
#define LOG_WARN
Definition: log.h:53
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:56
int tor_vasprintf(char **strp, const char *fmt, va_list args)
Definition: printf.c:96
int tor_asprintf(char **strp, const char *fmt,...)
Definition: printf.c:75
Header for printf.c.
void smartlist_add_strdup(struct smartlist_t *sl, const char *string)
smartlist_t * smartlist_new(void)
Top-level declarations for the smartlist_t dynamic array type.
Macros for iterating over the elements of a smartlist_t.
#define SMARTLIST_FOREACH(sl, type, var, cmd)
Header for threads.c.
void tor_raw_abort_(void)
Definition: torerr.c:222
Headers for torerr.c.
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:128
void tor_bug_increment_count_(void)
Definition: util_bug.c:115
void tor_assertion_failed_(const char *fname, unsigned int line, const char *func, const char *expr, const char *fmt,...)
Definition: util_bug.c:75
void tor_abort_(void)
Definition: util_bug.c:198
Macros to manage assertions, fatal and non-fatal.