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.
 
 
 
 
 
 

694 lines
14 KiB

/*++
Copyright (c) 1996-2001 Microsoft Corporation
Module Name:
dbgtrack.c
Abstract:
Allocation tracking implementation.
Author:
Jim Schmidt (jimschm) 18-Sept-2001
Revision History:
--*/
//
// Includes
//
#include "pch.h"
#include "commonp.h"
//
// NOTE: No code should appear outside the #ifdef DEBUG
//
#ifdef DEBUG
//
// Strings
//
// None
//
// Constants
//
#define TRACK_BUCKETS 1501
#define BUCKET_ITEMS_PER_POOL 8192
//
// Macros
//
// None
//
// Types
//
typedef ULONG_PTR ALLOCATION_ITEM_OFFSET;
typedef struct TAG_TRACKBUCKETITEM {
struct TAG_TRACKBUCKETITEM *Next;
struct TAG_TRACKBUCKETITEM *Prev;
ALLOCTYPE Type;
PCVOID Ptr;
ALLOCATION_ITEM_OFFSET ItemOffset;
} TRACKBUCKETITEM, *PTRACKBUCKETITEM;
typedef struct _tagBUCKETPOOL {
UINT Count;
TRACKBUCKETITEM Items[BUCKET_ITEMS_PER_POOL];
} TRACKBUCKETPOOL, *PTRACKBUCKETPOOL;
typedef struct {
ALLOCTYPE Type;
PCVOID Ptr;
PCSTR FileName;
UINT Line;
BOOL Allocated;
} ALLOCATION_ITEM, *PALLOCATION_ITEM;
typedef struct {
PTRACKBUCKETITEM TrackBuckets[TRACK_BUCKETS];
PTRACKBUCKETITEM TrackPoolDelHead;
PTRACKBUCKETPOOL TrackPool;
UINT DisabledRefCount;
INT UseCount;
CHAR TrackComment[1024];
PCSTR TrackFile;
UINT TrackLine;
BOOL FreeTrackFile;
} THREADTRACK, *PTHREADTRACK;
//
// Globals
//
DWORD g_TlsIndex = TLS_OUT_OF_INDEXES;
CRITICAL_SECTION g_AllocListCs;
GROWBUFFER g_AllocationList;
PVOID g_FirstDeletedAlloc;
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
//
// Macro expansion definition
//
// None
//
// Code
//
PBYTE
pUntrackedGbGrow (
IN OUT PGROWBUFFER GrowBuf,
IN DWORD SpaceNeeded
)
/*++
Routine Description:
pUntrackedGbGrow is the same as GbGrow, but it does not cause any tracking
to occur.
Arguments:
GrowBuf - A pointer to a GROWBUFFER structure.
Initialize this structure to zero for
the first call to GrowBuffer.
SpaceNeeded - The number of free bytes needed in the buffer
Return Value:
A pointer to the SpaceNeeded bytes, or NULL if a memory allocation
error occurred.
--*/
{
PBYTE newBuffer;
DWORD totalSpaceNeeded;
DWORD growTo;
MYASSERT(SpaceNeeded);
//
// Make sure structure is initialized properly
//
if (!GrowBuf->Buf) {
ZeroMemory (GrowBuf, sizeof (GROWBUFFER));
}
if (!GrowBuf->GrowSize) {
GrowBuf->GrowSize = 1024;
}
//
// Compute new buffer size
//
totalSpaceNeeded = GrowBuf->End + SpaceNeeded;
if (totalSpaceNeeded > GrowBuf->Size) {
growTo = (totalSpaceNeeded + GrowBuf->GrowSize) - (totalSpaceNeeded % GrowBuf->GrowSize);
} else {
growTo = 0;
}
//
// If no buffer, allocate one. If buffer is too small, reallocate it.
//
if (!GrowBuf->Buf) {
GrowBuf->Buf = (PBYTE) MemAllocNeverFail (g_hHeap, 0, growTo);
GrowBuf->Size = growTo;
} else if (growTo) {
newBuffer = MemReAllocNeverFail (g_hHeap, 0, GrowBuf->Buf, growTo);
GrowBuf->Size = growTo;
GrowBuf->Buf = newBuffer;
}
newBuffer = GrowBuf->Buf + GrowBuf->End;
GrowBuf->End += SpaceNeeded;
return newBuffer;
}
VOID
pUntrackedGbFree (
IN PGROWBUFFER GrowBuf
)
/*++
Routine Description:
pUntrackedGbFree frees a buffer allocated by pUntrackedGbGrow.
Arguments:
GrowBuf - A pointer to the same structure passed to pUntrackedGbGrow
Return Value:
none
--*/
{
MYASSERT(GrowBuf);
if (GrowBuf->Buf) {
HeapFree (g_hHeap, 0, GrowBuf->Buf);
ZeroMemory (GrowBuf, sizeof (GROWBUFFER));
}
}
PTHREADTRACK
pGetTrackStructForThread (
VOID
)
{
PTHREADTRACK result;
result = (PTHREADTRACK) TlsGetValue (g_TlsIndex);
if (!result) {
//
// Need to allocate a struct
//
result = (PTHREADTRACK) MemAllocNeverFail (
g_hHeap,
HEAP_ZERO_MEMORY,
sizeof (THREADTRACK)
);
TlsSetValue (g_TlsIndex, (PVOID) result);
}
return result;
}
VOID
DisableTrackComment (
VOID
)
{
PTHREADTRACK trackStruct;
trackStruct = pGetTrackStructForThread();
trackStruct->DisabledRefCount += 1;
}
VOID
EnableTrackComment (
VOID
)
{
PTHREADTRACK trackStruct;
trackStruct = pGetTrackStructForThread();
if (trackStruct->DisabledRefCount > 0) {
trackStruct->DisabledRefCount -= 1;
}
}
INT
DbgTrackPushEx (
PCSTR Msg,
PCSTR File,
UINT Line,
BOOL DupFileString
)
{
PTHREADTRACK trackStruct;
trackStruct = pGetTrackStructForThread();
if (trackStruct->DisabledRefCount > 0) {
return 0;
}
if (trackStruct->UseCount > 0) {
trackStruct->UseCount += 1;
return 0;
}
if (Msg) {
wsprintfA (trackStruct->TrackComment, "%s line %u [%s]", File, Line, Msg);
} else {
wsprintfA (trackStruct->TrackComment, "%s line %u", File, Line);
}
if (DupFileString) {
trackStruct->TrackFile = (PCSTR) MemAllocNeverFail (g_hHeap, 0, SzSizeA (File));
SzCopyA ((PSTR) trackStruct->TrackFile, File);
trackStruct->FreeTrackFile = TRUE;
} else {
trackStruct->TrackFile = File;
trackStruct->FreeTrackFile = FALSE;
}
trackStruct->TrackLine = Line;
trackStruct->UseCount = 1;
return 0;
}
INT
DbgTrackPop (
VOID
)
{
PTHREADTRACK trackStruct;
trackStruct = pGetTrackStructForThread();
if (trackStruct->DisabledRefCount > 0) {
return 0;
}
trackStruct->UseCount -= 1;
if (!(trackStruct->UseCount)) {
trackStruct->TrackComment[0] = 0;
if (trackStruct->FreeTrackFile && trackStruct->TrackFile) {
HeapFree (g_hHeap, 0, (PVOID)trackStruct->TrackFile);
}
trackStruct->TrackFile = NULL;
trackStruct->TrackLine = 0;
trackStruct->FreeTrackFile = FALSE;
}
return 0;
}
VOID
DbgTrackDump (
VOID
)
{
PTHREADTRACK trackStruct;
trackStruct = pGetTrackStructForThread();
if (trackStruct->UseCount > 0) {
DEBUGMSGA ((
DBG_INFO,
"Caller : %s line %u (%s)",
trackStruct->TrackFile,
trackStruct->TrackLine,
trackStruct->TrackComment
));
}
}
BOOL
DbgInitTracking (
VOID
)
{
if (g_TlsIndex == TLS_OUT_OF_INDEXES) {
g_TlsIndex = TlsAlloc();
if (g_TlsIndex == TLS_OUT_OF_INDEXES) {
return FALSE;
}
}
InitializeCriticalSection (&g_AllocListCs);
ZeroMemory (&g_AllocationList, sizeof (g_AllocationList));
g_AllocationList.GrowSize = 65536;
g_FirstDeletedAlloc = NULL;
return TRUE;
}
VOID
DbgTerminateTracking (
VOID
)
{
UINT size;
UINT u;
PALLOCATION_ITEM item;
GROWBUFFER msg = { 0, 0, 0, 0, 0, 0 };
CHAR text[1024];
PSTR p;
UINT byteCount;
PTHREADTRACK trackStruct;
EnterCriticalSection (&g_AllocListCs);
trackStruct = pGetTrackStructForThread();
size = g_AllocationList.End / sizeof (ALLOCATION_ITEM);
for (u = 0 ; u < size ; u++) {
item = (PALLOCATION_ITEM) g_AllocationList.Buf + u;
if (!item->FileName) {
continue;
}
//
// Append the string but not the nul
//
byteCount = (UINT) wsprintfA (text, "%s line %u\r\n", item->FileName, item->Line);
p = (PSTR) pUntrackedGbGrow (&msg, byteCount);
CopyMemory (p, text, byteCount);
}
pUntrackedGbFree (&g_AllocationList);
g_FirstDeletedAlloc = NULL;
LeaveCriticalSection (&g_AllocListCs);
//
// Put the message in the log
//
if (msg.End) {
p = (PSTR) pUntrackedGbGrow (&msg, 1);
*p = 0;
DEBUGMSGA ((DBG_WARNING, "Leaks : %s", msg.Buf));
pUntrackedGbFree (&msg);
}
// Intentional leak -- who cares about track memory
trackStruct->TrackPoolDelHead = NULL;
trackStruct->TrackPool = NULL;
TlsFree (g_TlsIndex);
g_TlsIndex = TLS_OUT_OF_INDEXES;
}
PTRACKBUCKETITEM
pAllocTrackBucketItem (
VOID
)
{
PTRACKBUCKETITEM bucketItem;
PTHREADTRACK trackStruct;
trackStruct = pGetTrackStructForThread();
if (trackStruct->TrackPoolDelHead) {
bucketItem = trackStruct->TrackPoolDelHead;
trackStruct->TrackPoolDelHead = bucketItem->Next;
} else {
if (!trackStruct->TrackPool || trackStruct->TrackPool->Count == BUCKET_ITEMS_PER_POOL) {
trackStruct->TrackPool = (PTRACKBUCKETPOOL) MemAllocNeverFail (g_hHeap, 0, sizeof (TRACKBUCKETPOOL));
trackStruct->TrackPool->Count = 0;
}
bucketItem = trackStruct->TrackPool->Items + trackStruct->TrackPool->Count;
trackStruct->TrackPool->Count++;
}
return bucketItem;
}
VOID
pFreeTrackBucketItem (
PTRACKBUCKETITEM BucketItem
)
{
PTHREADTRACK trackStruct;
trackStruct = pGetTrackStructForThread();
BucketItem->Next = trackStruct->TrackPoolDelHead;
trackStruct->TrackPoolDelHead = BucketItem;
}
UINT
pComputeTrackHashVal (
IN ALLOCTYPE Type,
IN PCVOID Ptr
)
{
ULONG_PTR hash;
hash = ((ULONG_PTR) Type << 16) ^ (ULONG_PTR)Ptr;
return (UINT) (hash % TRACK_BUCKETS);
}
VOID
pTrackHashTableInsert (
IN PBYTE Base,
IN ALLOCATION_ITEM_OFFSET ItemOffset
)
{
UINT hash;
PTRACKBUCKETITEM bucketItem;
PALLOCATION_ITEM item;
PTHREADTRACK trackStruct;
trackStruct = pGetTrackStructForThread();
item = (PALLOCATION_ITEM) (Base + ItemOffset);
hash = pComputeTrackHashVal (item->Type, item->Ptr);
bucketItem = pAllocTrackBucketItem();
bucketItem->Prev = NULL;
bucketItem->Next = trackStruct->TrackBuckets[hash];
bucketItem->Type = item->Type;
bucketItem->Ptr = item->Ptr;
bucketItem->ItemOffset = ItemOffset;
if (bucketItem->Next) {
bucketItem->Next->Prev = bucketItem;
}
trackStruct->TrackBuckets[hash] = bucketItem;
}
VOID
pTrackHashTableDelete (
IN PTRACKBUCKETITEM BucketItem
)
{
UINT hash;
PTHREADTRACK trackStruct;
trackStruct = pGetTrackStructForThread();
hash = pComputeTrackHashVal (BucketItem->Type, BucketItem->Ptr);
if (BucketItem->Prev) {
BucketItem->Prev->Next = BucketItem->Next;
} else {
trackStruct->TrackBuckets[hash] = BucketItem->Next;
}
if (BucketItem->Next) {
BucketItem->Next->Prev = BucketItem->Prev;
}
pFreeTrackBucketItem (BucketItem);
}
PTRACKBUCKETITEM
pTrackHashTableFind (
IN ALLOCTYPE Type,
IN PCVOID Ptr
)
{
PTRACKBUCKETITEM bucketItem;
UINT hash;
PTHREADTRACK trackStruct;
trackStruct = pGetTrackStructForThread();
hash = pComputeTrackHashVal (Type, Ptr);
bucketItem = trackStruct->TrackBuckets[hash];
while (bucketItem) {
if (bucketItem->Type == Type && bucketItem->Ptr == Ptr) {
return bucketItem;
}
bucketItem = bucketItem->Next;
}
return NULL;
}
VOID
DbgRegisterAllocation (
IN ALLOCTYPE Type,
IN PVOID Ptr,
IN PCSTR File,
IN UINT Line
)
{
PALLOCATION_ITEM item;
PTHREADTRACK trackStruct;
PCSTR fileToRecord;
UINT lineToRecord;
trackStruct = pGetTrackStructForThread();
if (!trackStruct->TrackFile) {
fileToRecord = File;
lineToRecord = Line;
} else {
fileToRecord = trackStruct->TrackFile;
lineToRecord = trackStruct->TrackLine;
}
EnterCriticalSection (&g_AllocListCs);
if (!g_FirstDeletedAlloc) {
item = (PALLOCATION_ITEM) pUntrackedGbGrow (&g_AllocationList,sizeof(ALLOCATION_ITEM));
} else {
item = (PALLOCATION_ITEM) g_FirstDeletedAlloc;
g_FirstDeletedAlloc = (PVOID)item->Ptr;
}
item->Type = Type;
item->Ptr = Ptr;
item->FileName = fileToRecord;
item->Line = lineToRecord;
pTrackHashTableInsert (
g_AllocationList.Buf,
(ALLOCATION_ITEM_OFFSET) ((PBYTE) item - g_AllocationList.Buf)
);
LeaveCriticalSection (&g_AllocListCs);
}
VOID
DbgUnregisterAllocation (
IN ALLOCTYPE Type,
IN PCVOID Ptr
)
{
PALLOCATION_ITEM item;
PTRACKBUCKETITEM bucketItem;
EnterCriticalSection (&g_AllocListCs);
bucketItem = pTrackHashTableFind (Type, Ptr);
if (!g_AllocationList.Buf) {
LeaveCriticalSection (&g_AllocListCs);
DEBUGMSG ((DBG_WARNING, "Unregister allocation: Allocation buffer already freed"));
return;
}
if (bucketItem) {
item = (PALLOCATION_ITEM) (g_AllocationList.Buf + bucketItem->ItemOffset);
if (item->Allocated) {
HeapFree (g_hHeap, 0, (PSTR)item->FileName);
}
item->FileName = NULL;
item->Type = (ALLOCTYPE) -1;
item->Ptr = g_FirstDeletedAlloc;
g_FirstDeletedAlloc = item;
pTrackHashTableDelete (bucketItem);
LeaveCriticalSection (&g_AllocListCs);
} else {
LeaveCriticalSection (&g_AllocListCs);
DEBUGMSG ((DBG_WARNING, "Unregister allocation: Pointer not registered"));
}
}
#endif