windows-nt/Source/XPSP1/NT/windows/winstate/cobra/utils/main/dbgtrack.c
2020-09-26 16:20:57 +08:00

576 lines
10 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
dbgtrack.c
Abstract:
Allocation tracking implementation. From old debug.c
Author:
Marc R. Whitten (marcw) 09-Sept-1999
Revision History:
--*/
//
// Includes
//
#include "pch.h"
//
// NOTE: No code should appear outside the #ifdef DEBUG
//
#ifdef DEBUG
#pragma message("DEBUG macros enabled")
//
// Strings
//
// None
//
// Constants
//
#define TRACK_BUCKETS 1501
#define BUCKET_ITEMS_PER_POOL 8192
//
// Macros
//
// None
//
// Types
//
typedef UBINT ALLOCATION_ITEM_OFFSET;
typedef struct _tagTRACKBUCKETITEM {
struct _tagTRACKBUCKETITEM *Next;
struct _tagTRACKBUCKETITEM *Prev;
ALLOCTYPE Type;
PVOID Ptr;
ALLOCATION_ITEM_OFFSET ItemOffset;
} TRACKBUCKETITEM, *PTRACKBUCKETITEM;
typedef struct _tagBUCKETPOOL {
UINT Count;
TRACKBUCKETITEM Items[BUCKET_ITEMS_PER_POOL];
} TRACKBUCKETPOOL, *PTRACKBUCKETPOOL;
typedef struct {
ALLOCTYPE Type;
PVOID Ptr;
PCSTR FileName;
UINT Line;
BOOL Allocated;
} ALLOCATION_ITEM, *PALLOCATION_ITEM;
//
// Globals
//
PTRACKBUCKETITEM g_TrackBuckets[TRACK_BUCKETS];
PTRACKBUCKETITEM g_TrackPoolDelHead;
PTRACKBUCKETPOOL g_TrackPool;
//
// The following pointer can be used to help identify memory leak sources.
// It is copied to the memory tracking log.
//
PCSTR g_TrackComment;
PCSTR g_TrackFile;
UINT g_TrackLine;
BOOL g_TrackAlloc;
INT g_UseCount;
UINT g_DisableTrackComment = 0;
GROWBUFFER g_AllocationList;
PVOID g_FirstDeletedAlloc;
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
//
// Macro expansion definition
//
// None
//
// Code
//
VOID
DisableTrackComment (
VOID
)
{
g_DisableTrackComment ++;
}
VOID
EnableTrackComment (
VOID
)
{
if (g_DisableTrackComment > 0) {
g_DisableTrackComment --;
}
}
PBYTE
pOurTrackedGbGrow (
IN PGROWBUFFER Buffer,
IN UINT Bytes
)
{
PBYTE p;
BOOL trackMsg = FALSE;
//
// Because grow buffers themselves cause tracking, we have to
// call the untracked version. To eliminate confusion, we
// give a helpful note.
//
if (!g_TrackFile) {
trackMsg = TRUE;
g_TrackFile = "<allocation tracking in dbgtrack.c, not a real leak>";
g_TrackLine = __LINE__;
}
p = (PSTR) RealGbGrow (Buffer, Bytes);
if (trackMsg) {
g_TrackFile = NULL;
}
return p;
}
INT
TrackPushEx (
PCSTR Msg,
PCSTR File,
UINT Line,
BOOL Alloc
)
{
if (g_DisableTrackComment > 0) {
return 0;
}
if (g_UseCount > 0) {
g_UseCount++;
return 0;
}
TrackPush (Msg, File, Line);
g_TrackAlloc = TRUE;
return 0;
}
INT
TrackPush (
PCSTR Msg,
PCSTR File,
UINT Line
)
{
static CHAR Buffer[1024];
if (g_DisableTrackComment > 0) {
return 0;
}
if (g_UseCount > 0) {
g_UseCount++;
return 0;
}
if (Msg) {
wsprintfA (Buffer, "%s line %u [%s]", File, Line, Msg);
} else {
wsprintfA (Buffer, "%s line %u", File, Line);
}
g_TrackFile = File;
g_TrackLine = Line;
g_TrackAlloc = FALSE;
g_TrackComment = Buffer;
g_UseCount = 1;
return 0;
}
INT
TrackPop (
VOID
)
{
if (g_DisableTrackComment > 0) {
return 0;
}
g_UseCount--;
if (!g_UseCount) {
g_TrackComment = NULL;
g_TrackFile = NULL;
g_TrackLine = 0;
g_TrackAlloc = FALSE;
}
return 0;
}
VOID
TrackDump (
VOID
)
{
if (g_UseCount > 0) {
DEBUGMSGA (("Caller", "%s line %u (%s)", g_TrackFile, g_TrackLine, g_TrackComment));
}
}
VOID
InitAllocationTracking (
VOID
)
{
ZeroMemory (&g_AllocationList, sizeof (g_AllocationList));
g_AllocationList.GrowSize = 65536;
g_FirstDeletedAlloc = NULL;
}
VOID
FreeAllocationTracking (
VOID
)
{
UINT Size;
UINT u;
PALLOCATION_ITEM Item;
GROWBUFFER Msg = INIT_GROWBUFFER;
CHAR Text[1024];
PSTR p;
UINT Bytes;
Size = g_AllocationList.End / sizeof (ALLOCATION_ITEM);;
for (u = 0 ; u < Size ; u++) {
Item = (PALLOCATION_ITEM) g_AllocationList.Buf + u;
if (!Item->FileName) {
continue;
}
Bytes = (UINT) wsprintfA (Text, "%s line %u\r\n", Item->FileName, Item->Line);
p = (PSTR) pOurTrackedGbGrow (&Msg, Bytes);
if (p) {
CopyMemory (p, Text, Bytes);
}
}
if (Msg.End) {
p = (PSTR) pOurTrackedGbGrow (&Msg, 1);
if (p) {
*p = 0;
DEBUGMSGA (("Leaks", "%s", Msg.Buf));
}
GbFree (&Msg);
}
GbFree (&g_AllocationList);
g_FirstDeletedAlloc = NULL;
// Intentional leak -- who cares about track memory
g_TrackPoolDelHead = NULL;
g_TrackPool = NULL;
}
PTRACKBUCKETITEM
pAllocTrackBucketItem (
VOID
)
{
PTRACKBUCKETITEM BucketItem;
if (g_TrackPoolDelHead) {
BucketItem = g_TrackPoolDelHead;
g_TrackPoolDelHead = BucketItem->Next;
} else {
if (!g_TrackPool || g_TrackPool->Count == BUCKET_ITEMS_PER_POOL) {
g_TrackPool = (PTRACKBUCKETPOOL) SafeHeapAlloc (g_hHeap, 0, sizeof (TRACKBUCKETPOOL));
if (!g_TrackPool) {
return NULL;
}
g_TrackPool->Count = 0;
}
BucketItem = g_TrackPool->Items + g_TrackPool->Count;
g_TrackPool->Count++;
}
return BucketItem;
}
VOID
pFreeTrackBucketItem (
PTRACKBUCKETITEM BucketItem
)
{
BucketItem->Next = g_TrackPoolDelHead;
g_TrackPoolDelHead = BucketItem;
}
DWORD
pComputeTrackHashVal (
IN ALLOCTYPE Type,
IN PVOID Ptr
)
{
DWORD Hash;
Hash = (DWORD) ((DWORD)Type << 16) ^ (DWORD)(UBINT)Ptr;
return Hash % TRACK_BUCKETS;
}
VOID
pTrackHashTableInsert (
IN PBYTE Base,
IN ALLOCATION_ITEM_OFFSET ItemOffset
)
{
DWORD Hash;
PTRACKBUCKETITEM BucketItem;
PALLOCATION_ITEM Item;
Item = (PALLOCATION_ITEM) (Base + ItemOffset);
Hash = pComputeTrackHashVal (Item->Type, Item->Ptr);
BucketItem = pAllocTrackBucketItem();
if (!BucketItem) {
DEBUGMSG ((DBG_WHOOPS, "pTrackHashTableInsert failed to alloc memory"));
return;
}
BucketItem->Prev = NULL;
BucketItem->Next = g_TrackBuckets[Hash];
BucketItem->Type = Item->Type;
BucketItem->Ptr = Item->Ptr;
BucketItem->ItemOffset = ItemOffset;
if (BucketItem->Next) {
BucketItem->Next->Prev = BucketItem;
}
g_TrackBuckets[Hash] = BucketItem;
}
VOID
pTrackHashTableDelete (
IN PTRACKBUCKETITEM BucketItem
)
{
DWORD Hash;
Hash = pComputeTrackHashVal (BucketItem->Type, BucketItem->Ptr);
if (BucketItem->Prev) {
BucketItem->Prev->Next = BucketItem->Next;
} else {
g_TrackBuckets[Hash] = BucketItem->Next;
}
if (BucketItem->Next) {
BucketItem->Next->Prev = BucketItem->Prev;
}
pFreeTrackBucketItem (BucketItem);
}
PTRACKBUCKETITEM
pTrackHashTableFind (
IN ALLOCTYPE Type,
IN PVOID Ptr
)
{
PTRACKBUCKETITEM BucketItem;
DWORD Hash;
Hash = pComputeTrackHashVal (Type, Ptr);
BucketItem = g_TrackBuckets[Hash];
while (BucketItem) {
if (BucketItem->Type == Type && BucketItem->Ptr == Ptr) {
return BucketItem;
}
BucketItem = BucketItem->Next;
}
return NULL;
}
VOID
DebugRegisterAllocationEx (
IN ALLOCTYPE Type,
IN PVOID Ptr,
IN PCSTR File,
IN UINT Line,
IN BOOL Alloc
)
{
PALLOCATION_ITEM Item;
MYASSERT (File);
if (!g_FirstDeletedAlloc) {
Item = (PALLOCATION_ITEM) pOurTrackedGbGrow (&g_AllocationList,sizeof(ALLOCATION_ITEM));
} else {
Item = (PALLOCATION_ITEM) g_FirstDeletedAlloc;
g_FirstDeletedAlloc = Item->Ptr;
}
if (Item) {
Item->Type = Type;
Item->Ptr = Ptr;
if (Alloc) {
Item->FileName = SafeHeapAlloc (g_hHeap, 0, SizeOfStringA (File));
if (Item->FileName) {
StringCopyA ((PSTR)Item->FileName, File);
}
Item->Allocated = TRUE;
} else {
Item->FileName = File;
Item->Allocated = FALSE;
}
Item->Line = Line;
pTrackHashTableInsert (
g_AllocationList.Buf,
(ALLOCATION_ITEM_OFFSET) ((PBYTE) Item - g_AllocationList.Buf)
);
//DEBUGMSG ((DBG_VERBOSE, "Allocation: File=%s, Line=%d, Size=%d", File, Line, Size));
}
}
VOID
DebugRegisterAllocation (
IN ALLOCTYPE Type,
IN PVOID Ptr,
IN PCSTR File,
IN UINT Line
)
{
PALLOCATION_ITEM Item;
MYASSERT (File);
if (!g_FirstDeletedAlloc) {
Item = (PALLOCATION_ITEM) pOurTrackedGbGrow (&g_AllocationList,sizeof(ALLOCATION_ITEM));
} else {
Item = (PALLOCATION_ITEM) g_FirstDeletedAlloc;
g_FirstDeletedAlloc = Item->Ptr;
}
if (Item) {
Item->Type = Type;
Item->Ptr = Ptr;
Item->FileName = File;
Item->Line = Line;
Item->Allocated = FALSE;
pTrackHashTableInsert (
g_AllocationList.Buf,
(ALLOCATION_ITEM_OFFSET) ((PBYTE) Item - g_AllocationList.Buf)
);
}
}
VOID
DebugUnregisterAllocation (
IN ALLOCTYPE Type,
IN PVOID Ptr
)
{
PALLOCATION_ITEM Item;
PTRACKBUCKETITEM BucketItem;
BucketItem = pTrackHashTableFind (Type, Ptr);
if (!g_AllocationList.Buf) {
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);
} else {
DEBUGMSG ((DBG_WARNING, "Unregister allocation: Pointer not registered"));
}
}
#endif