Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 52 additions & 4 deletions src/ffi/backtrace_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,51 @@
#include <tvm/ffi/error.h>

#include <iostream>
#include <mutex>
#include <vector>

#include "./backtrace_utils.h"

namespace {

/*! \brief Global singleton holding tvm_ffi's DbgHelp symbol session. */
struct DbgHelpSession {
/*! \brief Serializes every DbgHelp call made by tvm_ffi. */
std::mutex mutex;
/*! \brief Session handle, or nullptr when no session could be established. */
HANDLE handle = nullptr;

static DbgHelpSession* Global() {
static DbgHelpSession inst;
return &inst;
}

DbgHelpSession() {
HANDLE current_process_handle = GetCurrentProcess();
// Duplicate rather than key the session on GetCurrentProcess() directly: that
// value is the same in every component, so another DbgHelp user in this process
// could close our symbols. A duplicated handle is a key only we hold.
if (!DuplicateHandle(current_process_handle, current_process_handle, current_process_handle,
&handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
handle = nullptr;
return;
}
// LOAD_LINES keeps file and line information; UNDNAME demangles C++ names.
SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
// TRUE enumerates loaded modules now, so no module is discovered later while
// the mutex is held. Unlike the previous code the result is checked: a session
// that failed to initialize must not be cached as usable.
if (!SymInitialize(handle, NULL, TRUE)) {
// Nothing was filed under this key, so there is no session to SymCleanup;
// release the handle and leave it null to report the failure.
CloseHandle(handle);
handle = nullptr;
}
}
};

} // namespace

const TVMFFIByteArray* TVMFFIBacktrace(const char* filename, int lineno, const char* func,
int cross_ffi_boundary) {
static thread_local std::string backtrace_str;
Expand All @@ -51,11 +92,19 @@ const TVMFFIByteArray* TVMFFIBacktrace(const char* filename, int lineno, const c
backtrace.Append(filename, func, lineno);
}

HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();

SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
SymInitialize(process, NULL, TRUE);
DbgHelpSession* session = DbgHelpSession::Global();
std::lock_guard<std::mutex> lock(session->mutex);
HANDLE process = session->handle;
if (process == nullptr) {
// StackWalk64 resolves through the session, so without one there is nothing
// to walk. Report the caller's own frame instead of using a dead session.
backtrace_str = backtrace.GetBacktrace();
backtrace_array.data = backtrace_str.data();
backtrace_array.size = backtrace_str.size();
return &backtrace_array;
}
CONTEXT context = {};
RtlCaptureContext(&context);

Expand Down Expand Up @@ -138,7 +187,6 @@ const TVMFFIByteArray* TVMFFIBacktrace(const char* filename, int lineno, const c
}
backtrace.Append(filename, symbol, lineno);
}
SymCleanup(process);
backtrace_str = backtrace.GetBacktrace();
backtrace_array.data = backtrace_str.data();
backtrace_array.size = backtrace_str.size();
Expand Down