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.
 
 
 
 
 
 

1326 lines
26 KiB

/*
* memmgr.c - Memory manager module.
*/
/*
The memory manager implementation in this module uses either a private
shared heap (if PRIVATE_HEAP is #defined) or the non-shared process heap (if
PRIVATE_HEAP is not #defined). Thde debug implementation of this memory
manager keeps track of memory blocks allocated from the heap using a
doubly-linked list of heap element nodes. Each node describes one allocated
heap element.
Debug heap elements are allocated with extra space at the beginning and end
of the element. Prefix and suffix sentinels surround each allocated heap
element. New heap elements are filled with UNINITIALIZED_BYTE_VALUE. Freed
heap elements are filled with FREED_BYTE_VALUE. The new tails of grown heap
elements are filled with UNINITIALIZED_BYTE_VALUE.
*/
/* Headers
**********/
#include "project.h"
#pragma hdrstop
/* Constants
************/
#ifdef PRIVATE_HEAP
/* undocumented flag for HeapCreate() from kernel32.h */
#define HEAP_SHARED (0x04000000)
/*
* Set maximum shared heap size used for CreateHeap() to 0 since we don't know
* how big the heap may get, and we don't want to restrict its size
* artificially. BrianSm says this is ok.
*/
#define MAX_SHARED_HEAP_SIZE (0)
#endif /* PRIVATE_HEAP */
#ifdef DEBUG
/* heap element byte fill values */
#define UNINITIALIZED_BYTE_VALUE (0xcc)
#define FREED_BYTE_VALUE (0xdd)
#endif /* DEBUG */
/* Macros
*********/
/* atomic memory management function wrappers for translation */
#ifdef PRIVATE_HEAP
#define GetHeap() (Mhheap)
#define MEMALLOCATE(size) HeapAlloc(GetHeap(), 0, (size))
#define MEMREALLOCATE(pv, size) HeapReAlloc(GetHeap(), 0, (pv), (size))
#define MEMFREE(pv) HeapFree(GetHeap(), 0, (pv))
#define MEMSIZE(pv) (DWORD)HeapSize(GetHeap(), 0, (pv))
#else
#define MEMALLOCATE(size) LocalAlloc(LMEM_FIXED, (size))
#define MEMREALLOCATE(pv, size) LocalReAlloc((pv), (size), 0)
#define MEMFREE(pv) (! LocalFree(pv))
#define MEMSIZE(pv) (DWORD)LocalSize(pv)
#endif
/* Types
********/
#ifdef DEBUG
/* heap element descriptor structure */
typedef struct _heapelemdesc
{
TCHAR rgchSize[6]; /* enough for 99,999 lines */
TCHAR rgchFile[24];
ULONG ulLine;
}
HEAPELEMDESC;
DECLARE_STANDARD_TYPES(HEAPELEMDESC);
/* heap node */
typedef struct _heapnode
{
PCVOID pcv;
DWORD dwcbSize;
struct _heapnode *phnPrev;
struct _heapnode *phnNext;
HEAPELEMDESC hed;
}
HEAPNODE;
DECLARE_STANDARD_TYPES(HEAPNODE);
/* heap */
typedef struct _heap
{
HEAPNODE hnHead;
}
HEAP;
DECLARE_STANDARD_TYPES(HEAP);
/* heap summary filled in by AnalyzeHeap() */
typedef struct _heapsummary
{
ULONG ulcUsedElements;
DWORD dwcbUsedSize;
}
HEAPSUMMARY;
DECLARE_STANDARD_TYPES(HEAPSUMMARY);
/* debug flags */
typedef enum _memmgrdebugflags
{
MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY = 0x0001,
MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT = 0x0002,
ALL_MEMMGR_DFLAGS = (MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY |
MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT)
}
MEMMGRDEBUGFLAGS;
#endif /* DEBUG */
/* Global Variables
*******************/
#ifdef DEBUG
/* parameters used by debug AllocateMemory() macro */
PUBLIC_DATA LPCTSTR GpcszElemHdrSize = NULL;
PUBLIC_DATA LPCTSTR GpcszElemHdrFile = NULL;
PUBLIC_DATA ULONG GulElemHdrLine = 0;
#endif /* DEBUG */
/* Module Variables
*******************/
#ifdef PRIVATE_HEAP
/* handle to global shared heap */
PRIVATE_DATA HANDLE Mhheap = NULL;
#endif /* PRIVATE_HEAP */
#ifdef DEBUG
/* heap */
PRIVATE_DATA PHEAP Mpheap = NULL;
/* debug flags */
PRIVATE_DATA DWORD MdwMemoryManagerModuleFlags = 0;
/* heap element sentinels */
PRIVATE_DATA CONST struct
{
BYTE rgbyte[4];
}
MchsPrefix =
{
{ TEXT('H'), TEXT('E'), TEXT('A'), TEXT('D') }
};
PRIVATE_DATA CONST struct
{
BYTE rgbyte[4];
}
MchsSuffix =
{
{ TEXT('T'), TEXT('A'), TEXT('I'), TEXT('L') }
};
/* .ini file switch descriptions */
PRIVATE_DATA CBOOLINISWITCH cbisValidateHeapOnEntry =
{
IST_BOOL,
TEXT("ValidateHeapOnEntry"),
&MdwMemoryManagerModuleFlags,
MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY
};
PRIVATE_DATA CBOOLINISWITCH cbisValidateHeapOnExit =
{
IST_BOOL,
TEXT("ValidateHeapOnExit"),
&MdwMemoryManagerModuleFlags,
MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT
};
PRIVATE_DATA const PCVOID MrgcpcvisMemoryManagerModule[] =
{
&cbisValidateHeapOnEntry,
&cbisValidateHeapOnExit
};
#endif /* DEBUG */
/***************************** Private Functions *****************************/
/* Module Prototypes
********************/
#ifdef DEBUG
PRIVATE_CODE DWORD CalculatePrivateSize(DWORD);
PRIVATE_CODE PVOID GetPrivateHeapPtr(PVOID);
PRIVATE_CODE PVOID GetPublicHeapPtr(PVOID);
PRIVATE_CODE DWORD GetHeapSize(PCVOID);
PRIVATE_CODE BOOL AddHeapElement(PCVOID, DWORD);
PRIVATE_CODE void RemoveHeapElement(PCVOID);
PRIVATE_CODE void ModifyHeapElement(PCVOID, PCVOID, DWORD);
PRIVATE_CODE BOOL FindHeapElement(PCVOID, PHEAPNODE *);
PRIVATE_CODE void FillNewMemory(PBYTE, DWORD, DWORD);
PRIVATE_CODE void FillFreedMemory(PBYTE, DWORD);
PRIVATE_CODE void FillGrownMemory(PBYTE, DWORD, DWORD, DWORD);
PRIVATE_CODE void FillShrunkenMemory(PBYTE, DWORD, DWORD, DWORD);
PRIVATE_CODE BOOL IsValidHeapPtr(PCVOID);
PRIVATE_CODE BOOL IsHeapOK(void);
PRIVATE_CODE BOOL IsValidPCHEAPNODE(PCHEAPNODE);
PRIVATE_CODE BOOL IsValidPCHEAPELEMDESC(PCHEAPELEMDESC);
PRIVATE_CODE BOOL IsValidHeapElement(PCBYTE, DWORD, DWORD);
PRIVATE_CODE void SpewHeapElementInfo(PCHEAPNODE);
PRIVATE_CODE void AnalyzeHeap(PHEAPSUMMARY, DWORD);
#endif /* DEBUG */
#ifdef PRIVATE_HEAP
/*
** InitPrivateHeapModule()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL InitPrivateHeapModule(void)
{
BOOL bResult;
SYSTEM_INFO si;
ASSERT(! Mhheap);
/* Create shared heap. */
GetSystemInfo(&si);
Mhheap = HeapCreate(0, si.dwPageSize, MAX_SHARED_HEAP_SIZE);
if (Mhheap)
{
#ifdef DEBUG
ASSERT(! Mpheap);
Mpheap = MEMALLOCATE(sizeof(*Mpheap));
if (Mpheap)
{
FillMemory(Mpheap, sizeof(*Mpheap), 0);
bResult = TRUE;
TRACE_OUT((TEXT("InitMemoryManagerModule(): Created shared heap, initial size == %lu, maximum size == %lu."),
si.dwPageSize,
MAX_SHARED_HEAP_SIZE));
}
else
{
EVAL(HeapDestroy(Mhheap));
Mhheap = NULL;
bResult = FALSE;
WARNING_OUT((TEXT("InitMemoryManagerModule(): Failed to create shared heap head.")));
}
#else /* DEBUG */
bResult = TRUE;
#endif /* DEBUG */
}
else
{
bResult = FALSE;
WARNING_OUT((TEXT("InitMemoryManagerModule(): Failed to create shared heap.")));
}
return(bResult);
}
#else /* PRIVATE_HEAP */
/*
** InitHeapModule()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL InitHeapModule(void)
{
BOOL bResult;
#ifdef DEBUG
ASSERT(! Mpheap);
Mpheap = MEMALLOCATE(sizeof(*Mpheap));
if (Mpheap)
{
FillMemory(Mpheap, sizeof(*Mpheap), 0);
TRACE_OUT((TEXT("InitMemoryManagerModule(): Created heap.")));
}
else
WARNING_OUT((TEXT("InitMemoryManagerModule(): Failed to create heap head.")));
bResult = (Mpheap != NULL);
#else
bResult = TRUE;
#endif
return(bResult);
}
#endif /* PRIVATE_HEAP */
#ifdef DEBUG
/*
** CalculatePrivateSize()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE DWORD CalculatePrivateSize(DWORD dwcbPublicSize)
{
ASSERT(dwcbPublicSize <= DWORD_MAX - sizeof(MchsPrefix) - sizeof(MchsSuffix));
return(dwcbPublicSize + sizeof(MchsPrefix) + sizeof(MchsSuffix));
}
/*
** GetPrivateHeapPtr()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE PVOID GetPrivateHeapPtr(PVOID pvPublic)
{
ASSERT((ULONG_PTR)pvPublic > sizeof(MchsPrefix));
return((PBYTE)pvPublic - sizeof(MchsPrefix));
}
/*
** GetPublicHeapPtr()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE PVOID GetPublicHeapPtr(PVOID pvPrivate)
{
ASSERT((PCBYTE)pvPrivate <= (PCBYTE)PTR_MAX - sizeof(MchsPrefix));
return((PBYTE)pvPrivate + sizeof(MchsPrefix));
}
/*
** GetHeapSize()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE DWORD GetHeapSize(PCVOID pcv)
{
PHEAPNODE phn;
DWORD dwcbSize;
if (EVAL(FindHeapElement(pcv, &phn)))
dwcbSize = phn->dwcbSize;
else
dwcbSize = 0;
return(dwcbSize);
}
/*
** AddHeapElement()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
**
** Assumes that the global variables GpcszElemHdrSize, GpcszElemHdrFile, and
** GulElemHdrLine are filled in.
*/
PRIVATE_CODE BOOL AddHeapElement(PCVOID pcvNew, DWORD dwcbSize)
{
PHEAPNODE phnNew;
/* Is the new heap element already in the list? */
ASSERT(! FindHeapElement(pcvNew, &phnNew));
if (Mpheap)
{
/* Create new heap node. */
phnNew = MEMALLOCATE(sizeof(*phnNew));
if (phnNew)
{
/* Fill in heap node fields. */
phnNew->pcv = pcvNew;
phnNew->dwcbSize = dwcbSize;
/* Insert heap node at front of list. */
phnNew->phnNext = Mpheap->hnHead.phnNext;
phnNew->phnPrev = &(Mpheap->hnHead);
Mpheap->hnHead.phnNext = phnNew;
if (phnNew->phnNext)
phnNew->phnNext->phnPrev = phnNew;
/* Fill in heap element descriptor fields. */
MyLStrCpyN(phnNew->hed.rgchSize, GpcszElemHdrSize, ARRAYSIZE(phnNew->hed.rgchSize));
MyLStrCpyN(phnNew->hed.rgchFile, GpcszElemHdrFile, ARRAYSIZE(phnNew->hed.rgchFile));
phnNew->hed.ulLine = GulElemHdrLine;
ASSERT(IS_VALID_STRUCT_PTR(phnNew, CHEAPNODE));
}
}
else
phnNew = NULL;
return(phnNew != NULL);
}
/*
** RemoveHeapElement()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE void RemoveHeapElement(PCVOID pcvOld)
{
PHEAPNODE phnOld;
if (EVAL(FindHeapElement(pcvOld, &phnOld)))
{
/* Remove heap node from list. */
phnOld->phnPrev->phnNext = phnOld->phnNext;
if (phnOld->phnNext)
phnOld->phnNext->phnPrev = phnOld->phnPrev;
MEMFREE(phnOld);
}
return;
}
/*
** ModifyHeapElement()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE void ModifyHeapElement(PCVOID pcvOld, PCVOID pcvNew, DWORD dwcbNewSize)
{
PHEAPNODE phn;
if (EVAL(FindHeapElement(pcvOld, &phn)))
{
phn->pcv = pcvNew;
phn->dwcbSize = dwcbNewSize;
}
return;
}
/*
** FindHeapElement()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL FindHeapElement(PCVOID pcvTarget, PHEAPNODE *pphn)
{
BOOL bFound = FALSE;
PHEAPNODE phn;
ASSERT(IS_VALID_WRITE_PTR(pphn, PHEAPNODE));
if (Mpheap)
{
for (phn = Mpheap->hnHead.phnNext;
phn;
phn = phn->phnNext)
{
/*
* Verify each HEAPNODE structure carefully. We may be in the middle of
* a ModifyHeapElement() call, in which case just the target HEAPNODE may
* be invalid, e.g., after MEMREALLOCATE() in ReallocateMemory().
*/
ASSERT((IS_VALID_READ_PTR(phn, CHEAPNODE) && phn->pcv == pcvTarget) ||
IS_VALID_STRUCT_PTR(phn, CHEAPNODE));
if (phn->pcv == pcvTarget)
{
*pphn = phn;
bFound = TRUE;
break;
}
}
}
return(bFound);
}
/*
** FillNewMemory()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE void FillNewMemory(PBYTE pbyte, DWORD dwcbRequestedSize,
DWORD dwcbAllocatedSize)
{
ASSERT(dwcbRequestedSize >= sizeof(MchsPrefix) + sizeof(MchsSuffix));
ASSERT(dwcbAllocatedSize >= dwcbRequestedSize);
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyte, BYTE, (UINT)dwcbAllocatedSize));
/* Fill new heap element with the uninitialized byte value. */
FillMemory(pbyte, dwcbAllocatedSize, UNINITIALIZED_BYTE_VALUE);
/* Copy prefix and suffix heap element sentinels. */
CopyMemory(pbyte, &MchsPrefix, sizeof(MchsPrefix));
CopyMemory(pbyte + dwcbRequestedSize - sizeof(MchsSuffix), &MchsSuffix,
sizeof(MchsSuffix));
return;
}
/*
** FillFreedMemory()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE void FillFreedMemory(PBYTE pbyte, DWORD dwcbAllocatedSize)
{
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyte, BYTE, (UINT)dwcbAllocatedSize));
/* Fill old heap element with the freed byte value. */
FillMemory(pbyte, dwcbAllocatedSize, FREED_BYTE_VALUE);
return;
}
/*
** FillGrownMemory()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE void FillGrownMemory(PBYTE pbyte, DWORD dwcbOldRequestedSize,
DWORD dwcbNewRequestedSize,
DWORD dwcbNewAllocatedSize)
{
ASSERT(dwcbOldRequestedSize >= sizeof(MchsPrefix) + sizeof(MchsSuffix));
ASSERT(dwcbNewRequestedSize > dwcbOldRequestedSize);
ASSERT(dwcbNewAllocatedSize >= dwcbNewRequestedSize);
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyte, BYTE, (UINT)dwcbNewAllocatedSize));
ASSERT(MyMemComp(pbyte, &MchsPrefix, sizeof(MchsPrefix)) == CR_EQUAL);
/* Fill new heap element tail with the uninitialized byte value. */
FillMemory(pbyte + dwcbOldRequestedSize - sizeof(MchsSuffix),
dwcbNewRequestedSize - dwcbOldRequestedSize,
UNINITIALIZED_BYTE_VALUE);
/* Copy suffix heap element sentinel. */
CopyMemory(pbyte + dwcbNewRequestedSize - sizeof(MchsSuffix), &MchsSuffix,
sizeof(MchsSuffix));
return;
}
/*
** FillShrunkenMemory()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE void FillShrunkenMemory(PBYTE pbyte, DWORD dwcbOldRequestedSize,
DWORD dwcbNewRequestedSize,
DWORD dwcbNewAllocatedSize)
{
ASSERT(dwcbNewRequestedSize >= sizeof(MchsPrefix) + sizeof(MchsSuffix));
ASSERT(dwcbNewRequestedSize < dwcbOldRequestedSize);
ASSERT(dwcbNewAllocatedSize >= dwcbNewRequestedSize);
ASSERT(IS_VALID_WRITE_BUFFER_PTR(pbyte, BYTE, (UINT)dwcbNewAllocatedSize));
ASSERT(MyMemComp(pbyte, &MchsPrefix, sizeof(MchsPrefix)) == CR_EQUAL);
/* Fill old heap element tail with the freed byte value. */
FillMemory(pbyte + dwcbNewRequestedSize,
dwcbOldRequestedSize - dwcbNewRequestedSize, FREED_BYTE_VALUE);
/* Copy suffix heap element sentinel. */
CopyMemory(pbyte + dwcbNewRequestedSize - sizeof(MchsSuffix), &MchsSuffix,
sizeof(MchsSuffix));
return;
}
/*
** IsValidHeapPtr()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsValidHeapPtr(PCVOID pcv)
{
PHEAPNODE phnUnused;
return(FindHeapElement(pcv, &phnUnused));
}
/*
** IsHeapOK()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsHeapOK(void)
{
PHEAPNODE phn;
if (Mpheap)
{
for (phn = Mpheap->hnHead.phnNext;
phn && IS_VALID_STRUCT_PTR(phn, CHEAPNODE);
phn = phn->phnNext)
;
}
else
phn = (PHEAPNODE)0xFFFF;
return(phn == NULL);
}
/*
** IsValidPCHEAPNODE()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsValidPCHEAPNODE(PCHEAPNODE pchn)
{
BOOL bResult;
if (IS_VALID_READ_PTR(pchn, CHEAPNODE) &&
IS_VALID_READ_PTR(pchn->phnPrev, CHEAPNODE) &&
EVAL(pchn->phnPrev->phnNext == pchn) &&
EVAL(! pchn->phnNext ||
(IS_VALID_READ_PTR(pchn->phnNext, CHEAPNODE) &&
EVAL(pchn->phnNext->phnPrev == pchn))) &&
EVAL(IsValidHeapElement(pchn->pcv, pchn->dwcbSize, MEMSIZE((PVOID)(pchn->pcv)))) &&
IS_VALID_STRUCT_PTR(&(pchn->hed), CHEAPELEMDESC))
bResult = TRUE;
else
bResult = FALSE;
return(bResult);
}
/*
** IsValidPCHEAPELEMDESC()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsValidPCHEAPELEMDESC(PCHEAPELEMDESC pched)
{
BOOL bResult;
/* Any value for pched->ulLine is valid. */
if (IS_VALID_READ_PTR(pched, CHEAPELEMDESC))
bResult = TRUE;
else
bResult = FALSE;
return(bResult);
}
/*
** IsValidHeapElement()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE BOOL IsValidHeapElement(PCBYTE pcbyte, DWORD dwcbRequestedSize,
DWORD dwcbAllocatedSize)
{
BOOL bResult;
if (EVAL(dwcbRequestedSize >= sizeof(MchsPrefix) + sizeof(MchsSuffix)) &&
EVAL(dwcbAllocatedSize >= dwcbRequestedSize) &&
IS_VALID_READ_PTR(pcbyte, dwcbAllocatedSize) &&
EVAL(MyMemComp(pcbyte, &MchsPrefix, sizeof(MchsPrefix)) == CR_EQUAL) &&
EVAL(MyMemComp(pcbyte + dwcbRequestedSize - sizeof(MchsSuffix), &MchsSuffix, sizeof(MchsSuffix)) == CR_EQUAL))
bResult = TRUE;
else
bResult = FALSE;
return(bResult);
}
/*
** SpewHeapElementInfo()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE void SpewHeapElementInfo(PCHEAPNODE pchn)
{
ASSERT(IS_VALID_STRUCT_PTR(pchn, CHEAPNODE));
TRACE_OUT((TEXT("Used heap element at %#lx:\r\n")
TEXT(" %lu bytes requested\r\n")
TEXT(" %lu bytes allocated\r\n")
TEXT(" originally allocated as '%s' bytes in file %s at line %lu"),
pchn->pcv,
pchn->dwcbSize,
MEMSIZE((PVOID)(pchn->pcv)),
pchn->hed.rgchSize,
pchn->hed.rgchFile,
pchn->hed.ulLine));
return;
}
/*
** AnalyzeHeap()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PRIVATE_CODE void AnalyzeHeap(PHEAPSUMMARY phs, DWORD dwFlags)
{
PCHEAPNODE pchn;
ULONG ulcHeapElements = 0;
DWORD dwcbUsed = 0;
ASSERT(IS_VALID_WRITE_PTR(phs, HEAPSUMMARY));
ASSERT(FLAGS_ARE_VALID(dwFlags, SHS_FL_SPEW_USED_INFO));
ASSERT(IsHeapOK());
TRACE_OUT((TEXT("Starting private heap analysis.")));
if (Mpheap)
{
for (pchn = Mpheap->hnHead.phnNext;
pchn;
pchn = pchn->phnNext)
{
ASSERT(IS_VALID_STRUCT_PTR(pchn, CHEAPNODE));
ASSERT(ulcHeapElements < ULONG_MAX);
ulcHeapElements++;
ASSERT(dwcbUsed < DWORD_MAX - pchn->dwcbSize);
dwcbUsed += pchn->dwcbSize;
if (IS_FLAG_SET(dwFlags, SHS_FL_SPEW_USED_INFO))
SpewHeapElementInfo(pchn);
}
phs->ulcUsedElements = ulcHeapElements;
phs->dwcbUsedSize = dwcbUsed;
}
else
WARNING_OUT((TEXT("Private heap not allocated!")));
TRACE_OUT((TEXT("Private heap analysis complete.")));
return;
}
#endif /* DEBUG */
/****************************** Public Functions *****************************/
/*
** InitMemoryManagerModule()
**
** When PRIVATE_HEAP is defined, this function should be called only
** once, when the DLL is being first initialized. When PRIVATE_HEAP
** is not defined, this function should be called for every
** DLL_PROCESS_ATTACH.
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL InitMemoryManagerModule(void)
{
BOOL bResult;
#ifdef PRIVATE_HEAP
bResult = InitPrivateHeapModule();
#else /* PRIVATE_HEAP */
bResult = InitHeapModule();
#endif
return(bResult);
}
/*
** ExitMemoryManagerModule()
**
** When PRIVATE_HEAP is defined, this function should be called only
** once, when the DLL is finally being terminated. When PRIVATE_HEAP
** is not defined, this function should be called for every
** DLL_PROCESS_DETACH.
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void ExitMemoryManagerModule(void)
{
#ifdef DEBUG
if (Mpheap)
{
MEMFREE(Mpheap);
Mpheap = NULL;
}
else
WARNING_OUT((TEXT("ExitMemoryManagerModule() called when Mpheap is NULL.")));
#endif
#ifdef PRIVATE_HEAP
if (Mhheap)
{
EVAL(HeapDestroy(Mhheap));
Mhheap = NULL;
}
else
WARNING_OUT((TEXT("ExitMemoryManagerModule() called when Mhheap is NULL.")));
#endif
return;
}
/*
** MyMemComp()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE COMPARISONRESULT MyMemComp(PCVOID pcv1, PCVOID pcv2, DWORD dwcbSize)
{
int nResult = 0;
PCBYTE pcbyte1 = pcv1;
PCBYTE pcbyte2 = pcv2;
ASSERT(IS_VALID_READ_BUFFER_PTR(pcv1, BYTE, (UINT)dwcbSize));
ASSERT(IS_VALID_READ_BUFFER_PTR(pcv2, BYTE, (UINT)dwcbSize));
while (dwcbSize > 0 &&
! (nResult = *pcbyte1 - *pcbyte2))
{
pcbyte1++;
pcbyte2++;
dwcbSize--;
}
return(MapIntToComparisonResult(nResult));
}
/*
** MyAllocateMemory()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL MyAllocateMemory(DWORD dwcbSize, PVOID *ppvNew)
{
#ifdef DEBUG
DWORD dwcbRequestedSize = dwcbSize;
// ASSERT(dwcbSize >= 0); // DWORDs are nonnegative by definition
ASSERT(IS_VALID_WRITE_PTR(ppvNew, PVOID));
dwcbSize = CalculatePrivateSize(dwcbSize);
if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY))
ASSERT(IsHeapOK());
#endif
*ppvNew = MEMALLOCATE(dwcbSize);
#ifdef DEBUG
if (*ppvNew)
{
FillNewMemory(*ppvNew, dwcbSize, MEMSIZE(*ppvNew));
if (AddHeapElement(*ppvNew, dwcbSize))
{
*ppvNew = GetPublicHeapPtr(*ppvNew);
ASSERT(IS_VALID_WRITE_BUFFER_PTR(*ppvNew, BYTE, (UINT)dwcbRequestedSize));
}
else
{
EVAL(MEMFREE(*ppvNew));
*ppvNew = NULL;
}
}
if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT))
ASSERT(IsHeapOK());
#endif
return(*ppvNew != NULL);
}
/*
** FreeMemory()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void FreeMemory(PVOID pvOld)
{
#ifdef DEBUG
if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY))
ASSERT(IsHeapOK());
pvOld = GetPrivateHeapPtr(pvOld);
ASSERT(IsValidHeapPtr(pvOld));
RemoveHeapElement(pvOld);
FillFreedMemory(pvOld, MEMSIZE(pvOld));
#endif
EVAL(MEMFREE(pvOld));
#ifdef DEBUG
if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT))
ASSERT(IsHeapOK());
#endif /* DEBUG */
return;
}
/*
** ReallocateMemory()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL ReallocateMemory(PVOID pvOld, DWORD dwcbNewSize, PVOID *ppvNew)
{
#ifdef DEBUG
DWORD dwcbRequestedSize = dwcbNewSize;
DWORD dwcbOldSize;
ASSERT(IS_VALID_WRITE_PTR(ppvNew, PVOID));
if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_ENTRY))
ASSERT(IsHeapOK());
pvOld = GetPrivateHeapPtr(pvOld);
ASSERT(IsValidHeapPtr(pvOld));
dwcbNewSize = CalculatePrivateSize(dwcbNewSize);
dwcbOldSize = GetHeapSize(pvOld);
if (dwcbNewSize == dwcbOldSize)
WARNING_OUT((TEXT("ReallocateMemory(): Size of heap element %#lx is already %lu bytes."),
GetPublicHeapPtr(pvOld),
dwcbNewSize));
#endif
*ppvNew = MEMREALLOCATE(pvOld, dwcbNewSize);
#ifdef DEBUG
if (*ppvNew)
{
/* Bigger or smaller? */
if (dwcbNewSize > dwcbOldSize)
/* Bigger. */
FillGrownMemory(*ppvNew, dwcbOldSize, dwcbNewSize, MEMSIZE(*ppvNew));
else
/* Smaller. */
FillShrunkenMemory(*ppvNew, dwcbOldSize, dwcbNewSize, MEMSIZE(*ppvNew));
ModifyHeapElement(pvOld, *ppvNew, dwcbNewSize);
*ppvNew = GetPublicHeapPtr(*ppvNew);
ASSERT(IS_VALID_WRITE_BUFFER_PTR(*ppvNew, BYTE, (UINT)dwcbRequestedSize));
}
if (IS_FLAG_SET(MdwMemoryManagerModuleFlags, MEMMGR_DFL_VALIDATE_HEAP_ON_EXIT))
ASSERT(IsHeapOK());
#endif
return(*ppvNew != NULL);
}
/*
** GetMemorySize()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE DWORD GetMemorySize(PVOID pv)
{
ASSERT(IsValidHeapPtr(GetPrivateHeapPtr(pv)));
return(MEMSIZE(pv));
}
#ifdef DEBUG
/*
** SetMemoryManagerModuleIniSwitches()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE BOOL SetMemoryManagerModuleIniSwitches(void)
{
BOOL bResult;
bResult = SetIniSwitches(MrgcpcvisMemoryManagerModule,
ARRAY_ELEMENTS(MrgcpcvisMemoryManagerModule));
ASSERT(FLAGS_ARE_VALID(MdwMemoryManagerModuleFlags, ALL_MEMMGR_DFLAGS));
return(bResult);
}
/*
** SpewHeapSummary()
**
**
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
PUBLIC_CODE void SpewHeapSummary(DWORD dwFlags)
{
HEAPSUMMARY hs;
ASSERT(FLAGS_ARE_VALID(dwFlags, SHS_FL_SPEW_USED_INFO));
AnalyzeHeap(&hs, dwFlags);
TRACE_OUT((TEXT("Heap summary: %lu bytes in %lu used elements."),
hs.dwcbUsedSize,
hs.ulcUsedElements));
return;
}
#endif /* DEBUG */