From d0f2c4fcf79222d5c6f3c17188a811b0a47833c6 Mon Sep 17 00:00:00 2001 From: Tannin Date: Wed, 17 Jul 2013 20:58:58 +0200 Subject: - now avoids a few unnecessary copy operations during generation of the directory structure - bugfix: circular dependency caused a memory leak - bugfix: removing a single mod lead to the wrong mod being deleted --- src/shared/leaktrace.cpp | 109 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/shared/leaktrace.cpp (limited to 'src/shared/leaktrace.cpp') diff --git a/src/shared/leaktrace.cpp b/src/shared/leaktrace.cpp new file mode 100644 index 00000000..0c618b68 --- /dev/null +++ b/src/shared/leaktrace.cpp @@ -0,0 +1,109 @@ +#include "leaktrace.h" +#include +#include +#include +#include +#include + + +static const int FRAMES_TO_SKIP = 3; // StackData::StackData(), __TraceData::regTrace(), TraceAlloc() +static const int FRAMES_TO_CAPTURE = 10; + + +void initDbgIfNecessary() +{ + HANDLE process = ::GetCurrentProcess(); + static std::set initialized; + if (initialized.find(::GetCurrentProcessId()) == initialized.end()) { + static bool firstCall = true; + if (firstCall) { + ::SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); + firstCall = false; + } + if (!::SymInitialize(process, NULL, TRUE)) { + printf("failed to initialize symbols: %d", ::GetLastError()); + } + initialized.insert(::GetCurrentProcessId()); + } +} + + +class StackData { + friend bool operator==(const StackData &LHS, const StackData &RHS); + friend bool operator<(const StackData &LHS, const StackData &RHS); +public: + StackData() { + m_Count = ::CaptureStackBackTrace(FRAMES_TO_SKIP, FRAMES_TO_CAPTURE, m_Stack, &m_Hash); + } + std::string toString() const { + initDbgIfNecessary(); + + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + + std::ostringstream stackStream; + + for(unsigned int i = 0; i < m_Count; ++i) { + DWORD64 displacement = 0; + if (!::SymFromAddr(::GetCurrentProcess(), (DWORD64)m_Stack[i], &displacement, symbol)) { + stackStream << m_Count - i - 1 << ": [" << m_Stack[i] << "]\n"; + } else { + stackStream << m_Count - i - 1 << ": " << symbol->Name << "\n"; + } + } + return stackStream.str(); + } +private: + LPVOID m_Stack[FRAMES_TO_CAPTURE]; + USHORT m_Count; + ULONG m_Hash; +}; + +bool operator==(const StackData &LHS, const StackData &RHS) { + return LHS.m_Hash == RHS.m_Hash; +} + +bool operator<(const StackData &LHS, const StackData &RHS) { + return LHS.m_Hash < RHS.m_Hash; +} + + + +static struct __TraceData { + void regTrace(void *pointer) { + m_Traces[reinterpret_cast(pointer)] = StackData(); + } + void deregTrace(void *pointer) { + auto iter = m_Traces.find(reinterpret_cast(pointer)); + if (iter != m_Traces.end()) { + m_Traces.erase(iter); + } + } + + ~__TraceData() { + std::map result; + for (auto iter = m_Traces.begin(); iter != m_Traces.end(); ++iter) { + result[iter->second] += 1; + } + for (auto iter = result.begin(); iter != result.end(); ++iter) { + printf("-----------------------------------\n" + "%d objects not freed, allocated at:\n%s", + iter->second, iter->first.toString().c_str()); + } + } + + std::map m_Traces; +} __trace; + + +void LeakTrace::TraceAlloc(void *ptr) +{ + __trace.regTrace(ptr); +} + +void LeakTrace::TraceDealloc(void *ptr) +{ + __trace.deregTrace(ptr); +} -- cgit v1.3.1