Tor  0.4.7.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
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)
32 {
33  tor_end_capture_bugs_();
34  bug_messages = smartlist_new();
35  n_bugs_to_capture = n;
36 }
37 void
38 tor_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 }
47 const smartlist_t *
48 tor_get_captured_bug_log_(void)
49 {
50  return bug_messages;
51 }
52 static void
53 add_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  */
62 void
63 tor_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. */
73 void
74 tor_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. */
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, ...)
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  **/
170 void
172 {
174  tor_raw_abort_();
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  */
184 const char *
185 tor_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:52
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.
smartlist_t * smartlist_new(void)
void smartlist_add_strdup(struct smartlist_t *sl, const char *string)
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.