Merge from release/0.10

This commit is contained in:
Sebastian Messmer 2019-04-03 18:44:48 -07:00
commit 85cc1669a2
30 changed files with 315 additions and 188 deletions

View File

@ -95,7 +95,7 @@ references:
save_cache: save_cache:
key: v4_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_58_0 - /tmp/boost_1_65_1
upgrade_boost: &upgrade_boost upgrade_boost: &upgrade_boost
run: run:
name: Upgrade Boost name: Upgrade Boost
@ -104,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_58_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.58.0/boost_1_58_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;}') == "7480ec713b0aa13f0ec990603e87e3b5c8d53f4411329b10fae37fc963b90aad12dbd9290a33c3669ae801e9012a68683eadff057591e9ca2ebcd22b1a67b5d1" ]; 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
@ -117,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_58_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_58_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:
@ -419,18 +419,6 @@ jobs:
GTEST_ARGS: "" GTEST_ARGS: ""
CMAKE_FLAGS: "-DUSE_WERROR=on" CMAKE_FLAGS: "-DUSE_WERROR=on"
RUN_TESTS: false 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: no_compatibility:
<<: *job_definition <<: *job_definition
environment: environment:
@ -479,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:

View File

@ -7,7 +7,8 @@ cmake_policy(SET CMP0054 NEW)
project(cryfs) 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_gcc_version(5.0)
require_clang_version(4.0) require_clang_version(4.0)
@ -47,7 +48,7 @@ if(MSVC)
add_definitions(/bigobj) add_definitions(/bigobj)
endif() endif()
add_subdirectory(vendor) add_subdirectory(vendor EXCLUDE_FROM_ALL)
add_subdirectory(src) add_subdirectory(src)
add_subdirectory(doc) add_subdirectory(doc)
add_subdirectory(test) add_subdirectory(test)

View File

@ -1,12 +1,23 @@
Version 0.10.1 (unreleased) Version 0.10.2 (unreleased)
---------------
Version 0.10.1
--------------- ---------------
Fixed bugs: 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. * 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. * 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 * 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: Other:
* Updated to crypto++ 8.1 * Updated to crypto++ 8.1
* Updated to DokanY 1.2.1
* Unit tests can now be run from any directory
Version 0.10.0 Version 0.10.0

View File

@ -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.58 (including development headers) - Boost libraries version >= 1.65.1 (including development headers)
- filesystem - filesystem
- system - system
- chrono - chrono
@ -60,7 +60,7 @@ Requirements
You can use the following commands to install these requirements You can use the following commands to install these requirements
# Ubuntu # 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 # Fedora
sudo dnf install git gcc-c++ cmake make libcurl-devel boost-devel boost-static openssl-devel fuse-devel python 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: 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] -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. 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.

View File

@ -25,18 +25,18 @@ init:
- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\%VisualStudioVersion%\Community\VC\Auxiliary\Build\vcvars%arch%.bat" - cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\%VisualStudioVersion%\Community\VC\Auxiliary\Build\vcvars%arch%.bat"
install: 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 - cmake --version
build_script: build_script:
- cmd: mkdir build - cmd: mkdir build
- cmd: cd 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) # 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: cmake --build . --config %CONFIGURATION%
- cmd: .\test\gitversion\gitversion-test.exe - 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 # 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\fspp\fspp-test.exe
- cmd: .\test\parallelaccessstore\parallelaccessstore-test.exe - cmd: .\test\parallelaccessstore\parallelaccessstore-test.exe
- cmd: .\test\blockstore\blockstore-test.exe - cmd: .\test\blockstore\blockstore-test.exe

View 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 )

View File

@ -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.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") 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.58.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})

View File

