[Project64] Make mem test more header friendly

This commit is contained in:
zilmar 2018-11-18 12:26:00 +10:30
parent 3b0e7a8527
commit 485339300d
2 changed files with 156 additions and 360 deletions

View File

@ -1,33 +1,39 @@
#include "stdafx.h"
#if defined(_MSC_VER)
#include <crtdbg.h>
#else
#define _ASSERTE(expr) ((void)0)
#endif
#ifdef _DEBUG
#pragma warning(disable:4786) //Disable std library warning
#pragma warning(disable:4530) //Disable std library warning
#include <string>
#include <malloc.h>
#include "MemTest.h"
#ifdef MEM_LEAK_TEST
#include <shellapi.h> //Needed for ShellExecute
#pragma comment(lib, "shell32.lib") //Needed for ShellExecute
#include <Windows.h>
#undef new
#undef malloc
#undef realloc
#undef free
#undef VirtualAlloc
#undef VirtualFree
#ifndef MB_SERVICE_NOTIFICATION
#define MB_SERVICE_NOTIFICATION 0x00200000L
#endif
#ifdef _WIN32
#include <shellapi.h>
static bool InInit = false;
class CMemList
{
typedef struct
{
char File[300];
int line;
int size;
int order;
} DEBUG_LOCATION;
typedef std::map<void *, DEBUG_LOCATION> MEMLIST;
typedef MEMLIST::const_iterator MEMLIST_ITER;
public:
CMemList();
~CMemList();
void removeItem(void * ptr);
void RecordAddItem(void * ptr, size_t size, const char * filename, int line);
void DumpItems(void);
private:
MEMLIST * m_MemList;
HMODULE m_hModule;
CRITICAL_SECTION m_cs;
uint32_t m_NextOrder;
};
CMemList *MemList(void)
{
@ -36,15 +42,15 @@ CMemList *MemList(void)
return &m_MemList;
}
CMemList::CMemList()
CMemList::CMemList() :
m_MemList(NULL),
m_hModule(NULL),
m_cs({0}),
m_NextOrder(1)
{
MemList.clear();
hSemaphone = CreateSemaphore(NULL, 1, 1, NULL);
State = Initialized;
order = 0;
LogAllocate = false;
ThreadID = 0;
m_hModule = NULL;
InInit = true;
InitializeCriticalSection(&m_cs);
m_MemList = new MEMLIST;
for (UINT_PTR TestLoc = ((UINT_PTR)::MemList) & ~0xFFF; TestLoc != 0; TestLoc -= 0x1000)
{
@ -56,259 +62,152 @@ CMemList::CMemList()
m_hModule = (HMODULE)TestLoc;
break;
}
InInit = false;
}
CMemList::~CMemList()
{
size_t ItemsLeft = MemList.size();
InInit = true;
size_t ItemsLeft = m_MemList->size();
if (ItemsLeft > 0)
{
char path_buffer[_MAX_PATH], drive[_MAX_DRIVE], dir[_MAX_DIR];
char fname[_MAX_FNAME], ext[_MAX_EXT], LogFileName[_MAX_PATH];
memset(path_buffer, 0, sizeof(path_buffer));
memset(drive, 0, sizeof(drive));
memset(dir, 0, sizeof(dir));
memset(fname, 0, sizeof(fname));
memset(ext, 0, sizeof(ext));
memset(LogFileName, 0, sizeof(LogFileName));
GetModuleFileName(m_hModule, path_buffer, sizeof(path_buffer));
_splitpath(path_buffer, drive, dir, fname, ext);
_makepath(LogFileName, drive, dir, fname, "leak.csv");
HANDLE hLogFile = INVALID_HANDLE_VALUE;
do
{
hLogFile = CreateFile(
LogFileName,
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
if (hLogFile == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_SHARING_VIOLATION)
{
TCHAR Msg[3000];
sprintf(Msg, "%s\nCan not be opened for writing please close app using this file\n\nTry Again ?", LogFileName);
int Result = MessageBox(NULL, Msg, "Memory Leak", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_SERVICE_NOTIFICATION);
if (Result == IDNO)
{
break;
}
}
}
} while (hLogFile == INVALID_HANDLE_VALUE);
if (hLogFile != INVALID_HANDLE_VALUE)
{
SetFilePointer(hLogFile, 0, NULL, FILE_BEGIN);
DWORD dwWritten = 0;
char Msg[800];
_snprintf(Msg, sizeof(Msg), "Order, Source File, Line Number, Mem Size\r\n");
WriteFile(hLogFile, Msg, (DWORD)strlen(Msg), &dwWritten, NULL);
for (MEMLIST_ITER item = MemList.begin(); item != MemList.end(); item++)
{
_snprintf(Msg, sizeof(Msg), "%d,%s, %d, %d\r\n",
(*item).second.order,
(*item).second.File,
(*item).second.line,
(*item).second.size);
WriteFile(hLogFile, Msg, (DWORD)strlen(Msg), &dwWritten, NULL);
}
CloseHandle(hLogFile);
}
char Msg[3000];
sprintf(Msg, "%s%s\n\nMemory Leaks detected\n\nOpen the Log File ?", fname, ext);
int Result = MessageBox(NULL, Msg, "Memory Leak", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_SERVICE_NOTIFICATION);
if (Result == IDYES)
{
ShellExecute(NULL, "open", LogFileName, NULL, NULL, SW_SHOW);
}
DumpItems();
}
CloseHandle(hSemaphone);
hSemaphone = NULL;
State = NotInitialized;
}
void * CMemList::AddItem(size_t size, char * filename, int line)
{
void *res = malloc(size);
if (res == NULL)
{
return res;
}
RecordAddItem(res, size, filename, line);
return res;
delete m_MemList;
m_MemList = NULL;
DeleteCriticalSection(&m_cs);
}
void CMemList::RecordAddItem(void * ptr, size_t size, const char * filename, int line)
{
__try
EnterCriticalSection(&m_cs);
if (m_cs.RecursionCount > 1)
{
if (State == Initialized && hSemaphone != NULL)
LeaveCriticalSection(&m_cs);
return;
}
DEBUG_LOCATION info;
strncpy(info.File, filename, sizeof(info.File));
info.line = line;
info.size = (int)size;
info.order = m_NextOrder++;
if (info.order == 628)
{
int a = 5;
a = 6;
}
m_MemList->insert(MEMLIST::value_type(ptr, info));
LeaveCriticalSection(&m_cs);
}
void CMemList::removeItem(void * ptr)
{
EnterCriticalSection(&m_cs);
if (m_cs.RecursionCount > 1)
{
LeaveCriticalSection(&m_cs);
return;
}
MEMLIST_ITER item = m_MemList->find(ptr);
if (item != m_MemList->end())
{
m_MemList->erase(item);
}
LeaveCriticalSection(&m_cs);
}
void CMemList::DumpItems(void)
{
char path_buffer[_MAX_PATH] = { 0 }, drive[_MAX_DRIVE] = { 0 }, dir[_MAX_DIR] = { 0 };
char fname[_MAX_FNAME] = { 0 }, ext[_MAX_EXT] = { 0 }, LogFileName[_MAX_PATH] = { 0 };
GetModuleFileName(m_hModule, path_buffer, sizeof(path_buffer));
_splitpath(path_buffer, drive, dir, fname, ext);
_makepath(LogFileName, drive, dir, fname, "leak.csv");
HANDLE hLogFile = INVALID_HANDLE_VALUE;
do
{
hLogFile = CreateFile( LogFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
if (hLogFile == INVALID_HANDLE_VALUE)
{
DWORD CurrentThread = GetCurrentThreadId();
DWORD Result = WaitForSingleObject(hSemaphone, CurrentThread != ThreadID ? 30000 : 0);
if (Result != WAIT_TIMEOUT)
if (GetLastError() == ERROR_SHARING_VIOLATION)
{
ThreadID = CurrentThread;
DEBUG_LOCATION info;
strncpy(info.File, filename, sizeof(info.File));
info.line = line;
info.size = (int)size;
info.order = order++;
Insert(ptr, info);
long dwSemCount = 0;
ThreadID = (DWORD)-1;
ReleaseSemaphore(hSemaphone, 1, &dwSemCount);
TCHAR Msg[3000];
sprintf(Msg, "%s\nCan not be opened for writing please close app using this file\n\nTry Again ?", LogFileName);
int Result = MessageBox(NULL, Msg, "Memory Leak", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_SERVICE_NOTIFICATION);
if (Result == IDNO)
{
break;
}
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
} while (hLogFile == INVALID_HANDLE_VALUE);
if (hLogFile != INVALID_HANDLE_VALUE)
{
//_asm int 3
SetFilePointer(hLogFile, 0, NULL, FILE_BEGIN);
DWORD dwWritten = 0;
char Msg[800];
_snprintf(Msg, sizeof(Msg), "Order, Source File, Line Number, Mem Size\r\n");
WriteFile(hLogFile, Msg, (DWORD)strlen(Msg), &dwWritten, NULL);
for (MEMLIST_ITER item = m_MemList->begin(); item != m_MemList->end(); item++)
{
_snprintf(Msg, sizeof(Msg), "%d,%s, %d, %d\r\n", (*item).second.order, (*item).second.File, (*item).second.line, (*item).second.size);
WriteFile(hLogFile, Msg, (DWORD)strlen(Msg), &dwWritten, NULL);
}
CloseHandle(hLogFile);
}
char Msg[3000];
sprintf(Msg, "%s%s\n\nMemory Leaks detected\n\nOpen the Log File ?", fname, ext);
int Result = MessageBox(NULL, Msg, "Memory Leak", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_SERVICE_NOTIFICATION);
if (Result == IDYES)
{
ShellExecute(NULL, "open", LogFileName, NULL, NULL, SW_SHOW);
}
}
void CMemList::Insert(void *res, DEBUG_LOCATION &info)
void* AllocateMemory(size_t size, const char* filename, unsigned int line)
{
MemList.insert(MEMLIST::value_type(res, info));
}
void * CMemList::ReAllocItem(void * ptr, size_t size, const char * filename, int line)
{
void *res = realloc(ptr, size);
void * res = malloc(size);
if (res == NULL)
{
return res;
}
if (ptr != res)
if (!InInit)
{
__try
{
if (State == Initialized && hSemaphone != NULL)
{
DWORD CurrentThread = GetCurrentThreadId();
DWORD Result = WaitForSingleObject(hSemaphone, CurrentThread != ThreadID ? 30000 : 0);
if (Result != WAIT_TIMEOUT)
{
ThreadID = CurrentThread;
//Add new pointer
DEBUG_LOCATION info;
strncpy(info.File, filename, sizeof(info.File));
info.line = line;
info.size = (int)size;
info.order = order++;
Insert(res, info);
//remove old pointer
Remove(ptr);
long dwSemCount = 0;
ThreadID = (DWORD)-1;
ReleaseSemaphore(hSemaphone, 1, &dwSemCount);
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
//_asm int 3
}
MemList()->RecordAddItem(res, size, filename, line);
}
return res;
}
void CMemList::Remove(void *ptr)
void* operator new (size_t size, const char* filename, unsigned int line)
{
//remove old pointer
MEMLIST_ITER item = MemList.find(ptr);
if (item != MemList.end())
{
MemList.erase(ptr);
}
return AllocateMemory(size, filename, line);
}
void CMemList::removeItem(void * ptr, bool bFree)
void* operator new[] (size_t size, const char* filename, unsigned int line)
{
if (bFree)
{
free(ptr);
}
__try
{
if (State == Initialized && hSemaphone != NULL)
{
DWORD CurrentThread = GetCurrentThreadId();
DWORD Result = WaitForSingleObject(hSemaphone, CurrentThread != ThreadID ? 30000 : 0);
if (Result != WAIT_TIMEOUT)
{
ThreadID = CurrentThread;
Remove(ptr);
long dwSemCount = 0;
ThreadID = (DWORD)-1;
ReleaseSemaphore(hSemaphone, 1, &dwSemCount);
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
//_asm int 3
}
}
void MemTest_AddLeak(char* Comment)
{
MemList()->AddItem(1, Comment, -1);
}
void* MemTest_malloc(size_t size, char* filename, int line)
{
return MemList()->AddItem(size, filename, line);
}
void* MemTest_realloc(void* ptr, size_t size, char* filename, int line)
{
return MemList()->ReAllocItem(ptr, size, filename, line);
}
void* operator new (size_t size, char* filename, int line)
{
return MemList()->AddItem(size, filename, line);
return AllocateMemory(size, filename, line);
}
void* operator new (size_t size)
{
return MemList()->AddItem(size, "Unknown", 0);
}
void* operator new [](size_t size, char* filename, int line)
{
return MemList()->AddItem(size, filename, line);
}
void* operator new [](size_t size)
{
return MemList()->AddItem(size, "Unknown", 0);
return AllocateMemory(size, "Unknown", 0);
}
void operator delete (void* ptr)
{
MemList()->removeItem(ptr, true);
free(ptr);
if (!InInit)
{
MemList()->removeItem(ptr);
}
}
void operator delete[](void* ptr)
@ -316,31 +215,14 @@ void operator delete[](void* ptr)
delete ptr;
}
LPVOID MemTest_VirtualAlloc(
LPVOID lpAddress, // region to reserve or commit
SIZE_T dwSize, // size of region
DWORD flAllocationType, // type of allocation
DWORD flProtect, // type of access protection
LPCSTR filename,
int line)
void operator delete (void* ptr, const char* /*filename*/, unsigned int /*line*/)
{
LPVOID ptr = VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
if (ptr && lpAddress == NULL && (flAllocationType & MEM_RESERVE) != 0)
{
MemList()->RecordAddItem(ptr, dwSize, filename, line);
}
return ptr;
delete ptr;
}
BOOL MemTest_VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
void operator delete[](void* ptr, const char* /*filename*/, unsigned int /*line*/)
{
if ((dwFreeType & MEM_RELEASE) != 0)
{
MemList()->removeItem(lpAddress, false);
}
return VirtualFree(lpAddress, dwSize, dwFreeType);
delete ptr;
}
#endif
#endif

View File

@ -1,102 +1,16 @@
#ifdef _DEBUG
#pragma once
#if (defined(_MSC_VER) && (_MSC_VER < 1900))
#if (defined(_MSC_VER) && _DEBUG)
#define MEM_LEAK_TEST
#endif
#ifdef MEM_LEAK_TEST
#ifndef __MEM_TEST__H__
#define __MEM_TEST__H__
#pragma warning(disable:4786)
#pragma warning(disable:4291)
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include <xdebug>
#include <xlocale>
#include <xiosbase>
#include <xtree>
#define new new(__FILE__, __LINE__)
#include <map>
#include <windows.h>
#undef new
/*
#include <crtdbg.h>
#include <malloc.h>
#include <fstream>
#include <xlocnum>
#include <xlocmon>
#include <sstream>
#include <list>
*/
typedef struct {
char File[300];
int line;
int size;
int order;
} DEBUG_LOCATION;
typedef std::map<void *, DEBUG_LOCATION> MEMLIST;
typedef MEMLIST::iterator MEMLIST_ITER;
class CMemList {
MEMLIST MemList;
HANDLE hSemaphone;
DWORD ThreadID;
HMODULE m_hModule;
enum INIT { Initialized = 123, NotInitialized };
INIT State;
int order;
bool LogAllocate;
void Insert(void *res, DEBUG_LOCATION &info);
void Remove(void *ptr);
public:
CMemList();
~CMemList();
void * AddItem ( size_t size, char * filename, int line );
void * ReAllocItem ( void * ptr, size_t size, const char * filename, int line );
void removeItem ( void * ptr, bool bFree );
void RecordAddItem ( void * ptr, size_t size, const char * filename, int line );
};
void* operator new (size_t size );
void* operator new (size_t size, char* filename, int line);
void* operator new [] (size_t size );
void* operator new [] (size_t size, char* filename, int line);
void operator delete ( void* ptr);
void operator delete[](void* ptr);
void* MemTest_malloc(size_t size, char* filename, int line);
void* MemTest_realloc(void* ptr, size_t size, char* filename, int line);
void MemTest_AddLeak(char* Comment);
LPVOID MemTest_VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect, LPCSTR filename, int line);
BOOL MemTest_VirtualFree( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType );
void* operator new (size_t size, const char* filename, unsigned int line);
void* operator new[](size_t size, const char* filename, unsigned int line);
void operator delete (void* ptr, const char* filename, unsigned int line);
void operator delete[](void* ptr, const char* filename, unsigned int line);
#endif
#undef new
#undef malloc
#undef free
#define new new(__FILE__, __LINE__)
#define malloc(x) (MemTest_malloc((x),__FILE__, __LINE__))
#define realloc(mem,x) (MemTest_realloc((mem),(x),__FILE__, __LINE__))
#define free(x) (delete (x))
#define VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect ) \
(MemTest_VirtualAlloc((lpAddress), (dwSize), (flAllocationType), (flProtect),__FILE__, __LINE__))
#define VirtualFree(lpAddress, dwSize, dwFreeType ) \
(MemTest_VirtualFree((lpAddress), (dwSize), (dwFreeType)))
#endif
#define new new(__FILE__, __LINE__)
#endif