23#if !(defined(BI_COMP_MSC) && (defined(__DEBUG) || defined(_DEBUG)))
24#error StackWalker only supports debug mode for VC++.
44#define HASH_ENTRY_REMOVE_AT_FREE
51static ULONG g_ulShowStackAtAlloc = 0;
58#define ALLOC_HASH_ENTRIES 8192
62#define MAX_ESP_LEN_BUF 0x500
66#define IGNORE_CRT_ALLOC
69#define LOG_FILE_MAX_SIZE 1024*128
72#define WITH_IMALLOC_SPY
75#ifdef WITH_IMALLOC_SPY
77void IMallocHashInsert(
void *pData, CONTEXT &Context,
size_t nDataSize);
78BOOL IMallocHashRemove(
void *pData);
82class CMallocSpy :
public IMallocSpy
92 STDMETHOD(QueryInterface) (REFIID riid, LPVOID *ppUnk) {
94 if (IsEqualIID(riid, IID_IUnknown)) {
95 *ppUnk = (IUnknown *)
this;
97 else if (IsEqualIID(riid, IID_IMallocSpy)) {
98 *ppUnk = (IMalloc *)
this;
107 STDMETHOD_(ULONG, AddRef) (void) {
108 return InterlockedIncrement(&m_cRef);
110 STDMETHOD_(ULONG, Release) (void) {
112 cRef = InterlockedDecrement(&m_cRef);
120 STDMETHOD_(ULONG, PreAlloc) (ULONG cbRequest) {
121 m_cbRequest = cbRequest;
124 STDMETHOD_(
void *, PostAlloc) (
void *pActual) {
126 if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
127 GetCurrentProcess(), &hThread, 0,
false, DUPLICATE_SAME_ACCESS ) != 0) {
130 memset( &c,
'\0',
sizeof c );
131 c.ContextFlags = CONTEXT_FULL;
132 if ( GetThreadContext( hThread, &c ) != 0) {
134 IMallocHashInsert(pActual, c, m_cbRequest);
136 CloseHandle(hThread);
140 STDMETHOD_(
void *, PreFree) (
void *pRequest, BOOL fSpyed) {
141 IMallocHashRemove(pRequest);
144 STDMETHOD_(
void, PostFree) (BOOL fSpyed) {
147 STDMETHOD_(ULONG, PreRealloc) (
void *pRequest, ULONG cbRequest,
148 void **ppNewRequest, BOOL fSpyed) {
149 IMallocHashRemove(pRequest);
150 m_cbRequest = cbRequest;
152 *ppNewRequest = pRequest;
156 STDMETHOD_(
void *, PostRealloc) (
void *pActual, BOOL fSpyed) {
158 if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
159 GetCurrentProcess(), &hThread, 0,
false, DUPLICATE_SAME_ACCESS ) != 0) {
162 memset( &c,
'\0',
sizeof c );
163 c.ContextFlags = CONTEXT_FULL;
164 if ( GetThreadContext( hThread, &c ) != 0) {
166 IMallocHashInsert(pActual, c, m_cbRequest);
168 CloseHandle(hThread);
172 STDMETHOD_(
void *, PreGetSize) (
void *pRequest, BOOL fSpyed) {
175 STDMETHOD_(ULONG, PostGetSize) (ULONG cbActual, BOOL fSpyed) {
178 STDMETHOD_(
void *, PreDidAlloc) (
void *pRequest, BOOL fSpyed) {
181 STDMETHOD_(BOOL, PostDidAlloc) (
void *pRequest, BOOL fSpyed, BOOL fActual) {
184 STDMETHOD_(
void, PreHeapMinimize) (void) {
187 STDMETHOD_(
void, PostHeapMinimize) (void) {
199#error "'imagehlp.h' should only included here, not before this point! Otherwise there are some problems!"
201#pragma pack( push, before_imagehlp, 8 )
203#pragma pack( pop, before_imagehlp )
204#if API_VERSION_NUMBER < 7
211typedef struct _IMAGEHLP_LINE
218} IMAGEHLP_LINE, *PIMAGEHLP_LINE;
220#define SYMOPT_LOAD_LINES 0x00000010
227static void ShowStackRM( HANDLE hThread, CONTEXT& c, FILE *fLogFile, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryFunction, HANDLE hProcess);
228static void ShowStack( HANDLE hThread, CONTEXT& c, FILE *fLogFile);
230static void AllocHashOut(FILE*);
231static ULONG AllocHashOutLeaks(FILE*);
236static TCHAR *g_pszAllocLogName = NULL;
237static FILE *g_fFile = NULL;
243static void AllocCheckFileOpen(
bool bAppend =
true) {
246 if (g_pszAllocLogName != NULL)
248 if (bAppend ==
false)
249 g_fFile =
_tfopen(g_pszAllocLogName,
_T(
"w"));
251 g_fFile =
_tfopen(g_pszAllocLogName,
_T(
"a"));
258static void WriteDateTime(FILE *fFile, BOOL asXMLAttrs = FALSE) {
259 TCHAR pszTemp[11], pszTemp2[11];
262 _tstrdate( pszTemp );
263 _tstrtime( pszTemp2 );
264 if (asXMLAttrs == FALSE)
265 _ftprintf(fFile,
_T(
"%s %s"), pszTemp, pszTemp2 );
267 _ftprintf(fFile,
_T(
"date=\"%s\" time=\"%s\" "), pszTemp, pszTemp2 );
276#define MAX_EIP_LEN_BUF 4
278#define ALLOC_ENTRY_NOT_FOUND 0xFFFFFFFF
281typedef struct AllocHashEntryType {
285 struct AllocHashEntryType *Next;
299static ULONG AllocHashEntries = 0;
300static ULONG AllocHashCollisions = 0;
301static ULONG AllocHashFreed = 0;
302static ULONG AllocHashMaxUsed = 0;
303static ULONG AllocHashCurrentCount = 0;
305static ULONG AllocHashMaxCollisions = 0;
306static ULONG AllocHashCurrentCollisions = 0;
309#ifdef WITH_IMALLOC_SPY
311typedef struct IMallocHashEntryType {
315 struct IMallocHashEntryType *Next;
324} IMallocHashEntryType;
330static ULONG IMallocHashEntries = 0;
331static ULONG IMallocHashCollisions = 0;
332static ULONG IMallocHashFreed = 0;
333static ULONG IMallocHashMaxUsed = 0;
334static ULONG IMallocHashCurrentCount = 0;
336static ULONG IMallocHashMaxCollisions = 0;
337static ULONG IMallocHashCurrentCollisions = 0;
341static ULONG IMallocHashOutLeaks(FILE*);
344static ULONG IMallocHashFunction(
void *pData) {
346 DWORD dwPointer = (DWORD) pData;
359void IMallocHashInsert(
void *pData, CONTEXT &Context,
size_t nDataSize) {
361 IMallocHashEntryType *pHashEntry;
363 IMallocHashEntries++;
364 IMallocHashCurrentCount++;
365 if (IMallocHashCurrentCount > IMallocHashMaxUsed)
366 IMallocHashMaxUsed = IMallocHashCurrentCount;
368 HashIdx = IMallocHashFunction(pData);
371 pHashEntry = &IMallocHashTable[HashIdx];
372 if (pHashEntry->pData == 0) {
375 IMallocHashCollisions++;
376 IMallocHashCurrentCollisions++;
377 if (IMallocHashCurrentCollisions > IMallocHashMaxCollisions)
378 IMallocHashMaxCollisions = IMallocHashCurrentCollisions;
380 while(pHashEntry->Next != NULL) {
381 pHashEntry = pHashEntry->Next;
384 pHashEntry->Next = (IMallocHashEntryType*) _calloc_dbg(
sizeof(IMallocHashEntryType), 1, _CRT_BLOCK, __FILE__, __LINE__);
385 pHashEntry = pHashEntry->Next;
388 pHashEntry->pData = pData;
389 pHashEntry->nDataSize = nDataSize;
390 pHashEntry->Next = NULL;
392 pHashEntry->dwEIPOffset = Context.Eip;
393 if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Eip, &(pHashEntry->pcEIPAddr),
MAX_EIP_LEN_BUF, &(pHashEntry->dwEIPLen)) == 0) {
396 pHashEntry->dwEIPLen = 0;
397 pHashEntry->dwEIPOffset = 0;
401 pHashEntry->dwESPOffset = Context.Ebp;
402 if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr),
MAX_ESP_LEN_BUF, &(pHashEntry->dwESPLen)) == 0) {
405 pHashEntry->dwESPLen = 0;
406 pHashEntry->dwESPOffset = 0;
409 if (GetLastError() == ERROR_PARTIAL_COPY)
412 MEMORY_BASIC_INFORMATION MemBuffer;
413 DWORD dwRet = VirtualQuery((LPCVOID) Context.Ebp, &MemBuffer,
sizeof(MemBuffer));
417 DWORD len = ((DWORD) MemBuffer.BaseAddress + MemBuffer.RegionSize) - Context.Ebp;
421 if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), len, &(pHashEntry->dwESPLen)) == 0)
425 pHashEntry->dwESPLen = 0;
426 pHashEntry->dwESPOffset = 0;
430 pHashEntry->dwESPOffset = Context.Ebp;
439static IMallocHashEntryType *IMallocHashFind(
void *pData) {
441 IMallocHashEntryType *pHashEntry;
442 HashIdx = IMallocHashFunction(pData);
445 pHashEntry = &IMallocHashTable[HashIdx];
446 while(pHashEntry != NULL) {
447 if (pHashEntry->pData == pData) {
450 pHashEntry = pHashEntry->Next;
457BOOL IMallocHashRemove(
void *pData) {
459 IMallocHashEntryType *pHashEntry, *pHashEntryLast;
460 HashIdx = IMallocHashFunction(pData);
463 pHashEntryLast = NULL;
464 pHashEntry = &IMallocHashTable[HashIdx];
465 while(pHashEntry != NULL) {
466 if (pHashEntry->pData == pData) {
467#ifdef HASH_ENTRY_REMOVE_AT_FREE
469 IMallocHashCurrentCount--;
470 if (pHashEntryLast == NULL) {
471 if (pHashEntry->Next == NULL) {
472 memset(&IMallocHashTable[HashIdx], 0,
sizeof(IMallocHashTable[HashIdx]));
475 *pHashEntry = *(pHashEntry->Next);
480 IMallocHashCurrentCollisions--;
481 pHashEntryLast->Next = pHashEntry->Next;
482 _free_dbg(pHashEntry, _CRT_BLOCK);
486 pHashEntry->cRemovedFlag++;
490 pHashEntryLast = pHashEntry;
491 pHashEntry = pHashEntry->Next;
499#if API_VERSION_NUMBER >= 9
500static BOOL __stdcall ReadProcMemoryFromIMallocHash(HANDLE pData, DWORD lpBaseAddress, PVOID lpBuffer, DWORD nSize, PDWORD lpNumberOfBytesRead) {
502static BOOL __stdcall ReadProcMemoryFromIMallocHash(HANDLE pData, LPCVOID lpBaseAddress, PVOID lpBuffer, DWORD nSize, PDWORD lpNumberOfBytesRead) {
505 IMallocHashEntryType *pHashEntry;
506 *lpNumberOfBytesRead = 0;
508 pHashEntry = IMallocHashFind((PVOID) pData);
510 *lpNumberOfBytesRead = 0;
513 if ( ((DWORD) lpBaseAddress >= pHashEntry->dwESPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwESPOffset+pHashEntry->dwESPLen)) ) {
514 DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwESPOffset;
516 memcpy(lpBuffer, &(pHashEntry->pcESPAddr[dwOffset]), dwSize);
517 *lpNumberOfBytesRead = dwSize;
522 if ( ((DWORD) lpBaseAddress >= pHashEntry->dwEIPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwEIPOffset+pHashEntry->dwEIPLen)) ) {
523 DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwEIPOffset;
525 memcpy(lpBuffer, &(pHashEntry->pcEIPAddr[dwOffset]), dwSize);
526 *lpNumberOfBytesRead = dwSize;
531 if (*lpNumberOfBytesRead == 0)
538ULONG IMallocHashOutLeaks(FILE *fFile) {
540 IMallocHashEntryType *pHashEntry;
542 ULONG ulLeaksByte = 0;
545 pHashEntry = &IMallocHashTable[ulTemp];
546 if (pHashEntry->pData != 0) {
547 while(pHashEntry != NULL) {
548 if ( (pHashEntry->cRemovedFlag <= 0) || (pHashEntry->cRemovedFlag > 1) ) {
551 _ftprintf(fFile,
_T(
"<LEAK requestID=\"%u\" size=\"%u\">\n"), pHashEntry->pData, pHashEntry->nDataSize);
553 _ftprintf(fFile,
_T(
"Pointer (RequestID): %12i, Removed: %i, Size: %12i\n"), pHashEntry->pData, pHashEntry->cRemovedFlag, pHashEntry->nDataSize);
555 memset( &c,
'\0',
sizeof c );
556 c.Eip = pHashEntry->dwEIPOffset;
557 c.Ebp = pHashEntry->dwESPOffset;
558 ShowStackRM( NULL, c, fFile, &ReadProcMemoryFromIMallocHash, (HANDLE) pHashEntry->pData);
559 if (pHashEntry->nDataSize > 0)
560 ulLeaksByte += pHashEntry->nDataSize;
565 _ftprintf(fFile,
_T(
"</LEAK>\n"));
567 pHashEntry = pHashEntry->Next;
572 _ftprintf(fFile,
_T(
"\n**** Number of leaks: %i\n"), ulCount);
578static void AllocHashInit(
void) {
580 memset(AllocHashTable, 0,
sizeof(AllocHashTable));
581 AllocHashEntries = 0;
582 AllocHashCollisions = 0;
584 AllocHashCurrentCount = 0;
585 AllocHashMaxUsed = 0;
587 AllocHashMaxCollisions = 0;
588 AllocHashCurrentCollisions = 0;
590#ifdef WITH_IMALLOC_SPY
591 memset(IMallocHashTable, 0,
sizeof(IMallocHashTable));
592 IMallocHashEntries = 0;
593 IMallocHashCollisions = 0;
594 IMallocHashFreed = 0;
595 IMallocHashCurrentCount = 0;
596 IMallocHashMaxUsed = 0;
598 IMallocHashMaxCollisions = 0;
599 IMallocHashCurrentCollisions = 0;
607static ULONG AllocHashDeinit(
void) {
610 AllocCheckFileOpen(bAppend);
614 _ftprintf(g_fFile,
_T(
"<MEMREPORT "));
615 WriteDateTime(g_fFile, TRUE);
616 _ftprintf(g_fFile,
_T(
">\n"));
620 _ftprintf(g_fFile,
_T(
"\n##### Memory Report ########################################\n"));
621 WriteDateTime(g_fFile);
622 _ftprintf(g_fFile,
_T(
"\n"));
625#ifndef HASH_ENTRY_REMOVE_AT_FREE
628 _ftprintf(g_fFile,
_T(
"##### Memory used: #########################################\n"));
629 AllocHashOut(g_fFile);
634 _ftprintf(g_fFile,
_T(
"\n##### Leaks: ###############################################\n"));
635 ulRet = AllocHashOutLeaks(g_fFile);
640 _ftprintf(g_fFile,
_T(
"***** Hash-Table statistics:\n"));
642 _ftprintf(g_fFile,
_T(
" Inserts: %i\n"), AllocHashEntries);
643 _ftprintf(g_fFile,
_T(
" Freed: %i\n"), AllocHashFreed);
644 _ftprintf(g_fFile,
_T(
" Sum Collisions: %i\n"), AllocHashCollisions);
645 _ftprintf(g_fFile,
_T(
"\n"));
646 _ftprintf(g_fFile,
_T(
" Max used: %i\n"), AllocHashMaxUsed);
647 _ftprintf(g_fFile,
_T(
" Max Collisions: %i\n"), AllocHashMaxCollisions);
652 AllocHashEntryType *pHashEntry, *pHashEntryOld;
656 pHashEntry = &AllocHashTable[ulTemp];
657 while(pHashEntry != NULL) {
658 pHashEntryOld = pHashEntry;
659 pHashEntry = pHashEntry->Next;
660 if (pHashEntryOld != &AllocHashTable[ulTemp]) {
667 memset(AllocHashTable, 0,
sizeof(AllocHashTable));
669#ifdef WITH_IMALLOC_SPY
672 _ftprintf(g_fFile,
_T(
"\n##### COM-Leaks: ###############################################\n"));
673 ulRet = IMallocHashOutLeaks(g_fFile);
678 _ftprintf(g_fFile,
_T(
"***** Hash-Table statistics:\n"));
680 _ftprintf(g_fFile,
_T(
" Inserts: %i\n"), IMallocHashEntries);
681 _ftprintf(g_fFile,
_T(
" Freed: %i\n"), IMallocHashFreed);
682 _ftprintf(g_fFile,
_T(
" Sum Collisions: %i\n"), IMallocHashCollisions);
683 _ftprintf(g_fFile,
_T(
"\n"));
684 _ftprintf(g_fFile,
_T(
" Max used: %i\n"), IMallocHashMaxUsed);
685 _ftprintf(g_fFile,
_T(
" Max Collisions: %i\n"), IMallocHashMaxCollisions);
690 IMallocHashEntryType *pIMHashEntry, *pIMHashEntryOld;
693 pIMHashEntry = &IMallocHashTable[ulTemp];
694 while(pHashEntry != NULL) {
695 pIMHashEntryOld = pIMHashEntry;
696 pIMHashEntry = pIMHashEntry->Next;
697 if (pIMHashEntryOld != &IMallocHashTable[ulTemp]) {
698 _free_dbg(pIMHashEntryOld, _CRT_BLOCK);
702 memset(IMallocHashTable, 0,
sizeof(IMallocHashTable));
707 _ftprintf(g_fFile,
_T(
"</MEMREPORT>\n"));
714static inline ULONG AllocHashFunction(
long lRequestID) {
723static void AllocHashInsert(
long lRequestID, CONTEXT &Context,
size_t nDataSize) {
725 AllocHashEntryType *pHashEntry;
729 AllocHashCurrentCount++;
730 if (AllocHashCurrentCount > AllocHashMaxUsed)
731 AllocHashMaxUsed = AllocHashCurrentCount;
734 HashIdx = AllocHashFunction(lRequestID);
736 pHashEntry = &AllocHashTable[HashIdx];
737 if (pHashEntry->lRequestID == 0) {
745 AllocHashCollisions++;
746 AllocHashCurrentCollisions++;
747 if (AllocHashCurrentCollisions > AllocHashMaxCollisions)
748 AllocHashMaxCollisions = AllocHashCurrentCollisions;
750 while(pHashEntry->Next != NULL) {
751 pHashEntry = pHashEntry->Next;
754 pHashEntry->Next = (AllocHashEntryType*) calloc(
sizeof(AllocHashEntryType), 1);
755 pHashEntry = pHashEntry->Next;
758 pHashEntry->lRequestID = lRequestID;
759 pHashEntry->nDataSize = nDataSize;
760 pHashEntry->Next = NULL;
762 pHashEntry->dwEIPOffset = Context.Eip;
763 if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Eip, &(pHashEntry->pcEIPAddr),
MAX_EIP_LEN_BUF, &(pHashEntry->dwEIPLen)) == 0) {
766 pHashEntry->dwEIPLen = 0;
767 pHashEntry->dwEIPOffset = 0;
771 pHashEntry->dwESPOffset = Context.Ebp;
772 if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr),
MAX_ESP_LEN_BUF, &(pHashEntry->dwESPLen)) == 0) {
775 pHashEntry->dwESPLen = 0;
776 pHashEntry->dwESPOffset = 0;
779 if (GetLastError() == ERROR_PARTIAL_COPY)
782 MEMORY_BASIC_INFORMATION MemBuffer;
783 DWORD dwRet = VirtualQuery((LPCVOID) Context.Ebp, &MemBuffer,
sizeof(MemBuffer));
787 DWORD len = ((DWORD) MemBuffer.BaseAddress + MemBuffer.RegionSize) - Context.Ebp;
791 if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) Context.Ebp, &(pHashEntry->pcESPAddr), len, &(pHashEntry->dwESPLen)) == 0)
795 pHashEntry->dwESPLen = 0;
796 pHashEntry->dwESPOffset = 0;
800 pHashEntry->dwESPOffset = Context.Ebp;
811static AllocHashEntryType *AllocHashFind(
long lRequestID) {
813 AllocHashEntryType *pHashEntry;
816 HashIdx = AllocHashFunction(lRequestID);
821 pHashEntry = &AllocHashTable[HashIdx];
822 while(pHashEntry != NULL) {
823 if (pHashEntry->lRequestID == lRequestID) {
826 pHashEntry = pHashEntry->Next;
836static BOOL AllocHashRemove(
long lRequestID) {
838 AllocHashEntryType *pHashEntry, *pHashEntryLast;
841 HashIdx = AllocHashFunction(lRequestID);
846 pHashEntryLast = NULL;
847 pHashEntry = &AllocHashTable[HashIdx];
848 while(pHashEntry != NULL) {
849 if (pHashEntry->lRequestID == lRequestID) {
850#ifdef HASH_ENTRY_REMOVE_AT_FREE
852 AllocHashCurrentCount--;
854 if (pHashEntryLast == NULL) {
856 if (pHashEntry->Next == NULL) {
858 memset(&AllocHashTable[HashIdx], 0,
sizeof(AllocHashTable[HashIdx]));
862 *pHashEntry = *(pHashEntry->Next);
870 AllocHashCurrentCollisions--;
871 pHashEntryLast->Next = pHashEntry->Next;
877 pHashEntry->cRemovedFlag++;
881 pHashEntryLast = pHashEntry;
882 pHashEntry = pHashEntry->Next;
891#if API_VERSION_NUMBER >= 9
892static BOOL __stdcall ReadProcMemoryFromHash(HANDLE hRequestID, DWORD lpBaseAddress, PVOID lpBuffer, DWORD nSize, PDWORD lpNumberOfBytesRead) {
894static BOOL __stdcall ReadProcMemoryFromHash(HANDLE hRequestID, LPCVOID lpBaseAddress, PVOID lpBuffer, DWORD nSize, PDWORD lpNumberOfBytesRead) {
897 AllocHashEntryType *pHashEntry;
898 *lpNumberOfBytesRead = 0;
900 pHashEntry = AllocHashFind((LONG) hRequestID);
903 *lpNumberOfBytesRead = 0;
906 if ( ((DWORD) lpBaseAddress >= pHashEntry->dwESPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwESPOffset+pHashEntry->dwESPLen)) ) {
909 DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwESPOffset;
911 memcpy(lpBuffer, &(pHashEntry->pcESPAddr[dwOffset]), dwSize);
912 *lpNumberOfBytesRead = dwSize;
917 if ( ((DWORD) lpBaseAddress >= pHashEntry->dwEIPOffset) && ((DWORD) lpBaseAddress <= (pHashEntry->dwEIPOffset+pHashEntry->dwEIPLen)) ) {
920 DWORD dwOffset = (DWORD) lpBaseAddress - pHashEntry->dwEIPOffset;
922 memcpy(lpBuffer, &(pHashEntry->pcEIPAddr[dwOffset]), dwSize);
923 *lpNumberOfBytesRead = dwSize;
928 if (*lpNumberOfBytesRead == 0)
937ULONG AllocHashOutLeaks(FILE *fFile) {
939 AllocHashEntryType *pHashEntry;
941 ULONG ulLeaksByte = 0;
945 pHashEntry = &AllocHashTable[ulTemp];
946 if (pHashEntry->lRequestID != 0) {
947 while(pHashEntry != NULL) {
948 if ( (pHashEntry->cRemovedFlag <= 0) || (pHashEntry->cRemovedFlag > 1) ) {
951 _ftprintf(fFile,
_T(
"<LEAK requestID=\"%u\" size=\"%u\">\n"), pHashEntry->lRequestID, pHashEntry->nDataSize);
953 _ftprintf(fFile,
_T(
"RequestID: %12i, Removed: %i, Size: %12i\n"), pHashEntry->lRequestID, pHashEntry->cRemovedFlag, pHashEntry->nDataSize);
955 memset( &c,
'\0',
sizeof c );
956 c.Eip = pHashEntry->dwEIPOffset;
957 c.Ebp = pHashEntry->dwESPOffset;
958 ShowStackRM( NULL, c, fFile, &ReadProcMemoryFromHash, (HANDLE) pHashEntry->lRequestID);
960 if (pHashEntry->nDataSize > 0)
961 ulLeaksByte += pHashEntry->nDataSize;
966 _ftprintf(fFile,
_T(
"</LEAK>\n"));
968 pHashEntry = pHashEntry->Next;
973 _ftprintf(fFile,
_T(
"\n**** Number of leaks: %i\n"), ulCount);
978void AllocHashOut(FILE *fFile) {
980 AllocHashEntryType *pHashEntry;
983 pHashEntry = &AllocHashTable[ulTemp];
984 if (pHashEntry->lRequestID != 0) {
985 while(pHashEntry != NULL) {
987 _ftprintf(fFile,
_T(
"<MEMUSED requestID=\"%u\" size=\"%u\"\n"), pHashEntry->lRequestID, pHashEntry->nDataSize);
989 _ftprintf(fFile,
_T(
"RequestID: %12i, Removed: %i, Size: %12i\n"), pHashEntry->lRequestID, pHashEntry->cRemovedFlag, pHashEntry->nDataSize);
990 pHashEntry = pHashEntry->Next;
1009#define nNoMansLandSize 4
1012typedef struct _CrtMemBlockHeader
1014 struct _CrtMemBlockHeader * pBlockHeaderNext;
1015 struct _CrtMemBlockHeader * pBlockHeaderPrev;
1035} _CrtMemBlockHeader;
1038#define pbData(pblock) ((unsigned char *)((_CrtMemBlockHeader *)pblock + 1))
1039#define pHdr(pbData) (((_CrtMemBlockHeader *)pbData)-1)
1047static BOOL g_bInitialized = FALSE;
1048static HINSTANCE g_hImagehlpDll = NULL;
1050static DWORD g_dwShowCount = 0;
1051static CRITICAL_SECTION g_csFileOpenClose = {0};
1054static LONG g_lMallocCalled = 0;
1056static _CRT_ALLOC_HOOK pfnOldCrtAllocHook = NULL;
1059static void DeactivateMallocStackwalker(
void) {
1060 InterlockedIncrement(&g_lMallocCalled);
1067static int MyAllocHook(
int nAllocType,
void *pvData,
1068 size_t nSize,
int nBlockUse,
long lRequest,
1069 const char * szFileName,
int nLine ) {
1071static int MyAllocHook(
int nAllocType,
void *pvData,
1072 size_t nSize,
int nBlockUse,
long lRequest,
1073 const unsigned char * szFileName,
int nLine ) {
1075 static TCHAR *operation[] = {
_T(
""),
_T(
"ALLOCATIONG"),
_T(
"RE-ALLOCATING"),
_T(
"FREEING") };
1076 static TCHAR *blockType[] = {
_T(
"Free"),
_T(
"Normal"),
_T(
"CRT"),
_T(
"Ignore"),
_T(
"Client") };
1078#ifdef IGNORE_CRT_ALLOC
1079 if (_BLOCK_TYPE(nBlockUse) == _CRT_BLOCK)
1082 extern int _crtDbgFlag;
1083 if ( ((_CRTDBG_ALLOC_MEM_DF & _crtDbgFlag) == 0) && ( (nAllocType == _HOOK_ALLOC) || (nAllocType == _HOOK_REALLOC) ) )
1087 if (pfnOldCrtAllocHook != NULL)
1088 pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
1093 if (InterlockedIncrement(&g_lMallocCalled) > 1) {
1094 InterlockedDecrement(&g_lMallocCalled);
1096 if (pfnOldCrtAllocHook != NULL)
1097 pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
1101 if (g_ulShowStackAtAlloc > 0) {
1102 AllocCheckFileOpen();
1105 _ASSERT( (nAllocType == _HOOK_ALLOC) || (nAllocType == _HOOK_REALLOC) || (nAllocType == _HOOK_FREE) );
1106 _ASSERT( ( _BLOCK_TYPE(nBlockUse) >= 0 ) && ( _BLOCK_TYPE(nBlockUse) < 5 ) );
1108 if (nAllocType == _HOOK_FREE) {
1110 if (_CrtIsValidHeapPointer(pvData)) {
1112 _CrtMemBlockHeader *pHead;
1114 pHead =
pHdr(pvData);
1115 nSize = pHead->nDataSize;
1116 lRequest = pHead->lRequest;
1118 if (pHead->nBlockUse == _IGNORE_BLOCK)
1120 InterlockedDecrement(&g_lMallocCalled);
1121 if (pfnOldCrtAllocHook != NULL)
1122 pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
1128 if (g_ulShowStackAtAlloc > 0) {
1129 _ftprintf( g_fFile,
_T(
"##### Memory operation: %s a %d-byte '%s' block (# %ld)"),
1130 operation[nAllocType], nSize, blockType[_BLOCK_TYPE(nBlockUse)], lRequest );
1131 if ( pvData != NULL )
1132 _ftprintf( g_fFile,
_T(
" at 0x%X"), pvData );
1133 _ftprintf(g_fFile,
_T(
"\n"));
1136 if (nAllocType == _HOOK_FREE) {
1137 if (lRequest != 0) {
1140 bRet = AllocHashRemove(lRequest);
1141 if(g_ulShowStackAtAlloc > 0) {
1142 if (bRet == FALSE) {
1144 _ftprintf(g_fFile,
_T(
"###### RequestID not found in hash table for FREEING (%i)!\n"), lRequest);
1149 if(g_ulShowStackAtAlloc > 0) {
1151 _ftprintf(g_fFile,
_T(
"###### No valid RequestID for FREEING! (0x%X)\n"), pvData);
1157 if (nAllocType == _HOOK_REALLOC) {
1159 if (_CrtIsValidHeapPointer(pvData)) {
1161 LONG lReallocRequest;
1163 _CrtMemBlockHeader *pHead;
1165 pHead =
pHdr(pvData);
1167 lReallocRequest = pHead->lRequest;
1168 bRet = AllocHashRemove(lReallocRequest);
1169 if (g_ulShowStackAtAlloc > 0) {
1170 if (bRet == FALSE) {
1172 _ftprintf(g_fFile,
_T(
"###### RequestID not found in hash table for RE-ALLOCATING (%i)!\n"), lReallocRequest);
1175 _ftprintf(g_fFile,
_T(
"##### Implicit freeing because of re-allocation (# old: %ld, new: %ld)\n"), lReallocRequest, lRequest);
1181 if ( (g_ulShowStackAtAlloc < 3) && (nAllocType == _HOOK_FREE) ) {
1182 InterlockedDecrement(&g_lMallocCalled);
1184 if (pfnOldCrtAllocHook != NULL)
1185 pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
1191 if (DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
1192 GetCurrentProcess(), &hThread, 0,
false, DUPLICATE_SAME_ACCESS ) == 0) {
1194 _ftprintf(g_fFile,
_T(
"###### Could not call 'DuplicateHandle' successfully\n"));
1195 InterlockedDecrement(&g_lMallocCalled);
1197 if (pfnOldCrtAllocHook != NULL)
1198 pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
1203 memset( &c,
'\0',
sizeof c );
1204 c.ContextFlags = CONTEXT_FULL;
1207 if ( GetThreadContext( hThread, &c ) == 0) {
1208 if(g_ulShowStackAtAlloc > 1) {
1209 _ftprintf(g_fFile,
_T(
"###### Could not call 'GetThreadContext' successfully\n"));
1211 InterlockedDecrement(&g_lMallocCalled);
1213 if (pfnOldCrtAllocHook != NULL)
1214 pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
1215 CloseHandle(hThread);
1219 if(g_ulShowStackAtAlloc > 1) {
1220 if(g_ulShowStackAtAlloc > 2) {
1222 ShowStack( hThread, c, g_fFile);
1226 if (nAllocType != _HOOK_FREE) {
1227 ShowStack( hThread, c, g_fFile);
1231 CloseHandle( hThread );
1234 if (nAllocType != _HOOK_FREE) {
1236 AllocHashInsert(lRequest, c, nSize);
1239 InterlockedDecrement(&g_lMallocCalled);
1241 if (pfnOldCrtAllocHook != NULL)
1242 pfnOldCrtAllocHook(nAllocType, pvData, nSize, nBlockUse, lRequest, szFileName, nLine);
1254#define gle (GetLastError())
1255#define lenof(a) (sizeof(a) / sizeof((a)[0]))
1256#define MAXNAMELEN 1024
1257#define IMGSYMLEN ( sizeof IMAGEHLP_SYMBOL )
1258#define TTBUFLEN 8096
1263typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess );
1267typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD AddrBase );
1271typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD dwAddr,
1272 OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE Line );
1273tSGLFA pSGLFA = NULL;
1276typedef DWORD (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD dwAddr );
1280typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD dwAddr, OUT PIMAGEHLP_MODULE ModuleInfo );
1284typedef DWORD (__stdcall *tSGO)( VOID );
1288typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD dwAddr,
1289 OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_SYMBOL Symbol );
1290tSGSFA pSGSFA = NULL;
1293typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );
1297typedef DWORD (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile,
1298 IN PSTR ImageName, IN PSTR ModuleName, IN DWORD BaseOfDll, IN DWORD SizeOfDll );
1302typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions );
1306typedef BOOL (__stdcall *tSW)( DWORD MachineType, HANDLE hProcess,
1307 HANDLE hThread, LPSTACKFRAME StackFrame, PVOID ContextRecord,
1308 PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryRoutine,
1309 PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
1310 PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
1311 PTRANSLATE_ADDRESS_ROUTINE TranslateAddress );
1315typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName,
1316 DWORD UndecoratedLength, DWORD Flags );
1323 std::string imageName;
1324 std::string moduleName;
1328typedef std::vector< ModuleEntry > ModuleList;
1329typedef ModuleList::iterator ModuleListIter;
1333#define MAX_MODULE_NAME32 255
1334#define TH32CS_SNAPMODULE 0x00000008
1335#pragma pack( push, 8 )
1337typedef struct tagMODULEENTRY32
1341 DWORD th32ProcessID;
1350typedef MODULEENTRY32 * PMODULEENTRY32;
1351typedef MODULEENTRY32 * LPMODULEENTRY32;
1357static bool GetModuleListTH32(ModuleList& modules, DWORD pid, FILE *fLogFile)
1360 typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID);
1362 typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
1364 typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
1367 const TCHAR *dllname[] = {
_T(
"kernel32.dll"),
_T(
"tlhelp32.dll") };
1368 HINSTANCE hToolhelp;
1375 me.dwSize =
sizeof(me);
1380 for (i = 0; i<
lenof(dllname); i++ )
1382 hToolhelp = LoadLibrary( dllname[i] );
1383 if (hToolhelp == NULL)
1385 pCT32S = (tCT32S) GetProcAddress(hToolhelp,
"CreateToolhelp32Snapshot");
1386 pM32F = (tM32F) GetProcAddress(hToolhelp,
"Module32First");
1387 pM32N = (tM32N) GetProcAddress(hToolhelp,
"Module32Next");
1388 if ( pCT32S != 0 && pM32F != 0 && pM32N != 0 )
1390 FreeLibrary(hToolhelp);
1394 if (hToolhelp == NULL)
1398 if (hSnap == (HANDLE) -1)
1401 keepGoing = !!pM32F( hSnap, &me );
1404 e.imageName = me.szExePath;
1405 e.moduleName = me.szModule;
1406 e.baseAddress = (DWORD) me.modBaseAddr;
1407 e.size = me.modBaseSize;
1408 modules.push_back( e );
1409 keepGoing = !!pM32N( hSnap, &me );
1413 FreeLibrary(hToolhelp);
1415 return modules.size() != 0;
1421typedef struct _MODULEINFO {
1425} MODULEINFO, *LPMODULEINFO;
1428static bool GetModuleListPSAPI(ModuleList &modules, DWORD pid, HANDLE hProcess, FILE *fLogFile)
1431 typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
1433 typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
1435 typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
1437 typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize );
1452 hPsapi = LoadLibrary(
_T(
"psapi.dll") );
1458 pEPM = (tEPM) GetProcAddress( hPsapi,
"EnumProcessModules" );
1459 pGMFNE = (tGMFNE) GetProcAddress( hPsapi,
"GetModuleFileNameExA" );
1460 pGMBN = (tGMFNE) GetProcAddress( hPsapi,
"GetModuleBaseNameA" );
1461 pGMI = (tGMI) GetProcAddress( hPsapi,
"GetModuleInformation" );
1462 if ( pEPM == 0 || pGMFNE == 0 || pGMBN == 0 || pGMI == 0 )
1465 FreeLibrary( hPsapi );
1469 hMods = (HMODULE*) malloc(
sizeof(HMODULE) * (
TTBUFLEN /
sizeof HMODULE));
1470 tt = (
char*) malloc(
sizeof(
char) *
TTBUFLEN);
1472 if ( ! pEPM( hProcess, hMods,
TTBUFLEN, &cbNeeded ) )
1474 _ftprintf(fLogFile,
_T(
"%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount,
gle );
1480 _ftprintf(fLogFile,
_T(
"%lu: More than %lu module handles. Huh?\n"), g_dwShowCount,
lenof( hMods ) );
1484 for ( i = 0; i < cbNeeded /
sizeof hMods[0]; i++ )
1487 pGMI(hProcess, hMods[i], &mi,
sizeof mi );
1488 e.baseAddress = (DWORD) mi.lpBaseOfDll;
1489 e.size = mi.SizeOfImage;
1492 pGMFNE(hProcess, hMods[i], tt,
TTBUFLEN );
1496 pGMBN(hProcess, hMods[i], tt,
TTBUFLEN );
1499 modules.push_back(e);
1504 FreeLibrary(hPsapi);
1508 return modules.size() != 0;
1512static bool GetModuleList(ModuleList& modules, DWORD pid, HANDLE hProcess, FILE *fLogFile)
1515 if (GetModuleListTH32(modules, pid, fLogFile) )
1518 return GetModuleListPSAPI(modules, pid, hProcess, fLogFile);
1521static void EnumAndLoadModuleSymbols( HANDLE hProcess, DWORD pid, FILE *fLogFile )
1524 img[
sizeof(img) - 1] = 0;
1525 mod[
sizeof(mod) - 1] = 0;
1528 GetModuleList(modules, pid, hProcess, fLogFile);
1529 for (ModuleListIter it = modules.begin(); it != modules.end(); ++it)
1532 strncpy(img, it->imageName.c_str(),
sizeof(img) - 1);
1533 strncpy(mod, it->moduleName.c_str(),
sizeof(mod) - 1);
1535 pSLM( hProcess, 0, img, mod, it->baseAddress, it->size );
1539static int InitStackWalk(
void)
1541 if (g_bInitialized != FALSE)
1548 g_hImagehlpDll = LoadLibrary(
_T(
"dbghelp.dll") );
1549 if ( g_hImagehlpDll == NULL )
1551 printf(
"LoadLibrary( \"dbghelp.dll\" ): GetLastError = %lu\n",
gle );
1552 g_bInitialized = FALSE;
1556 pSC = (tSC) GetProcAddress( g_hImagehlpDll,
"SymCleanup" );
1557 pSFTA = (tSFTA) GetProcAddress( g_hImagehlpDll,
"SymFunctionTableAccess" );
1558 pSGLFA = (tSGLFA) GetProcAddress( g_hImagehlpDll,
"SymGetLineFromAddr" );
1559 pSGMB = (tSGMB) GetProcAddress( g_hImagehlpDll,
"SymGetModuleBase" );
1560 pSGMI = (tSGMI) GetProcAddress( g_hImagehlpDll,
"SymGetModuleInfo" );
1561 pSGO = (tSGO) GetProcAddress( g_hImagehlpDll,
"SymGetOptions" );
1562 pSGSFA = (tSGSFA) GetProcAddress( g_hImagehlpDll,
"SymGetSymFromAddr" );
1563 pSI = (tSI) GetProcAddress( g_hImagehlpDll,
"SymInitialize" );
1564 pSSO = (tSSO) GetProcAddress( g_hImagehlpDll,
"SymSetOptions" );
1565 pSW = (tSW) GetProcAddress( g_hImagehlpDll,
"StackWalk" );
1566 pUDSN = (tUDSN) GetProcAddress( g_hImagehlpDll,
"UnDecorateSymbolName" );
1567 pSLM = (tSLM) GetProcAddress( g_hImagehlpDll,
"SymLoadModule" );
1569 if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||
1570 pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||
1571 pSW == NULL || pUDSN == NULL || pSLM == NULL )
1573 printf(
"GetProcAddress(): some required function not found.\n" );
1574 FreeLibrary( g_hImagehlpDll );
1575 g_bInitialized = FALSE;
1579 g_bInitialized = TRUE;
1580 InitializeCriticalSection(&g_csFileOpenClose);
1585static BOOL s_bUnhandledExeptionFilterSet = FALSE;
1586static LONG __stdcall CrashHandlerExceptionFilter(EXCEPTION_POINTERS* pExPtrs)
1592 _T(
"*** Unhandled Exception!\n")
1593 _T(
" ExpCode: 0x%8.8X\n")
1594 _T(
" ExpFlags: %d\n")
1595 _T(
" ExpAddress: 0x%8.8X\n")
1596 _T(
" Please report!"),
1597 pExPtrs->ExceptionRecord->ExceptionCode,
1598 pExPtrs->ExceptionRecord->ExceptionFlags,
1599 pExPtrs->ExceptionRecord->ExceptionAddress);
1600 FatalAppExit(-1,lString);
1604static TCHAR *GetExpectionCodeText(DWORD dwExceptionCode) {
1605 switch(dwExceptionCode) {
1606 case EXCEPTION_ACCESS_VIOLATION:
return _T(
"ACCESS VIOLATION");
1607 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
return _T(
"ARRAY BOUNDS EXCEEDED");
1608 case EXCEPTION_BREAKPOINT:
return _T(
"BREAKPOINT");
1609 case EXCEPTION_DATATYPE_MISALIGNMENT:
return _T(
"DATATYPE MISALIGNMENT");
1610 case EXCEPTION_FLT_DENORMAL_OPERAND:
return _T(
"FLT DENORMAL OPERAND");
1611 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
return _T(
"FLT DIVIDE BY ZERO");
1612 case EXCEPTION_FLT_INEXACT_RESULT:
return _T(
"FLT INEXACT RESULT");
1613 case EXCEPTION_FLT_INVALID_OPERATION:
return _T(
"FLT INVALID OPERATION");
1614 case EXCEPTION_FLT_OVERFLOW:
return _T(
"FLT OVERFLOW");
1615 case EXCEPTION_FLT_STACK_CHECK:
return _T(
"FLT STACK CHECK");
1616 case EXCEPTION_FLT_UNDERFLOW:
return _T(
"FLT UNDERFLOW");
1617 case EXCEPTION_ILLEGAL_INSTRUCTION:
return _T(
"ILLEGAL INSTRUCTION");
1618 case EXCEPTION_IN_PAGE_ERROR:
return _T(
"IN PAGE ERROR");
1619 case EXCEPTION_INT_DIVIDE_BY_ZERO:
return _T(
"INT DIVIDE BY ZERO");
1620 case EXCEPTION_INT_OVERFLOW:
return _T(
"INT OVERFLOW");
1621 case EXCEPTION_INVALID_DISPOSITION:
return _T(
"INVALID DISPOSITION");
1622 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
return _T(
"NONCONTINUABLE EXCEPTION");
1623 case EXCEPTION_PRIV_INSTRUCTION:
return _T(
"PRIV INSTRUCTION");
1624 case EXCEPTION_SINGLE_STEP:
return _T(
"SINGLE STEP");
1625 case EXCEPTION_STACK_OVERFLOW:
return _T(
"STACK OVERFLOW");
1626 case DBG_CONTROL_C :
return _T(
"DBG CONTROL C ");
1628 return _T(
"<unkown exception>");
1633static TCHAR *GetAdditionalExpectionCodeText(PEXCEPTION_RECORD pExceptionRecord) {
1634 static TCHAR szTemp[100];
1636 switch(pExceptionRecord->ExceptionCode) {
1637 case EXCEPTION_ACCESS_VIOLATION:
1638 if (pExceptionRecord->NumberParameters == 2) {
1639 switch(pExceptionRecord->ExceptionInformation[0]) {
1641 _stprintf(szTemp,
_T(
" read attempt to address 0x%8.8X "), pExceptionRecord->ExceptionInformation[1]);
1644 _stprintf(szTemp,
_T(
" write attempt to address 0x%8.8X "), pExceptionRecord->ExceptionInformation[1]);
1656std::string SimpleXMLEncode(PCSTR szText)
1660 for (
size_t i=0; i<strlen(szText); i++)
1665 szRet.append(
"&");
1668 szRet.append(
"<");
1671 szRet.append(
">");
1674 szRet.append(
""");
1677 szRet.append(
"'");
1687void ShowStack( HANDLE hThread, CONTEXT& c, LPCTSTR pszLogFile)
1689 FILE *fFile = stdout;
1691 if (pszLogFile != NULL) {
1694 if (fFile != NULL) {
1696 fseek(fFile, 0, SEEK_END);
1697 size = ftell(fFile);
1705 _trename(pszLogFile, pszTemp);
1711 if (fFile == NULL) {
1715 ShowStack( hThread, c, fFile);
1721static void ShowStack( HANDLE hThread, CONTEXT& c, FILE *fLogFile) {
1722 ShowStackRM(hThread, c, fLogFile, NULL, GetCurrentProcess());
1725static void ShowStackRM( HANDLE hThread, CONTEXT& c, FILE *fLogFile, PREAD_PROCESS_MEMORY_ROUTINE ReadMemoryFunction, HANDLE hSWProcess) {
1727 DWORD imageType = IMAGE_FILE_MACHINE_I386;
1728 HANDLE hProcess = GetCurrentProcess();
1730 DWORD offsetFromSymbol;
1731 DWORD offsetFromLine;
1735 IMAGEHLP_SYMBOL*
const pSym =
reinterpret_cast<IMAGEHLP_SYMBOL*
>(&Sym);
1742 std::string symSearchPath;
1744 static int bFirstTime = TRUE;
1747 if (fLogFile == NULL) {
1752 memset( &s,
'\0',
sizeof s );
1754 if ( (g_bInitialized == FALSE) && (bFirstTime == TRUE) ) {
1758 if (g_bInitialized == FALSE)
1762 _ftprintf(fLogFile,
_T(
"%lu: Stackwalker not initialized (or was not able to initialize)!\n"), g_dwShowCount);
1767 EnterCriticalSection(&g_csFileOpenClose);
1769 InterlockedIncrement((
long*) &g_dwShowCount);
1778 _ftprintf(fLogFile,
_T(
"%lu: "), g_dwShowCount);
1779 WriteDateTime(fLogFile);
1780 _ftprintf(fLogFile,
_T(
"\n"));
1788 tt = (CHAR*) malloc(
sizeof(CHAR) *
TTBUFLEN);
1789 if (!tt)
goto cleanup;
1794 if ( GetCurrentDirectoryA(
TTBUFLEN, tt ) )
1795 symSearchPath += tt + std::string(
";" );
1797 if ( GetModuleFileNameA( 0, tt,
TTBUFLEN ) )
1799 for ( p = tt + strlen( tt ) - 1; p >= tt; -- p )
1802 if ( *p ==
'\\' || *p ==
'/' || *p ==
':' )
1812 symSearchPath += tt + std::string(
";" );
1816 if ( GetEnvironmentVariableA(
"_NT_SYMBOL_PATH", tt,
TTBUFLEN ) )
1817 symSearchPath += tt + std::string(
";" );
1819 if ( GetEnvironmentVariableA(
"_NT_ALTERNATE_SYMBOL_PATH", tt,
TTBUFLEN ) )
1820 symSearchPath += tt + std::string(
";" );
1822 if ( GetEnvironmentVariableA(
"SYSTEMROOT", tt,
TTBUFLEN ) )
1823 symSearchPath += tt + std::string(
";" );
1827 if ( symSearchPath.size() > 0 )
1828 symSearchPath = symSearchPath.substr( 0, symSearchPath.size() - 1 );
1831 strncpy( tt, symSearchPath.c_str(),
TTBUFLEN );
1835 if ( ! pSI( hProcess, tt,
false ) )
1838 _ftprintf(fLogFile,
_T(
"%lu: SymInitialize(): GetLastError = %lu\n"), g_dwShowCount,
gle );
1844 symOptions = pSGO();
1846 symOptions &= ~SYMOPT_UNDNAME;
1847 symOptions &= ~SYMOPT_DEFERRED_LOADS;
1852 EnumAndLoadModuleSymbols( hProcess, GetCurrentProcessId(), fLogFile );
1863 s.AddrPC.Offset = c.Eip;
1864 s.AddrPC.Mode = AddrModeFlat;
1865 s.AddrFrame.Offset = c.Ebp;
1866 s.AddrFrame.Mode = AddrModeFlat;
1872 memset( &Line,
'\0',
sizeof Line );
1873 Line.SizeOfStruct =
sizeof Line;
1875 memset( &Module,
'\0',
sizeof Module );
1878 for ( frameNum = 0; ; ++ frameNum )
1885 if ( ! pSW( imageType, hSWProcess, hThread, &s, NULL, ReadMemoryFunction, pSFTA, pSGMB, NULL ) )
1888 bXMLTagWrote = FALSE;
1891 _ftprintf(fLogFile,
_T(
"\n%lu: %3d"), g_dwShowCount, frameNum);
1892 if ( s.AddrPC.Offset == 0 )
1895 switch(g_CallstackOutputType)
1898 _ftprintf(fLogFile,
_T(
"%lu: (-nosymbols- PC == 0)\n"), g_dwShowCount);
1901 _ftprintf(fLogFile,
_T(
" (-nosymbols- PC == 0)\n"));
1905 _ftprintf(fLogFile,
_T(
"<STACKENTRY decl=\"(-nosymbols- PC == 0)\"/>\n"));
1914 offsetFromSymbol = 0;
1916 if ( ! pSGSFA( hProcess, s.AddrPC.Offset, &offsetFromSymbol, pSym ) )
1921 _ftprintf(fLogFile,
_T(
" SymGetSymFromAddr(): GetLastError = %lu\n"),
gle );
1923 _ftprintf(fLogFile,
_T(
"\n"));
1929 pUDSN( pSym->Name, undName,
MAXNAMELEN, UNDNAME_NAME_ONLY );
1930 pUDSN( pSym->Name, undFullName,
MAXNAMELEN, UNDNAME_COMPLETE );
1933 if (strlen(undName) > 0)
1934 fprintf(fLogFile,
" %s %+ld bytes\n", undName, (
long) offsetFromSymbol );
1937 fprintf(fLogFile,
" Sig: %s %+ld bytes\n", pSym->Name, (
long) offsetFromSymbol );
1938 strcpy(undName, pSym->Name);
1940 fprintf(fLogFile,
"%lu: Decl: %s\n", g_dwShowCount, undFullName );
1948 if ( pSGLFA != NULL )
1950 if ( ! pSGLFA( hProcess, s.AddrPC.Offset, &offsetFromLine, &Line ) )
1952 if ( (
gle != 487) && (frameNum > 0) )
1956 _ftprintf(fLogFile,
_T(
"<STACKENTRY "));
1957 bXMLTagWrote = TRUE;
1958 fprintf(fLogFile,
"decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (
long) offsetFromSymbol);
1959 _ftprintf(fLogFile,
_T(
"srcfile=\"SymGetLineFromAddr(): GetLastError = %lu\" "),
gle);
1962 _ftprintf(fLogFile,
_T(
"%lu: SymGetLineFromAddr(): GetLastError = %lu\n"), g_dwShowCount,
gle );
1967 switch(g_CallstackOutputType)
1970 fprintf(fLogFile,
"%lu: Line: %s(%lu) %+ld bytes\n", g_dwShowCount,
1971 Line.FileName, Line.LineNumber, offsetFromLine );
1974 fprintf(fLogFile,
"%lu: %s(%lu) %+ld bytes (%s)\n", g_dwShowCount,
1975 Line.FileName, Line.LineNumber, offsetFromLine, undName);
1978 _ftprintf(fLogFile,
_T(
"<STACKENTRY "));
1979 bXMLTagWrote = TRUE;
1980 fprintf(fLogFile,
"decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (
long) offsetFromSymbol);
1981 fprintf(fLogFile,
"srcfile=\"%s\" line=\"%lu\" line_offset=\"%+ld\" ",
1982 SimpleXMLEncode(Line.FileName).c_str(), Line.LineNumber, offsetFromLine, undName);
1991 if ( ! pSGMI( hProcess, s.AddrPC.Offset, &Module ) )
1994 _ftprintf(fLogFile,
_T(
"%lu: SymGetModuleInfo): GetLastError = %lu\n"), g_dwShowCount,
gle );
1999 switch (
Module.SymType )
2002 strcpy( ty,
"-nosymbols-" );
2005 strcpy( ty,
"COFF" );
2011 strcpy( ty,
"PDB" );
2014 strcpy( ty,
"-exported-" );
2017 strcpy( ty,
"-deferred-" );
2020 strcpy( ty,
"SYM" );
2027 _snprintf( ty,
sizeof ty,
"symtype=%ld", (
long)
Module.SymType );
2034 if (bXMLTagWrote == FALSE)
2036 _ftprintf(fLogFile,
_T(
"<STACKENTRY "));
2037 bXMLTagWrote = TRUE;
2038 fprintf(fLogFile,
"decl=\"%s\" decl_offset=\"%+ld\" ", SimpleXMLEncode(undName).c_str(), (
long) offsetFromSymbol);
2039 _ftprintf(fLogFile,
_T(
"srcfile=\"\" "));
2040 bXMLTagWrote = TRUE;
2046 fprintf(fLogFile,
"%lu: Mod: %s, base: %08lxh\n", g_dwShowCount,
2048 if (
Module.SymType == SymNone) {
2049 _ftprintf(fLogFile,
_T(
"%lu: Offset: 0x%8.8x\n"), g_dwShowCount, s.AddrPC.Offset);
2050 fprintf(fLogFile,
"%lu: Sym: type: %s, file: %s\n", g_dwShowCount,
2051 ty,
Module.LoadedImageName );
2057 if (bXMLTagWrote == TRUE)
2058 fprintf(fLogFile,
"module=\"%s\" base=\"%08lx\" ",
Module.ModuleName,
Module.BaseOfImage);
2062 if ( (g_CallstackOutputType ==
ACOutput_XML) && (bXMLTagWrote == TRUE) )
2063 _ftprintf(fLogFile,
_T(
"/>\n"));
2068 if ( s.AddrReturn.Offset == 0 )
2078 _ftprintf(fLogFile,
_T(
"\n%lu: StackWalk(): GetLastError = %lu\n"), g_dwShowCount,
gle );
2082 _ftprintf(fLogFile,
_T(
"\n\n"));
2083 if (g_dwShowCount % 1000)
2087 LeaveCriticalSection(&g_csFileOpenClose);
2100 if (g_bInitialized) {
2103 if (ulShowStackAtAlloc <= 3)
2104 g_ulShowStackAtAlloc = ulShowStackAtAlloc;
2106 g_ulShowStackAtAlloc = 0;
2108 if (pszFileName != NULL)
2109 g_pszAllocLogName = _tcsdup(pszFileName);
2111 g_pszAllocLogName = NULL;
2113 g_CallstackOutputType = eOutput;
2118#ifdef WITH_IMALLOC_SPY
2120 LPMALLOCSPY pMallocSpy =
new CMallocSpy();
2121 if (pMallocSpy != NULL)
2123 hr = CoRegisterMallocSpy(pMallocSpy);
2126 _tprintf(
_T(
"\nCoRegisterMallocSpay failed with %.8x"), hr);
2132 pfnOldCrtAllocHook = _CrtSetAllocHook(MyAllocHook);
2135 return InitStackWalk();
2141 if (GetModuleFileName(NULL, szModName,
sizeof(szModName)/
sizeof(
TCHAR)) != 0)
2143 _tcscpy(s_szExceptionLogFileName, szModName);
2145 _tcscat(s_szExceptionLogFileName,
_T(
".exp.xml"));
2147 _tcscat(s_szExceptionLogFileName,
_T(
".exp.log"));
2157 _tcscpy(szModName,
_T(
"\\mem-leaks.xml-leaks"));
2159 _tcscpy(szModName,
_T(
"\\mem-leaks.log"));
2162 if (bSetUnhandledExeptionFilter != FALSE)
2165 SetUnhandledExceptionFilter(CrashHandlerExceptionFilter);
2166 s_bUnhandledExeptionFilterSet = TRUE;
2179 if (g_bInitialized) {
2182 InterlockedIncrement(&g_lMallocCalled);
2183 ulRet = AllocHashDeinit();
2185 _CrtSetAllocHook(pfnOldCrtAllocHook);
2187#ifdef WITH_IMALLOC_SPY
2188 CoRevokeMallocSpy();
2193 EnterCriticalSection(&g_csFileOpenClose);
2194 g_bInitialized = FALSE;
2198 pSC( GetCurrentProcess() );
2199 FreeLibrary( g_hImagehlpDll );
2201 LeaveCriticalSection(&g_csFileOpenClose);
2202 if (g_pszAllocLogName != NULL) {
2203 free(g_pszAllocLogName);
2204 g_pszAllocLogName = NULL;
2206 if (g_fFile != NULL) {
2211 DeleteCriticalSection(&g_csFileOpenClose);
2212 InterlockedDecrement(&g_lMallocCalled);
2215 if (s_bUnhandledExeptionFilterSet != TRUE)
2217 SetUnhandledExceptionFilter(NULL);
2218 s_bUnhandledExeptionFilterSet = FALSE;
2248 FILE *fFile = stdout;
2250 if (pszLogFile != NULL) {
2253 if (fFile != NULL) {
2255 fseek(fFile, 0, SEEK_END);
2256 size = ftell(fFile);
2264 _trename(pszLogFile, pszTemp);
2270 if (fFile == NULL) {
2277 _ftprintf(fFile,
_T(
"<EXCEPTION code=\"%8.8X\" addr=\"%8.8X\" "),
2278 ep->ExceptionRecord->ExceptionCode,
2279 ep->ExceptionRecord->ExceptionAddress);
2280 WriteDateTime(fFile, TRUE);
2281 _ftprintf(fFile,
_T(
"code_desc=\"%s\" more_desc=\"%s\">\n"), GetExpectionCodeText(ep->ExceptionRecord->ExceptionCode),
2282 GetAdditionalExpectionCodeText(ep->ExceptionRecord));
2286 _ftprintf(fFile,
_T(
"######## EXCEPTION: 0x%8.8X at address: 0x%8.8X"),
2287 ep->ExceptionRecord->ExceptionCode,
2288 ep->ExceptionRecord->ExceptionAddress);
2289 _ftprintf(fFile,
_T(
": %s %s\n"), GetExpectionCodeText(ep->ExceptionRecord->ExceptionCode),
2290 GetAdditionalExpectionCodeText(ep->ExceptionRecord));
2293 DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
2294 GetCurrentProcess(), &hThread, 0,
false, DUPLICATE_SAME_ACCESS );
2295 ShowStack( hThread, *(ep->ContextRecord), fFile);
2296 CloseHandle( hThread );
2299 _ftprintf(fFile,
_T(
"</EXCEPTION>\n"));
#define LOG_FILE_MAX_SIZE
int InitAllocCheckWN(eAllocCheckOutput eOutput, LPCTSTR pszFileName, ULONG ulShowStackAtAlloc)
#define ALLOC_HASH_ENTRIES
#define TH32CS_SNAPMODULE
ULONG DeInitAllocCheck(void)
#define SYMOPT_LOAD_LINES
DWORD StackwalkFilter(EXCEPTION_POINTERS *ep, DWORD status, LPCTSTR pszLogFile)
#define ALLOC_ENTRY_NOT_FOUND
int InitAllocCheck(eAllocCheckOutput eOutput, BOOL bSetUnhandledExeptionFilter, ULONG ulShowStackAtAlloc)
#define MAX_MODULE_NAME32
#define EXCEPTION_EXECUTE_HANDLER