@ -61,13 +61,19 @@ set(SOURCES
add_library(${PROJECT_NAME} STATIC ${SOURCES}) add_library(${PROJECT_NAME} STATIC ${SOURCES})
if(MSVC)
if(NOT MSVC) target_link_libraries(${PROJECT_NAME} PUBLIC DbgHelp)
find_package(Backtrace REQUIRED) elseif (APPLE)
target_include_directories(${PROJECT_NAME} PUBLIC ${Backtrace_INCLUDE_DIRS}) target_compile_definitions(${PROJECT_NAME} PRIVATE BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC ${Backtrace_LIBRARIES})
else() 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() endif()
if (NOT MSVC) 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_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_enable_style_warnings(${PROJECT_NAME})
target_activate_cpp14(${PROJECT_NAME}) target_activate_cpp14(${PROJECT_NAME})

View File

@ -1,19 +1,12 @@
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
#include "backtrace.h"
#include <execinfo.h>
#include <csignal> #include <csignal>
#include <iostream>
#include <unistd.h>
#include <cxxabi.h>
#include <string>
#include <sstream> #include <sstream>
#include <string>
#include <dlfcn.h>
#include "../logging/logging.h" #include "../logging/logging.h"
#include <cpp-utils/process/SignalHandler.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::string;
using std::ostringstream; using std::ostringstream;
@ -21,91 +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 {
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() {
constexpr unsigned int MAX_SIZE = 100;
void *array[MAX_SIZE];
size_t size = ::backtrace(array, MAX_SIZE);
return backtrace_to_string(array, size);
}
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

View File

@ -88,7 +88,8 @@ public:
, _registerer(signal, this) , _registerer(signal, this)
, _handler(signal) { , _handler(signal) {
// note: the order of the members ensures that: // 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. // 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 // 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

View File

@ -9,7 +9,11 @@ namespace cpputils {
void set_thread_name(const char* name); void set_thread_name(const char* name);
std::string get_thread_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); std::string get_thread_name(std::thread* thread);
#endif
} }

View File

@ -5,6 +5,14 @@
#include <thread> #include <thread>
#include <pthread.h> #include <pthread.h>
#include <cpp-utils/assert/assert.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 { namespace cpputils {
@ -28,9 +36,47 @@ void set_thread_name(const char* name) {
} }
namespace { 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) { std::string get_thread_name(pthread_t thread) {
char name[MAX_NAME_LEN]; char name[MAX_NAME_LEN];
#if defined(__GLIBC__) || defined(__APPLE__)
int result = pthread_getname_np(thread, name, MAX_NAME_LEN); 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) { if (0 != result) {
throw std::runtime_error("Error getting thread name with pthread_getname_np. Code: " + std::to_string(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'; name[MAX_NAME_LEN - 1] = '\0';
return name; return name;
} }
} }
std::string get_thread_name() { std::string get_thread_name() {
return get_thread_name(pthread_self()); return get_thread_name(pthread_self());
} }
#if defined(__GLIBC__) || defined(__APPLE__)
std::string get_thread_name(std::thread* thread) { std::string get_thread_name(std::thread* thread) {
ASSERT(thread->joinable(), "Thread not running"); ASSERT(thread->joinable(), "Thread not running");
return get_thread_name(thread->native_handle()); return get_thread_name(thread->native_handle());
} }
#endif
} }

View File

@ -1,6 +1,7 @@
if (BUILD_TESTING) if (BUILD_TESTING)
include_directories(../src) include_directories(../src)
add_subdirectory(my-gtest-main)
add_subdirectory(gitversion) add_subdirectory(gitversion)
add_subdirectory(cpp-utils) add_subdirectory(cpp-utils)
if (NOT MSVC) if (NOT MSVC)

View File

@ -27,7 +27,7 @@ set(SOURCES
) )
add_executable(${PROJECT_NAME} ${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}) add_test(${PROJECT_NAME} ${PROJECT_NAME})
target_enable_style_warnings(${PROJECT_NAME}) target_enable_style_warnings(${PROJECT_NAME})

View File

@ -42,7 +42,7 @@ set(SOURCES
) )
add_executable(${PROJECT_NAME} ${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}) add_test(${PROJECT_NAME} ${PROJECT_NAME})
target_enable_style_warnings(${PROJECT_NAME}) target_enable_style_warnings(${PROJECT_NAME})

View File

