mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 20:12:57 +01:00
ci: build TSan with clang 15 and add -Werror=thread-safety, fix-up stacktraces (#5375)
## Description Pull request was inspired by the need to debug lock problems when working on https://github.com/dashpay/dash/pull/5352. As far as I'm aware, only macOS has `-Werror=thread-safety` as part of its default `CXXFLAGS` despite the capability being present on Linux as well. This PR introduces thread safety checks for that into our thread sanitizer build. Additionally, since we're using Clang, something that on first glimpse, appears to be something that `stacktraces.cpp` isn't happy with, due to `-Wl,-wrap` being available only on GCC, that no longer seems to be the case, since the version of Clang with comes with `focal`, its `lld` _does_ have support for `-wrap` (see [man page for `lld` on `focal`](https://manpages.ubuntu.com/manpages/focal/en/man1/lld.1.html)). The current `stable` version of Clang/LLVM is 15, at the time of this pull request (see https://apt.llvm.org/) but `focal` ships with an older version, requiring us to use the official LLVM APT repository. I feel we should be testing with recent compilers alongside the ones shipped by LTS distributions. Certain bugs are only made apparent when testing on rolling release distros or distros that have faster update cycles, like Fedora (see https://github.com/dashpay/dash/pull/5295 for an illustration of that), which ship with more recent compilers. Until we overhaul our CI systems to test using those distros directly (our current infrastructure is centered around using a "development image" with an LTS distro as the base), this is the best we can do. A similar pull request testing against the latest GCC stable will be welcome as that is currently outside the scope of this PR as the changes made were to make sure that builds were operating as expected on Clang/LLVM 15. --------- Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
parent
141e5ef348
commit
4963660b15
@ -11,6 +11,7 @@ export PACKAGES="clang-8 llvm-8 python3-zmq qtbase5-dev qttools5-dev-tools libev
|
|||||||
export DEP_OPTS="NO_UPNP=1 DEBUG=1"
|
export DEP_OPTS="NO_UPNP=1 DEBUG=1"
|
||||||
export TEST_RUNNER_EXTRA="--extended --exclude feature_pruning,feature_dbcrash,wallet_multiwallet.py" # Temporarily suppress ASan heap-use-after-free (see issue #14163)
|
export TEST_RUNNER_EXTRA="--extended --exclude feature_pruning,feature_dbcrash,wallet_multiwallet.py" # Temporarily suppress ASan heap-use-after-free (see issue #14163)
|
||||||
export GOAL="install"
|
export GOAL="install"
|
||||||
export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --enable-crash-hooks --with-sanitizers=thread"
|
export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --enable-crash-hooks --enable-suppress-external-warnings --with-sanitizers=thread"
|
||||||
|
export BITCOIN_CONFIG="${BITCOIN_CONFIG} CC=clang-15 CXX=clang++-15 CXXFLAGS=-Werror=thread-safety"
|
||||||
export CPPFLAGS="-DDEBUG_LOCKORDER -DENABLE_DASH_DEBUG -DARENA_DEBUG"
|
export CPPFLAGS="-DDEBUG_LOCKORDER -DENABLE_DASH_DEBUG -DARENA_DEBUG"
|
||||||
export PYZMQ=true
|
export PYZMQ=true
|
||||||
|
@ -77,8 +77,7 @@ RUN apt-get update && apt-get install $APT_ARGS \
|
|||||||
wine-stable \
|
wine-stable \
|
||||||
wine32 \
|
wine32 \
|
||||||
wine64 \
|
wine64 \
|
||||||
xorriso \
|
xorriso
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
ARG CPPCHECK_VERSION=2.10
|
ARG CPPCHECK_VERSION=2.10
|
||||||
RUN curl -sL "https://github.com/danmar/cppcheck/archive/${CPPCHECK_VERSION}.tar.gz" | tar -xvzf - --directory /tmp/
|
RUN curl -sL "https://github.com/danmar/cppcheck/archive/${CPPCHECK_VERSION}.tar.gz" | tar -xvzf - --directory /tmp/
|
||||||
@ -102,6 +101,20 @@ RUN \
|
|||||||
update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix; \
|
update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix; \
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
|
ARG LLVM_VERSION=15
|
||||||
|
# Setup Clang+LLVM support
|
||||||
|
RUN apt-get update && apt-get install $APT_ARGS \
|
||||||
|
lsb-release \
|
||||||
|
software-properties-common \
|
||||||
|
gnupg \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN cd /tmp && \
|
||||||
|
wget https://apt.llvm.org/llvm.sh && \
|
||||||
|
chmod +x llvm.sh && \
|
||||||
|
/tmp/llvm.sh ${LLVM_VERSION} && \
|
||||||
|
rm -rf /tmp/llvm.sh
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
mkdir -p /src/dash && \
|
mkdir -p /src/dash && \
|
||||||
mkdir -p /cache/ccache && \
|
mkdir -p /cache/ccache && \
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
#if WIN32
|
#if defined(WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@ -30,14 +30,14 @@
|
|||||||
#include <csignal>
|
#include <csignal>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !WIN32
|
#if !defined(WIN32)
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#if !__APPLE__
|
#if !defined(__APPLE__)
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __APPLE__
|
#if defined(__APPLE__)
|
||||||
#include <mach-o/dyld.h>
|
#include <mach-o/dyld.h>
|
||||||
#include <mach/mach_init.h>
|
#include <mach/mach_init.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
std::string DemangleSymbol(const std::string& name)
|
std::string DemangleSymbol(const std::string& name)
|
||||||
{
|
{
|
||||||
#if __GNUC__ || __clang__
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
int status = -4; // some arbitrary value to eliminate the compiler warning
|
int status = -4; // some arbitrary value to eliminate the compiler warning
|
||||||
char* str = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status);
|
char* str = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
@ -74,7 +74,7 @@ static std::atomic<bool> skipAbortSignal(false);
|
|||||||
|
|
||||||
static ssize_t GetExeFileNameImpl(char* buf, size_t bufSize)
|
static ssize_t GetExeFileNameImpl(char* buf, size_t bufSize)
|
||||||
{
|
{
|
||||||
#if WIN32
|
#if defined(WIN32)
|
||||||
std::vector<TCHAR> tmp(bufSize);
|
std::vector<TCHAR> tmp(bufSize);
|
||||||
DWORD len = GetModuleFileName(nullptr, tmp.data(), bufSize);
|
DWORD len = GetModuleFileName(nullptr, tmp.data(), bufSize);
|
||||||
if (len >= bufSize) {
|
if (len >= bufSize) {
|
||||||
@ -84,7 +84,7 @@ static ssize_t GetExeFileNameImpl(char* buf, size_t bufSize)
|
|||||||
buf[i] = (char)tmp[i];
|
buf[i] = (char)tmp[i];
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
#elif __APPLE__
|
#elif defined(__APPLE__)
|
||||||
uint32_t bufSize2 = (uint32_t)bufSize;
|
uint32_t bufSize2 = (uint32_t)bufSize;
|
||||||
if (_NSGetExecutablePath(buf, &bufSize2) != 0) {
|
if (_NSGetExecutablePath(buf, &bufSize2) != 0) {
|
||||||
// it's not entirely clear if the value returned by _NSGetExecutablePath includes the null character
|
// it's not entirely clear if the value returned by _NSGetExecutablePath includes the null character
|
||||||
@ -127,7 +127,7 @@ static void my_backtrace_error_callback (void *data, const char *msg,
|
|||||||
|
|
||||||
static backtrace_state* GetLibBacktraceState()
|
static backtrace_state* GetLibBacktraceState()
|
||||||
{
|
{
|
||||||
#if WIN32
|
#if defined(WIN32)
|
||||||
// libbacktrace is not able to handle the DWARF debuglink in the .exe
|
// libbacktrace is not able to handle the DWARF debuglink in the .exe
|
||||||
// but luckily we can just specify the .dbg file here as it's a valid PE/XCOFF file
|
// but luckily we can just specify the .dbg file here as it's a valid PE/XCOFF file
|
||||||
static std::string debugFileName = g_exeFileName + ".dbg";
|
static std::string debugFileName = g_exeFileName + ".dbg";
|
||||||
@ -140,7 +140,7 @@ static backtrace_state* GetLibBacktraceState()
|
|||||||
}
|
}
|
||||||
#endif // ENABLE_STACKTRACES
|
#endif // ENABLE_STACKTRACES
|
||||||
|
|
||||||
#if WIN32
|
#if defined(WIN32)
|
||||||
static uint64_t GetBaseAddress()
|
static uint64_t GetBaseAddress()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@ -188,7 +188,7 @@ static __attribute__((noinline)) std::vector<uint64_t> GetStackFrames(size_t ski
|
|||||||
STACKFRAME64 stackframe;
|
STACKFRAME64 stackframe;
|
||||||
ZeroMemory(&stackframe, sizeof(STACKFRAME64));
|
ZeroMemory(&stackframe, sizeof(STACKFRAME64));
|
||||||
|
|
||||||
#ifdef __i386__
|
#if defined(__i386__)
|
||||||
image = IMAGE_FILE_MACHINE_I386;
|
image = IMAGE_FILE_MACHINE_I386;
|
||||||
stackframe.AddrPC.Offset = context.Eip;
|
stackframe.AddrPC.Offset = context.Eip;
|
||||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||||
@ -196,7 +196,7 @@ static __attribute__((noinline)) std::vector<uint64_t> GetStackFrames(size_t ski
|
|||||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||||
stackframe.AddrStack.Offset = context.Esp;
|
stackframe.AddrStack.Offset = context.Esp;
|
||||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||||
#elif __x86_64__
|
#elif defined(__x86_64__)
|
||||||
image = IMAGE_FILE_MACHINE_AMD64;
|
image = IMAGE_FILE_MACHINE_AMD64;
|
||||||
stackframe.AddrPC.Offset = context.Rip;
|
stackframe.AddrPC.Offset = context.Rip;
|
||||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||||
@ -240,7 +240,7 @@ static __attribute__((noinline)) std::vector<uint64_t> GetStackFrames(size_t ski
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#if __APPLE__
|
#if defined(__APPLE__)
|
||||||
static uint64_t GetBaseAddress()
|
static uint64_t GetBaseAddress()
|
||||||
{
|
{
|
||||||
mach_port_name_t target_task;
|
mach_port_name_t target_task;
|
||||||
@ -534,14 +534,11 @@ static void PrintCrashInfo(const crash_info& ci)
|
|||||||
static StdMutex g_stacktraces_mutex;
|
static StdMutex g_stacktraces_mutex;
|
||||||
static std::map<void*, std::shared_ptr<std::vector<uint64_t>>> g_stacktraces;
|
static std::map<void*, std::shared_ptr<std::vector<uint64_t>>> g_stacktraces;
|
||||||
|
|
||||||
#if CRASH_HOOKS_WRAPPED_CXX_ABI
|
#ifdef CRASH_HOOKS_WRAPPED_CXX_ABI
|
||||||
// These come in through -Wl,-wrap
|
// These come in through -Wl,-wrap
|
||||||
// It only works on GCC
|
|
||||||
extern "C" void* __real___cxa_allocate_exception(size_t thrown_size);
|
extern "C" void* __real___cxa_allocate_exception(size_t thrown_size);
|
||||||
extern "C" void __real___cxa_free_exception(void * thrown_exception);
|
extern "C" void __real___cxa_free_exception(void * thrown_exception);
|
||||||
#if __clang__
|
#if defined(WIN32)
|
||||||
#error not supported on WIN32 (no dlsym support)
|
|
||||||
#elif WIN32
|
|
||||||
extern "C" void __real__assert(const char *assertion, const char *file, unsigned int line);
|
extern "C" void __real__assert(const char *assertion, const char *file, unsigned int line);
|
||||||
extern "C" void __real__wassert(const wchar_t *assertion, const wchar_t *file, unsigned int line);
|
extern "C" void __real__wassert(const wchar_t *assertion, const wchar_t *file, unsigned int line);
|
||||||
#else
|
#else
|
||||||
@ -560,13 +557,13 @@ extern "C" void __real___cxa_free_exception(void * thrown_exception)
|
|||||||
static auto f = (void(*)(void*))dlsym(RTLD_NEXT, "__cxa_free_exception");
|
static auto f = (void(*)(void*))dlsym(RTLD_NEXT, "__cxa_free_exception");
|
||||||
return f(thrown_exception);
|
return f(thrown_exception);
|
||||||
}
|
}
|
||||||
#if __clang__
|
#if defined(__clang__) && defined(__APPLE__)
|
||||||
extern "C" void __attribute__((noreturn)) __real___assert_rtn(const char *function, const char *file, int line, const char *assertion)
|
extern "C" void __attribute__((noreturn)) __real___assert_rtn(const char *function, const char *file, int line, const char *assertion)
|
||||||
{
|
{
|
||||||
static auto f = (void(__attribute__((noreturn)) *) (const char*, const char*, int, const char*))dlsym(RTLD_NEXT, "__assert_rtn");
|
static auto f = (void(__attribute__((noreturn)) *) (const char*, const char*, int, const char*))dlsym(RTLD_NEXT, "__assert_rtn");
|
||||||
f(function, file, line, assertion);
|
f(function, file, line, assertion);
|
||||||
}
|
}
|
||||||
#elif WIN32
|
#elif defined(WIN32)
|
||||||
#error not supported on WIN32 (no dlsym support)
|
#error not supported on WIN32 (no dlsym support)
|
||||||
#else
|
#else
|
||||||
extern "C" void __real___assert_fail(const char *assertion, const char *file, unsigned int line, const char *function)
|
extern "C" void __real___assert_fail(const char *assertion, const char *file, unsigned int line, const char *function)
|
||||||
@ -577,7 +574,7 @@ extern "C" void __real___assert_fail(const char *assertion, const char *file, un
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CRASH_HOOKS_WRAPPED_CXX_ABI
|
#ifdef CRASH_HOOKS_WRAPPED_CXX_ABI
|
||||||
#define WRAPPED_NAME(x) __wrap_##x
|
#define WRAPPED_NAME(x) __wrap_##x
|
||||||
#else
|
#else
|
||||||
#define WRAPPED_NAME(x) x
|
#define WRAPPED_NAME(x) x
|
||||||
@ -625,7 +622,7 @@ static __attribute__((noinline)) crash_info GetCrashInfoFromAssertion(const char
|
|||||||
return ci;
|
return ci;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __clang__
|
#if defined(__clang__) && defined(__APPLE__)
|
||||||
extern "C" void __attribute__((noinline)) WRAPPED_NAME(__assert_rtn)(const char *function, const char *file, int line, const char *assertion)
|
extern "C" void __attribute__((noinline)) WRAPPED_NAME(__assert_rtn)(const char *function, const char *file, int line, const char *assertion)
|
||||||
{
|
{
|
||||||
auto ci = GetCrashInfoFromAssertion(assertion, file, line, function);
|
auto ci = GetCrashInfoFromAssertion(assertion, file, line, function);
|
||||||
@ -633,7 +630,7 @@ extern "C" void __attribute__((noinline)) WRAPPED_NAME(__assert_rtn)(const char
|
|||||||
skipAbortSignal = true;
|
skipAbortSignal = true;
|
||||||
__real___assert_rtn(function, file, line, assertion);
|
__real___assert_rtn(function, file, line, assertion);
|
||||||
}
|
}
|
||||||
#elif WIN32
|
#elif defined(WIN32)
|
||||||
extern "C" void __attribute__((noinline)) WRAPPED_NAME(_assert)(const char *assertion, const char *file, unsigned int line)
|
extern "C" void __attribute__((noinline)) WRAPPED_NAME(_assert)(const char *assertion, const char *file, unsigned int line)
|
||||||
{
|
{
|
||||||
auto ci = GetCrashInfoFromAssertion(assertion, file, line, nullptr);
|
auto ci = GetCrashInfoFromAssertion(assertion, file, line, nullptr);
|
||||||
@ -763,7 +760,7 @@ void RegisterPrettyTerminateHander()
|
|||||||
std::set_terminate(terminate_handler);
|
std::set_terminate(terminate_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !WIN32
|
#if !defined(WIN32)
|
||||||
static void HandlePosixSignal(int s)
|
static void HandlePosixSignal(int s)
|
||||||
{
|
{
|
||||||
if (s == SIGABRT && skipAbortSignal) {
|
if (s == SIGABRT && skipAbortSignal) {
|
||||||
@ -840,7 +837,7 @@ LONG WINAPI HandleWindowsException(EXCEPTION_POINTERS * ExceptionInfo)
|
|||||||
|
|
||||||
void RegisterPrettySignalHandlers()
|
void RegisterPrettySignalHandlers()
|
||||||
{
|
{
|
||||||
#if WIN32
|
#if defined(WIN32)
|
||||||
SetUnhandledExceptionFilter(HandleWindowsException);
|
SetUnhandledExceptionFilter(HandleWindowsException);
|
||||||
#else
|
#else
|
||||||
const std::vector<int> posix_signals = {
|
const std::vector<int> posix_signals = {
|
||||||
@ -856,7 +853,7 @@ void RegisterPrettySignalHandlers()
|
|||||||
SIGTRAP, // Trace/breakpoint trap
|
SIGTRAP, // Trace/breakpoint trap
|
||||||
SIGXCPU, // CPU time limit exceeded (4.2BSD)
|
SIGXCPU, // CPU time limit exceeded (4.2BSD)
|
||||||
SIGXFSZ, // File size limit exceeded (4.2BSD)
|
SIGXFSZ, // File size limit exceeded (4.2BSD)
|
||||||
#if __APPLE__
|
#if defined(__APPLE__)
|
||||||
SIGEMT, // emulation instruction executed
|
SIGEMT, // emulation instruction executed
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user