900 lines
23 KiB
C++
900 lines
23 KiB
C++
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// File: mem.cpp
|
||
|
//
|
||
|
// Module: CMUTIL.DLL
|
||
|
//
|
||
|
// Synopsis: Basic memory manipulation routines
|
||
|
//
|
||
|
// Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
//
|
||
|
// Author: henryt Created 03/01/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
|
||
|
#include "cmmaster.h"
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
// definitions
|
||
|
//+----------------------------------------------------------------------------
|
||
|
HANDLE g_hProcessHeap = NULL;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
LONG g_lMallocCnt = 0; // a counter to detect memory leak
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if defined(DEBUG) && defined(DEBUG_MEM)
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// If DEBUG_MEM is defined, track all the memory alloction in debug version.
|
||
|
// Keep all the allocated memory blocks in the double link list.
|
||
|
// Record the file name and line #, where memory is allocated.
|
||
|
// Add extra tag at the beginning and end of the memory to watch for overwriten
|
||
|
// The whole list is checked against corruption for every alloc/free operation
|
||
|
//
|
||
|
// The folowing three function is exported:
|
||
|
// BOOL CheckDebugMem(void); // return TRUE for succeed
|
||
|
// void* AllocDebugMem(long size,const char* lpFileName,int nLine);
|
||
|
// BOOL FreeDebugMem(void* pMem); // return TRUE for succeed
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//#undef new
|
||
|
|
||
|
#define MEMTAG 0xBEEDB77D // the tag before/after the block to watch for overwriten
|
||
|
#define FREETAG 0xBD // the flag to fill freed memory
|
||
|
#define TAGSIZE (sizeof(long))// Size of the tags appended to the end of the block
|
||
|
|
||
|
|
||
|
//
|
||
|
// memory block, a double link list
|
||
|
//
|
||
|
struct TMemoryBlock
|
||
|
{
|
||
|
TMemoryBlock* pPrev;
|
||
|
TMemoryBlock* pNext;
|
||
|
long size;
|
||
|
const char* lpFileName; // The filename
|
||
|
int nLine; // The line number
|
||
|
long topTag; // The watch tag at the beginning
|
||
|
// followed by:
|
||
|
// BYTE data[nDataSize];
|
||
|
// long bottomTag;
|
||
|
BYTE* pbData() const // Return the pointer to the actual data
|
||
|
{ return (BYTE*) (this + 1); }
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// The following internal function can be overwritten to change the behaivor
|
||
|
//
|
||
|
|
||
|
static void* MemAlloc(long size);
|
||
|
static BOOL MemFree(void* pMem);
|
||
|
static void LockDebugMem();
|
||
|
static void UnlockDebugMem();
|
||
|
|
||
|
//
|
||
|
// Internal function
|
||
|
//
|
||
|
static BOOL RealCheckMemory(); // without call Enter/Leave critical Section
|
||
|
static BOOL CheckBlock(const TMemoryBlock* pBlock) ;
|
||
|
|
||
|
//
|
||
|
// Internal data, protected by the lock to be multi-thread safe
|
||
|
//
|
||
|
static long nTotalMem; // Total bytes of memory allocated
|
||
|
static long nTotalBlock; // Total # of blocks allocated
|
||
|
static TMemoryBlock head; // The head of the double link list
|
||
|
|
||
|
|
||
|
//
|
||
|
// critical section to lock \ unlock DebugMemory
|
||
|
// The constructor lock the memory, the destructor unlock the memory
|
||
|
//
|
||
|
class MemCriticalSection
|
||
|
{
|
||
|
public:
|
||
|
MemCriticalSection()
|
||
|
{
|
||
|
LockDebugMem();
|
||
|
}
|
||
|
|
||
|
~MemCriticalSection()
|
||
|
{
|
||
|
UnlockDebugMem();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
static BOOL fDebugMemInited = FALSE; // whether the debug memory is initialized
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: StartDebugMemory
|
||
|
//
|
||
|
// Synopsis: Initialize the data for debug memory
|
||
|
//
|
||
|
// Arguments: None
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// History: fengsun Created Header 4/2/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
static void StartDebugMemory()
|
||
|
{
|
||
|
fDebugMemInited = TRUE;
|
||
|
|
||
|
head.pNext = head.pPrev = NULL;
|
||
|
head.topTag = MEMTAG;
|
||
|
head.size = 0;
|
||
|
nTotalMem = 0;
|
||
|
nTotalBlock = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: MemAlloc
|
||
|
//
|
||
|
// Synopsis: Allocate a block of memory. This function should be overwriten
|
||
|
// if different allocation method is used
|
||
|
//
|
||
|
// Arguments: long size - size of the memory
|
||
|
//
|
||
|
// Returns: void* - the memory allocated or NULL
|
||
|
//
|
||
|
// History: fengsun Created Header 4/2/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
static void* MemAlloc(long size)
|
||
|
{
|
||
|
return (HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: MemFree
|
||
|
//
|
||
|
// Synopsis: Free a block of memory. This function should be overwriten
|
||
|
// if different allocation method is used
|
||
|
//
|
||
|
// Arguments: void* pMem - The memory to be freed
|
||
|
//
|
||
|
// Returns: static BOOL - TRUE if succeeded
|
||
|
//
|
||
|
// History: Created Header 4/2/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
static BOOL MemFree(void* pMem)
|
||
|
{
|
||
|
return HeapFree(GetProcessHeap(), 0, pMem);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Data / functions to provide mutual exclusion.
|
||
|
// Can be overwritten, if other methed is to be used.
|
||
|
//
|
||
|
static BOOL fLockInited = FALSE; // whether the critical section is inialized
|
||
|
static CRITICAL_SECTION cSection; // The critical section to protect the link list
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: InitLock
|
||
|
//
|
||
|
// Synopsis: Initialize the memory lock which protects the doublely linked list
|
||
|
// that contains all of the allocated memory blocks.
|
||
|
//
|
||
|
// Arguments: None
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
// History: quintinb Created Header 01/14/2000
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
static void InitLock()
|
||
|
{
|
||
|
fLockInited = TRUE;
|
||
|
InitializeCriticalSection(&cSection);
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: LockDebugMem
|
||
|
//
|
||
|
// Synopsis: Locks the doublely linked list that contains all of the
|
||
|
// allocated memory blocks so that it can only be accessed by the
|
||
|
// locking thread.
|
||
|
//
|
||
|
// Arguments: None
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
// History: quintinb Created Header 01/14/2000
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
static void LockDebugMem()
|
||
|
{
|
||
|
static int i = 0;
|
||
|
if(!fLockInited)
|
||
|
{
|
||
|
InitLock();
|
||
|
}
|
||
|
|
||
|
EnterCriticalSection(&cSection);
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: UnlockDebugMem
|
||
|
//
|
||
|
// Synopsis: Unlocks the doublely linked list that contains all of the
|
||
|
// allocated memory blocks.
|
||
|
//
|
||
|
// Arguments: None
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
// History: quintinb Created Header 01/14/2000
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
static void UnlockDebugMem()
|
||
|
{
|
||
|
LeaveCriticalSection(&cSection);
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: AllocDebugMem
|
||
|
//
|
||
|
// Synopsis: Process memory allocation request.
|
||
|
// Check the link list. Allocate a larger block.
|
||
|
// Record filename/linenumber, add tags and insert to the list
|
||
|
//
|
||
|
// Arguments: long size - Size of the memory to be allocated
|
||
|
// const char* lpFileName - File name to be recorded
|
||
|
// int nLine - Line number to be recorted
|
||
|
//
|
||
|
// Returns: CMUTILAPI void* - The memory allocated. Ready to use by the caller
|
||
|
//
|
||
|
// History: fengsun Created Header 4/2/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
CMUTILAPI void* AllocDebugMem(long size,const char* lpFileName,int nLine)
|
||
|
{
|
||
|
if (!fDebugMemInited)
|
||
|
{
|
||
|
StartDebugMemory();
|
||
|
}
|
||
|
|
||
|
if (size<0)
|
||
|
{
|
||
|
CMASSERTMSG(FALSE,"Negtive size for alloc");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (size>1024*1024)
|
||
|
{
|
||
|
CMASSERTMSG(FALSE," size for alloc is great than 1Mb");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (size == 0)
|
||
|
{
|
||
|
CMTRACE("Allocate memory of size 0");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Protect the access to the list
|
||
|
//
|
||
|
MemCriticalSection criticalSection;
|
||
|
|
||
|
//
|
||
|
// Check the link list first
|
||
|
//
|
||
|
if (!RealCheckMemory())
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate a large block to hold additional information
|
||
|
//
|
||
|
TMemoryBlock* pBlock = (TMemoryBlock*)MemAlloc(sizeof(TMemoryBlock)+size + TAGSIZE);
|
||
|
if (!pBlock)
|
||
|
{
|
||
|
CMTRACE("Outof Memory");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// record filename/line/size, add tag to the beginning and end
|
||
|
//
|
||
|
pBlock->size = size;
|
||
|
pBlock->topTag = MEMTAG;
|
||
|
pBlock->lpFileName = lpFileName;
|
||
|
pBlock->nLine = nLine;
|
||
|
*(long*)(pBlock->pbData() + size) = MEMTAG;
|
||
|
|
||
|
//
|
||
|
// insert at head
|
||
|
//
|
||
|
pBlock->pNext = head.pNext;
|
||
|
pBlock->pPrev = &head;
|
||
|
if(head.pNext)
|
||
|
head.pNext->pPrev = pBlock;
|
||
|
head.pNext = pBlock;
|
||
|
|
||
|
nTotalMem += size;
|
||
|
nTotalBlock ++;
|
||
|
|
||
|
return pBlock->pbData();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: FreeDebugMem
|
||
|
//
|
||
|
// Synopsis: Free the memory allocated by AllocDebugMem
|
||
|
// Check the link list, and the block to be freed.
|
||
|
// Fill the block data with FREETAG before freed
|
||
|
//
|
||
|
// Arguments: void* pMem - Memory to be freed
|
||
|
//
|
||
|
// Returns: BOOL - TRUE for succeeded
|
||
|
//
|
||
|
// History: fengsun Created Header 4/2/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
CMUTILAPI BOOL FreeDebugMem(void* pMem)
|
||
|
{
|
||
|
if (!fDebugMemInited)
|
||
|
{
|
||
|
StartDebugMemory();
|
||
|
}
|
||
|
|
||
|
if (!pMem)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the lock
|
||
|
//
|
||
|
MemCriticalSection criticalSection;
|
||
|
|
||
|
//
|
||
|
// Get pointer to our structure
|
||
|
//
|
||
|
TMemoryBlock* pBlock =(TMemoryBlock*)( (char*)pMem - sizeof(TMemoryBlock));
|
||
|
|
||
|
//
|
||
|
// Check the block to be freed
|
||
|
//
|
||
|
if (!CheckBlock(pBlock))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check the link list
|
||
|
//
|
||
|
if (!RealCheckMemory())
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// remove the block from the list
|
||
|
//
|
||
|
pBlock->pPrev->pNext = pBlock->pNext;
|
||
|
if (pBlock->pNext)
|
||
|
{
|
||
|
pBlock->pNext->pPrev = pBlock->pPrev;
|
||
|
}
|
||
|
|
||
|
nTotalMem -= pBlock->size;
|
||
|
nTotalBlock --;
|
||
|
|
||
|
//
|
||
|
// Fill the freed memory with 0xBD, leave the size/filename/lineNumber unchanged
|
||
|
//
|
||
|
memset(&pBlock->topTag, FREETAG, (size_t)pBlock->size + sizeof(pBlock->topTag) + TAGSIZE);
|
||
|
return MemFree(pBlock);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: void* ReAllocDebugMem
|
||
|
//
|
||
|
// Synopsis: Reallocate a memory with a diffirent size
|
||
|
//
|
||
|
// Arguments: void* pMem - memory to be reallocated
|
||
|
// long nSize - size of the request
|
||
|
// const char* lpFileName - FileName to be recorded
|
||
|
// int nLine - Line umber to be recorded
|
||
|
//
|
||
|
// Returns: void* - new memory returned
|
||
|
//
|
||
|
// History: fengsun Created Header 4/2/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
CMUTILAPI void* ReAllocDebugMem(void* pMem, long nSize, const char* lpFileName,int nLine)
|
||
|
{
|
||
|
if (!fDebugMemInited)
|
||
|
{
|
||
|
StartDebugMemory();
|
||
|
}
|
||
|
|
||
|
if (!pMem)
|
||
|
{
|
||
|
CMTRACE("Free a NULL pointer");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate a new block, copy the information over and free the old block.
|
||
|
//
|
||
|
TMemoryBlock* pBlock =(TMemoryBlock*)( (char*)pMem - sizeof(TMemoryBlock));
|
||
|
|
||
|
long lOrginalSize = pBlock->size;
|
||
|
|
||
|
void* pNew = AllocDebugMem(nSize, lpFileName, nLine);
|
||
|
if(pNew)
|
||
|
{
|
||
|
CopyMemory(pNew, pMem, (nSize < lOrginalSize ? nSize : lOrginalSize));
|
||
|
FreeDebugMem(pMem);
|
||
|
}
|
||
|
|
||
|
return pNew;
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CheckDebugMem
|
||
|
//
|
||
|
// Synopsis: Exported to external module.
|
||
|
// Call this function, whenever, you want to check against
|
||
|
// memory curruption
|
||
|
//
|
||
|
// Arguments: None
|
||
|
//
|
||
|
// Returns: BOOL - TRUE if the memory is fine.
|
||
|
//
|
||
|
// History: fengsun Created Header 4/2/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
CMUTILAPI BOOL CheckDebugMem()
|
||
|
{
|
||
|
if (!fDebugMemInited)
|
||
|
{
|
||
|
StartDebugMemory();
|
||
|
}
|
||
|
|
||
|
MemCriticalSection criticalSection;
|
||
|
|
||
|
return RealCheckMemory();
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: RealCheckMemory
|
||
|
//
|
||
|
// Synopsis: Go through the link list to check for memory corruption
|
||
|
//
|
||
|
// Arguments: None
|
||
|
//
|
||
|
// Returns: BOOL - TRUE if the memory is fine.
|
||
|
//
|
||
|
// History: fengsun Created Header 4/2/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
static BOOL RealCheckMemory()
|
||
|
{
|
||
|
TMemoryBlock* pBlock = head.pNext;
|
||
|
|
||
|
int nBlock =0;
|
||
|
while(pBlock!=NULL)
|
||
|
{
|
||
|
if(!CheckBlock(pBlock))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pBlock = pBlock->pNext;
|
||
|
nBlock++;
|
||
|
}
|
||
|
|
||
|
if(nBlock != nTotalBlock)
|
||
|
{
|
||
|
CMASSERTMSG(FALSE,"Memery corrupted");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CheckBlock
|
||
|
//
|
||
|
// Synopsis: Check a block for memory corruption
|
||
|
//
|
||
|
// Arguments: const TMemoryBlock* pBlock -
|
||
|
//
|
||
|
// Returns: BOOL - TRUE, if the block is fine
|
||
|
//
|
||
|
// History: fengsun Created Header 4/2/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
static BOOL CheckBlock(const TMemoryBlock* pBlock)
|
||
|
{
|
||
|
if (pBlock->topTag != MEMTAG) // overwriten at top
|
||
|
{
|
||
|
CMASSERTMSG(FALSE, "Memery corrupted");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (pBlock->size<0)
|
||
|
{
|
||
|
CMASSERTMSG(FALSE, "Memery corrupted");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (*(long*)(pBlock->pbData() +pBlock->size) != MEMTAG) // overwriten at bottom
|
||
|
{
|
||
|
CMASSERTMSG(FALSE, "Memery corrupted");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (pBlock->pPrev && pBlock->pPrev->pNext != pBlock)
|
||
|
{
|
||
|
CMASSERTMSG(FALSE, "Memery corrupted");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (pBlock->pNext && pBlock->pNext->pPrev != pBlock)
|
||
|
{
|
||
|
CMASSERTMSG(FALSE, "Memery corrupted");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// operator new, delete
|
||
|
/* We did not redefine new and delete
|
||
|
|
||
|
void* __cdecl operator new(size_t nSize)
|
||
|
{
|
||
|
void* p = AllocDebugMem(nSize,NULL,0);
|
||
|
|
||
|
if (p == NULL)
|
||
|
{
|
||
|
CMTRACE("New failed");
|
||
|
}
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void* __cdecl operator new(size_t nSize, const char* lpszFileName, int nLine)
|
||
|
{
|
||
|
void* p = AllocDebugMem(nSize, lpszFileName,nLine);
|
||
|
|
||
|
if (p == NULL)
|
||
|
{
|
||
|
CMTRACE("New failed");
|
||
|
}
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void __cdecl operator delete(void* p)
|
||
|
{
|
||
|
if(p)
|
||
|
FreeDebugMem(p);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: EndDebugMemory
|
||
|
//
|
||
|
// Synopsis: Called before the program exits. Report any unreleased memory leak
|
||
|
//
|
||
|
// Arguments: None
|
||
|
//
|
||
|
// Returns: Nothing
|
||
|
//
|
||
|
// History: fengsun Created Header 4/2/98
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
void EndDebugMemory()
|
||
|
{
|
||
|
if(head.pNext != NULL || nTotalMem!=0 || nTotalBlock !=0)
|
||
|
{
|
||
|
CMTRACE("Detected memory leaks");
|
||
|
TMemoryBlock * pBlock;
|
||
|
|
||
|
for(pBlock = head.pNext; pBlock != NULL; pBlock = pBlock->pNext)
|
||
|
{
|
||
|
TCHAR buf[1024];
|
||
|
wsprintf(buf, TEXT("Memory Leak of %d bytes:\n%S"), pBlock->size, pBlock->pbData());
|
||
|
MyDbgAssertA(pBlock->lpFileName, pBlock->nLine, buf); // do not print the file name
|
||
|
}
|
||
|
DeleteCriticalSection(&cSection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else // defined(DEBUG) && defined(DEBUG_MEM)
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// If DEBUG_MEM if NOT defined, only track a count of memory for debug version
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
|
||
|
void TraceHeapBlock(PROCESS_HEAP_ENTRY* pheEntry)
|
||
|
{
|
||
|
CMTRACE(TEXT("TraceHeapBlock -- Begin Entry Trace"));
|
||
|
|
||
|
CMTRACE1(TEXT("\tEntry->lpData = 0x%x"), pheEntry->lpData);
|
||
|
CMTRACE1(TEXT("\tEntry->cbData = %u"), pheEntry->cbData);
|
||
|
CMTRACE1(TEXT("\tEntry->cbOverhead = %u"), pheEntry->cbOverhead);
|
||
|
CMTRACE1(TEXT("\tEntry->iRegionIndex = %u"), pheEntry->iRegionIndex);
|
||
|
|
||
|
if (pheEntry->wFlags & PROCESS_HEAP_REGION)
|
||
|
{
|
||
|
CMTRACE1(TEXT("\tEntry->dwCommittedSize = %u"), pheEntry->Region.dwCommittedSize);
|
||
|
CMTRACE1(TEXT("\tEntry->dwUnCommittedSize = %u"), pheEntry->Region.dwUnCommittedSize);
|
||
|
CMTRACE1(TEXT("\tEntry->lpFirstBlock = 0x%x"), pheEntry->Region.lpFirstBlock);
|
||
|
CMTRACE1(TEXT("\tEntry->lpLastBlock = 0x%x"), pheEntry->Region.lpLastBlock);
|
||
|
CMTRACE(TEXT("\tPROCESS_HEAP_REGION flag set."));
|
||
|
}
|
||
|
|
||
|
if (pheEntry->wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE)
|
||
|
{
|
||
|
CMTRACE(TEXT("\tPROCESS_HEAP_UNCOMMITTED_RANGE flag set."));
|
||
|
}
|
||
|
|
||
|
if ((pheEntry->wFlags & PROCESS_HEAP_ENTRY_BUSY) && (pheEntry->wFlags & PROCESS_HEAP_ENTRY_MOVEABLE))
|
||
|
{
|
||
|
CMTRACE1(TEXT("\tEntry->hMem = 0x%x"), pheEntry->Block.hMem);
|
||
|
CMTRACE1(TEXT("\tEntry->dwReserved = %u"), pheEntry->Block.dwReserved);
|
||
|
|
||
|
CMTRACE(TEXT("\tPROCESS_HEAP_ENTRY_BUSY and PROCESS_HEAP_ENTRY_MOVEABLE flags are set."));
|
||
|
}
|
||
|
|
||
|
if ((pheEntry->wFlags & PROCESS_HEAP_ENTRY_BUSY) && (pheEntry->wFlags & PROCESS_HEAP_ENTRY_DDESHARE))
|
||
|
{
|
||
|
CMTRACE(TEXT("\tPROCESS_HEAP_ENTRY_BUSY and PROCESS_HEAP_ENTRY_DDESHARE flags are set."));
|
||
|
}
|
||
|
|
||
|
CMTRACE(TEXT("TraceHeapBlock -- End Entry Trace"));
|
||
|
CMTRACE(TEXT(""));
|
||
|
}
|
||
|
|
||
|
BOOL CheckProcessHeap()
|
||
|
{
|
||
|
BOOL bRet;
|
||
|
DWORD dwError;
|
||
|
PROCESS_HEAP_ENTRY pheEntry;
|
||
|
|
||
|
ZeroMemory(&pheEntry, sizeof(pheEntry));
|
||
|
|
||
|
do
|
||
|
{
|
||
|
bRet = HeapWalk(g_hProcessHeap, &pheEntry);
|
||
|
if (!bRet)
|
||
|
{
|
||
|
dwError = GetLastError();
|
||
|
if (ERROR_NO_MORE_ITEMS != dwError)
|
||
|
{
|
||
|
CMTRACE1(TEXT("HeapWalk returned FALSE, GLE returns %u"), dwError);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceHeapBlock(&pheEntry);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceHeapBlock(&pheEntry);
|
||
|
}
|
||
|
|
||
|
} while(!bRet);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif // DEBUG
|
||
|
|
||
|
CMUTILAPI void *CmRealloc(void *pvPtr, size_t nBytes)
|
||
|
{
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
|
||
|
{
|
||
|
CMTRACE(TEXT("CmRealloc -- HeapValidate Returns FALSE. Checking Process Heap."));
|
||
|
|
||
|
CheckProcessHeap();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void* p = HeapReAlloc(g_hProcessHeap, HEAP_ZERO_MEMORY, pvPtr, nBytes);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
|
||
|
{
|
||
|
CMTRACE(TEXT("CmRealloc -- HeapValidate Returns FALSE. Checking Process Heap."));
|
||
|
|
||
|
CheckProcessHeap();
|
||
|
}
|
||
|
|
||
|
CMASSERTMSG(p, TEXT("CmRealloc failed"));
|
||
|
#endif
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
|
||
|
CMUTILAPI void *CmMalloc(size_t nBytes)
|
||
|
{
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
|
||
|
InterlockedIncrement(&g_lMallocCnt);
|
||
|
|
||
|
MYDBGASSERT(nBytes < 1024*1024); // It should be less than 1 MB
|
||
|
MYDBGASSERT(nBytes > 0); // It should be *something*
|
||
|
|
||
|
if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
|
||
|
{
|
||
|
CMTRACE(TEXT("CmMalloc -- HeapValidate Returns FALSE. Checking Process Heap."));
|
||
|
|
||
|
CheckProcessHeap();
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
void* p = HeapAlloc(g_hProcessHeap, HEAP_ZERO_MEMORY, nBytes);
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
|
||
|
if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
|
||
|
{
|
||
|
CMTRACE(TEXT("CmMalloc -- HeapValidate Returns FALSE. Checking Process Heap."));
|
||
|
|
||
|
CheckProcessHeap();
|
||
|
}
|
||
|
|
||
|
CMASSERTMSG(p, TEXT("CmMalloc failed"));
|
||
|
|
||
|
#endif
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
|
||
|
CMUTILAPI void CmFree(void *pvPtr)
|
||
|
{
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
|
||
|
{
|
||
|
CMTRACE(TEXT("CmMalloc -- HeapValidate Returns FALSE. Checking Process Heap."));
|
||
|
|
||
|
CheckProcessHeap();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (pvPtr)
|
||
|
{
|
||
|
MYVERIFY(HeapFree(g_hProcessHeap, 0, pvPtr));
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
|
||
|
if (OS_NT && !HeapValidate(g_hProcessHeap, 0, NULL))
|
||
|
{
|
||
|
CMTRACE(TEXT("CmMalloc -- HeapValidate Returns FALSE. Checking Process Heap."));
|
||
|
|
||
|
CheckProcessHeap();
|
||
|
}
|
||
|
|
||
|
InterlockedDecrement(&g_lMallocCnt);
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
void EndDebugMemory()
|
||
|
{
|
||
|
if (g_lMallocCnt)
|
||
|
{
|
||
|
char buf[256];
|
||
|
wsprintfA(buf, TEXT("Detect Memory Leak of %d blocks"), g_lMallocCnt);
|
||
|
CMASSERTMSGA(FALSE, buf);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// the memory functions are for i386 only.
|
||
|
//
|
||
|
#ifdef _M_IX86
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// memmove - Copy source buffer to destination buffer. The code is copied from
|
||
|
// libc.
|
||
|
//
|
||
|
// Purpose:
|
||
|
// memmove() copies a source memory buffer to a destination memory buffer.
|
||
|
// This routine recognize overlapping buffers to avoid propogation.
|
||
|
// For cases where propogation is not a problem, memcpy() can be used.
|
||
|
//
|
||
|
// Entry:
|
||
|
// void *dst = pointer to destination buffer
|
||
|
// const void *src = pointer to source buffer
|
||
|
// size_t count = number of bytes to copy
|
||
|
//
|
||
|
// Exit:
|
||
|
// Returns a pointer to the destination buffer
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
CMUTILAPI PVOID WINAPI CmMoveMemory(
|
||
|
PVOID dst,
|
||
|
CONST PVOID src,
|
||
|
size_t count
|
||
|
)
|
||
|
{
|
||
|
void * ret = dst;
|
||
|
PVOID src1 = src;
|
||
|
|
||
|
if (dst <= src1 || (char *)dst >= ((char *)src1 + count)) {
|
||
|
/*
|
||
|
* Non-Overlapping Buffers
|
||
|
* copy from lower addresses to higher addresses
|
||
|
*/
|
||
|
while (count--) {
|
||
|
*(char *)dst = *(char *)src1;
|
||
|
dst = (char *)dst + 1;
|
||
|
src1 = (char *)src1 + 1;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
/*
|
||
|
* Overlapping Buffers
|
||
|
* copy from higher addresses to lower addresses
|
||
|
*/
|
||
|
dst = (char *)dst + count - 1;
|
||
|
src1 = (char *)src1 + count - 1;
|
||
|
|
||
|
while (count--) {
|
||
|
*(char *)dst = *(char *)src1;
|
||
|
dst = (char *)dst - 1;
|
||
|
src1 = (char *)src1 - 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
#endif //_M_IX86
|
||
|
|