@ -71,7 +71,7 @@ target_activate_cpp14(${PROJECT_NAME}_exit_signal)
target_link_libraries(${PROJECT_NAME}_exit_signal cpp-utils) target_link_libraries(${PROJECT_NAME}_exit_signal cpp-utils)
add_executable(${PROJECT_NAME} ${SOURCES}) 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_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_exit_status ${PROJECT_NAME}_exit_signal)
add_test(${PROJECT_NAME} ${PROJECT_NAME}) add_test(${PROJECT_NAME} ${PROJECT_NAME})

View File

@ -2,33 +2,30 @@
#include <csignal> #include <csignal>
#include "cpp-utils/assert/backtrace.h" #include "cpp-utils/assert/backtrace.h"
#include "cpp-utils/process/subprocess.h" #include "cpp-utils/process/subprocess.h"
#include <boost/filesystem.hpp>
#include "my-gtest-main.h"
using std::string; using std::string;
using testing::HasSubstr; using testing::HasSubstr;
namespace bf = boost::filesystem;
namespace { namespace {
std::string call_process_exiting_with(const std::string& kind, const std::string& signal = "") { std::string call_process_exiting_with(const std::string& kind, const std::string& signal = "") {
#if defined(_MSC_VER) #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 #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 #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); auto result = cpputils::Subprocess::call(command);
return result.output; return result.output;
} }
} }
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, ContainsExecutableName) {
string backtrace = cpputils::backtrace();
EXPECT_THAT(backtrace, HasSubstr("cpp-utils-test"));
}
TEST(BacktraceTest, ContainsTopLevelLine) { TEST(BacktraceTest, ContainsTopLevelLine) {
string backtrace = cpputils::backtrace(); string backtrace = cpputils::backtrace();
@ -84,26 +81,55 @@ 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();
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) { TEST(BacktraceTest, ShowBacktraceOnSigSegv) {
auto output = call_process_exiting_with_sigsegv(); 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) { TEST(BacktraceTest, ShowBacktraceOnUnhandledException) {
auto output = call_process_exiting_with_exception("my_exception_message"); 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) { TEST(BacktraceTest, ShowBacktraceOnSigIll) {
auto output = call_process_exiting_with_sigill(); 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 #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"));
@ -128,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("cpp-utils-test_exit_signal")); EXPECT_THAT(output, HasSubstr("cpputils::backtrace"));
} }
TEST(BacktraceTest, ShowBacktraceOnSigAbrt_ShowsCorrectSignalName) { TEST(BacktraceTest, ShowBacktraceOnSigAbrt_ShowsCorrectSignalName) {

View File

@ -1,19 +1,26 @@
#include <cpp-utils/process/subprocess.h> #include <cpp-utils/process/subprocess.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <boost/filesystem.hpp>
#include <cpp-utils/lock/ConditionBarrier.h> #include <cpp-utils/lock/ConditionBarrier.h>
#include "my-gtest-main.h"
using cpputils::Subprocess; using cpputils::Subprocess;
using cpputils::SubprocessError; using cpputils::SubprocessError;
using std::string;
namespace bf = boost::filesystem;
namespace { namespace {
std::string exit_with_message_and_status(const char* message, int status) { std::string exit_with_message_and_status(const char* message, int status) {
#if defined(_MSC_VER) #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 #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 #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);
} }
} }

View File

@ -11,6 +11,24 @@ TEST(ThreadDebuggingTest_ThreadName, givenMainThread_whenSettingAndGetting_thenD
get_thread_name(); 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) { TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenSettingAndGetting_thenDoesntCrash) {
ConditionBarrier nameIsChecked; ConditionBarrier nameIsChecked;
@ -27,37 +45,22 @@ TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenSettingAndGetting_then
EXPECT_TRUE(child_didnt_crash); 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) { TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenGettingFromOutside_thenIsCorrect) {
ConditionBarrier nameIsSet; ConditionBarrier nameIsSet;
ConditionBarrier nameIsChecked; ConditionBarrier nameIsChecked;
std::thread child([&] { std::thread child([&] {
set_thread_name("my_thread_name"); set_thread_name("my_thread_name");
nameIsSet.release(); nameIsSet.release();
nameIsChecked.wait(); nameIsChecked.wait();
}); });
nameIsSet.wait(); nameIsSet.wait();
set_thread_name("outer_thread_name"); // just to make sure the next line doesn't read the outer thread name 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); string name = get_thread_name(&child);
EXPECT_EQ("my_thread_name", name); EXPECT_EQ("my_thread_name", name);
nameIsChecked.release(); nameIsChecked.release();
child.join(); child.join();
} }
#endif

View File

@ -16,7 +16,7 @@ set(SOURCES
) )
add_executable(${PROJECT_NAME} ${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}) add_test(${PROJECT_NAME} ${PROJECT_NAME})
target_enable_style_warnings(${PROJECT_NAME}) target_enable_style_warnings(${PROJECT_NAME})

View File

@ -24,7 +24,7 @@ set(SOURCES
) )
add_executable(${PROJECT_NAME} ${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}) add_test(${PROJECT_NAME} ${PROJECT_NAME})
target_enable_style_warnings(${PROJECT_NAME}) target_enable_style_warnings(${PROJECT_NAME})

View File

@ -102,7 +102,7 @@ set(SOURCES
testutils/OpenFileHandle.cpp testutils/OpenFileHandle.h) testutils/OpenFileHandle.cpp testutils/OpenFileHandle.h)
add_executable(${PROJECT_NAME} ${SOURCES}) 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}) add_test(${PROJECT_NAME} ${PROJECT_NAME})
target_enable_style_warnings(${PROJECT_NAME}) target_enable_style_warnings(${PROJECT_NAME})

