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
22#include <string.h>
23#include <stdlib.h>
24
25#ifdef TOR_UNIT_TESTS
26static void (*failed_assertion_cb)(void) = NULL;
27static int n_bugs_to_capture = 0;
28static smartlist_t *bug_messages = NULL;
29#define capturing_bugs() (bug_messages != NULL && n_bugs_to_capture)
30void
31tor_capture_bugs_(int n)
32{
33 tor_end_capture_bugs_();
34 bug_messages = smartlist_new();
35 n_bugs_to_capture = n;
36}
37void
38tor_end_capture_bugs_(void)
39{
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;
46}
47const smartlist_t *
48tor_get_captured_bug_log_(void)
49{
50 return bug_messages;
51}
52static void
53add_captured_bug(const char *s)
54{
55 --n_bugs_to_capture;
56 smartlist_add_strdup(bug_messages, s);
57}
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.
61 */
62void
63tor_set_failed_assertion_callback(void (*fn)(void))
64{
65 failed_assertion_cb = fn;
66}
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) */
71
72/** Helper for tor_assert: report the assertion failure. */
73void
74tor_assertion_failed_(const char *fname, unsigned int line,
75 const char *func, const char *expr,
76 const char *fmt, ...)
77{
78 char *buf = NULL;
79 char *extra = NULL;
80 va_list ap;
81
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);
90 }
91#ifdef __clang__
92#pragma clang diagnostic pop
93#endif
94
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);
102}
103
104/** Helper for tor_assert_nonfatal: report the assertion failure. */
105void
106tor_bug_occurred_(const char *fname, unsigned int line,
107 const char *func, const char *expr,
108 int once, const char *fmt, ...)
109{
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;
117 }
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;
127 }
128
129 va_list ap;
130 char *extra = NULL;
131
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);
140 }
141#ifdef __clang__
142#pragma clang diagnostic pop
143#endif
144
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);
151 }
152 log_backtrace(LOG_WARN, LD_BUG, buf);
153 tor_free(buf);
154
155#ifdef TOR_UNIT_TESTS
156 if (failed_assertion_cb) {
157 failed_assertion_cb();
158 }
159#endif
160}
161
162/**
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.
166 *
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)
169 **/
170void
172{
175}
176
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.
183 */
184const char *
185tor_fix_source_file(const char *fname)
186{
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;
198 }
199 return r;
200}
201#endif /* defined(_WIN32) */
Header for backtrace.c.
void logs_flush_sigsafe(void)
Definition: log.c:791
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)
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:106
void tor_assertion_failed_(const char *fname, unsigned int line, const char *func, const char *expr, const char *fmt,...)
Definition: util_bug.c:74
void tor_abort_(void)
Definition: util_bug.c:171
Macros to manage assertions, fatal and non-fatal.