522 lines
12 KiB
C++
522 lines
12 KiB
C++
/*++
|
|
|
|
Copyright (C) 1999-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Abstract:
|
|
|
|
History:
|
|
|
|
--*/
|
|
|
|
|
|
// WMI Debugging DLL -- Kernel33 wrapper for memory allocations
|
|
|
|
#include <windows.h>
|
|
#include <kernel33.h>
|
|
#include <stktrace.h>
|
|
|
|
|
|
PFN_HeapAlloc pfnHeapAlloc = 0;
|
|
PFN_HeapReAlloc pfnHeapReAlloc = 0;
|
|
PFN_HeapFree pfnHeapFree = 0;
|
|
PFN_HeapSize pfnHeapSize = 0;
|
|
|
|
CRITICAL_SECTION cs;
|
|
CRITICAL_SECTION s_cs;
|
|
|
|
|
|
void _strcat(char *p1, char *p2)
|
|
{
|
|
while (*++p1);
|
|
while (*p2) *p1++=*p2++;
|
|
*p1 = 0;
|
|
}
|
|
|
|
void TrackingInit();
|
|
void TrackBlock(
|
|
size_t nSize,
|
|
LPVOID pAddr
|
|
);
|
|
|
|
HMODULE hLib = 0;
|
|
void Setup();
|
|
BOOL g_bMemTracking = FALSE;
|
|
|
|
BOOL UntrackBlock(LPVOID pBlock);
|
|
BOOL TestForWinMgmt();
|
|
BOOL g_bWinMgmt = FALSE;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL WINAPI DllEntry(
|
|
HINSTANCE hinstDLL,
|
|
DWORD dwReason,
|
|
LPVOID lpReserved
|
|
)
|
|
{
|
|
static BOOL bInit = FALSE;
|
|
|
|
if (dwReason == DLL_PROCESS_ATTACH)
|
|
{
|
|
if (bInit == FALSE)
|
|
{
|
|
bInit = TRUE;
|
|
BOOL bWinMgmt = TestForWinMgmt();
|
|
char buf[256];
|
|
*buf = 0;
|
|
GetSystemDirectory(buf, 256);
|
|
_strcat(buf, "\\kernel32.dll");
|
|
hLib = LoadLibrary(buf);
|
|
InitializeCriticalSection(&cs);
|
|
|
|
if (bWinMgmt)
|
|
TrackingInit();
|
|
|
|
pfnHeapAlloc = (PFN_HeapAlloc) GetProcAddress(hLib, "HeapAlloc");
|
|
pfnHeapReAlloc = (PFN_HeapReAlloc) GetProcAddress(hLib, "HeapReAlloc");
|
|
pfnHeapFree = (PFN_HeapFree) GetProcAddress(hLib, "HeapFree");
|
|
pfnHeapSize = (PFN_HeapSize) GetProcAddress(hLib, "HeapSize");
|
|
|
|
if (bWinMgmt)
|
|
Setup();
|
|
|
|
bInit = TRUE;
|
|
}
|
|
}
|
|
else if (dwReason == DLL_PROCESS_DETACH)
|
|
{
|
|
DeleteCriticalSection(&cs);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
extern "C"
|
|
LPVOID WINAPI HeapAlloc(
|
|
IN HANDLE hHeap,
|
|
IN DWORD dwFlags,
|
|
IN SIZE_T dwBytes
|
|
)
|
|
{
|
|
|
|
LPVOID p = pfnHeapAlloc(hHeap, dwFlags, dwBytes);
|
|
|
|
if (p && g_bMemTracking)
|
|
{
|
|
TrackBlock(dwBytes, p);
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
extern "C"
|
|
LPVOID WINAPI HeapReAlloc(
|
|
IN HANDLE hHeap,
|
|
IN DWORD dwFlags,
|
|
IN LPVOID lpMem,
|
|
IN SIZE_T dwBytes
|
|
)
|
|
{
|
|
if (g_bMemTracking)
|
|
UntrackBlock(lpMem);
|
|
|
|
LPVOID p = pfnHeapReAlloc(hHeap, dwFlags, lpMem, dwBytes);
|
|
|
|
if (p && g_bMemTracking)
|
|
TrackBlock(dwBytes, p);
|
|
|
|
return p;
|
|
}
|
|
|
|
extern "C"
|
|
BOOL WINAPI HeapFree(
|
|
IN HANDLE hHeap,
|
|
IN DWORD dwFlags,
|
|
IN LPVOID lpMem
|
|
)
|
|
{
|
|
if (g_bMemTracking)
|
|
UntrackBlock(lpMem);
|
|
|
|
return pfnHeapFree(hHeap, dwFlags, lpMem);
|
|
}
|
|
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
struct TrackingLink
|
|
{
|
|
TrackingLink *pNext;
|
|
DWORD dwThreadId;
|
|
size_t nSize;
|
|
DWORD dwSysTime;
|
|
StackTrace *pTrace;
|
|
void *pBlock;
|
|
};
|
|
|
|
|
|
TrackingLink *s_pHead;
|
|
HANDLE s_hTrackingHeap;
|
|
|
|
//******************************************************************************
|
|
//
|
|
//******************************************************************************
|
|
|
|
void TrackingInit()
|
|
{
|
|
InitializeCriticalSection(&s_cs);
|
|
EnterCriticalSection(&s_cs);
|
|
s_hTrackingHeap = HeapCreate(0, 0x8000, 0);
|
|
s_pHead = 0;
|
|
LeaveCriticalSection(&s_cs);
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
//******************************************************************************
|
|
|
|
void TrackingReset()
|
|
{
|
|
EnterCriticalSection(&s_cs);
|
|
|
|
TrackingLink *pTracer, *pTemp;
|
|
|
|
for (pTracer = s_pHead; pTracer; pTracer = pTemp)
|
|
{
|
|
pTemp = pTracer->pNext;
|
|
//if (pTracer->pTrace)
|
|
// pTracer->pTrace->Delete();
|
|
pfnHeapFree(s_hTrackingHeap, 0, pTracer);
|
|
}
|
|
|
|
s_pHead = 0;
|
|
|
|
LeaveCriticalSection(&s_cs);
|
|
}
|
|
|
|
//******************************************************************************
|
|
//
|
|
//******************************************************************************
|
|
|
|
void TrackBlock(
|
|
size_t nSize,
|
|
LPVOID pAddr
|
|
)
|
|
{
|
|
EnterCriticalSection(&s_cs);
|
|
|
|
// Allocate new memory blocks.
|
|
|
|
TrackingLink *pNew = (TrackingLink *) pfnHeapAlloc(s_hTrackingHeap, HEAP_ZERO_MEMORY,
|
|
sizeof(TrackingLink));
|
|
|
|
if (!pNew)
|
|
{
|
|
LeaveCriticalSection(&s_cs);
|
|
return;
|
|
}
|
|
|
|
StackTrace *pTrace = StackTrace__NewTrace();
|
|
|
|
// Attach to list.
|
|
// ===============
|
|
|
|
pNew->nSize = nSize;
|
|
pNew->pTrace = pTrace;
|
|
pNew->pNext = s_pHead;
|
|
pNew->pBlock = pAddr;
|
|
pNew->dwSysTime = GetCurrentTime();
|
|
pNew->dwThreadId = GetCurrentThreadId();
|
|
s_pHead = pNew;
|
|
|
|
LeaveCriticalSection(&s_cs);
|
|
}
|
|
|
|
BOOL UntrackBlock(LPVOID pBlock)
|
|
{
|
|
if (!pBlock)
|
|
return FALSE;
|
|
|
|
// Special case the head.
|
|
// ======================
|
|
|
|
EnterCriticalSection(&s_cs);
|
|
|
|
if (s_pHead == 0)
|
|
{
|
|
LeaveCriticalSection(&s_cs);
|
|
return FALSE;
|
|
};
|
|
|
|
if (s_pHead->pBlock == pBlock)
|
|
{
|
|
TrackingLink *pTemp = s_pHead;
|
|
s_pHead = s_pHead->pNext;
|
|
if (pTemp->pTrace)
|
|
StackTrace_Delete(pTemp->pTrace);
|
|
pfnHeapFree(s_hTrackingHeap, 0, pTemp);
|
|
LeaveCriticalSection(&s_cs);
|
|
return TRUE;
|
|
}
|
|
|
|
TrackingLink *pTracer , *pPrevious = 0;
|
|
|
|
for (pTracer = s_pHead; pTracer; pTracer = pTracer->pNext)
|
|
{
|
|
if (pTracer->pBlock == pBlock)
|
|
{
|
|
pPrevious->pNext = pTracer->pNext;
|
|
if (pTracer->pTrace)
|
|
StackTrace_Delete(pTracer->pTrace);
|
|
pfnHeapFree(s_hTrackingHeap, 0, pTracer);
|
|
LeaveCriticalSection(&s_cs);
|
|
return TRUE;
|
|
}
|
|
|
|
pPrevious = pTracer;
|
|
}
|
|
|
|
LeaveCriticalSection(&s_cs);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
extern "C" VOID WINAPI StartHeapTracking()
|
|
{
|
|
StackTrace_Init();
|
|
}
|
|
|
|
extern "C" DWORD WINAPI GetTotalHeap()
|
|
{
|
|
EnterCriticalSection(&s_cs);
|
|
TrackingLink *pTracer;
|
|
DWORD dwTotal = 0;
|
|
for (pTracer = s_pHead; pTracer; pTracer = pTracer->pNext)
|
|
dwTotal += pTracer->nSize;
|
|
LeaveCriticalSection(&s_cs);
|
|
return dwTotal;
|
|
}
|
|
|
|
extern "C" DWORD WINAPI DumpHeapStacks()
|
|
{
|
|
HANDLE hFile = CreateFile("c:\\temp\\heap.log", GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
return 0;
|
|
}
|
|
SetFilePointer(hFile, 0, 0, FILE_END);
|
|
|
|
DWORD dwWritten;
|
|
char *pStr = "*************** Dump *******************\r\n";
|
|
WriteFile(hFile, pStr, lstrlen(pStr), &dwWritten, 0);
|
|
|
|
EnterCriticalSection(&s_cs);
|
|
|
|
TrackingLink *pTracer;
|
|
DWORD dwTotal = 0;
|
|
for (pTracer = s_pHead; pTracer; pTracer = pTracer->pNext)
|
|
{
|
|
char *pStr = " --Block ";
|
|
WriteFile(hFile, pStr, lstrlen(pStr), &dwWritten, 0);
|
|
|
|
char Buf[256];
|
|
wsprintf(Buf, " Size=%d Address=0x%X Thread=%d Time=%d\r\n",
|
|
pTracer->nSize, pTracer->pBlock, pTracer->dwThreadId,
|
|
pTracer->dwSysTime
|
|
);
|
|
WriteFile(hFile, Buf, lstrlen(Buf), &dwWritten, 0);
|
|
|
|
StackTrace *pTrace = pTracer->pTrace;
|
|
char *pDump = 0;
|
|
if (pTrace)
|
|
pDump = StackTrace_Dump(pTrace);
|
|
if (pDump)
|
|
{
|
|
WriteFile(hFile, pDump, lstrlen(pDump), &dwWritten, 0);
|
|
}
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
LeaveCriticalSection(&s_cs);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
typedef enum { H_ENABLE_LEAK_TRACKING = 0,
|
|
H_DISABLE_LEAK_TRACKING = 1,
|
|
H_RESET_LEAK_TRACKING = 2,
|
|
H_DUMP_LEAK_TRACKING = 3,
|
|
H_FAIL_ALLOCATOR = 4,
|
|
H_RESTORE_ALLOCATOR = 5,
|
|
H_FAIL_NEXT_ALLOC = 6,
|
|
H_ENABLE_EXCEPTION_TRACKING = 7,
|
|
H_DISABLE_EXCEPTION_TRACKING = 8,
|
|
H_ENABLE_OBJECT_VALIDATION = 9,
|
|
H_DISABLE_OBJECT_VALIDATION = 10,
|
|
H_DEBUG_BREAK = 11,
|
|
H_LAST
|
|
} eTypes;
|
|
|
|
|
|
static HANDLE m_hArray[H_LAST];
|
|
|
|
static DWORD WINAPI ThreadProc(LPVOID pArg);
|
|
|
|
|
|
void Setup()
|
|
{
|
|
PSECURITY_DESCRIPTOR pSD;
|
|
|
|
// Initialize a security descriptor.
|
|
|
|
pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
|
|
SECURITY_DESCRIPTOR_MIN_LENGTH); // defined in WINNT.H
|
|
if (pSD == NULL)
|
|
return;
|
|
|
|
SECURITY_ATTRIBUTES sa;
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.lpSecurityDescriptor = pSD;
|
|
sa.bInheritHandle = FALSE;
|
|
|
|
if (!InitializeSecurityDescriptor(pSD,
|
|
SECURITY_DESCRIPTOR_REVISION))
|
|
return;
|
|
|
|
// Add a NULL disc. ACL to the security descriptor.
|
|
|
|
if (!SetSecurityDescriptorDacl(pSD,
|
|
TRUE, // specifying a disc. ACL
|
|
(PACL) NULL,
|
|
FALSE))
|
|
return;
|
|
|
|
// Set up the IPC signals.
|
|
// =======================
|
|
|
|
m_hArray[H_ENABLE_LEAK_TRACKING] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_ENABLE_LEAK_TRACKING");
|
|
m_hArray[H_DISABLE_LEAK_TRACKING] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_DISABLE_LEAK_TRACKING");
|
|
m_hArray[H_RESET_LEAK_TRACKING] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_RESET_LEAK_TRACKING");
|
|
m_hArray[H_DUMP_LEAK_TRACKING] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_DUMP_LEAK_TRACKING");
|
|
|
|
m_hArray[H_FAIL_ALLOCATOR] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_FAIL_ALLOCATOR");
|
|
m_hArray[H_RESTORE_ALLOCATOR] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_RESTORE_ALLOCATOR");
|
|
m_hArray[H_FAIL_NEXT_ALLOC] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_FAIL_NEXT_ALLOCATION");
|
|
|
|
m_hArray[H_ENABLE_EXCEPTION_TRACKING] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_ENABLE_EXCEPTION_TRACKING");
|
|
m_hArray[H_DISABLE_EXCEPTION_TRACKING] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_DISABLE_EXCEPTION_TRACKING");
|
|
|
|
m_hArray[H_ENABLE_OBJECT_VALIDATION] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_ENABLE_OBJECT_VALIDATION");
|
|
m_hArray[H_DISABLE_OBJECT_VALIDATION] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_DISABLE_OBJECT_VALIDATION");
|
|
|
|
m_hArray[H_DEBUG_BREAK] =
|
|
CreateEventW(&sa, FALSE, 0, L"EVENT_WINMGMT_DEBUG_BREAK");
|
|
|
|
// Create the waiting thread.
|
|
// ==========================
|
|
|
|
DWORD dwId;
|
|
HANDLE hThread = CreateThread(0, 0, ThreadProc, 0, 0, &dwId);
|
|
CloseHandle(hThread);
|
|
|
|
LocalFree(pSD);
|
|
}
|
|
|
|
|
|
//***************************************************************************
|
|
//
|
|
//***************************************************************************
|
|
|
|
static DWORD WINAPI ThreadProc(LPVOID pArg)
|
|
{
|
|
static bool bInitialized = false;
|
|
if (g_bWinMgmt == FALSE)
|
|
{
|
|
return 0;
|
|
}
|
|
for (;;)
|
|
{
|
|
DWORD dwRes = WaitForMultipleObjects(H_LAST, m_hArray, FALSE, INFINITE);
|
|
|
|
dwRes -= WAIT_OBJECT_0;
|
|
|
|
switch(dwRes)
|
|
{
|
|
case H_ENABLE_LEAK_TRACKING:
|
|
if (!bInitialized)
|
|
{
|
|
StartHeapTracking();
|
|
bInitialized = true;
|
|
}
|
|
g_bMemTracking = true;
|
|
break;
|
|
|
|
case H_DUMP_LEAK_TRACKING:
|
|
if (g_bMemTracking)
|
|
DumpHeapStacks();
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL TestForWinMgmt()
|
|
{
|
|
char mod[128];
|
|
|
|
GetModuleFileName(0, mod, 128);
|
|
|
|
// Upcase.
|
|
char *p = mod;
|
|
while (*p)
|
|
{
|
|
if (*p >= 'a' && *p <= 'z')
|
|
{
|
|
*p -= 32;
|
|
}
|
|
p++;
|
|
}
|
|
|
|
// Ensure WINMGMT.EXE
|
|
|
|
p = mod;
|
|
while (*p)
|
|
{
|
|
if ( p[0] != 0 && p[0] == 'W'
|
|
&& p[1] != 0 && p[1] == 'I'
|
|
&& p[2] != 0 && p[2] == 'N'
|
|
&& p[3] != 0 && p[3] == 'M'
|
|
&& p[4] != 0 && p[4] == 'G'
|
|
&& p[5] != 0 && p[5] == 'M'
|
|
&& p[6] != 0 && p[6] == 'T'
|
|
)
|
|
{
|
|
g_bWinMgmt = TRUE;
|
|
return TRUE;
|
|
}
|
|
p++;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|