Skip to content

Commit

Permalink
chore: print stack trace when abort() is called on Windows
Browse files Browse the repository at this point in the history
This is just a quick hack, the use of `cpptrace` should be more general
and platform-independent.
  • Loading branch information
mhx committed Oct 17, 2024
1 parent a38c526 commit 1015b49
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ if(WITH_LIBDWARFS)
endif()
endif()

if(WIN32)
find_package(cpptrace REQUIRED CONFIG)
endif()

pkg_check_modules(LIBCRYPTO REQUIRED IMPORTED_TARGET libcrypto>=${LIBCRYPTO_REQUIRED_VERSION})
pkg_check_modules(LIBARCHIVE REQUIRED IMPORTED_TARGET libarchive>=${LIBARCHIVE_REQUIRED_VERSION})
pkg_check_modules(XXHASH REQUIRED IMPORTED_TARGET libxxhash>=${XXHASH_REQUIRED_VERSION})
Expand Down Expand Up @@ -662,6 +666,7 @@ foreach(tgt ${LIBDWARFS_TARGETS} ${LIBDWARFS_OBJECT_TARGETS} dwarfs_test_helpers

if(WIN32)
target_link_libraries(${tgt} PRIVATE ntdll.lib dbghelp.lib)
target_link_libraries(${tgt} PRIVATE cpptrace::cpptrace)
endif()
endforeach()

Expand Down
3 changes: 3 additions & 0 deletions src/tool/safe_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ int safe_main(std::function<int(void)> fn) {
try {
install_signal_handlers();
setup_default_locale();
#ifdef _WIN32
::_set_abort_behavior(0, _WRITE_ABORT_MSG);
#endif

return fn();
} catch (...) {
Expand Down
69 changes: 69 additions & 0 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,15 @@

#include <dwarfs/config.h>

#ifdef _WIN32
#include <cpptrace/cpptrace.hpp>
#include <signal.h>
#include <tlhelp32.h>
#else
#ifdef DWARFS_STACKTRACE_ENABLED
#include <folly/debugging/symbolizer/SignalHandler.h>
#endif
#endif

#include <dwarfs/conv.h>
#include <dwarfs/error.h>
Expand Down Expand Up @@ -358,10 +364,73 @@ int get_current_umask() {
return mask;
}

#ifdef _WIN32

namespace {

std::vector<HANDLE> suspend_other_threads() {
std::vector<HANDLE> handles;
DWORD currend_tid = ::GetCurrentThreadId();
DWORD current_pid = ::GetCurrentProcessId();

HANDLE snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (snapshot == INVALID_HANDLE_VALUE) {
return handles;
}

THREADENTRY32 te;
te.dwSize = sizeof(THREADENTRY32);

if (::Thread32First(snapshot, &te)) {
do {
if (te.th32OwnerProcessID == current_pid &&
te.th32ThreadID != currend_tid) {
HANDLE th =
::OpenThread(THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
FALSE, te.th32ThreadID);
if (th) {
if (::SuspendThread(th) != static_cast<DWORD>(-1)) {
handles.push_back(th);
} else {
::CloseHandle(th);
}
}
}
} while (::Thread32Next(snapshot, &te));
}

::CloseHandle(snapshot);

return handles;
}

void resume_suspended_threads(const std::vector<HANDLE>& handles) {
for (auto th : handles) {
::ResumeThread(th);
::CloseHandle(th);
}
}

void abort_handler(int signal) {
auto suspended = suspend_other_threads();
std::cerr << "Caught signal " << signal << "\n";
cpptrace::generate_trace().print();
resume_suspended_threads(suspended);
::exit(1);
}

} // namespace

#endif

void install_signal_handlers() {
#ifdef _WIN32
::signal(SIGABRT, abort_handler);
#else
#ifdef DWARFS_STACKTRACE_ENABLED
folly::symbolizer::installFatalSignalHandler();
#endif
#endif
}

} // namespace dwarfs
1 change: 1 addition & 0 deletions vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"boost-uuid",
"boost-variant",
"brotli",
"cpptrace",
"date",
"double-conversion",
"fmt",
Expand Down

0 comments on commit 1015b49

Please sign in to comment.