summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--source/LeakFinder.cpp221
-rw-r--r--source/LeakFinder.h3
-rw-r--r--source/Server.cpp8
3 files changed, 147 insertions, 85 deletions
diff --git a/source/LeakFinder.cpp b/source/LeakFinder.cpp
index 2702fb47a..aa7848b65 100644
--- a/source/LeakFinder.cpp
+++ b/source/LeakFinder.cpp
@@ -252,7 +252,8 @@ LeakFinderXmlOutput::LeakFinderXmlOutput()
-LeakFinderXmlOutput::LeakFinderXmlOutput(LPCTSTR szFileName)
+LeakFinderXmlOutput::LeakFinderXmlOutput(LPCTSTR szFileName) :
+ m_Progress(10)
{
#if _MSC_VER < 1400
m_fXmlFile = _tfopen(szFileName, _T("w"));
@@ -264,6 +265,10 @@ LeakFinderXmlOutput::LeakFinderXmlOutput(LPCTSTR szFileName)
{
MessageBox(NULL, _T("Could not open xml-logfile for leakfinder!"), _T("Warning"), MB_ICONHAND);
}
+ else
+ {
+ fprintf(m_fXmlFile, "<MEMREPORT>\n");
+ }
}
@@ -297,7 +302,12 @@ void LeakFinderXmlOutput::OnLeakStartEntry(LPCSTR szKeyName, SIZE_T nDataSize)
{
if (m_fXmlFile != NULL)
{
- fprintf(m_fXmlFile, " <LEAK requestID=\"%s\" size=\"%d\">\n", SimpleXMLEncode(szKeyName).c_str(), nDataSize);
+ fprintf(m_fXmlFile, "\t<LEAK requestID=\"%s\" size=\"%d\">\n", SimpleXMLEncode(szKeyName).c_str(), nDataSize);
+ }
+ if (--m_Progress == 0)
+ {
+ m_Progress = 100;
+ putc('.', stdout);
}
}
@@ -311,14 +321,14 @@ void LeakFinderXmlOutput::OnCallstackEntry(CallstackEntryType eType, CallstackEn
{
if (eType != lastEntry)
{
- fprintf(m_fXmlFile, " <STACKENTRY decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(entry.undName).c_str(), entry.offsetFromSmybol);
+ fprintf(m_fXmlFile, "\t\t<STACKENTRY decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(entry.undName).c_str(), entry.offsetFromSmybol);
fprintf(m_fXmlFile, "srcfile=\"%s\" line=\"%d\" line_offset=\"%+ld\" ", SimpleXMLEncode(entry.lineFileName).c_str(), entry.lineNumber, entry.offsetFromLine);
fprintf(m_fXmlFile, "module=\"%s\" base=\"%08lx\" ", SimpleXMLEncode(entry.moduleName).c_str(), entry.baseOfImage);
fprintf(m_fXmlFile, "/>\n");
}
else
{
- fprintf(m_fXmlFile, " </LEAK>\n");
+ fprintf(m_fXmlFile, "\t</LEAK>\n");
}
}
}
@@ -754,6 +764,11 @@ typedef struct _CrtMemBlockHeader
static CRTTable *g_pCRTTable = NULL;
+size_t g_CurrentMemUsage = 0;
+
+
+
+
// MyAllocHook is Single-Threaded, that means the the calls are serialized in the calling function!
static int MyAllocHook(int nAllocType, void *pvData,
@@ -772,93 +787,131 @@ static int MyAllocHook(int nAllocType, void *pvData,
if (_BLOCK_TYPE(nBlockUse) == _CRT_BLOCK) // Ignore internal C runtime library allocations
return TRUE;
#endif
- extern int _crtDbgFlag;
- if ( ((_CRTDBG_ALLOC_MEM_DF & _crtDbgFlag) == 0) && ( (nAllocType == _HOOK_ALLOC) || (nAllocType == _HOOK_REALLOC) ) )
- {
- // Someone has disabled that the runtime should log this allocation
- // so we do not log this allocation
- if (s_pfnOldCrtAllocHook != NULL)
- s_pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
- return TRUE;
- }
-
- // Handle the Disable/Enable setting
- if (InterlockedExchangeAdd(&s_CrtDisableCount, 0) != 0)
- return TRUE;
+ extern int _crtDbgFlag;
+ if ( ((_CRTDBG_ALLOC_MEM_DF & _crtDbgFlag) == 0) && ( (nAllocType == _HOOK_ALLOC) || (nAllocType == _HOOK_REALLOC) ) )
+ {
+ // Someone has disabled that the runtime should log this allocation
+ // so we do not log this allocation
+ if (s_pfnOldCrtAllocHook != NULL)
+ s_pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+ return TRUE;
+ }
- // Prevent from reentrat calls
- if (InterlockedIncrement(&s_lMallocCalled) > 1) { // I was already called
- InterlockedDecrement(&s_lMallocCalled);
- // call the previous alloc hook
- if (s_pfnOldCrtAllocHook != NULL)
- s_pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
- return TRUE;
- }
+ // Handle the Disable/Enable setting
+ if (InterlockedExchangeAdd(&s_CrtDisableCount, 0) != 0)
+ {
+ return TRUE;
+ }
- _ASSERT( (nAllocType == _HOOK_ALLOC) || (nAllocType == _HOOK_REALLOC) || (nAllocType == _HOOK_FREE) );
- _ASSERT( ( _BLOCK_TYPE(nBlockUse) >= 0 ) && ( _BLOCK_TYPE(nBlockUse) < 5 ) );
+ // Prevent from reentrat calls
+ if (InterlockedIncrement(&s_lMallocCalled) > 1)
+ {
+ // I was already called
+ InterlockedDecrement(&s_lMallocCalled);
+ // call the previous alloc hook
+ if (s_pfnOldCrtAllocHook != NULL)
+ s_pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+ return TRUE;
+ }
- if (nAllocType == _HOOK_FREE) { // freeing
- // Try to get the header information
- if (_CrtIsValidHeapPointer(pvData)) { // it is a valid Heap-Pointer
- // get the ID
- _CrtMemBlockHeader *pHead;
- // get a pointer to memory block header
- pHead = pHdr(pvData);
- nSize = pHead->nDataSize;
- lRequest = pHead->lRequest; // This is the ID!
+ _ASSERT( (nAllocType == _HOOK_ALLOC) || (nAllocType == _HOOK_REALLOC) || (nAllocType == _HOOK_FREE) );
+ _ASSERT( ( _BLOCK_TYPE(nBlockUse) >= 0 ) && ( _BLOCK_TYPE(nBlockUse) < 5 ) );
- if (pHead->nBlockUse == _IGNORE_BLOCK)
- {
- InterlockedDecrement(&s_lMallocCalled);
- if (s_pfnOldCrtAllocHook != NULL)
- s_pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
- return TRUE;
- }
- }
- if (lRequest != 0) { // RequestID was found
- g_pCRTTable->Remove(lRequest);
- }
- } // freeing
-
- if (nAllocType == _HOOK_REALLOC) { // re-allocating
- // Try to get the header information
- if (_CrtIsValidHeapPointer(pvData)) { // it is a valid Heap-Pointer
- BOOL bRet;
- LONG lReallocRequest;
- // get the ID
- _CrtMemBlockHeader *pHead;
- // get a pointer to memory block header
- pHead = pHdr(pvData);
- // Try to find the RequestID in the Hash-Table, mark it that it was freed
- lReallocRequest = pHead->lRequest;
- bRet = g_pCRTTable->Remove(lReallocRequest);
- } // ValidHeapPointer
- } // re-allocating
-
- //if ( (g_ulShowStackAtAlloc < 3) && (nAllocType == _HOOK_FREE) ) {
- if (nAllocType == _HOOK_FREE) {
- InterlockedDecrement(&s_lMallocCalled);
- // call the previous alloc hook
- if (s_pfnOldCrtAllocHook != NULL)
- s_pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
- return TRUE;
- }
+ if (nAllocType == _HOOK_FREE)
+ {
+ // freeing
+ // Try to get the header information
+ if (_CrtIsValidHeapPointer(pvData)) { // it is a valid Heap-Pointer
+ // get the ID
+ _CrtMemBlockHeader *pHead;
+ // get a pointer to memory block header
+ pHead = pHdr(pvData);
+ nSize = pHead->nDataSize;
+ lRequest = pHead->lRequest; // This is the ID!
+
+ if (pHead->nBlockUse == _IGNORE_BLOCK)
+ {
+ InterlockedDecrement(&s_lMallocCalled);
+ if (s_pfnOldCrtAllocHook != NULL)
+ {
+ s_pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+ }
+ return TRUE;
+ }
+ }
+ if (lRequest != 0)
+ {
+ // RequestID was found
+ g_CurrentMemUsage -= nSize;
+ g_pCRTTable->Remove(lRequest);
+ }
+ } // freeing
+
+ if (nAllocType == _HOOK_REALLOC)
+ {
+ // re-allocating
+ // Try to get the header information
+ if (_CrtIsValidHeapPointer(pvData)) { // it is a valid Heap-Pointer
+ BOOL bRet;
+ LONG lReallocRequest;
+ // get the ID
+ _CrtMemBlockHeader *pHead;
+ // get a pointer to memory block header
+ pHead = pHdr(pvData);
+ // Try to find the RequestID in the Hash-Table, mark it that it was freed
+ lReallocRequest = pHead->lRequest;
+ g_CurrentMemUsage -= pHead->nDataSize;
+ bRet = g_pCRTTable->Remove(lReallocRequest);
+ } // ValidHeapPointer
+ } // re-allocating
+
+ //if ( (g_ulShowStackAtAlloc < 3) && (nAllocType == _HOOK_FREE) ) {
+ if (nAllocType == _HOOK_FREE)
+ {
+ InterlockedDecrement(&s_lMallocCalled);
+ // call the previous alloc hook
+ if (s_pfnOldCrtAllocHook != NULL)
+ {
+ s_pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+ }
+ return TRUE;
+ }
- CONTEXT c;
- GET_CURRENT_CONTEXT(c, CONTEXT_FULL);
+ CONTEXT c;
+ GET_CURRENT_CONTEXT(c, CONTEXT_FULL);
- // Only insert in the Hash-Table if it is not a "freeing"
- if (nAllocType != _HOOK_FREE) {
- if(lRequest != 0) // Always a valid RequestID should be provided (see comments in the header)
- g_pCRTTable->Insert(lRequest, c, nSize);
- }
+ // Only insert in the Hash-Table if it is not a "freeing"
+ if (nAllocType != _HOOK_FREE)
+ {
+ if (lRequest != 0) // Always a valid RequestID should be provided (see comments in the header)
+ {
+ g_CurrentMemUsage += nSize;
+
+ if (g_CurrentMemUsage > 1024 * 1024 * 1024)
+ {
+ printf("******************************************\n");
+ printf("** Server reached 1 GiB memory usage, **\n");
+ printf("** something is probably wrong. **\n");
+ printf("** Writing memory dump into memdump.xml **\n");
+ printf("******************************************\n");
+ printf("Please wait\n");
+
+ LeakFinderXmlOutput Output("memdump.xml");
+ DumpUsedMemory(&Output);
+
+ printf("\nMemory dump complete. Server will now abort.\n");
+ abort();
+ }
+
+ g_pCRTTable->Insert(lRequest, c, nSize);
+ }
+ }
- InterlockedDecrement(&s_lMallocCalled);
- // call the previous alloc hook
- if (s_pfnOldCrtAllocHook != NULL)
- s_pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
- return TRUE; // allow the memory operation to proceed
+ InterlockedDecrement(&s_lMallocCalled);
+ // call the previous alloc hook
+ if (s_pfnOldCrtAllocHook != NULL)
+ s_pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
+ return TRUE; // allow the memory operation to proceed
} // MyAllocHook
#endif // _DEBUG
diff --git a/source/LeakFinder.h b/source/LeakFinder.h
index 42af4f910..e63b9ec5d 100644
--- a/source/LeakFinder.h
+++ b/source/LeakFinder.h
@@ -98,7 +98,8 @@ protected:
virtual void OnOutput(LPCSTR szText) { }
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) { }
- FILE *m_fXmlFile;
+ FILE * m_fXmlFile;
+ int m_Progress;
};
// C++ interface:
diff --git a/source/Server.cpp b/source/Server.cpp
index 24d999b31..ce631f754 100644
--- a/source/Server.cpp
+++ b/source/Server.cpp
@@ -452,6 +452,14 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd)
DumpUsedMemory(&Output);
return;
}
+
+ if (split[0].compare("killmem") == 0)
+ {
+ while (true)
+ {
+ new char[100 * 1024 * 1024]; // Allocate and leak 100 MiB in a loop -> fill memory and kill MCS
+ }
+ }
#endif
if (cPluginManager::Get()->ExecuteConsoleCommand(split))