diff --git a/src/platform/dbghelp_syminit_manager.cpp b/src/platform/dbghelp_syminit_manager.cpp index e11f866..5bb0d07 100644 --- a/src/platform/dbghelp_syminit_manager.cpp +++ b/src/platform/dbghelp_syminit_manager.cpp @@ -7,7 +7,7 @@ #include "utils/error.hpp" #include "utils/microfmt.hpp" -#include +#include #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN @@ -19,20 +19,30 @@ namespace cpptrace { namespace detail { dbghelp_syminit_manager::~dbghelp_syminit_manager() { - for(auto handle : set) { - if(!SymCleanup(handle)) { + for(auto kvp : cache) { + if(!SymCleanup(kvp.second)) { ASSERT(false, microfmt::format("Cpptrace SymCleanup failed with code {}\n", GetLastError()).c_str()); } } } - void dbghelp_syminit_manager::init(HANDLE proc) { - if(set.count(proc) == 0) { - if(!SymInitialize(proc, NULL, TRUE)) { - throw internal_error("SymInitialize failed {}", GetLastError()); - } - set.insert(proc); + HANDLE dbghelp_syminit_manager::init(HANDLE proc) { + auto itr = cache.find(proc); + + if (itr != cache.end()) { + return itr->second; + } + HANDLE duplicatedHandle = nullptr; + if (!DuplicateHandle(proc, proc, proc, &duplicatedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { + throw internal_error("DuplicateHandle failed"); + } + + if(!SymInitialize(proc, NULL, TRUE)) { + throw internal_error("SymInitialize failed {}", GetLastError()); + } + cache[proc] = duplicatedHandle; + return duplicatedHandle; } // Thread-safety: Must only be called from symbols_with_dbghelp while the dbghelp_lock lock is held diff --git a/src/platform/dbghelp_syminit_manager.hpp b/src/platform/dbghelp_syminit_manager.hpp index 9d91d84..e569dda 100644 --- a/src/platform/dbghelp_syminit_manager.hpp +++ b/src/platform/dbghelp_syminit_manager.hpp @@ -1,17 +1,17 @@ #ifndef DBGHELP_SYMINIT_MANAGER_HPP #define DBGHELP_SYMINIT_MANAGER_HPP -#include +#include namespace cpptrace { namespace detail { struct dbghelp_syminit_manager { // The set below contains Windows `HANDLE` objects, `void*` is used to avoid // including the (expensive) Windows header here - std::unordered_set set; + std::map cache; ~dbghelp_syminit_manager(); - void init(void* proc); + void* init(void* proc); }; // Thread-safety: Must only be called from symbols_with_dbghelp while the dbghelp_lock lock is held diff --git a/src/unwind/unwind_with_dbghelp.cpp b/src/unwind/unwind_with_dbghelp.cpp index e7ec467..64e530d 100644 --- a/src/unwind/unwind_with_dbghelp.cpp +++ b/src/unwind/unwind_with_dbghelp.cpp @@ -103,12 +103,16 @@ namespace detail { // SymInitialize( GetCurrentProcess(), NULL, TRUE ) has // already been called. // + HANDLE duplicatedHandle = nullptr; HANDLE proc = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); if(get_cache_mode() == cache_mode::prioritize_speed) { - get_syminit_manager().init(proc); + duplicatedHandle = get_syminit_manager().init(proc); } else { - if(!SymInitialize(proc, NULL, TRUE)) { + if (!DuplicateHandle(proc, proc, proc, &duplicatedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { + throw internal_error("DuplicateHandle failed"); + } + if(!SymInitialize(duplicatedHandle, NULL, TRUE)) { throw internal_error("SymInitialize failed"); } } @@ -116,7 +120,7 @@ namespace detail { if( !StackWalk64( machine_type, - proc, + duplicatedHandle, thread, &frame, machine_type == IMAGE_FILE_MACHINE_I386 ? NULL : &context, @@ -145,7 +149,7 @@ namespace detail { } } if(get_cache_mode() != cache_mode::prioritize_speed) { - if(!SymCleanup(proc)) { + if(!SymCleanup(duplicatedHandle)) { throw internal_error("SymCleanup failed"); } }