mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-13 22:53:44 +01:00
Merge branch 'backtrace_squashed'
Conflicts: src/common/sandbox.c src/common/sandbox.h src/common/util.c src/or/main.c src/test/include.am src/test/test.c
This commit is contained in:
commit
fbc20294aa
2
.gitignore
vendored
2
.gitignore
vendored
@ -162,9 +162,11 @@
|
|||||||
/src/test/bench
|
/src/test/bench
|
||||||
/src/test/bench.exe
|
/src/test/bench.exe
|
||||||
/src/test/test
|
/src/test/test
|
||||||
|
/src/test/test-bt-cl
|
||||||
/src/test/test-child
|
/src/test/test-child
|
||||||
/src/test/test-ntor-cl
|
/src/test/test-ntor-cl
|
||||||
/src/test/test.exe
|
/src/test/test.exe
|
||||||
|
/src/test/test-bt-cl.exe
|
||||||
/src/test/test-child.exe
|
/src/test/test-child.exe
|
||||||
/src/test/test-ntor-cl.exe
|
/src/test/test-ntor-cl.exe
|
||||||
|
|
||||||
|
33
LICENSE
33
LICENSE
@ -134,6 +134,39 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
DATABASE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
DATABASE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
===============================================================================
|
||||||
|
m4/pc_from_ucontext.m4 is available under the following license. Note that
|
||||||
|
it is *not* built into the Tor license.
|
||||||
|
|
||||||
|
Copyright (c) 2005, Google Inc.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
If you got Tor as a static binary with OpenSSL included, then you should know:
|
If you got Tor as a static binary with OpenSSL included, then you should know:
|
||||||
"This product includes software developed by the OpenSSL Project
|
"This product includes software developed by the OpenSSL Project
|
||||||
|
8
changes/stack_trace
Normal file
8
changes/stack_trace
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
o Major features:
|
||||||
|
- On some platforms (currently: recent OSX versions, glibc-based
|
||||||
|
platforms that support the ELF format, and a few other
|
||||||
|
Unix-like operating systems), Tor can now dump stack traces
|
||||||
|
when a crash occurs or an assertion fails. By default, traces
|
||||||
|
are dumped to stderr (if possible) and to any logs that are
|
||||||
|
reporting errors.
|
||||||
|
|
@ -326,6 +326,8 @@ dnl exports strlcpy without defining it in a header.
|
|||||||
AC_CHECK_FUNCS(
|
AC_CHECK_FUNCS(
|
||||||
_NSGetEnviron \
|
_NSGetEnviron \
|
||||||
accept4 \
|
accept4 \
|
||||||
|
backtrace \
|
||||||
|
backtrace_symbols_fd \
|
||||||
clock_gettime \
|
clock_gettime \
|
||||||
flock \
|
flock \
|
||||||
ftime \
|
ftime \
|
||||||
@ -343,6 +345,7 @@ AC_CHECK_FUNCS(
|
|||||||
memmem \
|
memmem \
|
||||||
prctl \
|
prctl \
|
||||||
rint \
|
rint \
|
||||||
|
sigaction \
|
||||||
socketpair \
|
socketpair \
|
||||||
strlcat \
|
strlcat \
|
||||||
strlcpy \
|
strlcpy \
|
||||||
@ -629,6 +632,9 @@ if test x$enable_linker_hardening != xno; then
|
|||||||
TOR_CHECK_LDFLAGS(-z relro -z now, "$all_ldflags_for_check", "$all_libs_for_check")
|
TOR_CHECK_LDFLAGS(-z relro -z now, "$all_ldflags_for_check", "$all_libs_for_check")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# For backtrace support
|
||||||
|
TOR_CHECK_LDFLAGS(-rdynamic)
|
||||||
|
|
||||||
dnl ------------------------------------------------------
|
dnl ------------------------------------------------------
|
||||||
dnl Now see if we have a -fomit-frame-pointer compiler option.
|
dnl Now see if we have a -fomit-frame-pointer compiler option.
|
||||||
|
|
||||||
@ -841,6 +847,7 @@ dnl These headers are not essential
|
|||||||
AC_CHECK_HEADERS(
|
AC_CHECK_HEADERS(
|
||||||
arpa/inet.h \
|
arpa/inet.h \
|
||||||
crt_externs.h \
|
crt_externs.h \
|
||||||
|
execinfo.h \
|
||||||
grp.h \
|
grp.h \
|
||||||
ifaddrs.h \
|
ifaddrs.h \
|
||||||
inttypes.h \
|
inttypes.h \
|
||||||
@ -969,6 +976,8 @@ AC_CHECK_SIZEOF(pid_t)
|
|||||||
|
|
||||||
AC_CHECK_TYPES([uint, u_char, ssize_t])
|
AC_CHECK_TYPES([uint, u_char, ssize_t])
|
||||||
|
|
||||||
|
AC_PC_FROM_UCONTEXT([/bin/true])
|
||||||
|
|
||||||
dnl used to include sockaddr_storage, but everybody has that.
|
dnl used to include sockaddr_storage, but everybody has that.
|
||||||
AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t], , ,
|
AC_CHECK_TYPES([struct in6_addr, struct sockaddr_in6, sa_family_t], , ,
|
||||||
[#ifdef HAVE_SYS_TYPES_H
|
[#ifdef HAVE_SYS_TYPES_H
|
||||||
|
131
m4/pc_from_ucontext.m4
Normal file
131
m4/pc_from_ucontext.m4
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
# This file is from Google Performance Tools, svn revision r226.
|
||||||
|
#
|
||||||
|
# The Google Performance Tools license is:
|
||||||
|
########
|
||||||
|
# Copyright (c) 2005, Google Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above
|
||||||
|
# copyright notice, this list of conditions and the following disclaimer
|
||||||
|
# in the documentation and/or other materials provided with the
|
||||||
|
# distribution.
|
||||||
|
# * Neither the name of Google Inc. nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
########
|
||||||
|
# Original file follows below.
|
||||||
|
|
||||||
|
# We want to access the "PC" (Program Counter) register from a struct
|
||||||
|
# ucontext. Every system has its own way of doing that. We try all the
|
||||||
|
# possibilities we know about. Note REG_PC should come first (REG_RIP
|
||||||
|
# is also defined on solaris, but does the wrong thing).
|
||||||
|
|
||||||
|
# OpenBSD doesn't have ucontext.h, but we can get PC from ucontext_t
|
||||||
|
# by using signal.h.
|
||||||
|
|
||||||
|
# The first argument of AC_PC_FROM_UCONTEXT will be invoked when we
|
||||||
|
# cannot find a way to obtain PC from ucontext.
|
||||||
|
|
||||||
|
AC_DEFUN([AC_PC_FROM_UCONTEXT],
|
||||||
|
[AC_CHECK_HEADERS(ucontext.h)
|
||||||
|
# Redhat 7 has <sys/ucontext.h>, but it barfs if we #include it directly
|
||||||
|
# (this was fixed in later redhats). <ucontext.h> works fine, so use that.
|
||||||
|
if grep "Red Hat Linux release 7" /etc/redhat-release >/dev/null 2>&1; then
|
||||||
|
AC_DEFINE(HAVE_SYS_UCONTEXT_H, 0, [<sys/ucontext.h> is broken on redhat 7])
|
||||||
|
ac_cv_header_sys_ucontext_h=no
|
||||||
|
else
|
||||||
|
AC_CHECK_HEADERS(sys/ucontext.h) # ucontext on OS X 10.6 (at least)
|
||||||
|
fi
|
||||||
|
AC_CHECK_HEADERS(cygwin/signal.h) # ucontext on cywgin
|
||||||
|
AC_MSG_CHECKING([how to access the program counter from a struct ucontext])
|
||||||
|
pc_fields=" uc_mcontext.gregs[[REG_PC]]" # Solaris x86 (32 + 64 bit)
|
||||||
|
pc_fields="$pc_fields uc_mcontext.gregs[[REG_EIP]]" # Linux (i386)
|
||||||
|
pc_fields="$pc_fields uc_mcontext.gregs[[REG_RIP]]" # Linux (x86_64)
|
||||||
|
pc_fields="$pc_fields uc_mcontext.sc_ip" # Linux (ia64)
|
||||||
|
pc_fields="$pc_fields uc_mcontext.uc_regs->gregs[[PT_NIP]]" # Linux (ppc)
|
||||||
|
pc_fields="$pc_fields uc_mcontext.gregs[[R15]]" # Linux (arm old [untested])
|
||||||
|
pc_fields="$pc_fields uc_mcontext.arm_pc" # Linux (arm arch 5)
|
||||||
|
pc_fields="$pc_fields uc_mcontext.gp_regs[[PT_NIP]]" # Suse SLES 11 (ppc64)
|
||||||
|
pc_fields="$pc_fields uc_mcontext.mc_eip" # FreeBSD (i386)
|
||||||
|
pc_fields="$pc_fields uc_mcontext.mc_rip" # FreeBSD (x86_64 [untested])
|
||||||
|
pc_fields="$pc_fields uc_mcontext.__gregs[[_REG_EIP]]" # NetBSD (i386)
|
||||||
|
pc_fields="$pc_fields uc_mcontext.__gregs[[_REG_RIP]]" # NetBSD (x86_64)
|
||||||
|
pc_fields="$pc_fields uc_mcontext->ss.eip" # OS X (i386, <=10.4)
|
||||||
|
pc_fields="$pc_fields uc_mcontext->__ss.__eip" # OS X (i386, >=10.5)
|
||||||
|
pc_fields="$pc_fields uc_mcontext->ss.rip" # OS X (x86_64)
|
||||||
|
pc_fields="$pc_fields uc_mcontext->__ss.__rip" # OS X (>=10.5 [untested])
|
||||||
|
pc_fields="$pc_fields uc_mcontext->ss.srr0" # OS X (ppc, ppc64 [untested])
|
||||||
|
pc_fields="$pc_fields uc_mcontext->__ss.__srr0" # OS X (>=10.5 [untested])
|
||||||
|
pc_field_found=false
|
||||||
|
for pc_field in $pc_fields; do
|
||||||
|
if ! $pc_field_found; then
|
||||||
|
# Prefer sys/ucontext.h to ucontext.h, for OS X's sake.
|
||||||
|
if test "x$ac_cv_header_cygwin_signal_h" = xyes; then
|
||||||
|
AC_TRY_COMPILE([#define _GNU_SOURCE 1
|
||||||
|
#include <cygwin/signal.h>],
|
||||||
|
[ucontext_t u; return u.$pc_field == 0;],
|
||||||
|
AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field,
|
||||||
|
How to access the PC from a struct ucontext)
|
||||||
|
AC_MSG_RESULT([$pc_field])
|
||||||
|
pc_field_found=true)
|
||||||
|
elif test "x$ac_cv_header_sys_ucontext_h" = xyes; then
|
||||||
|
AC_TRY_COMPILE([#define _GNU_SOURCE 1
|
||||||
|
#include <sys/ucontext.h>],
|
||||||
|
[ucontext_t u; return u.$pc_field == 0;],
|
||||||
|
AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field,
|
||||||
|
How to access the PC from a struct ucontext)
|
||||||
|
AC_MSG_RESULT([$pc_field])
|
||||||
|
pc_field_found=true)
|
||||||
|
elif test "x$ac_cv_header_ucontext_h" = xyes; then
|
||||||
|
AC_TRY_COMPILE([#define _GNU_SOURCE 1
|
||||||
|
#include <ucontext.h>],
|
||||||
|
[ucontext_t u; return u.$pc_field == 0;],
|
||||||
|
AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field,
|
||||||
|
How to access the PC from a struct ucontext)
|
||||||
|
AC_MSG_RESULT([$pc_field])
|
||||||
|
pc_field_found=true)
|
||||||
|
else # hope some standard header gives it to us
|
||||||
|
AC_TRY_COMPILE([],
|
||||||
|
[ucontext_t u; return u.$pc_field == 0;],
|
||||||
|
AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field,
|
||||||
|
How to access the PC from a struct ucontext)
|
||||||
|
AC_MSG_RESULT([$pc_field])
|
||||||
|
pc_field_found=true)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if ! $pc_field_found; then
|
||||||
|
pc_fields=" sc_eip" # OpenBSD (i386)
|
||||||
|
pc_fields="$pc_fields sc_rip" # OpenBSD (x86_64)
|
||||||
|
for pc_field in $pc_fields; do
|
||||||
|
if ! $pc_field_found; then
|
||||||
|
AC_TRY_COMPILE([#include <signal.h>],
|
||||||
|
[ucontext_t u; return u.$pc_field == 0;],
|
||||||
|
AC_DEFINE_UNQUOTED(PC_FROM_UCONTEXT, $pc_field,
|
||||||
|
How to access the PC from a struct ucontext)
|
||||||
|
AC_MSG_RESULT([$pc_field])
|
||||||
|
pc_field_found=true)
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if ! $pc_field_found; then
|
||||||
|
[$1]
|
||||||
|
fi])
|
202
src/common/backtrace.c
Normal file
202
src/common/backtrace.c
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/* Copyright (c) 2013, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
#include "backtrace.h"
|
||||||
|
#include "compat.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "torlog.h"
|
||||||
|
|
||||||
|
#define __USE_GNU
|
||||||
|
|
||||||
|
#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
|
||||||
|
#ifdef HAVE_UCONTEXT_H
|
||||||
|
#include <ucontext.h>
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_SYS_UCONTEXT_H
|
||||||
|
#include <sys/ucontext.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
/** Version of Tor to report in backtrace messages. */
|
||||||
|
static char *bt_version = NULL;
|
||||||
|
|
||||||
|
#ifdef USE_BACKTRACE
|
||||||
|
/** 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];
|
||||||
|
|
||||||
|
/** 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.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
clean_backtrace(void **stack, int depth, const ucontext_t *ctx)
|
||||||
|
{
|
||||||
|
#ifdef PC_FROM_UCONTEXT
|
||||||
|
#if defined(__linux__)
|
||||||
|
const int n = 1;
|
||||||
|
#elif defined(__darwin__) || defined(__APPLE__) || defined(__OpenBSD__) \
|
||||||
|
|| defined(__FreeBSD__)
|
||||||
|
const int n = 2;
|
||||||
|
#else
|
||||||
|
const int n = 1;
|
||||||
|
#endif
|
||||||
|
if (depth <= n)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stack[n] = (void*) ctx->PC_FROM_UCONTEXT;
|
||||||
|
#else
|
||||||
|
(void) depth;
|
||||||
|
(void) ctx;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Log a message <b>msg</b> at <b>severity</b> in <b>domain</b>, and follow
|
||||||
|
* that with a backtrace log. */
|
||||||
|
void
|
||||||
|
log_backtrace(int severity, int domain, const char *msg)
|
||||||
|
{
|
||||||
|
int depth = backtrace(cb_buf, MAX_DEPTH);
|
||||||
|
char **symbols = backtrace_symbols(cb_buf, depth);
|
||||||
|
int i;
|
||||||
|
tor_log(severity, domain, "%s. Stack trace:", msg);
|
||||||
|
if (!symbols) {
|
||||||
|
tor_log(severity, domain, " Unable to generate backtrace.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (i=0; i < depth; ++i) {
|
||||||
|
tor_log(severity, domain, " %s", symbols[i]);
|
||||||
|
}
|
||||||
|
free(symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
int 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, depth, fds[i]);
|
||||||
|
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Install signal handlers as needed so that when we crash, we produce a
|
||||||
|
* useful stack trace. Return 0 on success, -1 on failure. */
|
||||||
|
static int
|
||||||
|
install_bt_handler(void)
|
||||||
|
{
|
||||||
|
int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS,
|
||||||
|
SIGIO, -1 };
|
||||||
|
int i, rv=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) {
|
||||||
|
log_warn(LD_BUG, "Sigaction failed: %s", strerror(errno));
|
||||||
|
rv = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Uninstall crash handlers. */
|
||||||
|
static void
|
||||||
|
remove_bt_handler(void)
|
||||||
|
{
|
||||||
|
/* We don't need to actually free anything at exit here. */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_BACKTRACE_IMPL
|
||||||
|
void
|
||||||
|
log_backtrace(int severity, int domain, const char *msg)
|
||||||
|
{
|
||||||
|
tor_log(severity, domain, "%s. (Stack trace not available)", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
install_bt_handler(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_bt_handler(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Set up code to handle generating error messages on crashes. */
|
||||||
|
int
|
||||||
|
configure_backtrace_handler(const char *tor_version)
|
||||||
|
{
|
||||||
|
tor_free(bt_version);
|
||||||
|
if (!tor_version)
|
||||||
|
tor_version = "";
|
||||||
|
tor_asprintf(&bt_version, "Tor %s", tor_version);
|
||||||
|
|
||||||
|
return install_bt_handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Perform end-of-process cleanup for code that generates error messages on
|
||||||
|
* crashes. */
|
||||||
|
void
|
||||||
|
clean_up_backtrace_handler(void)
|
||||||
|
{
|
||||||
|
remove_bt_handler();
|
||||||
|
|
||||||
|
tor_free(bt_version);
|
||||||
|
}
|
||||||
|
|
12
src/common/backtrace.h
Normal file
12
src/common/backtrace.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
/* Copyright (c) 2013, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#ifndef TOR_BACKTRACE_H
|
||||||
|
#define TOR_BACKTRACE_H
|
||||||
|
|
||||||
|
void log_backtrace(int severity, int domain, const char *msg);
|
||||||
|
int configure_backtrace_handler(const char *tor_version);
|
||||||
|
void clean_up_backtrace_handler(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -50,6 +50,7 @@ endif
|
|||||||
|
|
||||||
LIBOR_A_SOURCES = \
|
LIBOR_A_SOURCES = \
|
||||||
src/common/address.c \
|
src/common/address.c \
|
||||||
|
src/common/backtrace.c \
|
||||||
src/common/compat.c \
|
src/common/compat.c \
|
||||||
src/common/container.c \
|
src/common/container.c \
|
||||||
src/common/di_ops.c \
|
src/common/di_ops.c \
|
||||||
@ -90,6 +91,7 @@ src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
|||||||
|
|
||||||
COMMONHEADERS = \
|
COMMONHEADERS = \
|
||||||
src/common/address.h \
|
src/common/address.h \
|
||||||
|
src/common/backtrace.h \
|
||||||
src/common/aes.h \
|
src/common/aes.h \
|
||||||
src/common/ciphers.inc \
|
src/common/ciphers.inc \
|
||||||
src/common/compat.h \
|
src/common/compat.h \
|
||||||
|
140
src/common/log.c
140
src/common/log.c
@ -87,12 +87,12 @@ should_log_function_name(log_domain_mask_t domain, int severity)
|
|||||||
case LOG_DEBUG:
|
case LOG_DEBUG:
|
||||||
case LOG_INFO:
|
case LOG_INFO:
|
||||||
/* All debugging messages occur in interesting places. */
|
/* All debugging messages occur in interesting places. */
|
||||||
return 1;
|
return (domain & LD_NOFUNCNAME) == 0;
|
||||||
case LOG_NOTICE:
|
case LOG_NOTICE:
|
||||||
case LOG_WARN:
|
case LOG_WARN:
|
||||||
case LOG_ERR:
|
case LOG_ERR:
|
||||||
/* We care about places where bugs occur. */
|
/* We care about places where bugs occur. */
|
||||||
return (domain == LD_BUG);
|
return (domain & (LD_BUG|LD_NOFUNCNAME)) == LD_BUG;
|
||||||
default:
|
default:
|
||||||
/* Call assert, not tor_assert, since tor_assert calls log on failure. */
|
/* Call assert, not tor_assert, since tor_assert calls log on failure. */
|
||||||
assert(0); return 0;
|
assert(0); return 0;
|
||||||
@ -443,6 +443,126 @@ tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
|
|||||||
va_end(ap);
|
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[32];
|
||||||
|
time_t now = time(NULL);
|
||||||
|
|
||||||
|
if (!m)
|
||||||
|
return;
|
||||||
|
if (log_time_granularity >= 2000) {
|
||||||
|
int g = log_time_granularity / 1000;
|
||||||
|
now -= now % g;
|
||||||
|
}
|
||||||
|
timebuf[0] = '\0';
|
||||||
|
format_dec_number_sigsafe(now, timebuf, sizeof(timebuf));
|
||||||
|
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
|
||||||
|
int_array_contains(const int *array, int n, int item)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
for (j = 0; j < n; ++j) {
|
||||||
|
if (array[j] == item)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Function to call whenever the list of logs changes to get ready to log
|
||||||
|
* from signal handlers. */
|
||||||
|
void
|
||||||
|
tor_log_update_sigsafe_err_fds(void)
|
||||||
|
{
|
||||||
|
const logfile_t *lf;
|
||||||
|
int found_real_stderr = 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (lf = logfiles; lf; lf = lf->next) {
|
||||||
|
/* Don't try callback to the control port, or syslogs: We can't
|
||||||
|
* do them from a signal handler. Don't try stdout: we always do stderr.
|
||||||
|
*/
|
||||||
|
if (lf->is_temporary || lf->is_syslog ||
|
||||||
|
lf->callback || lf->seems_dead || lf->fd < 0)
|
||||||
|
continue;
|
||||||
|
if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] &
|
||||||
|
(LD_BUG|LD_GENERAL)) {
|
||||||
|
if (lf->fd == STDERR_FILENO)
|
||||||
|
found_real_stderr = 1;
|
||||||
|
/* Avoid duplicates */
|
||||||
|
if (int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, lf->fd))
|
||||||
|
continue;
|
||||||
|
sigsafe_log_fds[n_sigsafe_log_fds++] = lf->fd;
|
||||||
|
if (n_sigsafe_log_fds == MAX_SIGSAFE_FDS)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_real_stderr &&
|
||||||
|
int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, STDOUT_FILENO)) {
|
||||||
|
/* Don't use a virtual stderr when we're also logging to stdout. */
|
||||||
|
assert(n_sigsafe_log_fds >= 2); /* Don't use assert inside log functions*/
|
||||||
|
sigsafe_log_fds[0] = sigsafe_log_fds[--n_sigsafe_log_fds];
|
||||||
|
}
|
||||||
|
|
||||||
|
UNLOCK_LOGS();
|
||||||
|
}
|
||||||
|
|
||||||
/** Output a message to the log, prefixed with a function name <b>fn</b>. */
|
/** Output a message to the log, prefixed with a function name <b>fn</b>. */
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
/** GCC-based implementation of the log_fn backend, used when we have
|
/** GCC-based implementation of the log_fn backend, used when we have
|
||||||
@ -1142,22 +1262,6 @@ get_min_log_level(void)
|
|||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the fd of a file log that is receiving ERR messages, or -1 if
|
|
||||||
* no such log exists. */
|
|
||||||
int
|
|
||||||
get_err_logging_fd(void)
|
|
||||||
{
|
|
||||||
const logfile_t *lf;
|
|
||||||
for (lf = logfiles; lf; lf = lf->next) {
|
|
||||||
if (lf->is_temporary || lf->is_syslog || !lf->filename ||
|
|
||||||
lf->callback || lf->seems_dead || lf->fd < 0)
|
|
||||||
continue;
|
|
||||||
if (lf->severities->masks[LOG_ERR] & LD_GENERAL)
|
|
||||||
return lf->fd;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Switch all logs to output at most verbose level. */
|
/** Switch all logs to output at most verbose level. */
|
||||||
void
|
void
|
||||||
switch_logs_debug(void)
|
switch_logs_debug(void)
|
||||||
|
@ -1290,16 +1290,6 @@ install_syscall_filter(sandbox_cfg_t* cfg)
|
|||||||
return (rc < 0 ? -rc : rc);
|
return (rc < 0 ? -rc : rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Additional file descriptor to use when logging seccomp2 failures */
|
|
||||||
static int sigsys_debugging_fd = -1;
|
|
||||||
|
|
||||||
/** Use the file descriptor <b>fd</b> to log seccomp2 failures. */
|
|
||||||
static void
|
|
||||||
sigsys_set_debugging_fd(int fd)
|
|
||||||
{
|
|
||||||
sigsys_debugging_fd = fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function called when a SIGSYS is caught by the application. It notifies the
|
* Function called when a SIGSYS is caught by the application. It notifies the
|
||||||
* user that an error has occurred and either terminates or allows the
|
* user that an error has occurred and either terminates or allows the
|
||||||
@ -1309,8 +1299,8 @@ static void
|
|||||||
sigsys_debugging(int nr, siginfo_t *info, void *void_context)
|
sigsys_debugging(int nr, siginfo_t *info, void *void_context)
|
||||||
{
|
{
|
||||||
ucontext_t *ctx = (ucontext_t *) (void_context);
|
ucontext_t *ctx = (ucontext_t *) (void_context);
|
||||||
char message[256];
|
char number[32];
|
||||||
int rv = 0, syscall, length, err;
|
int syscall;
|
||||||
(void) nr;
|
(void) nr;
|
||||||
|
|
||||||
if (info->si_code != SYS_SECCOMP)
|
if (info->si_code != SYS_SECCOMP)
|
||||||
@ -1321,24 +1311,11 @@ sigsys_debugging(int nr, siginfo_t *info, void *void_context)
|
|||||||
|
|
||||||
syscall = ctx->uc_mcontext.gregs[REG_SYSCALL];
|
syscall = ctx->uc_mcontext.gregs[REG_SYSCALL];
|
||||||
|
|
||||||
strlcpy(message, "\n\n(Sandbox) Caught a bad syscall attempt (syscall 0x",
|
format_dec_number_sigsafe(syscall, number, sizeof(number));
|
||||||
sizeof(message));
|
tor_log_err_sigsafe("(Sandbox) Caught a bad syscall attempt (syscall ",
|
||||||
(void) format_hex_number_sigsafe(syscall, message+strlen(message),
|
number,
|
||||||
sizeof(message)-strlen(message));
|
")\n",
|
||||||
strlcat(message, ")\n", sizeof(message));
|
NULL);
|
||||||
length = strlen(message);
|
|
||||||
|
|
||||||
err = 0;
|
|
||||||
if (sigsys_debugging_fd >= 0) {
|
|
||||||
rv = write(sigsys_debugging_fd, message, length);
|
|
||||||
err += rv != length;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = write(STDOUT_FILENO, message, length);
|
|
||||||
err += rv != length;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
_exit(2);
|
|
||||||
|
|
||||||
#if defined(DEBUGGING_CLOSE)
|
#if defined(DEBUGGING_CLOSE)
|
||||||
_exit(1);
|
_exit(1);
|
||||||
@ -1453,16 +1430,6 @@ sandbox_init(sandbox_cfg_t *cfg)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
sandbox_set_debugging_fd(int fd)
|
|
||||||
{
|
|
||||||
#ifdef USE_LIBSECCOMP
|
|
||||||
sigsys_set_debugging_fd(fd);
|
|
||||||
#else
|
|
||||||
(void)fd;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef USE_LIBSECCOMP
|
#ifndef USE_LIBSECCOMP
|
||||||
int
|
int
|
||||||
sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file,
|
sandbox_cfg_allow_open_filename(sandbox_cfg_t **cfg, char *file,
|
||||||
|
@ -153,9 +153,6 @@ int sandbox_getaddrinfo(const char *name, const char *servname,
|
|||||||
((void)(name))
|
((void)(name))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Use <b>fd</b> to log non-survivable sandbox violations. */
|
|
||||||
void sandbox_set_debugging_fd(int fd);
|
|
||||||
|
|
||||||
#ifdef USE_LIBSECCOMP
|
#ifdef USE_LIBSECCOMP
|
||||||
/** Returns a registered protected string used with the sandbox, given that
|
/** Returns a registered protected string used with the sandbox, given that
|
||||||
* it matches the parameter.
|
* it matches the parameter.
|
||||||
|
@ -102,6 +102,9 @@
|
|||||||
/** This log message is not safe to send to a callback-based logger
|
/** This log message is not safe to send to a callback-based logger
|
||||||
* immediately. Used as a flag, not a log domain. */
|
* immediately. Used as a flag, not a log domain. */
|
||||||
#define LD_NOCB (1u<<31)
|
#define LD_NOCB (1u<<31)
|
||||||
|
/** This log message should not include a function name, even if it otherwise
|
||||||
|
* would. Used as a flag, not a log domain. */
|
||||||
|
#define LD_NOFUNCNAME (1u<<30)
|
||||||
|
|
||||||
/** Mask of zero or more log domains, OR'd together. */
|
/** Mask of zero or more log domains, OR'd together. */
|
||||||
typedef uint32_t log_domain_mask_t;
|
typedef uint32_t log_domain_mask_t;
|
||||||
@ -136,7 +139,6 @@ int get_min_log_level(void);
|
|||||||
void switch_logs_debug(void);
|
void switch_logs_debug(void);
|
||||||
void logs_free_all(void);
|
void logs_free_all(void);
|
||||||
void add_temp_log(int min_severity);
|
void add_temp_log(int min_severity);
|
||||||
int get_err_logging_fd(void);
|
|
||||||
void close_temp_logs(void);
|
void close_temp_logs(void);
|
||||||
void rollback_log_changes(void);
|
void rollback_log_changes(void);
|
||||||
void mark_logs_temp(void);
|
void mark_logs_temp(void);
|
||||||
@ -149,6 +151,10 @@ void set_log_time_granularity(int granularity_msec);
|
|||||||
void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
|
void tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
|
||||||
CHECK_PRINTF(3,4);
|
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);
|
||||||
|
|
||||||
#if defined(__GNUC__) || defined(RUNNING_DOXYGEN)
|
#if defined(__GNUC__) || defined(RUNNING_DOXYGEN)
|
||||||
extern int log_global_min_severity_;
|
extern int log_global_min_severity_;
|
||||||
|
|
||||||
|
@ -24,7 +24,8 @@
|
|||||||
#include "torint.h"
|
#include "torint.h"
|
||||||
#include "container.h"
|
#include "container.h"
|
||||||
#include "address.h"
|
#include "address.h"
|
||||||
#include "../common/sandbox.h"
|
#include "sandbox.h"
|
||||||
|
#include "backtrace.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
@ -94,6 +95,23 @@
|
|||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* =====
|
||||||
|
* Assertion helper.
|
||||||
|
* ===== */
|
||||||
|
/** Helper for tor_assert: report the assertion failure. */
|
||||||
|
void
|
||||||
|
tor_assertion_failed_(const char *fname, unsigned int line,
|
||||||
|
const char *func, const char *expr)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
log_err(LD_BUG, "%s:%u: %s: Assertion %s failed; aborting.",
|
||||||
|
fname, line, func, expr);
|
||||||
|
tor_snprintf(buf, sizeof(buf),
|
||||||
|
"Assertion %s failed in %s at %s:%u",
|
||||||
|
expr, func, fname, line);
|
||||||
|
log_backtrace(LOG_ERR, LD_BUG, buf);
|
||||||
|
}
|
||||||
|
|
||||||
/* =====
|
/* =====
|
||||||
* Memory management
|
* Memory management
|
||||||
* ===== */
|
* ===== */
|
||||||
@ -3400,6 +3418,51 @@ tor_join_win_cmdline(const char *argv[])
|
|||||||
return joined_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 = x % radix;
|
||||||
|
tor_assert(cp > buf);
|
||||||
|
--cp;
|
||||||
|
*cp = "0123456789ABCDEF"[digit];
|
||||||
|
x /= radix;
|
||||||
|
} while (x);
|
||||||
|
|
||||||
|
/* NOT tor_assert; see above. */
|
||||||
|
if (cp != buf) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to output hex numbers from within a signal handler.
|
* Helper function to output hex numbers from within a signal handler.
|
||||||
*
|
*
|
||||||
@ -3422,45 +3485,16 @@ tor_join_win_cmdline(const char *argv[])
|
|||||||
* arbitrary C functions.
|
* arbitrary C functions.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
format_hex_number_sigsafe(unsigned int x, char *buf, int buf_len)
|
format_hex_number_sigsafe(unsigned long x, char *buf, int buf_len)
|
||||||
{
|
{
|
||||||
int len;
|
return format_number_sigsafe(x, buf, buf_len, 16);
|
||||||
unsigned int tmp;
|
}
|
||||||
char *cur;
|
|
||||||
|
|
||||||
/* Sanity check */
|
/** As format_hex_number_sigsafe, but format the number in base 10. */
|
||||||
if (!buf || buf_len <= 1)
|
int
|
||||||
return 0;
|
format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len)
|
||||||
|
{
|
||||||
/* How many chars do we need for x? */
|
return format_number_sigsafe(x, buf, buf_len, 10);
|
||||||
if (x > 0) {
|
|
||||||
len = 0;
|
|
||||||
tmp = x;
|
|
||||||
while (tmp > 0) {
|
|
||||||
tmp >>= 4;
|
|
||||||
++len;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
len = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bail if we would go past the end of the buffer */
|
|
||||||
if (len+1 > buf_len)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Point to last one */
|
|
||||||
cur = buf + len - 1;
|
|
||||||
|
|
||||||
/* Convert x to hex */
|
|
||||||
do {
|
|
||||||
*cur-- = "0123456789ABCDEF"[x & 0xf];
|
|
||||||
x >>= 4;
|
|
||||||
} while (x != 0 && cur >= buf);
|
|
||||||
|
|
||||||
buf[len] = '\0';
|
|
||||||
|
|
||||||
/* Return len */
|
|
||||||
return len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@ -5047,4 +5081,3 @@ tor_weak_random_range(tor_weak_rng_t *rng, int32_t top)
|
|||||||
} while (result >= top);
|
} while (result >= top);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,13 +48,13 @@
|
|||||||
/** Like assert(3), but send assertion failures to the log as well as to
|
/** Like assert(3), but send assertion failures to the log as well as to
|
||||||
* stderr. */
|
* stderr. */
|
||||||
#define tor_assert(expr) STMT_BEGIN \
|
#define tor_assert(expr) STMT_BEGIN \
|
||||||
if (PREDICT_UNLIKELY(!(expr))) { \
|
if (PREDICT_UNLIKELY(!(expr))) { \
|
||||||
log_err(LD_BUG, "%s:%d: %s: Assertion %s failed; aborting.", \
|
tor_assertion_failed_(SHORT_FILE__, __LINE__, __func__, #expr); \
|
||||||
SHORT_FILE__, __LINE__, __func__, #expr); \
|
abort(); \
|
||||||
fprintf(stderr,"%s:%d %s: Assertion %s failed; aborting.\n", \
|
} STMT_END
|
||||||
SHORT_FILE__, __LINE__, __func__, #expr); \
|
|
||||||
abort(); \
|
void tor_assertion_failed_(const char *fname, unsigned int line,
|
||||||
} STMT_END
|
const char *func, const char *expr);
|
||||||
|
|
||||||
/* If we're building with dmalloc, we want all of our memory allocation
|
/* If we're building with dmalloc, we want all of our memory allocation
|
||||||
* functions to take an extra file/line pair of arguments. If not, not.
|
* functions to take an extra file/line pair of arguments. If not, not.
|
||||||
@ -524,7 +524,8 @@ int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top);
|
|||||||
* <b>n</b> */
|
* <b>n</b> */
|
||||||
#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n)))
|
#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n)))
|
||||||
|
|
||||||
int format_hex_number_sigsafe(unsigned int x, char *buf, int max_len);
|
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
|
#ifdef UTIL_PRIVATE
|
||||||
/* Prototypes for private functions only used by util.c (and unit tests) */
|
/* Prototypes for private functions only used by util.c (and unit tests) */
|
||||||
|
@ -1161,8 +1161,6 @@ options_act_reversible(const or_options_t *old_options, char **msg)
|
|||||||
goto rollback;
|
goto rollback;
|
||||||
}
|
}
|
||||||
|
|
||||||
sandbox_set_debugging_fd(get_err_logging_fd());
|
|
||||||
|
|
||||||
commit:
|
commit:
|
||||||
r = 0;
|
r = 0;
|
||||||
if (logs_marked) {
|
if (logs_marked) {
|
||||||
@ -1172,6 +1170,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
|
|||||||
add_callback_log(severity, control_event_logmsg);
|
add_callback_log(severity, control_event_logmsg);
|
||||||
control_adjust_event_log_severity();
|
control_adjust_event_log_severity();
|
||||||
tor_free(severity);
|
tor_free(severity);
|
||||||
|
tor_log_update_sigsafe_err_fds();
|
||||||
}
|
}
|
||||||
if (get_min_log_level() >= LOG_INFO &&
|
if (get_min_log_level() >= LOG_INFO &&
|
||||||
get_min_log_level() != old_min_log_level) {
|
get_min_log_level() != old_min_log_level) {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#define MAIN_PRIVATE
|
#define MAIN_PRIVATE
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
#include "addressmap.h"
|
#include "addressmap.h"
|
||||||
|
#include "backtrace.h"
|
||||||
#include "buffers.h"
|
#include "buffers.h"
|
||||||
#include "channel.h"
|
#include "channel.h"
|
||||||
#include "channeltls.h"
|
#include "channeltls.h"
|
||||||
@ -2330,13 +2331,14 @@ handle_signals(int is_parent)
|
|||||||
int
|
int
|
||||||
tor_init(int argc, char *argv[])
|
tor_init(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char buf[256];
|
char progname[256];
|
||||||
int quiet = 0;
|
int quiet = 0;
|
||||||
|
|
||||||
time_of_process_start = time(NULL);
|
time_of_process_start = time(NULL);
|
||||||
init_connection_lists();
|
init_connection_lists();
|
||||||
/* Have the log set up with our application name. */
|
/* Have the log set up with our application name. */
|
||||||
tor_snprintf(buf, sizeof(buf), "Tor %s", get_version());
|
tor_snprintf(progname, sizeof(progname), "Tor %s", get_version());
|
||||||
log_set_application_name(buf);
|
log_set_application_name(progname);
|
||||||
/* Initialize the history structures. */
|
/* Initialize the history structures. */
|
||||||
rep_hist_init();
|
rep_hist_init();
|
||||||
/* Initialize the service cache. */
|
/* Initialize the service cache. */
|
||||||
@ -2839,6 +2841,8 @@ tor_main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
configure_backtrace_handler(get_version());
|
||||||
|
|
||||||
update_approx_time(time(NULL));
|
update_approx_time(time(NULL));
|
||||||
tor_threads_init();
|
tor_threads_init();
|
||||||
init_logging();
|
init_logging();
|
||||||
|
42
src/test/bt_test.py
Executable file
42
src/test/bt_test.py
Executable file
@ -0,0 +1,42 @@
|
|||||||
|
# Copyright 2013, The Tor Project, Inc
|
||||||
|
# See LICENSE for licensing information
|
||||||
|
|
||||||
|
"""
|
||||||
|
bt_test.py
|
||||||
|
|
||||||
|
This file tests the output from test-bt-cl to make sure it's as expected.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
$ ./src/test/test-bt-cl crash | ./src/test/bt_test.py
|
||||||
|
OK
|
||||||
|
$ ./src/test/test-bt-cl assert | ./src/test/bt_test.py
|
||||||
|
OK
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def matches(lines, funcs):
|
||||||
|
if len(lines) < len(funcs):
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
for l, f in zip(lines, funcs):
|
||||||
|
l.index(f)
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
FUNCNAMES = "crash oh_what a_tangled_web we_weave main".split()
|
||||||
|
|
||||||
|
LINES = sys.stdin.readlines()
|
||||||
|
|
||||||
|
for I in range(len(LINES)):
|
||||||
|
if matches(LINES[I:], FUNCNAMES):
|
||||||
|
print "OK"
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print "BAD"
|
||||||
|
|
@ -30,6 +30,7 @@ src_test_test_SOURCES = \
|
|||||||
src/test/test_dir.c \
|
src/test/test_dir.c \
|
||||||
src/test/test_extorport.c \
|
src/test/test_extorport.c \
|
||||||
src/test/test_introduce.c \
|
src/test/test_introduce.c \
|
||||||
|
src/test/test_logging.c \
|
||||||
src/test/test_microdesc.c \
|
src/test/test_microdesc.c \
|
||||||
src/test/test_options.c \
|
src/test/test_options.c \
|
||||||
src/test/test_pt.c \
|
src/test/test_pt.c \
|
||||||
@ -86,6 +87,15 @@ else
|
|||||||
CMDLINE_TEST_TOR = ./src/or/tor
|
CMDLINE_TEST_TOR = ./src/or/tor
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
noinst_PROGRAMS += src/test/test-bt-cl
|
||||||
|
src_test_test_bt_cl_SOURCES = src/test/test_bt_cl.c
|
||||||
|
src_test_test_bt_cl_LDADD = src/common/libor-testing.a \
|
||||||
|
@TOR_LIB_MATH@ \
|
||||||
|
@TOR_LIB_WS32@ @TOR_LIB_GDI@
|
||||||
|
src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||||
|
src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS)
|
||||||
|
|
||||||
|
|
||||||
check-local: $(NTOR_TEST_DEPS) $(CMDLINE_TEST_TOR)
|
check-local: $(NTOR_TEST_DEPS) $(CMDLINE_TEST_TOR)
|
||||||
if USEPYTHON
|
if USEPYTHON
|
||||||
$(PYTHON) $(top_srcdir)/src/test/test_cmdline_args.py $(CMDLINE_TEST_TOR) "${top_srcdir}"
|
$(PYTHON) $(top_srcdir)/src/test/test_cmdline_args.py $(CMDLINE_TEST_TOR) "${top_srcdir}"
|
||||||
@ -93,4 +103,6 @@ if CURVE25519_ENABLED
|
|||||||
$(PYTHON) $(top_srcdir)/src/test/ntor_ref.py test-tor
|
$(PYTHON) $(top_srcdir)/src/test/ntor_ref.py test-tor
|
||||||
$(PYTHON) $(top_srcdir)/src/test/ntor_ref.py self-test
|
$(PYTHON) $(top_srcdir)/src/test/ntor_ref.py self-test
|
||||||
endif
|
endif
|
||||||
|
./src/test/test-bt-cl assert | $(PYTHON) $(top_srcdir)/src/test/bt_test.py
|
||||||
|
./src/test/test-bt-cl crash | $(PYTHON) $(top_srcdir)/src/test/bt_test.py
|
||||||
endif
|
endif
|
||||||
|
@ -1621,6 +1621,8 @@ extern struct testcase_t options_tests[];
|
|||||||
extern struct testcase_t socks_tests[];
|
extern struct testcase_t socks_tests[];
|
||||||
extern struct testcase_t extorport_tests[];
|
extern struct testcase_t extorport_tests[];
|
||||||
extern struct testcase_t controller_event_tests[];
|
extern struct testcase_t controller_event_tests[];
|
||||||
|
extern struct testcase_t logging_tests[];
|
||||||
|
extern struct testcase_t backtrace_tests[];
|
||||||
|
|
||||||
static struct testgroup_t testgroups[] = {
|
static struct testgroup_t testgroups[] = {
|
||||||
{ "", test_array },
|
{ "", test_array },
|
||||||
@ -1630,6 +1632,7 @@ static struct testgroup_t testgroups[] = {
|
|||||||
{ "crypto/", crypto_tests },
|
{ "crypto/", crypto_tests },
|
||||||
{ "container/", container_tests },
|
{ "container/", container_tests },
|
||||||
{ "util/", util_tests },
|
{ "util/", util_tests },
|
||||||
|
{ "util/logging/", logging_tests },
|
||||||
{ "cellfmt/", cell_format_tests },
|
{ "cellfmt/", cell_format_tests },
|
||||||
{ "cellqueue/", cell_queue_tests },
|
{ "cellqueue/", cell_queue_tests },
|
||||||
{ "dir/", dir_tests },
|
{ "dir/", dir_tests },
|
||||||
|
110
src/test/test_bt_cl.c
Normal file
110
src/test/test_bt_cl.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/* Copyright (c) 2012-2013, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "or.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "backtrace.h"
|
||||||
|
#include "torlog.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* -1: no crash.
|
||||||
|
* 0: crash with a segmentation fault.
|
||||||
|
* 1x: crash with an assertion failure. */
|
||||||
|
static int crashtype = 0;
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define NOINLINE __attribute__((noinline))
|
||||||
|
#define NORETURN __attribute__((noreturn))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int crash(int x) NOINLINE;
|
||||||
|
int oh_what(int x) NOINLINE;
|
||||||
|
int a_tangled_web(int x) NOINLINE;
|
||||||
|
int we_weave(int x) NOINLINE;
|
||||||
|
static void abort_handler(int s) NORETURN;
|
||||||
|
|
||||||
|
int
|
||||||
|
crash(int x)
|
||||||
|
{
|
||||||
|
if (crashtype == 0) {
|
||||||
|
*(volatile int *)0 = 0;
|
||||||
|
} else if (crashtype == 1) {
|
||||||
|
tor_assert(1 == 0);
|
||||||
|
} else if (crashtype == -1) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
crashtype *= x;
|
||||||
|
return crashtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
oh_what(int x)
|
||||||
|
{
|
||||||
|
/* We call crash() twice here, so that the compiler won't try to do a
|
||||||
|
* tail-call optimization. Only the first call will actually happen, but
|
||||||
|
* telling the compiler to maybe do the second call will prevent it from
|
||||||
|
* replacing the first call with a jump. */
|
||||||
|
return crash(x) + crash(x*2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
a_tangled_web(int x)
|
||||||
|
{
|
||||||
|
return oh_what(x) * 99 + oh_what(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
we_weave(int x)
|
||||||
|
{
|
||||||
|
return a_tangled_web(x) + a_tangled_web(x+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
abort_handler(int s)
|
||||||
|
{
|
||||||
|
(void)s;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
log_severity_list_t severity;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
puts("I take an argument. It should be \"assert\" or \"crash\" or "
|
||||||
|
"\"none\"");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!strcmp(argv[1], "assert")) {
|
||||||
|
crashtype = 1;
|
||||||
|
} else if (!strcmp(argv[1], "crash")) {
|
||||||
|
crashtype = 0;
|
||||||
|
} else if (!strcmp(argv[1], "none")) {
|
||||||
|
crashtype = -1;
|
||||||
|
} else {
|
||||||
|
puts("Argument should be \"assert\" or \"crash\" or \"none\"");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_logging();
|
||||||
|
set_log_severity_config(LOG_WARN, LOG_ERR, &severity);
|
||||||
|
add_stream_log(&severity, "stdout", STDOUT_FILENO);
|
||||||
|
tor_log_update_sigsafe_err_fds();
|
||||||
|
|
||||||
|
configure_backtrace_handler(NULL);
|
||||||
|
|
||||||
|
signal(SIGABRT, abort_handler);
|
||||||
|
|
||||||
|
printf("%d\n", we_weave(2));
|
||||||
|
|
||||||
|
clean_up_backtrace_handler();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
135
src/test/test_logging.c
Normal file
135
src/test/test_logging.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/* Copyright (c) 2013, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
#include "or.h"
|
||||||
|
#include "torlog.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
dummy_cb_fn(int severity, uint32_t domain, const char *msg)
|
||||||
|
{
|
||||||
|
(void)severity; (void)domain; (void)msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_get_sigsafe_err_fds(void *arg)
|
||||||
|
{
|
||||||
|
const int *fds;
|
||||||
|
int n;
|
||||||
|
log_severity_list_t include_bug, no_bug, no_bug2;
|
||||||
|
(void) arg;
|
||||||
|
init_logging();
|
||||||
|
|
||||||
|
n = tor_log_get_sigsafe_err_fds(&fds);
|
||||||
|
tt_int_op(n, ==, 1);
|
||||||
|
tt_int_op(fds[0], ==, STDERR_FILENO);
|
||||||
|
|
||||||
|
set_log_severity_config(LOG_WARN, LOG_ERR, &include_bug);
|
||||||
|
set_log_severity_config(LOG_WARN, LOG_ERR, &no_bug);
|
||||||
|
no_bug.masks[0] &= ~(LD_BUG|LD_GENERAL);
|
||||||
|
set_log_severity_config(LOG_INFO, LOG_NOTICE, &no_bug2);
|
||||||
|
|
||||||
|
/* Add some logs; make sure the output is as expected. */
|
||||||
|
mark_logs_temp();
|
||||||
|
add_stream_log(&include_bug, "dummy-1", 3);
|
||||||
|
add_stream_log(&no_bug, "dummy-2", 4);
|
||||||
|
add_stream_log(&no_bug2, "dummy-3", 5);
|
||||||
|
add_callback_log(&include_bug, dummy_cb_fn);
|
||||||
|
close_temp_logs();
|
||||||
|
tor_log_update_sigsafe_err_fds();
|
||||||
|
|
||||||
|
n = tor_log_get_sigsafe_err_fds(&fds);
|
||||||
|
tt_int_op(n, ==, 2);
|
||||||
|
tt_int_op(fds[0], ==, STDERR_FILENO);
|
||||||
|
tt_int_op(fds[1], ==, 3);
|
||||||
|
|
||||||
|
/* Allow STDOUT to replace STDERR. */
|
||||||
|
add_stream_log(&include_bug, "dummy-4", STDOUT_FILENO);
|
||||||
|
tor_log_update_sigsafe_err_fds();
|
||||||
|
n = tor_log_get_sigsafe_err_fds(&fds);
|
||||||
|
tt_int_op(n, ==, 2);
|
||||||
|
tt_int_op(fds[0], ==, 3);
|
||||||
|
tt_int_op(fds[1], ==, STDOUT_FILENO);
|
||||||
|
|
||||||
|
/* But don't allow it to replace explicit STDERR. */
|
||||||
|
add_stream_log(&include_bug, "dummy-5", STDERR_FILENO);
|
||||||
|
tor_log_update_sigsafe_err_fds();
|
||||||
|
n = tor_log_get_sigsafe_err_fds(&fds);
|
||||||
|
tt_int_op(n, ==, 3);
|
||||||
|
tt_int_op(fds[0], ==, STDERR_FILENO);
|
||||||
|
tt_int_op(fds[1], ==, STDOUT_FILENO);
|
||||||
|
tt_int_op(fds[2], ==, 3);
|
||||||
|
|
||||||
|
/* Don't overflow the array. */
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=5; i<20; ++i) {
|
||||||
|
add_stream_log(&include_bug, "x-dummy", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tor_log_update_sigsafe_err_fds();
|
||||||
|
n = tor_log_get_sigsafe_err_fds(&fds);
|
||||||
|
tt_int_op(n, ==, 8);
|
||||||
|
|
||||||
|
done:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_sigsafe_err(void *arg)
|
||||||
|
{
|
||||||
|
const char *fn=get_fname("sigsafe_err_log");
|
||||||
|
char *content=NULL;
|
||||||
|
log_severity_list_t include_bug;
|
||||||
|
smartlist_t *lines = smartlist_new();
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
set_log_severity_config(LOG_WARN, LOG_ERR, &include_bug);
|
||||||
|
|
||||||
|
init_logging();
|
||||||
|
mark_logs_temp();
|
||||||
|
add_file_log(&include_bug, fn);
|
||||||
|
tor_log_update_sigsafe_err_fds();
|
||||||
|
close_temp_logs();
|
||||||
|
|
||||||
|
close(STDERR_FILENO);
|
||||||
|
log_err(LD_BUG, "Say, this isn't too cool.");
|
||||||
|
tor_log_err_sigsafe("Minimal.\n", NULL);
|
||||||
|
|
||||||
|
set_log_time_granularity(100*1000);
|
||||||
|
tor_log_err_sigsafe("Testing any ",
|
||||||
|
"attempt to manually log ",
|
||||||
|
"from a signal.\n",
|
||||||
|
NULL);
|
||||||
|
mark_logs_temp();
|
||||||
|
close_temp_logs();
|
||||||
|
close(STDERR_FILENO);
|
||||||
|
content = read_file_to_str(fn, 0, NULL);
|
||||||
|
|
||||||
|
tt_assert(content != NULL);
|
||||||
|
tor_split_lines(lines, content, (int)strlen(content));
|
||||||
|
tt_int_op(smartlist_len(lines), >=, 5);
|
||||||
|
|
||||||
|
if (strstr(smartlist_get(lines, 0), "opening new log file"))
|
||||||
|
smartlist_del_keeporder(lines, 0);
|
||||||
|
tt_assert(strstr(smartlist_get(lines, 0), "Say, this isn't too cool"));
|
||||||
|
/* Next line is blank. */
|
||||||
|
tt_assert(!strcmpstart(smartlist_get(lines, 1), "=============="));
|
||||||
|
tt_assert(!strcmpstart(smartlist_get(lines, 2), "Minimal."));
|
||||||
|
/* Next line is blank. */
|
||||||
|
tt_assert(!strcmpstart(smartlist_get(lines, 3), "=============="));
|
||||||
|
tt_str_op(smartlist_get(lines, 4), ==,
|
||||||
|
"Testing any attempt to manually log from a signal.");
|
||||||
|
|
||||||
|
done:
|
||||||
|
tor_free(content);
|
||||||
|
smartlist_free(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct testcase_t logging_tests[] = {
|
||||||
|
{ "sigsafe_err_fds", test_get_sigsafe_err_fds, TT_FORK, NULL, NULL },
|
||||||
|
{ "sigsafe_err", test_sigsafe_err, TT_FORK, NULL, NULL },
|
||||||
|
END_OF_TESTCASES
|
||||||
|
};
|
||||||
|
|
@ -2778,6 +2778,56 @@ test_util_format_hex_number(void *ptr)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for format_hex_number_sigsafe()
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_util_format_dec_number(void *ptr)
|
||||||
|
{
|
||||||
|
int i, len;
|
||||||
|
char buf[33];
|
||||||
|
const struct {
|
||||||
|
const char *str;
|
||||||
|
unsigned int x;
|
||||||
|
} test_data[] = {
|
||||||
|
{"0", 0},
|
||||||
|
{"1", 1},
|
||||||
|
{"1234", 1234},
|
||||||
|
{"12345678", 12345678},
|
||||||
|
{"99999999", 99999999},
|
||||||
|
{"100000000", 100000000},
|
||||||
|
{"4294967295", 4294967295u},
|
||||||
|
#if UINT_MAX > 0xffffffff
|
||||||
|
{"18446744073709551615", 18446744073709551615u },
|
||||||
|
#endif
|
||||||
|
{NULL, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
(void)ptr;
|
||||||
|
|
||||||
|
for (i = 0; test_data[i].str != NULL; ++i) {
|
||||||
|
len = format_dec_number_sigsafe(test_data[i].x, buf, sizeof(buf));
|
||||||
|
test_neq(len, 0);
|
||||||
|
test_eq(len, strlen(buf));
|
||||||
|
test_streq(buf, test_data[i].str);
|
||||||
|
|
||||||
|
len = format_dec_number_sigsafe(test_data[i].x, buf,
|
||||||
|
(int)(strlen(test_data[i].str) + 1));
|
||||||
|
test_eq(len, strlen(buf));
|
||||||
|
test_streq(buf, test_data[i].str);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_eq(4, format_dec_number_sigsafe(7331, buf, 5));
|
||||||
|
test_streq(buf, "7331");
|
||||||
|
test_eq(0, format_dec_number_sigsafe(7331, buf, 4));
|
||||||
|
test_eq(1, format_dec_number_sigsafe(0, buf, 2));
|
||||||
|
test_eq(0, format_dec_number_sigsafe(0, buf, 1));
|
||||||
|
|
||||||
|
done:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that we can properly format a Windows command line
|
* Test that we can properly format a Windows command line
|
||||||
*/
|
*/
|
||||||
@ -3598,6 +3648,7 @@ struct testcase_t util_tests[] = {
|
|||||||
UTIL_TEST(spawn_background_fail, 0),
|
UTIL_TEST(spawn_background_fail, 0),
|
||||||
UTIL_TEST(spawn_background_partial_read, 0),
|
UTIL_TEST(spawn_background_partial_read, 0),
|
||||||
UTIL_TEST(format_hex_number, 0),
|
UTIL_TEST(format_hex_number, 0),
|
||||||
|
UTIL_TEST(format_dec_number, 0),
|
||||||
UTIL_TEST(join_win_cmdline, 0),
|
UTIL_TEST(join_win_cmdline, 0),
|
||||||
UTIL_TEST(split_lines, 0),
|
UTIL_TEST(split_lines, 0),
|
||||||
UTIL_TEST(n_bits_set, 0),
|
UTIL_TEST(n_bits_set, 0),
|
||||||
|
Loading…
Reference in New Issue
Block a user