You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
472 lines
12 KiB
472 lines
12 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: pooltrk.cxx
|
|
*
|
|
* Pool allocation tracker.
|
|
*
|
|
* Created: 23-Feb-1998 20:09:03
|
|
* Author: Gilman Wong [gilmanw]
|
|
*
|
|
* Copyright (c) 1998-1999 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
#include "pooltrk.hxx"
|
|
|
|
#if DBG
|
|
|
|
#ifdef _HYDRA_
|
|
#ifndef USER_POOL_TAGGING_ON
|
|
|
|
extern BOOL G_fConsole;
|
|
|
|
LIST_ENTRY gleDebugGrePoolTrackerHead;
|
|
HSEMAPHORE ghsemDebugGrePoolTracker = NULL;
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DebugGrePoolTrackerInit
|
|
*
|
|
* Initialize the pool tracker.
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 23-Feb-1998 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
DebugGrePoolTrackerInit()
|
|
{
|
|
//
|
|
// Initialize doubly linked list used to track pool allocations.
|
|
//
|
|
|
|
InitializeListHead(&gleDebugGrePoolTrackerHead);
|
|
|
|
//
|
|
// Initialize the list semaphore.
|
|
//
|
|
// Note: allocate from non-tracked pool. We will trust the pool
|
|
// tracker to cleanup its own allocation.
|
|
//
|
|
|
|
ghsemDebugGrePoolTracker = GreCreateSemaphoreNonTracked();
|
|
|
|
return (ghsemDebugGrePoolTracker != NULL);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DebugGrePoolTrackerAdd
|
|
*
|
|
* Add specified pool allocation to list.
|
|
*
|
|
* History:
|
|
* 23-Feb-1998 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
DebugGrePoolTrackerAdd(POOLTRACKHDR *pTrack, SIZE_T cj, ULONG ulTag)
|
|
{
|
|
PLIST_ENTRY pleNew = (PLIST_ENTRY) pTrack;
|
|
|
|
//
|
|
// Setup pool track header.
|
|
//
|
|
// Sundown note: pool allocations in GRE should be < 4GB
|
|
//
|
|
|
|
pTrack->ulSize = cj;
|
|
pTrack->ulTag = ulTag;
|
|
|
|
//
|
|
// Lock the pool tracking list.
|
|
//
|
|
// During GRE initialization, we may be called while allocating
|
|
// the ghsemDebugGrePoolTracker. So we actually need to check
|
|
// if it exists.
|
|
//
|
|
|
|
if (ghsemDebugGrePoolTracker) GreAcquireSemaphore(ghsemDebugGrePoolTracker);
|
|
|
|
//
|
|
// Insert into the pool tracking list.
|
|
//
|
|
|
|
InsertTailList(&gleDebugGrePoolTrackerHead, pleNew);
|
|
|
|
//
|
|
// Unlock the pool tracking list.
|
|
//
|
|
|
|
if (ghsemDebugGrePoolTracker) GreReleaseSemaphore(ghsemDebugGrePoolTracker);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DebugGrePoolTrackerRemove
|
|
*
|
|
* Remove specified pool allocation from list.
|
|
*
|
|
* History:
|
|
* 23-Feb-1998 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
DebugGrePoolTrackerRemove(POOLTRACKHDR *pTrack)
|
|
{
|
|
PLIST_ENTRY pleVictim = (PLIST_ENTRY) pTrack;
|
|
|
|
//
|
|
// Lock the pool tracking list.
|
|
//
|
|
// During GRE initialization, we may be called while allocating
|
|
// the ghsemDebugGrePoolTracker. So we actually need to check
|
|
// if it exists.
|
|
//
|
|
|
|
if (ghsemDebugGrePoolTracker) GreAcquireSemaphore(ghsemDebugGrePoolTracker);
|
|
|
|
//
|
|
// Remove entry from pool tracking list.
|
|
//
|
|
|
|
RemoveEntryList(pleVictim);
|
|
|
|
//
|
|
// Unlock the pool tracking list.
|
|
//
|
|
|
|
if (ghsemDebugGrePoolTracker) GreReleaseSemaphore(ghsemDebugGrePoolTracker);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DebugGreAllocPool
|
|
*
|
|
* Allocates paged pool and tracks it in the pool tracking list.
|
|
* Free with DebugGreFreePool.
|
|
*
|
|
* Buffer
|
|
* pTrack --> +----------------+
|
|
* | POOLTRACKHDR |
|
|
* pvRet --> +----------------+
|
|
* | Returned |
|
|
* | Buffer |
|
|
* | Allocation |
|
|
* | |
|
|
* ...
|
|
* | |
|
|
* +----------------+
|
|
*
|
|
*
|
|
* History:
|
|
* 23-Feb-1998 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" PVOID
|
|
DebugGreAllocPool(SIZE_T ulBytes, ULONG ulTag)
|
|
{
|
|
PVOID pv;
|
|
|
|
//
|
|
// If Hydra, adjust requested size to include tracking header.
|
|
//
|
|
// Sundown note: sizeof(POOLTRACKHDR) will fit into 32-bits.
|
|
//
|
|
|
|
if (!G_fConsole)
|
|
{
|
|
if (ulBytes <= (MAXULONG - sizeof(POOLTRACKHDR)))
|
|
ulBytes += ((ULONG) sizeof(POOLTRACKHDR));
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Allocate paged pool.
|
|
//
|
|
|
|
pv = ExAllocatePoolWithTag(
|
|
(POOL_TYPE) (SESSION_POOL_MASK | PagedPool),
|
|
ulBytes, ulTag);
|
|
|
|
if (pv)
|
|
{
|
|
//
|
|
// Tracking overhead if Hydra.
|
|
//
|
|
|
|
if (!G_fConsole)
|
|
{
|
|
//
|
|
// Add allocation to tracking list.
|
|
//
|
|
|
|
POOLTRACKHDR *pTrack = (POOLTRACKHDR *) pv;
|
|
|
|
DebugGrePoolTrackerAdd(pTrack, ulBytes, ulTag);
|
|
|
|
#ifdef POOLTRACK_STACKTRACE_ENABLE
|
|
//
|
|
// Save the stack back trace.
|
|
//
|
|
|
|
ULONG ulHash;
|
|
|
|
RtlZeroMemory(pTrack->apvStackTrace,
|
|
POOLTRACK_TRACESIZE * sizeof(PVOID));
|
|
|
|
RtlCaptureStackBackTrace(1,
|
|
POOLTRACK_TRACESIZE,
|
|
pTrack->apvStackTrace,
|
|
&ulHash);
|
|
#endif
|
|
|
|
//
|
|
// Adjust return pointer to exclude tracking header.
|
|
//
|
|
|
|
pv = (PVOID) (pTrack + 1);
|
|
}
|
|
}
|
|
|
|
return pv;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DebugGreAllocPoolNonPaged
|
|
*
|
|
* Allocates nonpaged pool and tracks it in the pool tracking list.
|
|
* Free with DebugGreFreePool.
|
|
*
|
|
* History:
|
|
* 23-Feb-1998 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" PVOID
|
|
DebugGreAllocPoolNonPaged(SIZE_T ulBytes, ULONG ulTag)
|
|
{
|
|
PVOID pv;
|
|
|
|
//
|
|
// If Hydra, adjust requested size to include tracking header.
|
|
//
|
|
// Sundown note: sizeof(POOLTRACKHDR) will fit into 32-bits.
|
|
//
|
|
|
|
if (!G_fConsole)
|
|
{
|
|
ulBytes += ((ULONG) sizeof(POOLTRACKHDR));
|
|
}
|
|
|
|
//
|
|
// Allocate nonpaged pool.
|
|
//
|
|
|
|
pv = ExAllocatePoolWithTag(
|
|
(POOL_TYPE)NonPagedPool,
|
|
ulBytes, ulTag);
|
|
|
|
if (pv)
|
|
{
|
|
//
|
|
// Tracking overhead if Hydra.
|
|
//
|
|
|
|
if (!G_fConsole)
|
|
{
|
|
//
|
|
// Add allocation to tracking list.
|
|
//
|
|
|
|
POOLTRACKHDR *pTrack = (POOLTRACKHDR *) pv;
|
|
|
|
DebugGrePoolTrackerAdd(pTrack, ulBytes, ulTag);
|
|
|
|
//
|
|
// Adjust return pointer to exclude tracking header.
|
|
//
|
|
|
|
pv = (PVOID) (pTrack + 1);
|
|
}
|
|
}
|
|
|
|
return pv;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DebugGreFreePool
|
|
*
|
|
* Free pool memory allocated by DebugGreAllocPool and
|
|
* DebugGreAllocPoolNonPaged. Removes the allocation from tracking list.
|
|
*
|
|
* History:
|
|
* 23-Feb-1998 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
extern "C" VOID
|
|
DebugGreFreePool(PVOID pv)
|
|
{
|
|
if (pv)
|
|
{
|
|
//
|
|
// Tracking overhead if Hydra.
|
|
//
|
|
|
|
if (!G_fConsole)
|
|
{
|
|
//
|
|
// Find header and remove from tracking list.
|
|
//
|
|
|
|
POOLTRACKHDR *pTrack = ((POOLTRACKHDR *) pv) - 1;
|
|
|
|
DebugGrePoolTrackerRemove(pTrack);
|
|
|
|
//
|
|
// Adjust pointer to base of allocation.
|
|
//
|
|
|
|
pv = (PVOID) pTrack;
|
|
}
|
|
|
|
//
|
|
// Free the pool allocation.
|
|
//
|
|
|
|
ExFreePool(pv);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DebugGreCleanupPoolTracker
|
|
*
|
|
* Frees any allocations remaining in the tracking list (but asserts so
|
|
* that debugger is informed that a leak exists). Free resources used
|
|
* to maintain the tracking list.
|
|
*
|
|
* History:
|
|
* 23-Feb-1998 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID
|
|
DebugGreCleanupPoolTracker()
|
|
{
|
|
BOOL bTitle = FALSE;
|
|
ULONG cLeaks = 0;
|
|
volatile PLIST_ENTRY pleNext;
|
|
|
|
//
|
|
// Assert if list not empty (i.e., there are leaks!).
|
|
//
|
|
// What to do if there is a leak?
|
|
//
|
|
// Well, it might be enough just to look at the tags that leak.
|
|
// If that doesn't provide enough detail to track the leak,
|
|
// recompile with USER_POOL_TAGGING_ON defined in engine.h and
|
|
// define POOL_ALLOC_TRACE in w32\w32inc\usergdi.h to use the
|
|
// USER pool tracking code. You'll have build a checked version
|
|
// of win32k (clean build both USER and GDI), but this pool tracker
|
|
// will record a stack trace for every allocation. If we leak,
|
|
// USER will assert during Hydra session shutdown and the userkdx
|
|
// dpa extension will dump the allocations (use !dpa -ts 24 to
|
|
// dump the leaked TAG_GDI allocations with a stack trace).
|
|
//
|
|
|
|
if (!IsListEmpty(&gleDebugGrePoolTrackerHead))
|
|
{
|
|
DbgPrint("DebugGreCleanupPoolTracker: "
|
|
"gleDebugGrePoolTrackerHead 0x%08lx not empty\n",
|
|
&gleDebugGrePoolTrackerHead);
|
|
RIP("DebugGreCleanupPoolTracker: leak detected\n");
|
|
}
|
|
|
|
//
|
|
// Free all allocations in the list.
|
|
//
|
|
|
|
pleNext = gleDebugGrePoolTrackerHead.Flink;
|
|
|
|
while (pleNext != &gleDebugGrePoolTrackerHead)
|
|
{
|
|
//
|
|
// Pool allocation starts after the POOLTRACKHDR.
|
|
//
|
|
|
|
PVOID pvVictim = (PVOID) (((POOLTRACKHDR *) pleNext) + 1);
|
|
|
|
//
|
|
// Count the number of leaked allocations.
|
|
//
|
|
|
|
cLeaks++;
|
|
|
|
//
|
|
// Print out the allocation information.
|
|
//
|
|
|
|
if (!bTitle)
|
|
{
|
|
DbgPrint("\nDebugGreCleanupPoolTracker: cleaning up pool allocations\n");
|
|
DbgPrint("----------\t----------\t-----------------\n");
|
|
DbgPrint("Address \tSize \tTag\n");
|
|
DbgPrint("----------\t----------\t-----------------\n");
|
|
bTitle = TRUE;
|
|
}
|
|
|
|
DbgPrint("0x%08lx\t0x%08lx\t0x%08lx (%c%c%c%c)\n",
|
|
pleNext,
|
|
((POOLTRACKHDR *) pleNext)->ulSize,
|
|
((POOLTRACKHDR *) pleNext)->ulTag,
|
|
((((POOLTRACKHDR *) pleNext)->ulTag) ) & 0xff,
|
|
((((POOLTRACKHDR *) pleNext)->ulTag) >> 8) & 0xff,
|
|
((((POOLTRACKHDR *) pleNext)->ulTag) >> 16) & 0xff,
|
|
((((POOLTRACKHDR *) pleNext)->ulTag) >> 24) & 0xff);
|
|
|
|
//
|
|
// Delete the allocation.
|
|
//
|
|
|
|
DebugGreFreePool(pvVictim);
|
|
|
|
//
|
|
// Restart at the begining of the list since our
|
|
// entry got deleted.
|
|
//
|
|
|
|
pleNext = gleDebugGrePoolTrackerHead.Flink;
|
|
}
|
|
|
|
if (bTitle)
|
|
{
|
|
DbgPrint("----------\t----------\t-----------------\n");
|
|
}
|
|
|
|
if (cLeaks)
|
|
{
|
|
DbgPrint("%ld allocations leaked\n\n", cLeaks);
|
|
}
|
|
|
|
//
|
|
// Delete the list lock.
|
|
//
|
|
// Note that the list lock was allocated from non-tracked pool.
|
|
// It is also a non-tracked semaphore - that is, it must be deleted
|
|
// explicitly.
|
|
//
|
|
|
|
GreDeleteSemaphoreNonTracked(ghsemDebugGrePoolTracker);
|
|
ghsemDebugGrePoolTracker = NULL;
|
|
}
|
|
|
|
#endif //USER_POOL_TAGGING_ON
|
|
|
|
#endif //_HYDRA_
|
|
|
|
#endif //DBG
|