diff options
author | Nick Mathewson <nickm@torproject.org> | 2018-06-21 09:53:08 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2018-06-21 10:47:11 -0400 |
commit | 2cfcb7b364541c27749ae0df73eabd7a56797f93 (patch) | |
tree | 1fb03761e4631f1d5edd893fc9164a49ff8981b6 /src/common | |
parent | b2346b12019c45288bbae3bd009fe0bafe80ff58 (diff) | |
download | tor-2cfcb7b364541c27749ae0df73eabd7a56797f93.tar.gz tor-2cfcb7b364541c27749ae0df73eabd7a56797f93.zip |
Extract error functionality into a new lowest-level library.
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/backtrace.c | 282 | ||||
-rw-r--r-- | src/common/backtrace.h | 29 | ||||
-rw-r--r-- | src/common/include.am | 4 | ||||
-rw-r--r-- | src/common/torerr.c | 229 | ||||
-rw-r--r-- | src/common/torerr.h | 47 |
5 files changed, 0 insertions, 591 deletions
diff --git a/src/common/backtrace.c b/src/common/backtrace.c deleted file mode 100644 index d83cbba0e8..0000000000 --- a/src/common/backtrace.c +++ /dev/null @@ -1,282 +0,0 @@ -/* Copyright (c) 2013-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file backtrace.c - * - * \brief Functions to produce backtraces on bugs, crashes, or assertion - * failures. - * - * Currently, we've only got an implementation here using the backtrace() - * family of functions, which are sometimes provided by libc and sometimes - * provided by libexecinfo. We tie into the sigaction() backend in order to - * detect crashes. - */ - -#include "orconfig.h" -#include "common/torerr.h" - -#ifdef HAVE_EXECINFO_H -#include <execinfo.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#include <errno.h> -#include <stdlib.h> -#include <string.h> - -#ifdef HAVE_CYGWIN_SIGNAL_H -#include <cygwin/signal.h> -#elif defined(HAVE_SYS_UCONTEXT_H) -#include <sys/ucontext.h> -#elif defined(HAVE_UCONTEXT_H) -#include <ucontext.h> -#endif /* defined(HAVE_CYGWIN_SIGNAL_H) || ... */ - -#ifdef HAVE_PTHREAD_H -#include <pthread.h> -#endif - -#define EXPOSE_CLEAN_BACKTRACE -#include "common/backtrace.h" -#include "common/torerr.h" - -#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ - defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) -#define USE_BACKTRACE -#endif - -#if !defined(USE_BACKTRACE) -#define NO_BACKTRACE_IMPL -#endif - -// Redundant with util.h, but doing it here so we can avoid that dependency. -#define raw_free free - -#ifdef USE_BACKTRACE -/** Version of Tor to report in backtrace messages. */ -static char bt_version[128] = ""; - -/** Largest stack depth to try to dump. */ -#define MAX_DEPTH 256 -/** Static allocation of stack to dump. This is static so we avoid stack - * pressure. */ -static void *cb_buf[MAX_DEPTH]; -/** Protects cb_buf from concurrent access. Pthreads, since this code - * is Unix-only, and since this code needs to be lowest-level. */ -static pthread_mutex_t cb_buf_mutex = PTHREAD_MUTEX_INITIALIZER; - -/** Change a stacktrace in <b>stack</b> of depth <b>depth</b> so that it will - * log the correct function from which a signal was received with context - * <b>ctx</b>. (When we get a signal, the current function will not have - * called any other function, and will therefore have not pushed its address - * onto the stack. Fortunately, we usually have the program counter in the - * ucontext_t structure. - */ -void -clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx) -{ -#ifdef PC_FROM_UCONTEXT -#if defined(__linux__) - const size_t n = 1; -#elif defined(__darwin__) || defined(__APPLE__) || defined(OpenBSD) \ - || defined(__FreeBSD__) - const size_t n = 2; -#else - const size_t n = 1; -#endif /* defined(__linux__) || ... */ - if (depth <= n) - return; - - stack[n] = (void*) ctx->PC_FROM_UCONTEXT; -#else /* !(defined(PC_FROM_UCONTEXT)) */ - (void) depth; - (void) ctx; - (void) stack; -#endif /* defined(PC_FROM_UCONTEXT) */ -} - -/** Log a message <b>msg</b> at <b>severity</b> in <b>domain</b>, and follow - * that with a backtrace log. Send messages via the tor_log function at - * logger". */ -void -log_backtrace_impl(int severity, int domain, const char *msg, - tor_log_fn logger) -{ - size_t depth; - char **symbols; - size_t i; - - pthread_mutex_lock(&cb_buf_mutex); - - depth = backtrace(cb_buf, MAX_DEPTH); - symbols = backtrace_symbols(cb_buf, (int)depth); - - logger(severity, domain, "%s. Stack trace:", msg); - if (!symbols) { - /* LCOV_EXCL_START -- we can't provoke this. */ - logger(severity, domain, " Unable to generate backtrace."); - goto done; - /* LCOV_EXCL_STOP */ - } - for (i=0; i < depth; ++i) { - logger(severity, domain, " %s", symbols[i]); - } - raw_free(symbols); - - done: - pthread_mutex_unlock(&cb_buf_mutex); -} - -static void crash_handler(int sig, siginfo_t *si, void *ctx_) - __attribute__((noreturn)); - -/** Signal handler: write a crash message with a stack trace, and die. */ -static void -crash_handler(int sig, siginfo_t *si, void *ctx_) -{ - char buf[40]; - size_t depth; - ucontext_t *ctx = (ucontext_t *) ctx_; - int n_fds, i; - const int *fds = NULL; - - (void) si; - - depth = backtrace(cb_buf, MAX_DEPTH); - /* Clean up the top stack frame so we get the real function - * name for the most recently failing function. */ - clean_backtrace(cb_buf, depth, ctx); - - format_dec_number_sigsafe((unsigned)sig, buf, sizeof(buf)); - - tor_log_err_sigsafe(bt_version, " died: Caught signal ", buf, "\n", - NULL); - - n_fds = tor_log_get_sigsafe_err_fds(&fds); - for (i=0; i < n_fds; ++i) - backtrace_symbols_fd(cb_buf, (int)depth, fds[i]); - - abort(); -} - -/** Write a backtrace to all of the emergency-error fds. */ -void -dump_stack_symbols_to_error_fds(void) -{ - int n_fds, i; - const int *fds = NULL; - size_t depth; - - depth = backtrace(cb_buf, MAX_DEPTH); - - n_fds = tor_log_get_sigsafe_err_fds(&fds); - for (i=0; i < n_fds; ++i) - backtrace_symbols_fd(cb_buf, (int)depth, fds[i]); -} - -/** Install signal handlers as needed so that when we crash, we produce a - * useful stack trace. Return 0 on success, -errno on failure. */ -static int -install_bt_handler(const char *software) -{ - int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS, - SIGIO, -1 }; - int i, rv=0; - - strncpy(bt_version, software, sizeof(bt_version) - 1); - bt_version[sizeof(bt_version) - 1] = 0; - - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = crash_handler; - sa.sa_flags = SA_SIGINFO; - sigfillset(&sa.sa_mask); - - for (i = 0; trap_signals[i] >= 0; ++i) { - if (sigaction(trap_signals[i], &sa, NULL) == -1) { - /* LCOV_EXCL_START */ - rv = -errno; - /* LCOV_EXCL_STOP */ - } - } - - { - /* Now, generate (but do not log) a backtrace. This ensures that - * libc has pre-loaded the symbols we need to dump things, so that later - * reads won't be denied by the sandbox code */ - char **symbols; - size_t depth = backtrace(cb_buf, MAX_DEPTH); - symbols = backtrace_symbols(cb_buf, (int) depth); - if (symbols) - raw_free(symbols); - } - - return rv; -} - -/** Uninstall crash handlers. */ -static void -remove_bt_handler(void) -{ -} -#endif /* defined(USE_BACKTRACE) */ - -#ifdef NO_BACKTRACE_IMPL -void -log_backtrace_impl(int severity, int domain, const char *msg, - tor_log_fn logger) -{ - logger(severity, domain, "%s. (Stack trace not available)", msg); -} - -static int -install_bt_handler(const char *software) -{ - (void) software; - return 0; -} - -static void -remove_bt_handler(void) -{ -} - -void -dump_stack_symbols_to_error_fds(void) -{ -} -#endif /* defined(NO_BACKTRACE_IMPL) */ - -/** Set up code to handle generating error messages on crashes. */ -int -configure_backtrace_handler(const char *tor_version) -{ - char version[128]; - strncpy(version, "Tor", sizeof(version)-1); - - if (tor_version) { - strncat(version, " ", sizeof(version)-1); - strncat(version, tor_version, sizeof(version)-1); - } - - version[sizeof(version) - 1] = 0; - - return install_bt_handler(version); -} - -/** Perform end-of-process cleanup for code that generates error messages on - * crashes. */ -void -clean_up_backtrace_handler(void) -{ - remove_bt_handler(); -} diff --git a/src/common/backtrace.h b/src/common/backtrace.h deleted file mode 100644 index 0a145fc92d..0000000000 --- a/src/common/backtrace.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (c) 2013-2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_BACKTRACE_H -#define TOR_BACKTRACE_H - -#include "orconfig.h" -#include "common/compat_compiler.h" - -typedef void (*tor_log_fn)(int, unsigned, const char *fmt, ...) - CHECK_PRINTF(3,4); - -void log_backtrace_impl(int severity, int domain, const char *msg, - tor_log_fn logger); -int configure_backtrace_handler(const char *tor_version); -void clean_up_backtrace_handler(void); -void dump_stack_symbols_to_error_fds(void); - -#define log_backtrace(sev, dom, msg) \ - log_backtrace_impl((sev), (dom), (msg), tor_log) - -#ifdef EXPOSE_CLEAN_BACKTRACE -#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ - defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) -void clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx); -#endif -#endif /* defined(EXPOSE_CLEAN_BACKTRACE) */ - -#endif /* !defined(TOR_BACKTRACE_H) */ diff --git a/src/common/include.am b/src/common/include.am index 8afec9c054..5337034861 100644 --- a/src/common/include.am +++ b/src/common/include.am @@ -82,7 +82,6 @@ src_common_libor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS) LIBOR_A_SRC = \ src/common/address.c \ src/common/address_set.c \ - src/common/backtrace.c \ src/common/buffers.c \ src/common/compat.c \ src/common/compat_threads.c \ @@ -99,7 +98,6 @@ 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) \ @@ -161,7 +159,6 @@ src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) COMMONHEADERS = \ src/common/address.h \ src/common/address_set.h \ - src/common/backtrace.h \ src/common/buffers.h \ src/common/buffers_tls.h \ src/common/aes.h \ @@ -203,7 +200,6 @@ COMMONHEADERS = \ src/common/testsupport.h \ src/common/timers.h \ src/common/token_bucket.h \ - src/common/torerr.h \ src/common/torint.h \ src/common/torlog.h \ src/common/tortls.h \ diff --git a/src/common/torerr.c b/src/common/torerr.c deleted file mode 100644 index 0e0c4db355..0000000000 --- a/src/common/torerr.c +++ /dev/null @@ -1,229 +0,0 @@ -/* 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" -#include "common/backtrace.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"); - } - - dump_stack_symbols_to_error_fds(); -} - -/* 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. Not even - * raw_assert(), since raw_assert() calls this function on failure. */ - 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); - if (cp <= buf) { - /* Not tor_assert(); see above. */ - abort(); - } - --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 deleted file mode 100644 index 10d9f481c0..0000000000 --- a/src/common/torerr.h +++ /dev/null @@ -1,47 +0,0 @@ -/* 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 - -#include "common/compat_compiler.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) STMT_BEGIN \ - if (!(expr)) { \ - tor_raw_assertion_failed_msg_(__FILE__, __LINE__, #expr, NULL); \ - abort(); \ - } \ - STMT_END -#define raw_assert_unreached(expr) raw_assert(0) -#define raw_assert_unreached_msg(msg) STMT_BEGIN \ - tor_raw_assertion_failed_msg_(__FILE__, __LINE__, "0", (msg)); \ - abort(); \ - STMT_END - -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) */ |