Merge from release/0.10
This commit is contained in:
commit
85cc1669a2
@ -95,7 +95,7 @@ references:
|
||||
save_cache:
|
||||
key: v4_upgrade_boost_cache_{{ checksum "/tmp/_build_env_vars" }}_{{ arch }}
|
||||
paths:
|
||||
- /tmp/boost_1_58_0
|
||||
- /tmp/boost_1_65_1
|
||||
upgrade_boost: &upgrade_boost
|
||||
run:
|
||||
name: Upgrade Boost
|
||||
@ -104,10 +104,10 @@ references:
|
||||
export NUMCORES=`nproc`
|
||||
echo Using $NUMCORES cores
|
||||
# Download and prepare boost (only if not already present from cache)
|
||||
if [ ! -d "/tmp/boost_1_58_0" ]; then
|
||||
if [ ! -d "/tmp/boost_1_65_1" ]; then
|
||||
echo "Didn't find boost in cache. Downloading and building."
|
||||
wget -O /tmp/boost.tar.bz2 https://sourceforge.net/projects/boost/files/boost/1.58.0/boost_1_58_0.tar.bz2/download
|
||||
if [ $(sha512sum /tmp/boost.tar.bz2 | awk '{print $1;}') == "7480ec713b0aa13f0ec990603e87e3b5c8d53f4411329b10fae37fc963b90aad12dbd9290a33c3669ae801e9012a68683eadff057591e9ca2ebcd22b1a67b5d1" ]; then
|
||||
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;}') == "a9e6866d3bb3e7c198f442ff09f5322f58064dca79bc420f2f0168eb63964226dfbc4f034a5a5e5958281fdf7518a1b057c894fbda0b61fced59c1661bf30f1a" ]; then
|
||||
echo Correct sha512sum
|
||||
else
|
||||
echo Wrong sha512sum
|
||||
@ -117,14 +117,14 @@ references:
|
||||
echo Extracting...
|
||||
tar -xf /tmp/boost.tar.bz2 -C /tmp
|
||||
rm -rf boost.tar.bz2
|
||||
cd /tmp/boost_1_58_0
|
||||
cd /tmp/boost_1_65_1
|
||||
./bootstrap.sh --with-toolset=${BUILD_TOOLSET} --with-libraries=filesystem,thread,chrono,program_options
|
||||
cd ..
|
||||
else
|
||||
echo Found boost in cache. Use cache and build.
|
||||
fi
|
||||
# Compile and install boost (if cached, this should be fast)
|
||||
cd /tmp/boost_1_58_0
|
||||
cd /tmp/boost_1_65_1
|
||||
sudo ./b2 toolset=${BUILD_TOOLSET} link=static cxxflags=-fPIC -d0 -j$NUMCORES install
|
||||
build_pre: &build_pre
|
||||
restore_cache:
|
||||
@ -419,18 +419,6 @@ jobs:
|
||||
GTEST_ARGS: ""
|
||||
CMAKE_FLAGS: "-DUSE_WERROR=on"
|
||||
RUN_TESTS: false
|
||||
gcc_werror:
|
||||
<<: *job_definition
|
||||
environment:
|
||||
CC: gcc-8
|
||||
CXX: g++-8
|
||||
BUILD_TOOLSET: gcc
|
||||
APT_COMPILER_PACKAGE: "g++-8"
|
||||
CXXFLAGS: "-Werror"
|
||||
BUILD_TYPE: "Release"
|
||||
GTEST_ARGS: ""
|
||||
CMAKE_FLAGS: ""
|
||||
RUN_TESTS: false
|
||||
no_compatibility:
|
||||
<<: *job_definition
|
||||
environment:
|
||||
@ -479,7 +467,7 @@ jobs:
|
||||
OMP_NUM_THREADS: "1"
|
||||
CXXFLAGS: "-O2 -fsanitize=thread -fno-omit-frame-pointer"
|
||||
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: ""
|
||||
RUN_TESTS: true
|
||||
clang_tidy:
|
||||
|
@ -7,7 +7,8 @@ cmake_policy(SET CMP0054 NEW)
|
||||
|
||||
project(cryfs)
|
||||
|
||||
include(cmake-utils/utils.cmake)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake-utils)
|
||||
include(utils)
|
||||
|
||||
require_gcc_version(5.0)
|
||||
require_clang_version(4.0)
|
||||
@ -47,7 +48,7 @@ if(MSVC)
|
||||
add_definitions(/bigobj)
|
||||
endif()
|
||||
|
||||
add_subdirectory(vendor)
|
||||
add_subdirectory(vendor EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(test)
|
||||
|
@ -1,12 +1,23 @@
|
||||
Version 0.10.1 (unreleased)
|
||||
Version 0.10.2 (unreleased)
|
||||
---------------
|
||||
|
||||
|
||||
Version 0.10.1
|
||||
---------------
|
||||
Fixed bugs:
|
||||
* If file system migration encounters files or folders with the wrong format in the base directory, it now just ignores them instead of crashing.
|
||||
* When trying to migrate a file system from CryFS 0.9.3 or older, show an error message suggesting to first open it with 0.9.10 because we can't load that anymore.
|
||||
* The '--unmount-idle' parameter works again
|
||||
* Fix building with boost 1.67
|
||||
|
||||
Compatibility:
|
||||
* Fixed some incompatibilities with systems using the musl libc
|
||||
* 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:
|
||||
* Updated to crypto++ 8.1
|
||||
* Updated to DokanY 1.2.1
|
||||
* Unit tests can now be run from any directory
|
||||
|
||||
|
||||
Version 0.10.0
|
||||
|
@ -46,7 +46,7 @@ Requirements
|
||||
- GCC version >= 5.0 or Clang >= 4.0
|
||||
- CMake version >= 3.0
|
||||
- libcurl4 (including development headers)
|
||||
- Boost libraries version >= 1.58 (including development headers)
|
||||
- Boost libraries version >= 1.65.1 (including development headers)
|
||||
- filesystem
|
||||
- system
|
||||
- chrono
|
||||
@ -60,7 +60,7 @@ Requirements
|
||||
You can use the following commands to install these requirements
|
||||
|
||||
# Ubuntu
|
||||
$ sudo apt-get 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
|
||||
$ 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
|
||||
sudo dnf install git gcc-c++ cmake make libcurl-devel boost-devel boost-static openssl-devel fuse-devel python
|
||||
@ -96,7 +96,7 @@ Building on Windows (experimental)
|
||||
|
||||
Build with Visual Studio 2017 and pass in the following flags to CMake:
|
||||
|
||||
-DDOKAN_PATH=[dokan library location, e.g. "C:\Program Files\Dokan\DokanLibrary-1.1.0"]
|
||||
-DDOKAN_PATH=[dokan library location, e.g. "C:\Program Files\Dokan\DokanLibrary-1.2.1"]
|
||||
-DBOOST_ROOT=[path to root of boost installation]
|
||||
|
||||
If you set these variables correctly in the `CMakeSettings.json` file, you should be able to open the cryfs source folder with Visual Studio 2017.
|
||||
|
@ -25,18 +25,18 @@ init:
|
||||
- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\%VisualStudioVersion%\Community\VC\Auxiliary\Build\vcvars%arch%.bat"
|
||||
|
||||
install:
|
||||
- choco install -y dokany --version 1.1.0.2000 --installargs INSTALLDEVFILES=1
|
||||
- choco install -y dokany --version 1.2.1.2000 --installargs INSTALLDEVFILES=1
|
||||
- cmake --version
|
||||
|
||||
build_script:
|
||||
- cmd: mkdir build
|
||||
- cmd: cd build
|
||||
# note: The cmake+ninja workflow requires us to set build type in both cmake commands ('cmake' and 'cmake --build'), otherwise the cryfs.exe will depend on debug versions of the visual studio c++ runtime (i.e. msvcp140d.dll)
|
||||
- cmd: cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DBUILD_TESTING=on -DBOOST_ROOT="C:/Libraries/boost_1_65_1" -DDOKAN_PATH="C:/Program Files/Dokan/DokanLibrary-1.1.0"
|
||||
- cmd: cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=%CONFIGURATION% -DBUILD_TESTING=on -DBOOST_ROOT="C:/Libraries/boost_1_67_0" -DDOKAN_PATH="C:/Program Files/Dokan/DokanLibrary-1.2.1"
|
||||
- cmd: cmake --build . --config %CONFIGURATION%
|
||||
- cmd: .\test\gitversion\gitversion-test.exe
|
||||
# cpp-utils-test disables ThreadDebuggingTest_ThreadName.*_thenIsCorrect because the appveyor image is too old to support the API needed for that
|
||||
- cmd: cd .\test\cpp-utils\ && .\cpp-utils-test.exe --gtest_filter=-ThreadDebuggingTest_ThreadName.*_thenIsCorrect && cd ..\..
|
||||
- cmd: .\test\cpp-utils\cpp-utils-test.exe --gtest_filter=-ThreadDebuggingTest_ThreadName.*_thenIsCorrect
|
||||
#- cmd: .\test\fspp\fspp-test.exe
|
||||
- cmd: .\test\parallelaccessstore\parallelaccessstore-test.exe
|
||||
- cmd: .\test\blockstore\blockstore-test.exe
|
||||
|
44
cmake-utils/FindLibunwind.cmake
Normal file
44
cmake-utils/FindLibunwind.cmake
Normal file
@ -0,0 +1,44 @@
|
||||
# Taken from https://github.com/monero-project/monero/blob/31bdf7bd113c2576fe579ef3a25a2d8fef419ffc/cmake/FindLibunwind.cmake
|
||||
# modifications:
|
||||
# - remove linkage against gcc_eh because it was causing segfaults in various of our unit tests
|
||||
|
||||
# - Try to find libunwind
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBUNWIND_FOUND - system has libunwind
|
||||
# LIBUNWIND_INCLUDE_DIR - the libunwind include directory
|
||||
# LIBUNWIND_LIBRARIES - Link these to use libunwind
|
||||
# LIBUNWIND_DEFINITIONS - Compiler switches required for using libunwind
|
||||
|
||||
# Copyright (c) 2006, Alexander Dymo, <adymo@kdevelop.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
find_path(LIBUNWIND_INCLUDE_DIR libunwind.h
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
)
|
||||
|
||||
find_library(LIBUNWIND_LIBRARIES NAMES unwind )
|
||||
if(NOT LIBUNWIND_LIBRARIES STREQUAL "LIBUNWIND_LIBRARIES-NOTFOUND")
|
||||
if (CMAKE_COMPILER_IS_GNUCC)
|
||||
set(LIBUNWIND_LIBRARIES "${LIBUNWIND_LIBRARIES}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# some versions of libunwind need liblzma, and we don't use pkg-config
|
||||
# so we just look whether liblzma is installed, and add it if it is.
|
||||
# It might not be actually needed, but doesn't hurt if it is not.
|
||||
# We don't need any headers, just the lib, as it's privately needed.
|
||||
message(STATUS "looking for liblzma")
|
||||
find_library(LIBLZMA_LIBRARIES lzma )
|
||||
if(NOT LIBLZMA_LIBRARIES STREQUAL "LIBLZMA_LIBRARIES-NOTFOUND")
|
||||
message(STATUS "liblzma found")
|
||||
set(LIBUNWIND_LIBRARIES "${LIBUNWIND_LIBRARIES};${LIBLZMA_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Libunwind "Could not find libunwind" LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES)
|
||||
# show the LIBUNWIND_INCLUDE_DIR and LIBUNWIND_LIBRARIES variables only in the advanced view
|
||||
mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES )
|
@ -108,7 +108,7 @@ endfunction(target_enable_style_warnings)
|
||||
function(target_add_boost TARGET)
|
||||
# Load boost libraries
|
||||
if(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS)
|
||||
# Many supported systems don't have boost >= 1.58. 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")
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
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)
|
||||
endif(NOT DEFINED Boost_USE_STATIC_LIBS OR Boost_USE_STATIC_LIBS)
|
||||
set(BOOST_THREAD_VERSION 4)
|
||||
find_package(Boost 1.58.0
|
||||
find_package(Boost 1.65.1
|
||||
REQUIRED
|
||||
COMPONENTS ${ARGN})
|
||||
target_include_directories(${TARGET} SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
|
||||
|
@ -61,13 +61,19 @@ set(SOURCES
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||
|
||||
|
||||
if(NOT MSVC)
|
||||
find_package(Backtrace REQUIRED)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${Backtrace_INCLUDE_DIRS})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${Backtrace_LIBRARIES})
|
||||
if(MSVC)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC DbgHelp)
|
||||
elseif (APPLE)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED)
|
||||
else()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC DbgHelp)
|
||||
find_program(ADDR2LINE addr2line)
|
||||
if ("${ADDR2LINE}" STREQUAL "ADDR2LINE-NOTFOUND")
|
||||
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()
|
||||
|
||||
if (NOT MSVC)
|
||||
@ -85,6 +91,6 @@ target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC spdlog cryptopp)
|
||||
|
||||
target_add_boost(${PROJECT_NAME} filesystem system thread)
|
||||
target_add_boost(${PROJECT_NAME} filesystem system thread chrono)
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
target_activate_cpp14(${PROJECT_NAME})
|
||||
|
@ -1,19 +1,12 @@
|
||||
#if !defined(_MSC_VER)
|
||||
|
||||
#include "backtrace.h"
|
||||
#include <execinfo.h>
|
||||
#include <csignal>
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
#include <cxxabi.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "../logging/logging.h"
|
||||
#include <cpp-utils/process/SignalHandler.h>
|
||||
|
||||
// TODO Add file and line number on non-windows
|
||||
#include <boost/stacktrace.hpp>
|
||||
|
||||
using std::string;
|
||||
using std::ostringstream;
|
||||
@ -21,91 +14,36 @@ using namespace cpputils::logging;
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
namespace {
|
||||
std::string demangle(const string &mangledName) {
|
||||
string result;
|
||||
int status = -10;
|
||||
char *demangledName = nullptr;
|
||||
try {
|
||||
demangledName = abi::__cxa_demangle(mangledName.c_str(), NULL, NULL, &status);
|
||||
if (status == 0) {
|
||||
result = demangledName;
|
||||
} else {
|
||||
result = "[demangling error " + std::to_string(status) + "]" + mangledName;
|
||||
}
|
||||
free(demangledName);
|
||||
return result;
|
||||
} catch (...) {
|
||||
free(demangledName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void pretty_print(std::ostream& str, const void *addr) {
|
||||
Dl_info info;
|
||||
if (0 == dladdr(addr, &info)) {
|
||||
str << "[failed parsing line]";
|
||||
} else {
|
||||
if (nullptr == info.dli_fname) {
|
||||
str << "[no dli_fname]";
|
||||
} else {
|
||||
str << info.dli_fname;
|
||||
}
|
||||
str << ":" << std::hex << info.dli_fbase << " ";
|
||||
if (nullptr == info.dli_sname) {
|
||||
str << "[no symbol name]";
|
||||
} else if (info.dli_sname[0] == '_') {
|
||||
// is a mangled name
|
||||
str << demangle(info.dli_sname);
|
||||
} else {
|
||||
// is not a mangled name
|
||||
str << info.dli_sname;
|
||||
}
|
||||
str << " : " << std::hex << info.dli_saddr;
|
||||
}
|
||||
}
|
||||
|
||||
string backtrace_to_string(void *array[], size_t size) {
|
||||
ostringstream result;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
result << "#" << std::dec << i << " ";
|
||||
pretty_print(result, array[i]);
|
||||
result << "\n";
|
||||
}
|
||||
return result.str();
|
||||
}
|
||||
string backtrace() {
|
||||
std::ostringstream str;
|
||||
str << boost::stacktrace::stacktrace();
|
||||
return str.str();
|
||||
}
|
||||
|
||||
string backtrace() {
|
||||
constexpr unsigned int MAX_SIZE = 100;
|
||||
void *array[MAX_SIZE];
|
||||
size_t size = ::backtrace(array, MAX_SIZE);
|
||||
return backtrace_to_string(array, size);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void sigsegv_handler(int) {
|
||||
LOG(ERR, "SIGSEGV\n{}", backtrace());
|
||||
exit(1);
|
||||
}
|
||||
void sigill_handler(int) {
|
||||
LOG(ERR, "SIGILL\n{}", backtrace());
|
||||
exit(1);
|
||||
}
|
||||
void sigabrt_handler(int) {
|
||||
LOG(ERR, "SIGABRT\n{}", backtrace());
|
||||
exit(1);
|
||||
}
|
||||
void sigsegv_handler(int) {
|
||||
LOG(ERR, "SIGSEGV\n{}", backtrace());
|
||||
exit(1);
|
||||
}
|
||||
void sigill_handler(int) {
|
||||
LOG(ERR, "SIGILL\n{}", backtrace());
|
||||
exit(1);
|
||||
}
|
||||
void sigabrt_handler(int) {
|
||||
LOG(ERR, "SIGABRT\n{}", backtrace());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void showBacktraceOnCrash() {
|
||||
// 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)
|
||||
void showBacktraceOnCrash() {
|
||||
// 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)
|
||||
|
||||
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
|
||||
|
@ -88,7 +88,8 @@ public:
|
||||
, _registerer(signal, this)
|
||||
, _handler(signal) {
|
||||
// note: the order of the members ensures that:
|
||||
// - when registering the signal handler fails, the registerer will be destroyed, unregistering the signal_occurred_flag,
|
||||
// - when registering the signal handler, the SignalCatcher impl already has a valid _signal_occurred_flag set.
|
||||
// - when registering the signal handler fails, the _registerer will be destroyed again, unregistering this SignalCatcherImpl,
|
||||
// i.e. there is no leak.
|
||||
|
||||
// Allow only the set of signals that is supported on all platforms, see for Windows: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/signal?view=vs-2017
|
||||
|
@ -9,7 +9,11 @@ namespace cpputils {
|
||||
|
||||
void set_thread_name(const char* name);
|
||||
std::string get_thread_name();
|
||||
|
||||
#if defined(__GLIBC__) || defined(__APPLE__) || defined(_MSC_VER)
|
||||
// this is not supported on musl systems, that's why we ifdef it for glibc only.
|
||||
std::string get_thread_name(std::thread* thread);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,14 @@
|
||||
#include <thread>
|
||||
#include <pthread.h>
|
||||
#include <cpp-utils/assert/assert.h>
|
||||
#if !(defined(__GLIBC__) || defined(__APPLE__))
|
||||
// for pthread_getname_np_gcompat
|
||||
#include <errno.h> // errno
|
||||
#include <fcntl.h> // O_CLOEXEC, O_RDONLY
|
||||
#include <unistd.h> // open, read
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
@ -28,9 +36,47 @@ void set_thread_name(const char* name) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
#if !(defined(__GLIBC__) || defined(__APPLE__))
|
||||
|
||||
struct OpenFileRAII final {
|
||||
explicit OpenFileRAII(const char* filename) : fd(::open(filename, O_RDONLY | O_CLOEXEC)) {}
|
||||
~OpenFileRAII() {
|
||||
int result = close(fd);
|
||||
if (result != 0) {
|
||||
throw std::runtime_error("Error closing file. Errno: " + std::to_string(errno));
|
||||
}
|
||||
}
|
||||
|
||||
int fd;
|
||||
};
|
||||
|
||||
// get the name of a thread
|
||||
int pthread_getname_np_gcompat(pthread_t thread, char *name, size_t len) {
|
||||
ASSERT(thread == pthread_self(), "On musl systems, it's only supported to get the name of the current thread.");
|
||||
|
||||
auto file = OpenFileRAII("/proc/thread-self/comm");
|
||||
ssize_t n;
|
||||
if (file.fd < 0)
|
||||
return errno;
|
||||
n = read(file.fd, name, len);
|
||||
if (n < 0)
|
||||
return errno;
|
||||
// if the trailing newline was not read, the buffer was too small
|
||||
if (n == 0 || name[n - 1] != '\n')
|
||||
return ERANGE;
|
||||
// null-terminate string
|
||||
name[n - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string get_thread_name(pthread_t thread) {
|
||||
char name[MAX_NAME_LEN];
|
||||
#if defined(__GLIBC__) || defined(__APPLE__)
|
||||
int result = pthread_getname_np(thread, name, MAX_NAME_LEN);
|
||||
#else
|
||||
int result = pthread_getname_np_gcompat(thread, name, MAX_NAME_LEN);
|
||||
#endif
|
||||
if (0 != result) {
|
||||
throw std::runtime_error("Error getting thread name with pthread_getname_np. Code: " + std::to_string(result));
|
||||
}
|
||||
@ -39,16 +85,19 @@ std::string get_thread_name(pthread_t thread) {
|
||||
name[MAX_NAME_LEN - 1] = '\0';
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::string get_thread_name() {
|
||||
return get_thread_name(pthread_self());
|
||||
}
|
||||
|
||||
#if defined(__GLIBC__) || defined(__APPLE__)
|
||||
std::string get_thread_name(std::thread* thread) {
|
||||
ASSERT(thread->joinable(), "Thread not running");
|
||||
return get_thread_name(thread->native_handle());
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
if (BUILD_TESTING)
|
||||
include_directories(../src)
|
||||
|
||||
add_subdirectory(my-gtest-main)
|
||||
add_subdirectory(gitversion)
|
||||
add_subdirectory(cpp-utils)
|
||||
if (NOT MSVC)
|
||||
|
@ -27,7 +27,7 @@ set(SOURCES
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} googletest blobstore)
|
||||
target_link_libraries(${PROJECT_NAME} my-gtest-main googletest blobstore)
|
||||
add_test(${PROJECT_NAME} ${PROJECT_NAME})
|
||||
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
|
@ -42,7 +42,7 @@ set(SOURCES
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} googletest blockstore)
|
||||
target_link_libraries(${PROJECT_NAME} my-gtest-main googletest blockstore)
|
||||
add_test(${PROJECT_NAME} ${PROJECT_NAME})
|
||||
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
|
@ -71,7 +71,7 @@ target_activate_cpp14(${PROJECT_NAME}_exit_signal)
|
||||
target_link_libraries(${PROJECT_NAME}_exit_signal cpp-utils)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} googletest cpp-utils)
|
||||
target_link_libraries(${PROJECT_NAME} my-gtest-main googletest cpp-utils)
|
||||
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_exit_status ${PROJECT_NAME}_exit_signal)
|
||||
add_test(${PROJECT_NAME} ${PROJECT_NAME})
|
||||
|
||||
|
@ -2,33 +2,30 @@
|
||||
#include <csignal>
|
||||
#include "cpp-utils/assert/backtrace.h"
|
||||
#include "cpp-utils/process/subprocess.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "my-gtest-main.h"
|
||||
|
||||
using std::string;
|
||||
using testing::HasSubstr;
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
namespace {
|
||||
std::string call_process_exiting_with(const std::string& kind, const std::string& signal = "") {
|
||||
#if defined(_MSC_VER)
|
||||
constexpr const char* executable = "cpp-utils-test_exit_signal.exe";
|
||||
auto executable = get_executable().parent_path() / "cpp-utils-test_exit_signal.exe";
|
||||
#else
|
||||
constexpr const char* executable = "./test/cpp-utils/cpp-utils-test_exit_signal";
|
||||
auto executable = get_executable().parent_path() / "cpp-utils-test_exit_signal";
|
||||
#endif
|
||||
const std::string command = std::string(executable) + " \"" + kind + "\" \"" + signal + "\" 2>&1";
|
||||
if (!bf::exists(executable)) {
|
||||
throw std::runtime_error(executable.string() + " not found.");
|
||||
}
|
||||
const std::string command = executable.string() + " \"" + kind + "\" \"" + signal + "\" 2>&1";
|
||||
auto result = cpputils::Subprocess::call(command);
|
||||
return result.output;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ContainsBacktrace) {
|
||||
string backtrace = cpputils::backtrace();
|
||||
EXPECT_THAT(backtrace, HasSubstr("#1"));
|
||||
}
|
||||
|
||||
#if !(defined(_MSC_VER) && defined(NDEBUG))
|
||||
TEST(BacktraceTest, ContainsExecutableName) {
|
||||
string backtrace = cpputils::backtrace();
|
||||
EXPECT_THAT(backtrace, HasSubstr("cpp-utils-test"));
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ContainsTopLevelLine) {
|
||||
string backtrace = cpputils::backtrace();
|
||||
@ -84,26 +81,55 @@ TEST(BacktraceTest, DoesntCrashOnCaughtException) {
|
||||
}
|
||||
|
||||
#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) {
|
||||
auto output = call_process_exiting_with_nullptr_violation();
|
||||
EXPECT_THAT(output, HasSubstr("cpp-utils-test_exit_signal"));
|
||||
#if defined(_MSC_VER)
|
||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||
#else
|
||||
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigSegv) {
|
||||
auto output = call_process_exiting_with_sigsegv();
|
||||
EXPECT_THAT(output, HasSubstr("cpp-utils-test_exit_signal"));
|
||||
#if defined(_MSC_VER)
|
||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||
#else
|
||||
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnUnhandledException) {
|
||||
auto output = call_process_exiting_with_exception("my_exception_message");
|
||||
EXPECT_THAT(output, HasSubstr("cpp-utils-test_exit_signal"));
|
||||
#if defined(_MSC_VER)
|
||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||
#else
|
||||
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigIll) {
|
||||
auto output = call_process_exiting_with_sigill();
|
||||
EXPECT_THAT(output, HasSubstr("cpp-utils-test_exit_signal"));
|
||||
#if defined(_MSC_VER)
|
||||
EXPECT_THAT(output, HasSubstr("handle_exit_signal"));
|
||||
#else
|
||||
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
TEST(BacktraceTest, ContainsBacktrace) {
|
||||
string backtrace = cpputils::backtrace();
|
||||
EXPECT_THAT(backtrace, HasSubstr("#1"));
|
||||
}
|
||||
TEST(BacktraceTest, ShowBacktraceOnNullptrAccess) {
|
||||
auto output = call_process_exiting_with_nullptr_violation();
|
||||
EXPECT_THAT(output, HasSubstr("#1"));
|
||||
@ -128,7 +154,7 @@ TEST(BacktraceTest, ShowBacktraceOnSigIll) {
|
||||
#if !defined(_MSC_VER)
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigAbrt) {
|
||||
auto output = call_process_exiting_with_sigabrt();
|
||||
EXPECT_THAT(output, HasSubstr("cpp-utils-test_exit_signal"));
|
||||
EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigAbrt_ShowsCorrectSignalName) {
|
||||
|
@ -1,19 +1,26 @@
|
||||
#include <cpp-utils/process/subprocess.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <cpp-utils/lock/ConditionBarrier.h>
|
||||
#include "my-gtest-main.h"
|
||||
|
||||
using cpputils::Subprocess;
|
||||
using cpputils::SubprocessError;
|
||||
using std::string;
|
||||
namespace bf = boost::filesystem;
|
||||
|
||||
namespace {
|
||||
std::string exit_with_message_and_status(const char* message, int status) {
|
||||
#if defined(_MSC_VER)
|
||||
constexpr const char* executable = "cpp-utils-test_exit_status.exe";
|
||||
auto executable = get_executable().parent_path() / "cpp-utils-test_exit_status.exe";
|
||||
#else
|
||||
constexpr const char* executable = "./test/cpp-utils/cpp-utils-test_exit_status";
|
||||
auto executable = get_executable().parent_path() / "cpp-utils-test_exit_status";
|
||||
#endif
|
||||
return std::string(executable) + " \"" + message + "\" " + std::to_string(status);
|
||||
if (!bf::exists(executable)) {
|
||||
throw std::runtime_error(executable.string() + " not found.");
|
||||
}
|
||||
return executable.string() + " \"" + message + "\" " + std::to_string(status);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,24 @@ TEST(ThreadDebuggingTest_ThreadName, givenMainThread_whenSettingAndGetting_thenD
|
||||
get_thread_name();
|
||||
}
|
||||
|
||||
TEST(ThreadDebuggingTest_ThreadName, givenMainThread_whenGettingFromInside_thenIsCorrect) {
|
||||
set_thread_name("my_thread_name");
|
||||
string name = get_thread_name();
|
||||
EXPECT_EQ("my_thread_name", name);
|
||||
}
|
||||
|
||||
TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenGettingFromInside_thenIsCorrect) {
|
||||
std::thread child([] {
|
||||
set_thread_name("my_thread_name");
|
||||
string name = get_thread_name();
|
||||
EXPECT_EQ("my_thread_name", name);
|
||||
});
|
||||
child.join();
|
||||
}
|
||||
|
||||
|
||||
#if defined(__GLIBC__) || defined(__APPLE__) || defined(_MSC_VER)
|
||||
// disabled on musl because getting the thread name for a child thread doesn't work there
|
||||
TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenSettingAndGetting_thenDoesntCrash) {
|
||||
ConditionBarrier nameIsChecked;
|
||||
|
||||
@ -27,37 +45,22 @@ TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenSettingAndGetting_then
|
||||
EXPECT_TRUE(child_didnt_crash);
|
||||
}
|
||||
|
||||
TEST(ThreadDebuggingTest_ThreadName, givenMainThread_whenGettingFromInside_thenIsCorrect) {
|
||||
set_thread_name("my_thread_name");
|
||||
string name = get_thread_name();
|
||||
EXPECT_EQ("my_thread_name", name);
|
||||
}
|
||||
|
||||
TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenGettingFromInside_thenIsCorrect) {
|
||||
std::thread child([] {
|
||||
set_thread_name("my_thread_name");
|
||||
string name = get_thread_name();
|
||||
EXPECT_EQ("my_thread_name", name);
|
||||
});
|
||||
child.join();
|
||||
}
|
||||
|
||||
TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenGettingFromOutside_thenIsCorrect) {
|
||||
ConditionBarrier nameIsSet;
|
||||
ConditionBarrier nameIsChecked;
|
||||
ConditionBarrier nameIsSet;
|
||||
ConditionBarrier nameIsChecked;
|
||||
|
||||
std::thread child([&] {
|
||||
set_thread_name("my_thread_name");
|
||||
nameIsSet.release();
|
||||
nameIsChecked.wait();
|
||||
});
|
||||
std::thread child([&] {
|
||||
set_thread_name("my_thread_name");
|
||||
nameIsSet.release();
|
||||
nameIsChecked.wait();
|
||||
});
|
||||
|
||||
nameIsSet.wait();
|
||||
set_thread_name("outer_thread_name"); // just to make sure the next line doesn't read the outer thread name
|
||||
string name = get_thread_name(&child);
|
||||
EXPECT_EQ("my_thread_name", name);
|
||||
nameIsSet.wait();
|
||||
set_thread_name("outer_thread_name"); // just to make sure the next line doesn't read the outer thread name
|
||||
string name = get_thread_name(&child);
|
||||
EXPECT_EQ("my_thread_name", name);
|
||||
|
||||
nameIsChecked.release();
|
||||
child.join();
|
||||
nameIsChecked.release();
|
||||
child.join();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -16,7 +16,7 @@ set(SOURCES
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} googletest cryfs-cli cryfs-unmount fspp-fuse)
|
||||
target_link_libraries(${PROJECT_NAME} my-gtest-main googletest cryfs-cli cryfs-unmount fspp-fuse)
|
||||
add_test(${PROJECT_NAME} ${PROJECT_NAME})
|
||||
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
|
@ -24,7 +24,7 @@ set(SOURCES
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} googletest cryfs)
|
||||
target_link_libraries(${PROJECT_NAME} my-gtest-main googletest cryfs)
|
||||
add_test(${PROJECT_NAME} ${PROJECT_NAME})
|
||||
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
|
@ -102,7 +102,7 @@ set(SOURCES
|
||||
testutils/OpenFileHandle.cpp testutils/OpenFileHandle.h)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} googletest fspp-interface fspp-fuse)
|
||||
target_link_libraries(${PROJECT_NAME} my-gtest-main googletest fspp-interface fspp-fuse)
|
||||
add_test(${PROJECT_NAME} ${PROJECT_NAME})
|
||||
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
|
@ -14,7 +14,13 @@ using fspp::fuse::FuseErrnoException;
|
||||
|
||||
class FuseFlushErrorTest: public FuseFlushTest, public WithParamInterface<int> {
|
||||
};
|
||||
INSTANTIATE_TEST_CASE_P(FuseFlushErrorTest, FuseFlushErrorTest, Values(EBADF, EINTR, EIO));
|
||||
INSTANTIATE_TEST_CASE_P(FuseFlushErrorTest, FuseFlushErrorTest, Values(
|
||||
EBADF,
|
||||
#if defined(__GLIBC__) || defined(__APPLE__)
|
||||
// musl has different handling for EINTR, see https://ewontfix.com/4/
|
||||
EINTR,
|
||||
#endif
|
||||
EIO));
|
||||
|
||||
TEST_P(FuseFlushErrorTest, ReturnErrorFromFlush) {
|
||||
ReturnIsFileOnLstat(FILENAME);
|
||||
|
@ -29,9 +29,7 @@ void FuseThread::start(const bf::path &mountDir, const vector<string> &fuseOptio
|
||||
}
|
||||
|
||||
void FuseThread::stop() {
|
||||
if (0 != pthread_kill(_child.native_handle(), SIGINT)) {
|
||||
throw std::runtime_error("Error sending stop signal");
|
||||
}
|
||||
_fuse->stop();
|
||||
bool thread_stopped = _child.try_join_for(seconds(10));
|
||||
ASSERT(thread_stopped, "FuseThread could not be stopped");
|
||||
//Wait until it is properly shutdown (busy waiting is simple and doesn't hurt much here)
|
||||
|
@ -6,7 +6,7 @@ set(SOURCES
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} googletest gitversion)
|
||||
target_link_libraries(${PROJECT_NAME} my-gtest-main googletest gitversion)
|
||||
add_test(${PROJECT_NAME} ${PROJECT_NAME})
|
||||
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
|
13
test/my-gtest-main/CMakeLists.txt
Normal file
13
test/my-gtest-main/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
project (my-gtest-main)
|
||||
|
||||
set(SOURCES
|
||||
my-gtest-main.cpp
|
||||
)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC googletest cpp-utils)
|
||||
target_add_boost(${PROJECT_NAME} filesystem system)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC .)
|
||||
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
target_activate_cpp14(${PROJECT_NAME})
|
27
test/my-gtest-main/my-gtest-main.cpp
Normal file
27
test/my-gtest-main/my-gtest-main.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "my-gtest-main.h"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <cpp-utils/assert/assert.h>
|
||||
|
||||
namespace {
|
||||
boost::optional<boost::filesystem::path> executable;
|
||||
}
|
||||
|
||||
const boost::filesystem::path& get_executable() {
|
||||
ASSERT(executable != boost::none, "Executable path not set");
|
||||
return *executable;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
executable = boost::filesystem::path(argv[0]);
|
||||
|
||||
// Since Google Mock depends on Google Test, InitGoogleMock() is
|
||||
// also responsible for initializing Google Test. Therefore there's
|
||||
// no need for calling testing::InitGoogleTest() separately.
|
||||
testing::InitGoogleMock(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
5
test/my-gtest-main/my-gtest-main.h
Normal file
5
test/my-gtest-main/my-gtest-main.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
const boost::filesystem::path& get_executable();
|
@ -6,7 +6,7 @@ set(SOURCES
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} googletest parallelaccessstore)
|
||||
target_link_libraries(${PROJECT_NAME} my-gtest-main googletest parallelaccessstore)
|
||||
add_test(${PROJECT_NAME} ${PROJECT_NAME})
|
||||
|
||||
target_enable_style_warnings(${PROJECT_NAME})
|
||||
|
1
vendor/googletest/CMakeLists.txt
vendored
1
vendor/googletest/CMakeLists.txt
vendored
@ -10,7 +10,6 @@ if (BUILD_TESTING)
|
||||
project (googletest)
|
||||
add_library(${PROJECT_NAME} dummy.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC gtest gmock)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE gmock_main)
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM INTERFACE ${gtest_INCLUDE_DIRS}/include SYSTEM ${gmock_INCLUDE_DIRS}/include)
|
||||
|
||||
# Disable "missing override" warning because gmock MOCK_METHOD() don't use override :(
|
||||
|
Loading…
Reference in New Issue
Block a user