commit 5ecd1fec1583b8aa865ac5cae0cece42451395bd
Author: Nick Mathewson <nickm(a)torproject.org>
Date: Wed Jun 20 13:02:05 2018 -0400
Move horrible-emergency handling into torerr.[ch]
Previously we had code like this for bad things happening from
signal handlers, but it makes sense to use the same logic to handle
cases when something is happening at a level too low for log.c to be
involved.
My raw_assert*() stuff now uses this code.
---
src/common/backtrace.c | 2 +-
src/common/compat_time.c | 1 +
src/common/include.am | 2 +
src/common/log.c | 89 ++++---------------
src/common/sandbox.c | 4 +-
src/common/torerr.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++
src/common/torerr.h | 45 ++++++++++
src/common/torlog.h | 3 -
src/common/util.c | 79 -----------------
src/common/util.h | 4 +-
src/common/util_bug.h | 15 ----
src/test/test_logging.c | 2 +-
12 files changed, 291 insertions(+), 177 deletions(-)
diff --git a/src/common/backtrace.c b/src/common/backtrace.c
index c3c0b77ab..56cefdf93 100644
--- a/src/common/backtrace.c
+++ b/src/common/backtrace.c
@@ -17,6 +17,7 @@
#include "common/compat.h"
#include "common/util.h"
#include "common/torlog.h"
+#include "common/torerr.h"
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
@@ -245,4 +246,3 @@ clean_up_backtrace_handler(void)
tor_free(bt_version);
}
-
diff --git a/src/common/compat_time.c b/src/common/compat_time.c
index 5c7067461..913fa666e 100644
--- a/src/common/compat_time.c
+++ b/src/common/compat_time.c
@@ -34,6 +34,7 @@
#include <mach/mach_time.h>
#endif
+#include "common/torerr.h"
#include "common/torlog.h"
#include "common/util.h"
#include "common/container.h"
diff --git a/src/common/include.am b/src/common/include.am
index 724473c14..67b60d3ee 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -99,6 +99,7 @@ LIBOR_A_SRC = \
src/common/sandbox.c \
src/common/storagedir.c \
src/common/token_bucket.c \
+ src/common/torerr.c \
src/common/workqueue.c \
$(libor_extra_source) \
$(threads_impl_source) \
@@ -201,6 +202,7 @@ COMMONHEADERS = \
src/common/testsupport.h \
src/common/timers.h \
src/common/token_bucket.h \
+ src/common/torerr.c \
src/common/torint.h \
src/common/torlog.h \
src/common/tortls.h \
diff --git a/src/common/log.c b/src/common/log.c
index 6aa2203a5..6dba5bf4b 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -34,6 +34,8 @@
#define LOG_PRIVATE
#include "common/torlog.h"
#include "common/container.h"
+#include "common/torerr.h"
+
#ifdef HAVE_ANDROID_LOG_H
#include <android/log.h>
#endif // HAVE_ANDROID_LOG_H.
@@ -265,6 +267,7 @@ void
set_log_time_granularity(int granularity_msec)
{
log_time_granularity = granularity_msec;
+ tor_log_sigsafe_err_set_granularity(granularity_msec);
}
/** Helper: Write the standard prefix for log lines to a
@@ -631,71 +634,6 @@ tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
va_end(ap);
}
-/** Maximum number of fds that will get notifications if we crash */
-#define MAX_SIGSAFE_FDS 8
-/** Array of fds to log crash-style warnings to. */
-static int sigsafe_log_fds[MAX_SIGSAFE_FDS] = { STDERR_FILENO };
-/** The number of elements used in sigsafe_log_fds */
-static int n_sigsafe_log_fds = 1;
-
-/** Write <b>s</b> to each element of sigsafe_log_fds. Return 0 on success, -1
- * on failure. */
-static int
-tor_log_err_sigsafe_write(const char *s)
-{
- int i;
- ssize_t r;
- size_t len = strlen(s);
- int err = 0;
- for (i=0; i < n_sigsafe_log_fds; ++i) {
- r = write(sigsafe_log_fds[i], s, len);
- err += (r != (ssize_t)len);
- }
- return err ? -1 : 0;
-}
-
-/** Given a list of string arguments ending with a NULL, writes them
- * to our logs and to stderr (if possible). This function is safe to call
- * from within a signal handler. */
-void
-tor_log_err_sigsafe(const char *m, ...)
-{
- va_list ap;
- const char *x;
- char timebuf[33];
- time_t now = time(NULL);
-
- if (!m)
- return;
- if (log_time_granularity >= 2000) {
- int g = log_time_granularity / 1000;
- now -= now % g;
- }
- timebuf[0] = now < 0 ? '-' : ' ';
- if (now < 0) now = -now;
- timebuf[1] = '\0';
- format_dec_number_sigsafe(now, timebuf+1, sizeof(timebuf)-1);
- tor_log_err_sigsafe_write("\n=========================================="
- "================== T=");
- tor_log_err_sigsafe_write(timebuf);
- tor_log_err_sigsafe_write("\n");
- tor_log_err_sigsafe_write(m);
- va_start(ap, m);
- while ((x = va_arg(ap, const char*))) {
- tor_log_err_sigsafe_write(x);
- }
- va_end(ap);
-}
-
-/** Set *<b>out</b> to a pointer to an array of the fds to log errors to from
- * inside a signal handler. Return the number of elements in the array. */
-int
-tor_log_get_sigsafe_err_fds(const int **out)
-{
- *out = sigsafe_log_fds;
- return n_sigsafe_log_fds;
-}
-
/** Helper function; return true iff the <b>n</b>-element array <b>array</b>
* contains <b>item</b>. */
static int
@@ -717,11 +655,14 @@ tor_log_update_sigsafe_err_fds(void)
const logfile_t *lf;
int found_real_stderr = 0;
+ int fds[TOR_SIGSAFE_LOG_MAX_FDS];
+ int n_fds;
+
LOCK_LOGS();
/* Reserve the first one for stderr. This is safe because when we daemonize,
* we dup2 /dev/null to stderr, */
- sigsafe_log_fds[0] = STDERR_FILENO;
- n_sigsafe_log_fds = 1;
+ fds[0] = STDERR_FILENO;
+ n_fds = 1;
for (lf = logfiles; lf; lf = lf->next) {
/* Don't try callback to the control port, or syslogs: We can't
@@ -735,22 +676,24 @@ tor_log_update_sigsafe_err_fds(void)
if (lf->fd == STDERR_FILENO)
found_real_stderr = 1;
/* Avoid duplicates */
- if (int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, lf->fd))
+ if (int_array_contains(fds, n_fds, lf->fd))
continue;
- sigsafe_log_fds[n_sigsafe_log_fds++] = lf->fd;
- if (n_sigsafe_log_fds == MAX_SIGSAFE_FDS)
+ fds[n_fds++] = lf->fd;
+ if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS)
break;
}
}
if (!found_real_stderr &&
- int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, STDOUT_FILENO)) {
+ int_array_contains(fds, n_fds, STDOUT_FILENO)) {
/* Don't use a virtual stderr when we're also logging to stdout. */
- raw_assert(n_sigsafe_log_fds >= 2); /* Don't tor_assert inside log fns */
- sigsafe_log_fds[0] = sigsafe_log_fds[--n_sigsafe_log_fds];
+ raw_assert(n_fds >= 2); /* Don't tor_assert inside log fns */
+ fds[0] = fds[--n_fds];
}
UNLOCK_LOGS();
+
+ tor_log_set_sigsafe_err_fds(fds, n_fds);
}
/** Add to <b>out</b> a copy of every currently configured log file name. Used
diff --git a/src/common/sandbox.c b/src/common/sandbox.c
index cba63e04f..3679037f8 100644
--- a/src/common/sandbox.c
+++ b/src/common/sandbox.c
@@ -1,4 +1,4 @@
- /* Copyright (c) 2001 Matej Pfajfar.
+/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2018, The Tor Project, Inc. */
@@ -34,6 +34,7 @@
#include "common/sandbox.h"
#include "common/container.h"
+#include "common/torerr.h"
#include "common/torlog.h"
#include "common/torint.h"
#include "common/util.h"
@@ -1974,4 +1975,3 @@ sandbox_disable_getaddrinfo_cache(void)
{
}
#endif /* !defined(USE_LIBSECCOMP) */
-
diff --git a/src/common/torerr.c b/src/common/torerr.c
new file mode 100644
index 000000000..c22526254
--- /dev/null
+++ b/src/common/torerr.c
@@ -0,0 +1,222 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file torerr.c
+ *
+ * \brief Handling code for unrecoverable emergencies, at a lower level
+ * than the logging code.
+ */
+
+#include "orconfig.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "common/torerr.h"
+
+/** Array of fds to log crash-style warnings to. */
+static int sigsafe_log_fds[TOR_SIGSAFE_LOG_MAX_FDS] = { STDERR_FILENO };
+/** The number of elements used in sigsafe_log_fds */
+static int n_sigsafe_log_fds = 1;
+/** Log granularity in milliseconds. */
+static int log_granularity = 1000;
+
+/** Write <b>s</b> to each element of sigsafe_log_fds. Return 0 on success, -1
+ * on failure. */
+static int
+tor_log_err_sigsafe_write(const char *s)
+{
+ int i;
+ ssize_t r;
+ size_t len = strlen(s);
+ int err = 0;
+ for (i=0; i < n_sigsafe_log_fds; ++i) {
+ r = write(sigsafe_log_fds[i], s, len);
+ err += (r != (ssize_t)len);
+ }
+ return err ? -1 : 0;
+}
+
+/** Given a list of string arguments ending with a NULL, writes them
+ * to our logs and to stderr (if possible). This function is safe to call
+ * from within a signal handler. */
+void
+tor_log_err_sigsafe(const char *m, ...)
+{
+ va_list ap;
+ const char *x;
+ char timebuf[33];
+ time_t now = time(NULL);
+
+ if (!m)
+ return;
+ if (log_granularity >= 2000) {
+ int g = log_granularity / 1000;
+ now -= now % g;
+ }
+ timebuf[0] = now < 0 ? '-' : ' ';
+ if (now < 0) now = -now;
+ timebuf[1] = '\0';
+ format_dec_number_sigsafe(now, timebuf+1, sizeof(timebuf)-1);
+ tor_log_err_sigsafe_write("\n=========================================="
+ "================== T=");
+ tor_log_err_sigsafe_write(timebuf);
+ tor_log_err_sigsafe_write("\n");
+ tor_log_err_sigsafe_write(m);
+ va_start(ap, m);
+ while ((x = va_arg(ap, const char*))) {
+ tor_log_err_sigsafe_write(x);
+ }
+ va_end(ap);
+}
+
+/** Set *<b>out</b> to a pointer to an array of the fds to log errors to from
+ * inside a signal handler or other emergency condition. Return the number of
+ * elements in the array. */
+int
+tor_log_get_sigsafe_err_fds(const int **out)
+{
+ *out = sigsafe_log_fds;
+ return n_sigsafe_log_fds;
+}
+
+/**
+ * Update the list of fds that get errors from inside a signal handler or
+ * other emergency condition. Ignore any beyond the first
+ * TOR_SIGSAFE_LOG_MAX_FDS.
+ */
+void
+tor_log_set_sigsafe_err_fds(const int *fds, int n)
+{
+ if (n > TOR_SIGSAFE_LOG_MAX_FDS) {
+ n = TOR_SIGSAFE_LOG_MAX_FDS;
+ }
+
+ memcpy(sigsafe_log_fds, fds, n * sizeof(int));
+ n_sigsafe_log_fds = n;
+}
+
+/**
+ * Set the granularity (in ms) to use when reporting fatal errors outside
+ * the logging system.
+ */
+void
+tor_log_sigsafe_err_set_granularity(int ms)
+{
+ log_granularity = ms;
+}
+
+/**
+ * Log an emergency assertion failure message.
+ *
+ * This kind of message is safe to send from within a log handler,
+ * a signal handler, or other emergency situation.
+ */
+void
+tor_raw_assertion_failed_msg_(const char *file, int line, const char *expr,
+ const char *msg)
+{
+ char linebuf[16];
+ format_dec_number_sigsafe(line, linebuf, sizeof(linebuf));
+ tor_log_err_sigsafe("INTERNAL ERROR: Raw assertion failed at ",
+ file, ":", linebuf, ": ", expr, NULL);
+ if (msg) {
+ tor_log_err_sigsafe_write(msg);
+ tor_log_err_sigsafe_write("\n");
+ }
+}
+
+/* As format_{hex,dex}_number_sigsafe, but takes a <b>radix</b> argument
+ * in range 2..16 inclusive. */
+static int
+format_number_sigsafe(unsigned long x, char *buf, int buf_len,
+ unsigned int radix)
+{
+ unsigned long tmp;
+ int len;
+ char *cp;
+
+ /* NOT tor_assert. This needs to be safe to run from within a signal handler,
+ * and from within the 'tor_assert() has failed' code. */
+ if (radix < 2 || radix > 16)
+ return 0;
+
+ /* Count how many digits we need. */
+ tmp = x;
+ len = 1;
+ while (tmp >= radix) {
+ tmp /= radix;
+ ++len;
+ }
+
+ /* Not long enough */
+ if (!buf || len >= buf_len)
+ return 0;
+
+ cp = buf + len;
+ *cp = '\0';
+ do {
+ unsigned digit = (unsigned) (x % radix);
+ raw_assert(cp > buf);
+ --cp;
+ *cp = "0123456789ABCDEF"[digit];
+ x /= radix;
+ } while (x);
+
+ /* NOT tor_assert; see above. */
+ if (cp != buf) {
+ abort(); // LCOV_EXCL_LINE
+ }
+
+ return len;
+}
+
+/**
+ * Helper function to output hex numbers from within a signal handler.
+ *
+ * Writes the nul-terminated hexadecimal digits of <b>x</b> into a buffer
+ * <b>buf</b> of size <b>buf_len</b>, and return the actual number of digits
+ * written, not counting the terminal NUL.
+ *
+ * If there is insufficient space, write nothing and return 0.
+ *
+ * This accepts an unsigned int because format_helper_exit_status() needs to
+ * call it with a signed int and an unsigned char, and since the C standard
+ * does not guarantee that an int is wider than a char (an int must be at
+ * least 16 bits but it is permitted for a char to be that wide as well), we
+ * can't assume a signed int is sufficient to accommodate an unsigned char.
+ * Thus, format_helper_exit_status() will still need to emit any require '-'
+ * on its own.
+ *
+ * For most purposes, you'd want to use tor_snprintf("%x") instead of this
+ * function; it's designed to be used in code paths where you can't call
+ * arbitrary C functions.
+ */
+int
+format_hex_number_sigsafe(unsigned long x, char *buf, int buf_len)
+{
+ return format_number_sigsafe(x, buf, buf_len, 16);
+}
+
+/** As format_hex_number_sigsafe, but format the number in base 10. */
+int
+format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len)
+{
+ return format_number_sigsafe(x, buf, buf_len, 10);
+}
diff --git a/src/common/torerr.h b/src/common/torerr.h
new file mode 100644
index 000000000..09d8eeb76
--- /dev/null
+++ b/src/common/torerr.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2001, Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2018, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file torerr.h
+ *
+ * \brief Headers for torerr.c.
+ **/
+
+#ifndef TOR_TORERR_H
+#define TOR_TORERR_H
+
+/* The raw_assert...() variants are for use within code that can't call
+ * tor_assertion_failed_() because of call circularity issues. */
+#define raw_assert(expr) do { \
+ if (!(expr)) { \
+ tor_raw_assertion_failed_msg_(__FILE__, __LINE__, #expr, NULL); \
+ abort(); \
+ } \
+ } while (0)
+#define raw_assert_unreached(expr) raw_assert(0)
+#define raw_assert_unreached_msg(msg) do { \
+ tor_raw_assertion_failed_msg_(__FILE__, __LINE__, "0", (msg)); \
+ abort(); \
+ } while (0)
+
+void tor_raw_assertion_failed_msg_(const char *file, int line,
+ const char *expr,
+ const char *msg);
+
+/** Maximum number of fds that will get notifications if we crash */
+#define TOR_SIGSAFE_LOG_MAX_FDS 8
+
+void tor_log_err_sigsafe(const char *m, ...);
+int tor_log_get_sigsafe_err_fds(const int **out);
+void tor_log_set_sigsafe_err_fds(const int *fds, int n);
+void tor_log_sigsafe_err_set_granularity(int ms);
+
+int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len);
+int format_dec_number_sigsafe(unsigned long x, char *buf, int max_len);
+
+#endif /* !defined(TOR_TORLOG_H) */
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 65921c7b0..56f922d40 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -175,8 +175,6 @@ void truncate_logs(void);
void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
CHECK_PRINTF(3,4);
-void tor_log_err_sigsafe(const char *m, ...);
-int tor_log_get_sigsafe_err_fds(const int **out);
void tor_log_update_sigsafe_err_fds(void);
struct smartlist_t;
@@ -272,4 +270,3 @@ MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain,
# define TOR_TORLOG_H
#endif /* !defined(TOR_TORLOG_H) */
-
diff --git a/src/common/util.c b/src/common/util.c
index 7d10a9e24..5a477eeba 100644
--- a/src/common/util.c
+++ b/src/common/util.c
@@ -3865,85 +3865,6 @@ tor_join_win_cmdline(const char *argv[])
return joined_argv;
}
-/* As format_{hex,dex}_number_sigsafe, but takes a <b>radix</b> argument
- * in range 2..16 inclusive. */
-static int
-format_number_sigsafe(unsigned long x, char *buf, int buf_len,
- unsigned int radix)
-{
- unsigned long tmp;
- int len;
- char *cp;
-
- /* NOT tor_assert. This needs to be safe to run from within a signal handler,
- * and from within the 'tor_assert() has failed' code. */
- if (radix < 2 || radix > 16)
- return 0;
-
- /* Count how many digits we need. */
- tmp = x;
- len = 1;
- while (tmp >= radix) {
- tmp /= radix;
- ++len;
- }
-
- /* Not long enough */
- if (!buf || len >= buf_len)
- return 0;
-
- cp = buf + len;
- *cp = '\0';
- do {
- unsigned digit = (unsigned) (x % radix);
- tor_assert(cp > buf);
- --cp;
- *cp = "0123456789ABCDEF"[digit];
- x /= radix;
- } while (x);
-
- /* NOT tor_assert; see above. */
- if (cp != buf) {
- abort(); // LCOV_EXCL_LINE
- }
-
- return len;
-}
-
-/**
- * Helper function to output hex numbers from within a signal handler.
- *
- * Writes the nul-terminated hexadecimal digits of <b>x</b> into a buffer
- * <b>buf</b> of size <b>buf_len</b>, and return the actual number of digits
- * written, not counting the terminal NUL.
- *
- * If there is insufficient space, write nothing and return 0.
- *
- * This accepts an unsigned int because format_helper_exit_status() needs to
- * call it with a signed int and an unsigned char, and since the C standard
- * does not guarantee that an int is wider than a char (an int must be at
- * least 16 bits but it is permitted for a char to be that wide as well), we
- * can't assume a signed int is sufficient to accommodate an unsigned char.
- * Thus, format_helper_exit_status() will still need to emit any require '-'
- * on its own.
- *
- * For most purposes, you'd want to use tor_snprintf("%x") instead of this
- * function; it's designed to be used in code paths where you can't call
- * arbitrary C functions.
- */
-int
-format_hex_number_sigsafe(unsigned long x, char *buf, int buf_len)
-{
- return format_number_sigsafe(x, buf, buf_len, 16);
-}
-
-/** As format_hex_number_sigsafe, but format the number in base 10. */
-int
-format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len)
-{
- return format_number_sigsafe(x, buf, buf_len, 10);
-}
-
#ifndef _WIN32
/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in
* <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler
diff --git a/src/common/util.h b/src/common/util.h
index 7921357ac..a5e6c4d46 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -22,6 +22,7 @@
/* for the correct alias to struct stat */
#include <sys/stat.h>
#endif
+#include "common/torerr.h"
#include "common/util_bug.h"
#ifndef O_BINARY
@@ -522,9 +523,6 @@ int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top);
* <b>n</b> */
#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n)))
-int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len);
-int format_dec_number_sigsafe(unsigned long x, char *buf, int max_len);
-
#ifdef UTIL_PRIVATE
/* Prototypes for private functions only used by util.c (and unit tests) */
diff --git a/src/common/util_bug.h b/src/common/util_bug.h
index 0e1af2da1..1d499a197 100644
--- a/src/common/util_bug.h
+++ b/src/common/util_bug.h
@@ -55,21 +55,6 @@
#error "Sorry; we don't support building with NDEBUG."
#endif /* defined(NDEBUG) */
-/* The raw_assert...() variants are for use within code that can't call
- * tor_assertion_failed_() because of call circularity issues. */
-#define raw_assert(expr) STMT_BEGIN \
- if (!(expr)) { \
- fprintf(stderr, "RAW ASSERTION FAILURE AT %s:%d: %s\n", \
- __FILE__, __LINE__, #expr); \
- abort(); \
- } \
- STMT_END
-#define raw_assert_unreached(expr) raw_assert(0)
-#define raw_assert_unreached_msg(msg) STMT_BEGIN \
- fprintf(stderr, "ERROR: %s\n", (msg)); \
- raw_assert_unreached(); \
- STMT_END
-
/* Sometimes we don't want to use assertions during branch coverage tests; it
* leads to tons of unreached branches which in reality are only assertions we
* didn't hit. */
diff --git a/src/test/test_logging.c b/src/test/test_logging.c
index aebfd3606..eaad7ed13 100644
--- a/src/test/test_logging.c
+++ b/src/test/test_logging.c
@@ -3,6 +3,7 @@
#include "orconfig.h"
#include "or/or.h"
+#include "common/torerr.h"
#include "common/torlog.h"
#include "test/test.h"
@@ -170,4 +171,3 @@ struct testcase_t logging_tests[] = {
{ "ratelim", test_ratelim, 0, NULL, NULL },
END_OF_TESTCASES
};
-