|
|
/*
* @doc INTERNAL * * @module utilmem.cpp - Debug memory tracking/allocation routines * * History: <nl> * 8/17/99 KeithCu Move to a separate module to prevent errors. * * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved. */
#define W32SYS_CPP
#include "_common.h"
#undef PvAlloc
#undef PvReAlloc
#undef FreePv
#undef new
#if defined(DEBUG)
#undef PvSet
#undef ZeroMemory
#undef strcmp
MST vrgmst[100];
typedef struct tagPVH //PV Header
{ char *szFile; int line; tagPVH *ppvhNext; int cbAlloc; //On Win'95, the size returned is not the size allocated.
int magicPvh; //Should be last
} PVH; #define cbPvh (sizeof(PVH))
typedef struct //PV Tail { int magicPvt; //Must be first
} PVT;
#define cbPvt (sizeof(PVT))
#define cbPvDebug (cbPvh + cbPvt)
void *vpHead = 0;
/*
* UpdateMst(void) * * @func Fills up the vrgmst structure with summary information about our memory * usage. * * @rdesc * void */ void UpdateMst(void) { W32->ZeroMemory(vrgmst, sizeof(vrgmst));
PVH *ppvh; MST *pmst;
ppvh = (PVH*) vpHead;
while (ppvh != 0) { pmst = vrgmst;
//Look for entry in list...
while (pmst->szFile) { if (W32->strcmp(pmst->szFile, ppvh->szFile) == 0) { pmst->cbAlloc += ppvh->cbAlloc; break; } pmst++; }
if (pmst->szFile == 0) { pmst->szFile = ppvh->szFile; pmst->cbAlloc = ppvh->cbAlloc; }
ppvh = ppvh->ppvhNext; } }
/*
* PvDebugValidate(void) * * @func Verifies the the node is proper. Pass in a pointer to the users data * (after the header node.) * * @rdesc * void */ void PvDebugValidate(void *pv) { PVH *ppvh; UNALIGNED PVT *ppvt;
ppvh = (PVH*) ((char*) pv - cbPvh); ppvt = (PVT*) ((char*) pv + ppvh->cbAlloc);
AssertSz(ppvh->magicPvh == 0x12345678, "PvDebugValidate: header bytes are corrupt"); AssertSz(ppvt->magicPvt == 0xfedcba98, "PvDebugValidate: tail bytes are corrupt"); }
/*
* CW32System::PvSet(pv, szFile, line) * * @mfunc Sets a different module and line number for * * @rdesc * void */ void CW32System::PvSet(void *pv, char *szFile, int line) { if (pv == 0) return;
PvDebugValidate(pv); PVH *ppvh = (PVH*) ((char*) pv - cbPvh);
ppvh->szFile = szFile; ppvh->line = line; } /*
* CW32System::PvAllocDebug(cb, uiMemFlags, szFile, line) * * @mfunc Allocates a generic (void*) pointer. This is a debug only routine which * tracks the allocation. * * @rdesc * void */ void* CW32System::PvAllocDebug(ULONG cb, UINT uiMemFlags, char *szFile, int line) { void *pv;
pv = PvAlloc(cb + cbPvDebug, uiMemFlags); if (!pv) return 0;
PVH *ppvh; UNALIGNED PVT *ppvt;
ppvt = (PVT*) ((char*) pv + cb + cbPvh); ppvh = (PVH*) pv;
ZeroMemory(ppvh, sizeof(PVH)); ppvh->magicPvh = 0x12345678; ppvt->magicPvt = 0xfedcba98; ppvh->szFile = szFile; ppvh->line = line; ppvh->cbAlloc = cb;
ppvh->ppvhNext = (PVH*) vpHead; vpHead = pv;
return (char*) pv + cbPvh; }
/*
* CW32System::PvReAllocDebug(pv, cb, szFile, line) * * @mfunc ReAllocates a generic (void*) pointer. This is a debug only routine which * tracks the allocation. * * @rdesc * void */ void* CW32System::PvReAllocDebug(void *pv, ULONG cb, char *szFile, int line) { void *pvNew; PVH *ppvh, *ppvhHead, *ppvhTail; UNALIGNED PVT *ppvt; ppvh = (PVH*) ((char*) pv - cbPvh);
if (!pv) return PvAllocDebug(cb, 0, szFile, line);
PvDebugValidate(pv);
pvNew = PvReAlloc((char*) pv - cbPvh, cb + cbPvDebug);
if (!pvNew) return 0;
ppvt = (PVT*) ((char*) pvNew + cb + cbPvh); ppvh = (PVH*) pvNew; ppvh->cbAlloc = cb;
//Put the new trailer bytes in.
ppvt->magicPvt = 0xfedcba98;
//Make the pointer list up to date again
if (pv != pvNew) { ppvhTail = 0; ppvhHead = (PVH*) vpHead;
while ((char*)ppvhHead != (char*)pv - cbPvh) { AssertSz(ppvhHead, "entry not found in list."); ppvhTail = ppvhHead; ppvhHead = (PVH*) ppvhHead->ppvhNext; }
if (ppvhTail == 0) vpHead = pvNew; else ppvhTail->ppvhNext = (PVH*) pvNew; }
return (char*) pvNew + cbPvh; }
/*
* CW32System::FreePvDebug(pv) * * @mfunc Returns a pointer when you are done with it. * * @rdesc * void */ void CW32System::FreePvDebug(void *pv) { if (!pv) return;
PvDebugValidate(pv);
PVH *ppvhHead, *ppvhTail, *ppvh;
AssertSz(vpHead, "Deleting from empty free list.");
ppvh = (PVH*) ((char*) pv - cbPvh); //Search and remove the entry from the list
ppvhTail = 0; ppvhHead = (PVH*) vpHead;
while ((char*) ppvhHead != ((char*) pv - cbPvh)) { AssertSz(ppvhHead, "entry not found in list."); ppvhTail = ppvhHead; ppvhHead = (PVH*) ppvhHead->ppvhNext; }
if (ppvhTail == 0) vpHead = ppvhHead->ppvhNext; else ppvhTail->ppvhNext = ppvhHead->ppvhNext;
FreePv((char*) pv - cbPvh); }
/*
* CatchLeaks(void) * * @func Displays any memory leaks in a dialog box. * * @rdesc * void */ void CatchLeaks(void) { PVH *ppvh; char szLeak[512];
ppvh = (PVH*) vpHead; while (ppvh != 0) { #ifndef NOFULLDEBUG
wsprintfA(szLeak, "Memory Leak of %d bytes: -- File: %s, Line: %d", ppvh->cbAlloc, ppvh->szFile, ppvh->line); #endif
if (NULL != pfnAssert) { // if we have an assert hook, give the user a chance to process the leak message
if (pfnAssert(szLeak, ppvh->szFile, &ppvh->line)) { #ifdef NOFULLDEBUG
DebugBreak(); #else
// hook returned true, show the message box
MessageBoxA(NULL, szLeak, "", MB_OK); #endif
} } else { #ifdef NOFULLDEBUG
DebugBreak(); #else
MessageBoxA(NULL, szLeak, "", MB_OK); #endif
} ppvh = ppvh->ppvhNext; } }
void* _cdecl operator new (size_t size, char *szFile, int line) { TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "new");
return W32->PvAllocDebug(size, GMEM_ZEROINIT, szFile, line); }
void _cdecl operator delete (void* pv) { TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "delete");
W32->FreePvDebug(pv); }
#else //DEBUG
void* _cdecl operator new (size_t size) { TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "new");
return W32->PvAlloc(size, GMEM_ZEROINIT); }
void _cdecl operator delete (void* pv) { TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "delete");
W32->FreePv(pv); }
#endif //DEBUG
HANDLE g_hHeap;
/*
* PvAlloc (cbBuf, uiMemFlags) * * @mfunc memory allocation. Similar to GlobalAlloc. * * @comm The only flag of interest is GMEM_ZEROINIT, which * specifies that memory should be zeroed after allocation. */ PVOID CW32System::PvAlloc( ULONG cbBuf, //@parm Count of bytes to allocate
UINT uiMemFlags) //@parm Flags controlling allocation
{ TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "PvAlloc"); if (g_hHeap == 0) { CLock lock; g_hHeap = HeapCreate(0, 0, 0); }
void *pv = HeapAlloc(g_hHeap, (uiMemFlags & GMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0, cbBuf); return pv; }
/*
* PvReAlloc (pv, cbBuf) * * @mfunc memory reallocation. * */ PVOID CW32System::PvReAlloc( PVOID pv, //@parm Buffer to reallocate
DWORD cbBuf) //@parm New size of buffer
{ TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "PvReAlloc");
if(pv) return HeapReAlloc(g_hHeap, 0, pv, cbBuf);
return PvAlloc(cbBuf, 0); }
/*
* FreePv (pv) * * @mfunc frees memory * * @rdesc void */ void CW32System::FreePv( PVOID pv) //@parm Buffer to free
{ TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "FreePv");
if(pv) HeapFree(g_hHeap, 0, pv); }
|