|
|
/*****************************************************************************\
* MODULE: mem.c * * Memory management routines. These routines provide head/tail checking * to verify memory corruption problems. * * * Copyright (C) 1996-1997 Microsoft Corporation * Copyright (C) 1996-1997 Hewlett Packard * * History: * 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT * \*****************************************************************************/
#include "precomp.h"
#include "priv.h"
/*********************************************************** local routine ***\
* mem_HeadPtr * * Returns the pointer to the head-block. This needs to decrement enough * to account for the extra information stored at the head. * \*****************************************************************************/ _inline PMEMHEAD mem_HeadPtr( PVOID pvMem) { return (PMEMHEAD)(pvMem ? (((PBYTE)pvMem) - MEM_HEADSIZE) : NULL); }
/*********************************************************** local routine ***\
* mem_TailPtr * * Returns the pointer to the tail-block. This requires the aligned-size * to retrieve the offset. * \*****************************************************************************/ _inline PMEMTAIL mem_TailPtr( PMEMHEAD pmh, DWORD cbAlign) { return (PMEMTAIL)((PBYTE)pmh + cbAlign - MEM_TAILSIZE); }
#ifdef DEBUG
PMEMHEAD g_pmHead = NULL;
/*********************************************************** local routine ***\
* mem_InsPtr * * Inserts the pointer into our list for tracking allocations. * \*****************************************************************************/ _inline VOID mem_InsPtr( PMEMHEAD pmHead) { if (g_pmHead) {
g_pmHead->pmPrev = pmHead; pmHead->pmNext = g_pmHead;
} else {
pmHead->pmNext = NULL; }
g_pmHead = pmHead; }
/*********************************************************** local routine ***\
* mem_DelPtr * * Removes the pointer from our list of tracked allocations. | \*****************************************************************************/ _inline VOID mem_DelPtr( PMEMHEAD pmHead) { PMEMHEAD pmPtr;
if (pmHead->pmNext) {
pmPtr = pmHead->pmNext; pmPtr->pmPrev = pmHead->pmPrev; }
if (pmHead->pmPrev) {
pmPtr = pmHead->pmPrev; pmPtr->pmNext = pmHead->pmNext;
} else {
g_pmHead = pmHead->pmNext; } }
/*****************************************************************************\
* _mem_validate (Local Routine) * * Checks memory blocks allocated by memAlloc. These blocks contain * debugging information that helps to check for pointer overruns and * underruns. * * Returns a pointer to the memory header. Otherwise, we return NULL. * \*****************************************************************************/ PVOID _mem_validate( PVOID pvMem, UINT cbSize) { DWORD cbAlign; PMEMHEAD pmHead; PMEMTAIL pmTail; PMEMHEAD pmRet = NULL;
// Retrieve the head-pointer.
//
if (pmHead = mem_HeadPtr(pvMem)) {
// Calculate the "real" size of our allocated block and round it
// up to an even number of DWORD blocks.
//
cbAlign = memAlignSize(cbSize + MEM_SIZE);
// Get the tail location.
//
pmTail = mem_TailPtr(pmHead, cbAlign);
// Compare the values that memAlloc stored at the beginning
// and end of the block
//
if ((pmHead->cbSize == cbSize) && (pmTail->dwSignature == DEADBEEF)) pmRet = pmHead;
// Assert if errors.
//
DBG_ASSERT((pmHead->cbSize == cbSize), (TEXT("Err : _mem_validate: Bad Size at %08lX"), pvMem)); DBG_ASSERT((pmTail->dwSignature == DEADBEEF), (TEXT("Err : _mem_validate: Block Corruption at %08lX"), pvMem));
} else {
DBG_MSG(DBG_LEV_ERROR, (TEXT("Err : _mem_validate: Bad Pointer"))); }
return pmRet; }
#else
/*********************************************************** local routine ***\
* Non-Debug Mappings. * * On non-debug builds, we will just return the most efficient values. * \*****************************************************************************/ #define mem_InsPtr(pmHead) {}
#define mem_DelPtr(pmHead) {}
#define _mem_validate(pvMem, cbSize) mem_HeadPtr(pvMem)
#endif
/*****************************************************************************\
* memAlloc * * \*****************************************************************************/ PVOID memAlloc( UINT cbSize) { PMEMHEAD pmHead; PMEMTAIL pmTail; DWORD cbAlign;
// The size of this memory-block will include header-information. So,
// we will add the header-size and align our memory on DWORD boundries.
//
cbAlign = memAlignSize(cbSize + MEM_SIZE);
// Attempt to allocate the memory. Proceed to setup
// the memory block.
//
if (pmHead = (PMEMHEAD)GlobalAlloc(GPTR, cbAlign)) {
pmTail = mem_TailPtr(pmHead, cbAlign);
// Zero the memory-block so that we're dealing with
// a clean contiguous array.
//
ZeroMemory((PVOID)pmHead, cbAlign);
// Set up header/tail-information. This contains the requested
// size of the memory-block. Increment the block so we return
// the next available memory for the caller to use.
//
pmTail->dwSignature = DEADBEEF; pmHead->dwTag = 0; pmHead->cbSize = cbSize; pmHead->pmPrev = NULL; pmHead->pmNext = NULL;
mem_InsPtr(pmHead);
} else {
SetLastError(ERROR_NOT_ENOUGH_MEMORY); }
return (pmHead ? pmHead->pvMem : NULL); }
/*****************************************************************************\
* memFree * * \*****************************************************************************/ BOOL memFree( PVOID pvMem, UINT cbSize) { PMEMHEAD pmHead; BOOL bRet = FALSE;
// Try to at least make sure it's our memory and that no pointers have
// gone astray in it.
//
if (pmHead = (PMEMHEAD) _mem_validate(pvMem, cbSize)) {
mem_DelPtr(pmHead);
bRet = (GlobalFree((PVOID)pmHead) == NULL); }
return bRet; }
/*****************************************************************************\
* memCopy * * Copies a block of memory into a Win32 format buffer -- a structure at the * front of the buffer and strings packed into the end. * * On entry, *buf should point to the last available byte in the buffer. * \*****************************************************************************/ VOID memCopy( PSTR *ppDst, PSTR pSrc, UINT cbSize, PSTR *ppBuf) {
if (pSrc != NULL) {
// Place bytes at end of buffer.
//
(*ppBuf) -= cbSize + 1;
memcpy(*ppBuf, pSrc, cbSize);
// Place buffer address in structure and save pointer to new
// last available byte.
//
*ppDst = *ppBuf;
(*ppBuf)--;
} else {
*ppDst = NULL; } }
/*****************************************************************************\
* memGetSize * * Returns the size of a block of memory that was allocated with memAlloc(). * \*****************************************************************************/ UINT memGetSize( PVOID pvMem) { PMEMHEAD pmHead;
return ((pmHead = mem_HeadPtr(pvMem)) ? pmHead->cbSize : 0); }
/*****************************************************************************\
* memAllocStr * * Allocates local memory to store the specified string. This takes in a * (lpszStr) which is copied to the new memory. * \*****************************************************************************/ PTSTR memAllocStr( LPCTSTR lpszStr) { PTSTR pMem = NULL; size_t uSize = 0;
if (lpszStr == NULL) { return NULL; }
uSize = utlStrSize(lpszStr);
pMem = (PTSTR)memAlloc(uSize);
if (pMem) { if (FAILED(StringCbCopy((LPTSTR)pMem, uSize, lpszStr))) { memFreeStr (pMem); pMem = NULL; } }
return pMem; }
/*****************************************************************************\
* memFreeStr * * Frees the memory allocated by memAllocStr. * \*****************************************************************************/ BOOL memFreeStr( PTSTR pszStr) { return memFree(pszStr, memGetSize(pszStr)); }
|