View File

@ -14,7 +14,13 @@ using fspp::fuse::FuseErrnoException;
class FuseFlushErrorTest: public FuseFlushTest, public WithParamInterface<int> { 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) { TEST_P(FuseFlushErrorTest, ReturnErrorFromFlush) {
ReturnIsFileOnLstat(FILENAME); ReturnIsFileOnLstat(FILENAME);

View File

@ -29,9 +29,7 @@ void FuseThread::start(const bf::path &mountDir, const vector<string> &fuseOptio
} }
void FuseThread::stop() { void FuseThread::stop() {
if (0 != pthread_kill(_child.native_handle(), SIGINT)) { _fuse->stop();
throw std::runtime_error("Error sending stop signal");
}
bool thread_stopped = _child.try_join_for(seconds(10)); bool thread_stopped = _child.try_join_for(seconds(10));
ASSERT(thread_stopped, "FuseThread could not be stopped"); ASSERT(thread_stopped, "FuseThread could not be stopped");
//Wait until it is properly shutdown (busy waiting is simple and doesn't hurt much here) //Wait until it is properly shutdown (busy waiting is simple and doesn't hurt much here)

View File

@ -6,7 +6,7 @@ set(SOURCES
) )
add_executable(${PROJECT_NAME} ${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}) add_test(${PROJECT_NAME} ${PROJECT_NAME})
target_enable_style_warnings(${PROJECT_NAME}) target_enable_style_warnings(${PROJECT_NAME})

View 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})

View 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();
}

View File

@ -0,0 +1,5 @@
#pragma once
#include <boost/filesystem/path.hpp>
const boost::filesystem::path& get_executable();

View File

@ -6,7 +6,7 @@ set(SOURCES
) )
add_executable(${PROJECT_NAME} ${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}) add_test(${PROJECT_NAME} ${PROJECT_NAME})
target_enable_style_warnings(${PROJECT_NAME}) target_enable_style_warnings(${PROJECT_NAME})

View File

@ -10,7 +10,6 @@ if (BUILD_TESTING)
project (googletest) project (googletest)
add_library(${PROJECT_NAME} dummy.cpp) add_library(${PROJECT_NAME} dummy.cpp)
target_link_libraries(${PROJECT_NAME} PUBLIC gtest gmock) 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) 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 :( # Disable "missing override" warning because gmock MOCK_METHOD() don't use override :(