Switch from libunwind to boost::stacktrace
This commit is contained in:
parent
62862933e2
commit
276e7f08e4
|
@ -86,60 +86,16 @@ references:
|
||||||
cmake --version
|
cmake --version
|
||||||
/usr/local/bin/$CC --version
|
/usr/local/bin/$CC --version
|
||||||
/usr/local/bin/$CXX --version
|
/usr/local/bin/$CXX --version
|
||||||
upgrade_libunwind_pre: &upgrade_libunwind_pre
|
|
||||||
restore_cache:
|
|
||||||
keys:
|
|
||||||
# Find the most recent cache from any branch
|
|
||||||
- v1_upgrade_libunwind_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }}
|
|
||||||
upgrade_libunwind_post: &upgrade_libunwind_post
|
|
||||||
save_cache:
|
|
||||||
key: v1_upgrade_libunwind_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }}
|
|
||||||
paths:
|
|
||||||
- /tmp/libunwind-1.2.1
|
|
||||||
upgrade_libunwind: &upgrade_libunwind
|
|
||||||
run:
|
|
||||||
name: Upgrade Libunwind
|
|
||||||
command: |
|
|
||||||
# We need to install libunwind manually because Circle CI uses Ubuntu 14.04 and the default libunwind version
|
|
||||||
# on that Ubuntu suffers from http://savannah.nongnu.org/bugs/?43752.
|
|
||||||
# This isn't an issue for any later version of Ubuntu.
|
|
||||||
|
|
||||||
# Detect number of CPU cores
|
|
||||||
export NUMCORES=`nproc`
|
|
||||||
echo Using $NUMCORES cores
|
|
||||||
# Download and prepare libunwind (only if not already present from cache)
|
|
||||||
if [ ! -d "/tmp/libunwind-1.2.1" ]; then
|
|
||||||
echo "Didn't find libunwind in cache. Downloading and building."
|
|
||||||
wget -O /tmp/libunwind-1.2.1.tar.gz http://download.savannah.nongnu.org/releases/libunwind/libunwind-1.2.1.tar.gz
|
|
||||||
if [ $(sha512sum /tmp/libunwind-1.2.1.tar.gz | awk '{print $1;}') == "af7c280d2a963779a4a2711887618bc96383011e4e5d52e4085aa7fb351e55e357468f6ff85e66a216f1c6826538f498335a917a5970575c93be74c96316319b" ]; then
|
|
||||||
echo Correct sha512sum
|
|
||||||
else
|
|
||||||
echo Wrong sha512sum
|
|
||||||
sha512sum /tmp/libunwind-1.2.1.tar.gz
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo Extracting...
|
|
||||||
tar -xf /tmp/libunwind-1.2.1.tar.gz -C /tmp
|
|
||||||
rm -rf /tmp/libunwind-1.2.1.tar.gz
|
|
||||||
cd /tmp/libunwind-1.2.1
|
|
||||||
./configure
|
|
||||||
make -j${NUMCORES}
|
|
||||||
else
|
|
||||||
echo Found libunwind in cache. Use cache and build.
|
|
||||||
fi
|
|
||||||
# Compile and install libunwind (if cached, this should be fast)
|
|
||||||
cd /tmp/libunwind-1.2.1
|
|
||||||
sudo make -j${NUMCORES} install
|
|
||||||
upgrade_boost_pre: &upgrade_boost_pre
|
upgrade_boost_pre: &upgrade_boost_pre
|
||||||
restore_cache:
|
restore_cache:
|
||||||
keys:
|
keys:
|
||||||
# Find the most recent cache from any branch
|
# Find the most recent cache from any branch
|
||||||
- v3_upgrade_boost_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }}
|
- v4_upgrade_boost_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }}
|
||||||
upgrade_boost_post: &upgrade_boost_post
|
upgrade_boost_post: &upgrade_boost_post
|
||||||
save_cache:
|
save_cache:
|
||||||
key: v3_upgrade_boost_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }}
|
key: v4_upgrade_boost_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }}
|
||||||
paths:
|
paths:
|
||||||
- /tmp/boost_1_57_0
|
- /tmp/boost_1_65_1
|
||||||
upgrade_boost: &upgrade_boost
|
upgrade_boost: &upgrade_boost
|
||||||
run:
|
run:
|
||||||
name: Upgrade Boost
|
name: Upgrade Boost
|
||||||
|
@ -148,10 +104,10 @@ references:
|
||||||
export NUMCORES=`nproc`
|
export NUMCORES=`nproc`
|
||||||
echo Using $NUMCORES cores
|
echo Using $NUMCORES cores
|
||||||
# Download and prepare boost (only if not already present from cache)
|
# Download and prepare boost (only if not already present from cache)
|
||||||
if [ ! -d "/tmp/boost_1_57_0" ]; then
|
if [ ! -d "/tmp/boost_1_65_1" ]; then
|
||||||
echo "Didn't find boost in cache. Downloading and building."
|
echo "Didn't find boost in cache. Downloading and building."
|
||||||
wget -O /tmp/boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.57.0/boost_1_57_0.tar.bz2/download
|
wget -O /tmp/boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.65.1/boost_1_65_1.tar.bz2/download
|
||||||
if [ $(sha512sum /tmp/boost.tar.bz2 | awk '{print $1;}') == "61881440fd89644c43c6e3bc6292e9fed75a6d3a76f98654b189d0ed4e1087d77b585884e882270c08bf9f7132b173bfc1fde05848e06aa78ba7f1008d10714d" ]; then
|
if [ $(sha512sum /tmp/boost.tar.bz2 | awk '{print $1;}') == "a9e6866d3bb3e7c198f442ff09f5322f58064dca79bc420f2f0168eb63964226dfbc4f034a5a5e5958281fdf7518a1b057c894fbda0b61fced59c1661bf30f1a" ]; then
|
||||||
echo Correct sha512sum
|
echo Correct sha512sum
|
||||||
else
|
else
|
||||||
echo Wrong sha512sum
|
echo Wrong sha512sum
|
||||||
|
@ -161,14 +117,14 @@ references:
|
||||||
echo Extracting...
|
echo Extracting...
|
||||||
tar -xf /tmp/boost.tar.bz2 -C /tmp
|
tar -xf /tmp/boost.tar.bz2 -C /tmp
|
||||||
rm -rf boost.tar.bz2
|
rm -rf boost.tar.bz2
|
||||||
cd /tmp/boost_1_57_0
|
cd /tmp/boost_1_65_1
|
||||||
./bootstrap.sh --with-toolset=${BUILD_TOOLSET} --with-libraries=filesystem,thread,chrono,program_options
|
./bootstrap.sh --with-toolset=${BUILD_TOOLSET} --with-libraries=filesystem,thread,chrono,program_options
|
||||||
cd ..
|
cd ..
|
||||||
else
|
else
|
||||||
echo Found boost in cache. Use cache and build.
|
echo Found boost in cache. Use cache and build.
|
||||||
fi
|
fi
|
||||||
# Compile and install boost (if cached, this should be fast)
|
# Compile and install boost (if cached, this should be fast)
|
||||||
cd /tmp/boost_1_57_0
|
cd /tmp/boost_1_65_1
|
||||||
sudo ./b2 toolset=${BUILD_TOOLSET} link=static cxxflags=-fPIC -d0 -j$NUMCORES install
|
sudo ./b2 toolset=${BUILD_TOOLSET} link=static cxxflags=-fPIC -d0 -j$NUMCORES install
|
||||||
build_pre: &build_pre
|
build_pre: &build_pre
|
||||||
restore_cache:
|
restore_cache:
|
||||||
|
@ -233,9 +189,6 @@ references:
|
||||||
- <<: *container_setup_pre
|
- <<: *container_setup_pre
|
||||||
- <<: *container_setup
|
- <<: *container_setup
|
||||||
- <<: *container_setup_post
|
- <<: *container_setup_post
|
||||||
- <<: *upgrade_libunwind_pre
|
|
||||||
- <<: *upgrade_libunwind
|
|
||||||
- <<: *upgrade_libunwind_post
|
|
||||||
- <<: *upgrade_boost_pre
|
- <<: *upgrade_boost_pre
|
||||||
- <<: *upgrade_boost
|
- <<: *upgrade_boost
|
||||||
- <<: *upgrade_boost_post
|
- <<: *upgrade_boost_post
|
||||||
|
@ -514,7 +467,7 @@ jobs:
|
||||||
OMP_NUM_THREADS: "1"
|
OMP_NUM_THREADS: "1"
|
||||||
CXXFLAGS: "-O2 -fsanitize=thread -fno-omit-frame-pointer"
|
CXXFLAGS: "-O2 -fsanitize=thread -fno-omit-frame-pointer"
|
||||||
BUILD_TYPE: "Debug"
|
BUILD_TYPE: "Debug"
|
||||||
GTEST_ARGS: "--gtest_filter=-LoggingTest.LoggingAlsoWorksAfterFork:AssertTest_DebugBuild.*:SignalCatcherTest.*_thenDies:SignalHandlerTest.*_thenDies:SignalHandlerTest.givenMultipleSigIntHandlers_whenRaising_thenCatchesCorrectSignal:CliTest_Setup.*:CliTest_IntegrityCheck.*:*/CliTest_WrongEnvironment.*:CliTest_Unmount.*"
|
GTEST_ARGS: "--gtest_filter=-LoggingTest.LoggingAlsoWorksAfterFork:AssertTest_*:BacktraceTest.*:SignalCatcherTest.*_thenDies:SignalHandlerTest.*_thenDies:SignalHandlerTest.givenMultipleSigIntHandlers_whenRaising_thenCatchesCorrectSignal:CliTest_Setup.*:CliTest_IntegrityCheck.*:*/CliTest_WrongEnvironment.*:CliTest_Unmount.*"
|
||||||
CMAKE_FLAGS: ""
|
CMAKE_FLAGS: ""
|
||||||
RUN_TESTS: true
|
RUN_TESTS: true
|
||||||
clang_tidy:
|
clang_tidy:
|
||||||
|
@ -524,9 +477,6 @@ jobs:
|
||||||
- <<: *container_setup_pre
|
- <<: *container_setup_pre
|
||||||
- <<: *container_setup
|
- <<: *container_setup
|
||||||
- <<: *container_setup_post
|
- <<: *container_setup_post
|
||||||
- <<: *upgrade_libunwind_pre
|
|
||||||
- <<: *upgrade_libunwind
|
|
||||||
- <<: *upgrade_libunwind_post
|
|
||||||
- <<: *upgrade_boost_pre
|
- <<: *upgrade_boost_pre
|
||||||
- <<: *upgrade_boost
|
- <<: *upgrade_boost
|
||||||
- <<: *upgrade_boost_post
|
- <<: *upgrade_boost_post
|
||||||
|
|
|
@ -7,7 +7,7 @@ Fixed bugs:
|
||||||
|
|
||||||
Compatibility:
|
Compatibility:
|
||||||
* Fixed some incompatibilities with systems using the musl libc
|
* Fixed some incompatibilities with systems using the musl libc
|
||||||
* Use libunwind instead of libbacktrace to build stack traces. This fixes a segfault issue with platforms using libexecinfo and is generally more portable.
|
* Use boost::stacktrace instead of libbacktrace to build stack traces. This fixes a segfault issue with platforms using libexecinfo and is generally more portable.
|
||||||
|
|
||||||
Other:
|
Other:
|
||||||
* Updated to crypto++ 8.1
|
* Updated to crypto++ 8.1
|
||||||
|
|
|
@ -46,7 +46,7 @@ Requirements
|
||||||
- GCC version >= 5.0 or Clang >= 4.0
|
- GCC version >= 5.0 or Clang >= 4.0
|
||||||
- CMake version >= 3.0
|
- CMake version >= 3.0
|
||||||
- libcurl4 (including development headers)
|
- libcurl4 (including development headers)
|
||||||
- Boost libraries version >= 1.57 (including development headers)
|
- Boost libraries version >= 1.65.1 (including development headers)
|
||||||
- filesystem
|
- filesystem
|
||||||
- system
|
- system
|
||||||
- chrono
|
- chrono
|
||||||
|
@ -56,15 +56,14 @@ Requirements
|
||||||
- libFUSE version >= 2.8.6 (including development headers), on Mac OS X instead install osxfuse from https://osxfuse.github.io/
|
- libFUSE version >= 2.8.6 (including development headers), on Mac OS X instead install osxfuse from https://osxfuse.github.io/
|
||||||
- Python >= 2.7
|
- Python >= 2.7
|
||||||
- OpenMP
|
- OpenMP
|
||||||
- Libunwind
|
|
||||||
|
|
||||||
You can use the following commands to install these requirements
|
You can use the following commands to install these requirements
|
||||||
|
|
||||||
# Ubuntu
|
# Ubuntu
|
||||||
$ sudo apt install git g++ cmake make libcurl4-openssl-dev libboost-filesystem-dev libboost-system-dev libboost-chrono-dev libboost-program-options-dev libboost-thread-dev libssl-dev libfuse-dev python libunwind-dev
|
$ sudo apt install git g++ cmake make libcurl4-openssl-dev libboost-filesystem-dev libboost-system-dev libboost-chrono-dev libboost-program-options-dev libboost-thread-dev libssl-dev libfuse-dev python
|
||||||
|
|
||||||
# Fedora
|
# Fedora
|
||||||
sudo dnf install git gcc-c++ cmake make libcurl-devel boost-devel boost-static openssl-devel fuse-devel python libunwind-devel
|
sudo dnf install git gcc-c++ cmake make libcurl-devel boost-devel boost-static openssl-devel fuse-devel python
|
||||||
|
|
||||||
# Macintosh
|
# Macintosh
|
||||||
brew install cmake boost openssl libomp
|
brew install cmake boost openssl libomp
|
||||||
|
|
|
@ -108,7 +108,7 @@ endfunction(target_enable_style_warnings)
|
||||||
function(target_add_boost TARGET)
|
function(target_add_boost TARGET)
|
||||||
# Load boost libraries
|
# Load boost libraries
|
||||||
if(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS)
|
if(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS)
|
||||||
# Many supported systems don't have boost >= 1.57. Better link it statically.
|
# Many supported systems don't have boost >= 1.65.1. Better link it statically.
|
||||||
message(STATUS "Boost will be statically linked")
|
message(STATUS "Boost will be statically linked")
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
else(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS)
|
else(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS)
|
||||||
|
@ -116,7 +116,7 @@ function(target_add_boost TARGET)
|
||||||
set(Boost_USE_STATIC_LIBS OFF)
|
set(Boost_USE_STATIC_LIBS OFF)
|
||||||
endif(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS)
|
endif(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS)
|
||||||
set(BOOST_THREAD_VERSION 4)
|
set(BOOST_THREAD_VERSION 4)
|
||||||
find_package(Boost 1.57.0
|
find_package(Boost 1.65.1
|
||||||
REQUIRED
|
REQUIRED
|
||||||
COMPONENTS ${ARGN})
|
COMPONENTS ${ARGN})
|
||||||
target_include_directories(${TARGET} SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
|
target_include_directories(${TARGET} SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
|
||||||
|
|
|
@ -63,12 +63,17 @@ add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC DbgHelp)
|
target_link_libraries(${PROJECT_NAME} PUBLIC DbgHelp)
|
||||||
elseif(NOT APPLE)
|
elseif (APPLE)
|
||||||
# note: We use the libunwind code on Apple, but we don't seem to need these lines to link against it.
|
target_compile_definitions(${PROJECT_NAME} PRIVATE BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED)
|
||||||
find_package(Libunwind REQUIRED)
|
else()
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE ${LIBUNWIND_INCLUDE_DIR})
|
find_program(ADDR2LINE addr2line)
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBUNWIND_LIBRARIES})
|
if ("${ADDR2LINE}" STREQUAL "ADDR2LINE-NOTFOUND")
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE ${LIBUNWIND_DEFINITIONS})
|
message(WARNING "addr2line not found. Backtraces will be reduced.")
|
||||||
|
else()
|
||||||
|
message(STATUS "addr2line found. Using it for backtraces.")
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE BOOST_STACKTRACE_USE_ADDR2LINE)
|
||||||
|
target_compile_definitions(${PROJECT_NAME} PRIVATE BOOST_STACKTRACE_ADDR2LINE_LOCATION=${ADDR2LINE})
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT MSVC)
|
if (NOT MSVC)
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER)
|
||||||
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <cxxabi.h>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "../logging/logging.h"
|
#include "../logging/logging.h"
|
||||||
#include <cpp-utils/process/SignalHandler.h>
|
#include <cpp-utils/process/SignalHandler.h>
|
||||||
|
|
||||||
#define UNW_LOCAL_ONLY
|
#include <boost/stacktrace.hpp>
|
||||||
#include <libunwind.h>
|
|
||||||
|
|
||||||
// TODO Add file and line number on non-windows
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::ostringstream;
|
using std::ostringstream;
|
||||||
|
@ -18,105 +14,36 @@ using namespace cpputils::logging;
|
||||||
|
|
||||||
namespace cpputils {
|
namespace cpputils {
|
||||||
|
|
||||||
namespace {
|
string backtrace() {
|
||||||
std::string demangle(const string &mangledName) {
|
std::ostringstream str;
|
||||||
string result;
|
str << boost::stacktrace::stacktrace();
|
||||||
int status = -10;
|
return str.str();
|
||||||
char *demangledName = nullptr;
|
|
||||||
try {
|
|
||||||
demangledName = abi::__cxa_demangle(mangledName.c_str(), NULL, NULL, &status);
|
|
||||||
if (status == 0) {
|
|
||||||
result = demangledName;
|
|
||||||
} else if (status == -2) {
|
|
||||||
// mangledName was not a c++ mangled name, probably because it's a C name like for static
|
|
||||||
// initialization or stuff. Let's just return the name instead.
|
|
||||||
result = mangledName;
|
|
||||||
} else {
|
|
||||||
// other error
|
|
||||||
result = "[demangling error " + std::to_string(status) + "]" + mangledName;
|
|
||||||
}
|
|
||||||
free(demangledName);
|
|
||||||
return result;
|
|
||||||
} catch (...) {
|
|
||||||
free(demangledName);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void pretty_print(std::ostringstream& str, unw_cursor_t* cursor) {
|
|
||||||
constexpr unsigned int MAXNAMELEN=256;
|
|
||||||
char name[MAXNAMELEN];
|
|
||||||
unw_word_t offp = 0, ip = 0;
|
|
||||||
|
|
||||||
int status = unw_get_reg(cursor, UNW_REG_IP, &ip);
|
|
||||||
if (0 != status) {
|
|
||||||
str << "[unw_get_reg error: " << status << "]: ";
|
|
||||||
} else {
|
|
||||||
str << "0x" << std::hex << ip << ": ";
|
|
||||||
}
|
|
||||||
|
|
||||||
status = unw_get_proc_name(cursor, name, MAXNAMELEN, &offp);
|
|
||||||
if (0 != status) {
|
|
||||||
str << "[unw_get_proc_name error: " << status << "]";
|
|
||||||
} else {
|
|
||||||
str << demangle(name);
|
|
||||||
}
|
|
||||||
str << " +0x" << std::hex << offp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string backtrace() {
|
|
||||||
std::ostringstream result;
|
|
||||||
|
|
||||||
unw_context_t uc;
|
|
||||||
int status = unw_getcontext(&uc);
|
|
||||||
if (0 != status) {
|
|
||||||
return "[unw_getcontext error: " + std::to_string(status) + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
unw_cursor_t cursor;
|
|
||||||
status = unw_init_local(&cursor, &uc);
|
|
||||||
if (0 != status) {
|
|
||||||
return "[unw_init_local error: " + std::to_string(status) + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
size_t line = 0;
|
|
||||||
while ((status = unw_step(&cursor)) > 0) {
|
|
||||||
result << "#" << std::dec << (line++) << " ";
|
|
||||||
pretty_print(result, &cursor);
|
|
||||||
result << "\n";
|
|
||||||
}
|
|
||||||
if (status != 0) {
|
|
||||||
result << "[unw_step error :" << status << "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void sigsegv_handler(int) {
|
void sigsegv_handler(int) {
|
||||||
LOG(ERR, "SIGSEGV\n{}", backtrace());
|
LOG(ERR, "SIGSEGV\n{}", backtrace());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
void sigill_handler(int) {
|
void sigill_handler(int) {
|
||||||
LOG(ERR, "SIGILL\n{}", backtrace());
|
LOG(ERR, "SIGILL\n{}", backtrace());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
void sigabrt_handler(int) {
|
void sigabrt_handler(int) {
|
||||||
LOG(ERR, "SIGABRT\n{}", backtrace());
|
LOG(ERR, "SIGABRT\n{}", backtrace());
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void showBacktraceOnCrash() {
|
void showBacktraceOnCrash() {
|
||||||
// the signal handler RAII objects will be initialized on first call (which will register the signal handler)
|
// the signal handler RAII objects will be initialized on first call (which will register the signal handler)
|
||||||
// and destroyed on program exit (which will unregister the signal handler)
|
// and destroyed on program exit (which will unregister the signal handler)
|
||||||
|
|
||||||
|
static SignalHandlerRAII<&sigsegv_handler> segv(SIGSEGV);
|
||||||
|
static SignalHandlerRAII<&sigabrt_handler> abrt(SIGABRT);
|
||||||
|
static SignalHandlerRAII<&sigill_handler> ill(SIGILL);
|
||||||
|
}
|
||||||
|
|
||||||
static SignalHandlerRAII<&sigsegv_handler> segv(SIGSEGV);
|
|
||||||
static SignalHandlerRAII<&sigabrt_handler> abrt(SIGABRT);
|
|
||||||
static SignalHandlerRAII<&sigill_handler> ill(SIGILL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,66 +1 @@
|
||||||
#include "SignalHandler.h"
|
#include "SignalHandler.h"
|
||||||
|
|
||||||
#if !defined(_MSC_VER)
|
|
||||||
|
|
||||||
namespace cpputils {
|
|
||||||
namespace detail {
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
std::atomic<bool> already_checked_for_libunwind_bug(false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sigset_t _sigemptyset() {
|
|
||||||
sigset_t result;
|
|
||||||
int error = sigemptyset(&result);
|
|
||||||
if (0 != error) {
|
|
||||||
throw std::runtime_error("Error calling sigemptyset. Errno: " + std::to_string(errno));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _sigmask(sigset_t* new_value, sigset_t* old_value) {
|
|
||||||
int error = pthread_sigmask(SIG_SETMASK, new_value, old_value);
|
|
||||||
if (0 != error) {
|
|
||||||
throw std::runtime_error("Error calling pthread_sigmask. Errno: " + std::to_string(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that we're not running into http://savannah.nongnu.org/bugs/?43752
|
|
||||||
void check_against_libunwind_bug() {
|
|
||||||
if (already_checked_for_libunwind_bug.exchange(true)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set new signal handler
|
|
||||||
sigset_t old_value = _sigemptyset();
|
|
||||||
sigset_t new_value = _sigemptyset();
|
|
||||||
|
|
||||||
_sigmask(&new_value, &old_value);
|
|
||||||
|
|
||||||
sigset_t before_exception = _sigemptyset();
|
|
||||||
_sigmask(nullptr, &before_exception);
|
|
||||||
|
|
||||||
// throw an exception
|
|
||||||
try {
|
|
||||||
throw std::runtime_error("Some exception");
|
|
||||||
} catch (const std::exception &e) {}
|
|
||||||
|
|
||||||
sigset_t after_exception = _sigemptyset();
|
|
||||||
_sigmask(nullptr, &after_exception);
|
|
||||||
|
|
||||||
// reset to old signal handler
|
|
||||||
_sigmask(&old_value, nullptr);
|
|
||||||
|
|
||||||
// check that the exception didn't screw up the signal mask
|
|
||||||
if (0 != std::memcmp(&before_exception, &after_exception, sizeof(sigset_t))) { // NOLINT(cppcoreguidelines-pro-type-union-access)
|
|
||||||
ASSERT(false,
|
|
||||||
"Throwing an exception screwed up the signal mask. You likely ran into this bug: http://savannah.nongnu.org/bugs/?43752 . Please build CryFS against a newer version of libunwind or build libunwind with --disable-cxx-exceptions.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -20,17 +20,11 @@ using SignalHandlerFunction = void(int);
|
||||||
|
|
||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER)
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
void check_against_libunwind_bug();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<SignalHandlerFunction* handler>
|
template<SignalHandlerFunction* handler>
|
||||||
class SignalHandlerRAII final {
|
class SignalHandlerRAII final {
|
||||||
public:
|
public:
|
||||||
explicit SignalHandlerRAII(int signal)
|
explicit SignalHandlerRAII(int signal)
|
||||||
: _old_handler(), _signal(signal) {
|
: _old_handler(), _signal(signal) {
|
||||||
detail::check_against_libunwind_bug();
|
|
||||||
|
|
||||||
struct sigaction new_signal_handler{};
|
struct sigaction new_signal_handler{};
|
||||||
std::memset(&new_signal_handler, 0, sizeof(new_signal_handler));
|
std::memset(&new_signal_handler, 0, sizeof(new_signal_handler));
|
||||||
new_signal_handler.sa_handler = handler; // NOLINT(cppcoreguidelines-pro-type-union-access)
|
new_signal_handler.sa_handler = handler; // NOLINT(cppcoreguidelines-pro-type-union-access)
|
||||||
|
|
|
@ -25,12 +25,8 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BacktraceTest, ContainsBacktrace) {
|
|
||||||
string backtrace = cpputils::backtrace();
|
|
||||||
EXPECT_THAT(backtrace, HasSubstr("#1"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !(defined(_MSC_VER) && defined(NDEBUG))
|
#if !(defined(_MSC_VER) && defined(NDEBUG))
|
||||||
|
|
||||||
TEST(BacktraceTest, ContainsTopLevelLine) {
|
TEST(BacktraceTest, ContainsTopLevelLine) {
|
||||||
string backtrace = cpputils::backtrace();
|
string backtrace = cpputils::backtrace();
|
||||||
EXPECT_THAT(backtrace, HasSubstr("BacktraceTest"));
|
EXPECT_THAT(backtrace, HasSubstr("BacktraceTest"));
|
||||||
|
@ -85,12 +81,21 @@ TEST(BacktraceTest, DoesntCrashOnCaughtException) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !(defined(_MSC_VER) && defined(NDEBUG))
|
#if !(defined(_MSC_VER) && defined(NDEBUG))
|
||||||
|
TEST(BacktraceTest, ContainsBacktrace) {
|
||||||
|
string backtrace = cpputils::backtrace();
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
EXPECT_THAT(backtrace, HasSubstr("testing::Test::Run"));
|
||||||
|
#else
|
||||||
|
EXPECT_THAT(backtrace, HasSubstr("BacktraceTest_ContainsBacktrace_Test::TestBody"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
TEST(BacktraceTest, ShowBacktraceOnNullptrAccess) {
|
TEST(BacktraceTest, ShowBacktraceOnNullptrAccess) {
|
||||||
auto output = call_process_exiting_with_nullptr_violation();
|
auto output = call_process_exiting_with_nullptr_violation();
|
||||||
#if !defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
EXPECT_THAT(output, HasSubstr("cpputils::(anonymous namespace)::sig"));
|
|
||||||
#else
|
|
||||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||||
|
#else
|
||||||
|
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +104,7 @@ TEST(BacktraceTest, ShowBacktraceOnSigSegv) {
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||||
#else
|
#else
|
||||||
EXPECT_THAT(output, HasSubstr("cpputils::(anonymous namespace)::sigsegv_handler(int)"));
|
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,19 +113,23 @@ TEST(BacktraceTest, ShowBacktraceOnUnhandledException) {
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||||
#else
|
#else
|
||||||
EXPECT_THAT(output, HasSubstr("cpputils::(anonymous namespace)::sigabrt_handler(int)"));
|
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BacktraceTest, ShowBacktraceOnSigIll) {
|
TEST(BacktraceTest, ShowBacktraceOnSigIll) {
|
||||||
auto output = call_process_exiting_with_sigill();
|
auto output = call_process_exiting_with_sigill();
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||||
#else
|
#else
|
||||||
EXPECT_THAT(output, HasSubstr("cpputils::(anonymous namespace)::sigill_handler(int)"));
|
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
TEST(BacktraceTest, ContainsBacktrace) {
|
||||||
|
string backtrace = cpputils::backtrace();
|
||||||
|
EXPECT_THAT(backtrace, HasSubstr("#1"));
|
||||||
|
}
|
||||||
TEST(BacktraceTest, ShowBacktraceOnNullptrAccess) {
|
TEST(BacktraceTest, ShowBacktraceOnNullptrAccess) {
|
||||||
auto output = call_process_exiting_with_nullptr_violation();
|
auto output = call_process_exiting_with_nullptr_violation();
|
||||||
EXPECT_THAT(output, HasSubstr("#1"));
|
EXPECT_THAT(output, HasSubstr("#1"));
|
||||||
|
@ -145,7 +154,7 @@ TEST(BacktraceTest, ShowBacktraceOnSigIll) {
|
||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER)
|
||||||
TEST(BacktraceTest, ShowBacktraceOnSigAbrt) {
|
TEST(BacktraceTest, ShowBacktraceOnSigAbrt) {
|
||||||
auto output = call_process_exiting_with_sigabrt();
|
auto output = call_process_exiting_with_sigabrt();
|
||||||
EXPECT_THAT(output, HasSubstr("cpputils::(anonymous namespace)::sigabrt_handler(int)"));
|
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BacktraceTest, ShowBacktraceOnSigAbrt_ShowsCorrectSignalName) {
|
TEST(BacktraceTest, ShowBacktraceOnSigAbrt_ShowsCorrectSignalName) {
|
||||||
|
|
Loading…
Reference in New Issue