From d2780443c64e058f0840c3ab7ea6a0a8c12e7343 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Fri, 19 Oct 2012 22:09:33 +0000 Subject: [PATCH] Use leakfinder in debug builds to dump all currently used memory via the "dumpmem" console command. git-svn-id: http://mc-server.googlecode.com/svn/trunk@984 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/LeakFinder.cpp | 327 ++++++++++++++---------------------------- source/LeakFinder.h | 10 ++ source/Server.cpp | 23 +++ source/main.cpp | 1 - 4 files changed, 143 insertions(+), 218 deletions(-) diff --git a/source/LeakFinder.cpp b/source/LeakFinder.cpp index 769b52222..c1446291f 100644 --- a/source/LeakFinder.cpp +++ b/source/LeakFinder.cpp @@ -129,6 +129,10 @@ #define _tcscat_s _tcscat #endif + + + + static std::string SimpleXMLEncode(LPCSTR szText) { std::string szRet; @@ -159,22 +163,40 @@ static std::string SimpleXMLEncode(LPCSTR szText) } + + + LeakFinderOutput::LeakFinderOutput(int options, LPCSTR szSymPath) : StackWalker(options, szSymPath) { } + + + + + void LeakFinderOutput::OnLeakSearchStart(LPCSTR szLeakFinderName) { CHAR buffer[1024]; _snprintf_s(buffer, 1024, "######## %s ########\n", szLeakFinderName); this->OnOutput(buffer); } + + + + + void LeakFinderOutput::OnLeakStartEntry(LPCSTR szKeyName, SIZE_T nDataSize) { CHAR buffer[1024]; _snprintf_s(buffer, 1024, "--------------- Key: %s, %d bytes ---------\n", szKeyName, nDataSize); this->OnOutput(buffer); } + + + + + void LeakFinderOutput::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry) { if ( (eType != lastEntry) && (entry.offset != 0) ) @@ -195,6 +217,9 @@ void LeakFinderOutput::OnCallstackEntry(CallstackEntryType eType, CallstackEntry } + + + // #################################################################### // XML-Output LeakFinderXmlOutput::LeakFinderXmlOutput() @@ -222,6 +247,11 @@ LeakFinderXmlOutput::LeakFinderXmlOutput() MessageBox(NULL, _T("Could not open xml-logfile for leakfinder!"), _T("Warning"), MB_ICONHAND); } } + + + + + LeakFinderXmlOutput::LeakFinderXmlOutput(LPCTSTR szFileName) { #if _MSC_VER < 1400 @@ -235,6 +265,11 @@ LeakFinderXmlOutput::LeakFinderXmlOutput(LPCTSTR szFileName) MessageBox(NULL, _T("Could not open xml-logfile for leakfinder!"), _T("Warning"), MB_ICONHAND); } } + + + + + LeakFinderXmlOutput::~LeakFinderXmlOutput() { if (m_fXmlFile != NULL) @@ -245,9 +280,19 @@ LeakFinderXmlOutput::~LeakFinderXmlOutput() } m_fXmlFile = NULL; } + + + + + void LeakFinderXmlOutput::OnLeakSearchStart(LPCSTR sszLeakFinderName) { } + + + + + void LeakFinderXmlOutput::OnLeakStartEntry(LPCSTR szKeyName, SIZE_T nDataSize) { if (m_fXmlFile != NULL) @@ -255,6 +300,11 @@ void LeakFinderXmlOutput::OnLeakStartEntry(LPCSTR szKeyName, SIZE_T nDataSize) fprintf(m_fXmlFile, " \n", SimpleXMLEncode(szKeyName).c_str(), nDataSize); } } + + + + + void LeakFinderXmlOutput::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry) { if (m_fXmlFile != NULL) @@ -273,6 +323,10 @@ void LeakFinderXmlOutput::OnCallstackEntry(CallstackEntryType eType, CallstackEn } } + + + + // ########################################################################## // ########################################################################## // ########################################################################## @@ -567,6 +621,9 @@ public: }; // template class ContextHashtableBase + + + // ########################################################################## // ########################################################################## // ########################################################################## @@ -802,186 +859,6 @@ static int MyAllocHook(int nAllocType, void *pvData, #endif // _DEBUG -// ########################################################################## -// ########################################################################## -// ########################################################################## -// Specialization for COM-Leaks: - -// forwards: -class COMTable; -class CMallocSpy : public IMallocSpy -{ -public: - CMallocSpy() { m_cbRequest = 0; m_cRef = 0; m_disableCount = 0; } - virtual ~CMallocSpy() {} - // IUnknown methods - STDMETHOD(QueryInterface) (REFIID riid, LPVOID *ppUnk); - STDMETHOD_(ULONG, AddRef) (); - STDMETHOD_(ULONG, Release) (); - // IMallocSpy methods - STDMETHOD_(SIZE_T, PreAlloc) (SIZE_T cbRequest); - STDMETHOD_(void *, PostAlloc) (void *pActual); - STDMETHOD_(void *, PreFree) (void *pRequest, BOOL fSpyed); - STDMETHOD_(void, PostFree) (BOOL fSpyed) { return; }; - STDMETHOD_(SIZE_T, PreRealloc) (void *pRequest, SIZE_T cbRequest, void **ppNewRequest, BOOL fSpyed); - STDMETHOD_(void *, PostRealloc) (void *pActual, BOOL fSpyed); - STDMETHOD_(void *, PreGetSize) (void *pRequest, BOOL fSpyed) { return pRequest; } - STDMETHOD_(SIZE_T, PostGetSize) (SIZE_T cbActual, BOOL fSpyed) { return cbActual; } - STDMETHOD_(void *, PreDidAlloc) (void *pRequest, BOOL fSpyed) { return pRequest; } - STDMETHOD_(BOOL, PostDidAlloc) (void *pRequest, BOOL fSpyed, BOOL fActual) { return fActual; } - STDMETHOD_(void, PreHeapMinimize) (void) { return; } - STDMETHOD_(void, PostHeapMinimize) (void) { return; } -private: - LONG m_cRef; - SIZE_T m_cbRequest; -protected: - COMTable *m_pComTable; - LONG m_disableCount; - friend COMTable; -}; - -class COMTable : public ContextHashtableBase -{ -public: - COMTable() : ContextHashtableBase(1021, "COM-Leaks") - { - m_pMallocSpy = new CMallocSpy(); // wird später durch Release freigegeben - if (m_pMallocSpy != NULL) - { - m_pMallocSpy->m_pComTable = this; - // CoInitilize(); // ??? Is this necessary ? - HRESULT hr = CoRegisterMallocSpy(m_pMallocSpy); - if FAILED(hr) - { - _tprintf(_T("\nCoRegisterMallocSpay failed with %.8x"), hr); - } - } - } - - virtual ~COMTable() - { - if (m_pMallocSpy != NULL) - m_pMallocSpy->m_pComTable = NULL; - CoRevokeMallocSpy(); - } - - virtual LONG Disable() - { - return InterlockedIncrement(&(m_pMallocSpy->m_disableCount)); - } - virtual LONG Enable() - { - return InterlockedDecrement(&(m_pMallocSpy->m_disableCount)); - } - - virtual SIZE_T HashFunction(LPVOID &key) - { - // I couldn´t find any better and faster -#ifdef _M_IX86 -#if _MSC_VER > 1100 -#pragma warning (push) -#endif -#pragma warning (disable: 4311) - DWORD llP = (DWORD) key; -#if _MSC_VER > 1100 -#pragma warning (pop) -#endif -#else - ULONGLONG llP = (ULONGLONG) key; -#endif - return (SIZE_T) llP % sAllocEntries; - } - virtual BOOL IsKeyEmpty(LPVOID &key) - { - if (key == 0) - return TRUE; - return FALSE; - } - virtual VOID SetEmptyKey(LPVOID &key) - { - key = 0; - } - virtual VOID GetKeyAsString(LPVOID &key, CHAR *szName, SIZE_T nBufferLen) - { -#if _MSC_VER < 1400 - _snprintf_s(szName, nBufferLen, "%p", key); -#else - _snprintf_s(szName, nBufferLen, nBufferLen, "%p", key); -#endif - } - - CMallocSpy *m_pMallocSpy; - friend CMallocSpy; -}; // class COMTable - - -STDMETHODIMP CMallocSpy::QueryInterface(REFIID riid, LPVOID *ppUnk) { - HRESULT hr = S_OK; - if (IsEqualIID(riid, IID_IUnknown)) { - *ppUnk = (IUnknown *) this; - } - else if (IsEqualIID(riid, IID_IMallocSpy)) { - *ppUnk = (IMalloc *) this; - } - else { - *ppUnk = NULL; - hr = E_NOINTERFACE; - } - AddRef(); - return hr; -} -STDMETHODIMP_(ULONG) CMallocSpy::AddRef(void) { - return (ULONG) InterlockedIncrement(&m_cRef); -} -STDMETHODIMP_(ULONG) CMallocSpy::Release(void) { - LONG cRef; - cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) - { - delete this; - } - return (ULONG) cRef; -} -// IMallocSpy methods -STDMETHODIMP_(SIZE_T) CMallocSpy::PreAlloc(SIZE_T cbRequest) { - m_cbRequest = cbRequest; - return cbRequest; -} -STDMETHODIMP_(void *) CMallocSpy::PostAlloc(void *pActual) { - if (m_pComTable != NULL) - { - CONTEXT c; - GET_CURRENT_CONTEXT(c, CONTEXT_FULL); - m_pComTable->Insert(pActual, c, m_cbRequest); - } - return pActual; -} -STDMETHODIMP_(void *) CMallocSpy::PreFree(void *pRequest, BOOL fSpyed) { - if (m_pComTable != NULL) - { - m_pComTable->Remove(pRequest); - } - return pRequest; -} -STDMETHODIMP_(SIZE_T) CMallocSpy::PreRealloc(void *pRequest, SIZE_T cbRequest, - void **ppNewRequest, BOOL fSpyed) { - if (m_pComTable != NULL) - { - m_pComTable->Remove(pRequest); - } - *ppNewRequest = pRequest; // Bug fixed. Thanx to Christoph Weber - return cbRequest; -} -STDMETHODIMP_(void *) CMallocSpy::PostRealloc(void *pActual, BOOL fSpyed) { - if (m_pComTable != NULL) - { - CONTEXT c; - GET_CURRENT_CONTEXT(c, CONTEXT_FULL); - m_pComTable->Insert(pActual, c, m_cbRequest); - } - return pActual; -} - @@ -990,51 +867,67 @@ STDMETHODIMP_(void *) CMallocSpy::PostRealloc(void *pActual, BOOL fSpyed) { // ########################################################################## // Init/Deinit functions - -static COMTable *g_pCOMTable; HRESULT InitLeakFinder() { - // _X: Disabled COM monitoring: g_pCOMTable = new COMTable(); -#ifdef _DEBUG - g_pCRTTable = new CRTTable(); -#endif - return S_OK; + #ifdef _DEBUG + g_pCRTTable = new CRTTable(); + #endif + return S_OK; } + + + + +void DumpUsedMemory(LeakFinderOutput * output) +{ + LeakFinderOutput *pLeakFinderOutput = output; + + #ifdef _DEBUG + g_pCRTTable->Disable(); + #endif + + if (pLeakFinderOutput == NULL) + { + pLeakFinderOutput = new LeakFinderOutput(); + } + + // explicitly load the modules: + pLeakFinderOutput->LoadModules(); + + #ifdef _DEBUG + g_pCRTTable->ShowLeaks(*pLeakFinderOutput); + #endif + + if (output == NULL) + { + delete pLeakFinderOutput; + } +} + + + + + void DeinitLeakFinder(LeakFinderOutput *output) { - LeakFinderOutput *pLeakFinderOutput = output; + DumpUsedMemory(output); -#ifdef _DEBUG - g_pCRTTable->Disable(); -#endif - // _X: Disabled COM monitoring: g_pCOMTable->Disable(); - - if (pLeakFinderOutput == NULL) - pLeakFinderOutput = new LeakFinderOutput(); - - // explicite load the modules: - pLeakFinderOutput->LoadModules(); - -#ifdef _DEBUG - g_pCRTTable->ShowLeaks(*pLeakFinderOutput); - if (g_pCRTTable != NULL) - delete g_pCRTTable; - g_pCRTTable = NULL; -#endif - - /* - // _X: Disabled COM monitoring: - g_pCOMTable->ShowLeaks(*pLeakFinderOutput); - if (g_pCOMTable != NULL) - delete g_pCOMTable; - g_pCOMTable = NULL; - */ - - if (output == NULL) - delete pLeakFinderOutput; + #ifdef _DEBUG + delete g_pCRTTable; + g_pCRTTable = NULL; + #endif } + + + + + void DeinitLeakFinder() { - DeinitLeakFinder(NULL); + DeinitLeakFinder(NULL); } + + + + diff --git a/source/LeakFinder.h b/source/LeakFinder.h index 6743adda0..42af4f910 100644 --- a/source/LeakFinder.h +++ b/source/LeakFinder.h @@ -143,3 +143,13 @@ ZZZ_LeakFinder zzz_LeakFinder; #endif #endif // __cplusplus + + + + +extern void DumpUsedMemory(LeakFinderOutput * output = NULL); + + + + + diff --git a/source/Server.cpp b/source/Server.cpp index 8b1fd3c1e..ea25392a5 100644 --- a/source/Server.cpp +++ b/source/Server.cpp @@ -38,6 +38,20 @@ extern "C" { +// For the "dumpmem" server command: +/// Synchronize this with main.cpp - the leak finder needs initialization before it can be used to dump memory +#define ENABLE_LEAK_FINDER + +#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) + #pragma warning(push) + #pragma warning(disable:4100) + #include "LeakFinder.h" + #pragma warning(pop) +#endif + + + + typedef std::list< cClientHandle* > ClientList; @@ -528,6 +542,15 @@ void cServer::ServerCommand(const AString & a_Cmd) return; } + #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) + if (split[0].compare("dumpmem") == 0) + { + LeakFinderXmlOutput Output("memdump.xml"); + DumpUsedMemory(&Output); + return; + } + #endif + if (split.size() > 1) { if (split[0].compare("say") == 0) diff --git a/source/main.cpp b/source/main.cpp index 5e67531ab..71110c265 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -27,7 +27,6 @@ #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) - #define XML_LEAK_FINDER #pragma warning(push) #pragma warning(disable:4100) #include "LeakFinder.h"