Leaked source code of windows server 2003
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

/******************************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