cpptrace/src/platform/dbghelp_syminit_manager.cpp
firesgc 1bcfcff021
Incompatible with JNI on Windows: use unique handle for SymInitialize #204 (#206)
WinDbg: Duplicate the process handle before using it in SymInitialize,
because other libraries may have already called SymInitialize for the
process
(https://learn.microsoft.com/en-us/windows/win32/debug/initializing-the-symbol-handler)


Fixes https://github.com/jeremy-rifkin/cpptrace/issues/204

---------

Co-authored-by: Jeremy <51220084+jeremy-rifkin@users.noreply.github.com>
2025-01-25 22:25:54 -06:00

60 lines
1.6 KiB
C++

#include "platform/platform.hpp"
#if IS_WINDOWS
#include "platform/dbghelp_syminit_manager.hpp"
#include "utils/error.hpp"
#include "utils/microfmt.hpp"
#include <unordered_map>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <dbghelp.h>
namespace cpptrace {
namespace detail {
dbghelp_syminit_manager::~dbghelp_syminit_manager() {
for(auto kvp : cache) {
if(!SymCleanup(kvp.second)) {
ASSERT(false, microfmt::format("Cpptrace SymCleanup failed with code {}\n", GetLastError()).c_str());
}
if(!CloseHandle(kvp.second)) {
ASSERT(false, microfmt::format("Cpptrace CloseHandle failed with code {}\n", GetLastError()).c_str());
}
}
}
HANDLE dbghelp_syminit_manager::init(HANDLE proc) {
auto itr = cache.find(proc);
if(itr != cache.end()) {
return itr->second;
}
HANDLE duplicated_handle = nullptr;
if(!DuplicateHandle(proc, proc, proc, &duplicated_handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
throw internal_error("DuplicateHandle failed {}", GetLastError());
}
if(!SymInitialize(duplicated_handle, NULL, TRUE)) {
throw internal_error("SymInitialize failed {}", GetLastError());
}
cache[proc] = duplicated_handle;
return duplicated_handle;
}
// Thread-safety: Must only be called from symbols_with_dbghelp while the dbghelp_lock lock is held
dbghelp_syminit_manager& get_syminit_manager() {
static dbghelp_syminit_manager syminit_manager;
return syminit_manager;
}
}
}
#endif