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.
 
 
 
 
 
 

612 lines
15 KiB

////////////////////////////////////////////////////////////////////////////////
// File: memCore.c
//
// This module which replaces the Win32 Global heap functions used by Word
// with functions which place objects at the end of a physical page. In
// this way, we hope to catch out-of-bounds memory references exactly where
// they happen, helping to isolate heap corruption problems.
//
//
// This module is not enabled for ship builds.
//
// lenoxb: 4/05/94
//
////////////////////////////////////////////////////////////////////////////////
#include "precomp.h"
#if defined(_DEBUG) && (defined(_M_IX86) || defined (_M_ALPHA))
#include "dbgmemp.h"
static DWORD s_cbMemPage = 0; // Initialize to 0 so init can check
static void * FreePvCore(void*);
static LPVOID PvReallocCore(PVOID, DWORD, UINT);
static LPVOID DoAlloc(UINT, DWORD);
static void AddToList(struct head*);
static void RemoveFromList(struct head*);
static void TrackHeapUsage(long dcb);
static DWORD idBlockNext;
static struct head* phead;
static CRITICAL_SECTION csMine;
#undef GlobalAlloc
#undef GlobalReAlloc
#undef GlobalFree
#undef GlobalLock
#undef GlobalUnlock
#undef GlobalSize
#undef GlobalHandle
BOOL g_fTrackHeapUsage;
DWORD g_cbAllocMax;
DWORD g_cbAlloc;
/*
*Function Name:InitDebugMem
*
*Parameters:
*
*Description: Initialize Memory Manager
*
*Returns:
*
*/
void WINAPI InitDebugMem(void)
{
SYSTEM_INFO SysInfo;
Assert(!s_cbMemPage);
InitializeCriticalSection(&csMine);
GetSystemInfo( &SysInfo ); // get the system memory page size
s_cbMemPage = SysInfo.dwPageSize;
}
BOOL WINAPI FiniDebugMem(void)
{
Assert(s_cbMemPage);
s_cbMemPage = 0;
DeleteCriticalSection(&csMine);
if (!phead) // no outstanding mem blocks
return FALSE;
else
{
struct head* pheadThis = phead;
char buf[256];
OutputDebugStringA("Unfreed Memory Blocks\n");
for ( ; pheadThis; pheadThis = pheadThis->pheadNext)
{
sprintf(buf, "ID %d size %d\n",
pheadThis->idBlock,
pheadThis->cbBlock
);
OutputDebugStringA(buf);
}
}
return TRUE;
}
/* D B G L O B A L A L L O C */
/*----------------------------------------------------------------------------
%%Function: dbGlobalAlloc
%%Contact: lenoxb
Replacement for GlobalAlloc
Now an Internal Routine
----------------------------------------------------------------------------*/
static void * WINAPI dbGlobalAlloc(UINT uFlags, DWORD cb)
{
/* Send "tough" requests to actual memory manager */
if ((uFlags & GMEM_DDESHARE) || ((uFlags & GMEM_MOVEABLE) && !fMove))
return GlobalAlloc(uFlags,cb);
if (uFlags & GMEM_MOVEABLE)
{
return HgAllocateMoveable(uFlags, cb);
}
return (void *) PvAllocateCore(uFlags, cb);
}
/* D B G L O B A L F R E E */
/*----------------------------------------------------------------------------
%%Function: dbGlobalFree
%%Contact: lenoxb
Replacement for GlobalFree()
Now an internal routine
----------------------------------------------------------------------------*/
static void * WINAPI dbGlobalFree(void * hMem)
{
void** ppv;
if (!fMove && FActualHandle(hMem))
return GlobalFree(hMem);
ppv = PpvFromHandle(hMem);
if (ppv)
{
if (FreePvCore(*ppv) != NULL)
return hMem;
*ppv = NULL;
return NULL;
}
return FreePvCore (hMem);
}
/* D B G L O B A L S I Z E */
/*----------------------------------------------------------------------------
%%Function: dbGlobalSize
%%Contact: lenoxb
Replacement for GlobalSize()
Now an internal routine
----------------------------------------------------------------------------*/
static DWORD WINAPI dbGlobalSize(void * hMem)
{
void** ppv;
HEAD * phead;
if (!fMove && FActualHandle(hMem))
return GlobalSize(hMem);
if (hMem == 0)
return 0;
ppv = PpvFromHandle(hMem);
phead = GetBlockHeader(ppv ? *ppv : hMem);
return phead ? phead->cbBlock : 0;
}
/* D B G L O B A L R E A L L O C */
/*----------------------------------------------------------------------------
%%Function: dbGlobalReAlloc
%%Contact: lenoxb
Replacement for GlobalReAlloc()
Now an internal routine
----------------------------------------------------------------------------*/
static void * WINAPI dbGlobalReAlloc(void * hMem, DWORD cb, UINT uFlags)
{
LPVOID pvNew;
void** ppv;
if (!fMove && FActualHandle(hMem))
return GlobalReAlloc(hMem,cb,uFlags);
/* REVIEW: what's supposed to happen when hMem==NULL */
ppv = PpvFromHandle(hMem);
if (uFlags & GMEM_MODIFY) /* Modify block attributes */
{
if (uFlags & GMEM_MOVEABLE)
{
return HgModifyMoveable(hMem, cb, uFlags);
}
else
{
HEAD * phead;
if (ppv == NULL) /* Already fixed */
return hMem;
phead = GetBlockHeader(*ppv);
if (phead->cLock != 0) /* Don't realloc a locked block */
return NULL;
*ppv = NULL;
return phead+1;
}
}
if (ppv)
{
pvNew = PvReallocCore (*ppv, cb, uFlags);
if (pvNew == NULL)
return NULL;
*ppv = pvNew;
return hMem;
}
if (!(uFlags & GMEM_MOVEABLE))
return NULL;
return PvReallocCore (hMem, cb, uFlags);
}
/***********************************************
External interface for routines that can track usage
***********************************************/
void* WINAPI dbgMallocCore(size_t cb, BOOL fTrackUsage)
{
void* pv;
// make sure we're initialized
if (s_cbMemPage == 0)
InitDebugMem();
EnterCriticalSection(&csMine);
pv = dbGlobalAlloc(GMEM_FIXED, cb);
if (fTrackUsage)
TrackHeapUsage((long)dbGlobalSize(pv));
LeaveCriticalSection(&csMine);
return pv;
}
void * WINAPI dbgFreeCore(void* pv, BOOL fTrackUsage)
{
void * hRes;
// make sure we're initialized
if (s_cbMemPage == 0)
InitDebugMem();
EnterCriticalSection(&csMine);
if (fTrackUsage)
TrackHeapUsage(-(long)dbGlobalSize(pv));
hRes = dbGlobalFree(pv);
LeaveCriticalSection(&csMine);
return hRes;
}
void* WINAPI dbgReallocCore(void* pv, size_t cb, BOOL fTrackUsage)
{
long cbOld, cbNew;
// make sure we're initialized
if (s_cbMemPage == 0)
InitDebugMem();
EnterCriticalSection(&csMine);
cbOld = dbGlobalSize(pv);
pv = dbGlobalReAlloc(pv,cb,GMEM_MOVEABLE);
if (pv && fTrackUsage)
{
cbNew = dbGlobalSize(pv);
TrackHeapUsage(cbNew - cbOld);
}
LeaveCriticalSection(&csMine);
return pv;
}
/**************************************************************
Normal Public Interface
**************************************************************/
void* WINAPI dbgMalloc(size_t cb)
{
return dbgMallocCore(cb, FALSE);
}
void* WINAPI dbgCalloc(size_t c, size_t cb)
{
void *pMem = dbgMallocCore(cb * c, FALSE);
if (pMem)
{
memset(pMem, 0, cb * c);
}
return pMem;
}
HLOCAL WINAPI dbgFree(void* pv)
{
return dbgFreeCore(pv, FALSE);
}
void* WINAPI dbgRealloc(void* pv, size_t cb)
{
return dbgReallocCore(pv, cb, FALSE);
}
static void TrackHeapUsage(long dcb)
{
long cbAlloc=0, cbAllocMax=0;
if (!g_fTrackHeapUsage)
return;
g_cbAlloc += dcb;
g_cbAllocMax = (g_cbAllocMax > g_cbAlloc ? g_cbAllocMax : g_cbAlloc);
cbAlloc = g_cbAlloc;
cbAllocMax = g_cbAllocMax;
LeaveCriticalSection(&csMine);
Assert(cbAlloc >= 0);
Assert(cbAllocMax >= 0);
}
//////////////////////////////////////
/// NLG (ex T-Hammer) interfaces ///
//////////////////////////////////////
BOOL WINAPI
fNLGNewMemory(
OUT PVOID *ppv,
IN ULONG cb)
{
Assert(ppv != NULL && cb != 0);
*ppv = dbgMalloc(cb);
return *ppv != NULL;
}
DWORD WINAPI
NLGMemorySize(
VOID *pvMem)
{
Assert (pvMem != NULL);
return dbGlobalSize(pvMem);
}
BOOL WINAPI
fNLGResizeMemory(
IN OUT PVOID *ppv,
IN ULONG cbNew)
{
PVOID pv;
Assert( ppv != NULL && *ppv != NULL && cbNew != 0 );
// Note that the semantics of GMEM_MOVEABLE are different
// between Alloc and ReAlloc; with ReAlloc, it only means that
// it's OK for the realloc'ed block to start at a different location
// than the original...
pv = dbgRealloc(*ppv, cbNew);
if (pv != NULL)
{
*ppv = pv;
}
return (pv != NULL);
}
VOID WINAPI
NLGFreeMemory(
IN PVOID pvMem)
{
Assert(pvMem != NULL);
dbgFree(pvMem);
}
// These two are the same in retail and debug;
// find a home for the retail versions...
BOOL WINAPI
fNLGHeapDestroy(
VOID)
{
return TRUE;
}
/* G E T B L O C K H E A D E R */
/*----------------------------------------------------------------------------
%%Function: GetBlockHeader
%%Contact: lenoxb
tmp
Returns memory block header associated with indicated handle.
Generates access violation if passed an invalid handle.
------------------------------------------tmp----------------------------------*/
static HEAD * GetBlockHeader(void* pvMem)
{
HEAD * phead = ((HEAD *) pvMem) - 1;
Assert (!IsBadWritePtr(phead, sizeof *phead));
return phead;
}
/* P V A L L O C A T E C O R E */
/*----------------------------------------------------------------------------
%%Function: PvAllocateCore
%%Contact: lenoxb
Workhorse routine to allocate memory blocks
----------------------------------------------------------------------------*/
static LPVOID PvAllocateCore (UINT uFlags, DWORD cb)
{
HEAD headNew;
HEAD *pAllocHead;
DWORD cbTotal, cbPadded, cbPages;
if (fPadBlocks)
cbPadded = PAD(cb,4); /* For RISC platforms, makes sure the block is aligned */
else
cbPadded = cb;
cbTotal = PAD(cbPadded + sizeof headNew, s_cbMemPage);
if (fExtraReadPage)
cbPages = cbTotal+1;
else
cbPages = cbTotal;
cbPages += s_cbMemPage;
headNew.dwTag = HEAD_TAG;
headNew.cbBlock = cb;
headNew.cLock = 0;
headNew.idBlock = idBlockNext++;
headNew.pheadNext = NULL;
headNew.pbBase = VirtualAlloc(NULL,
cbPages, MEM_RESERVE, PAGE_READWRITE
);
if (headNew.pbBase == NULL)
return NULL;
pAllocHead = VirtualAlloc(headNew.pbBase,
cbTotal, MEM_COMMIT, PAGE_READWRITE
);
if (pAllocHead == NULL)
{
VirtualFree(headNew.pbBase, 0, MEM_RELEASE);
return NULL;
}
headNew.pbBase = (LPBYTE)pAllocHead;
if (fExtraReadPage)
{
if (!VirtualAlloc(headNew.pbBase+cbTotal,1, MEM_COMMIT, PAGE_READONLY))
{
VirtualFree(headNew.pbBase, 0, MEM_RELEASE);
return NULL;
}
}
// FUTURE: do something with PAGE_GUARD?
if (!VirtualAlloc(headNew.pbBase + cbPages - s_cbMemPage,
1, MEM_COMMIT, PAGE_NOACCESS))
{
// the entire reserved range must be either committed or decommitted
VirtualFree(headNew.pbBase, cbTotal, MEM_DECOMMIT);
VirtualFree(headNew.pbBase, 0, MEM_RELEASE);
return FALSE;
}
if ((uFlags & GMEM_ZEROINIT) == 0)
memset(headNew.pbBase, bNewGarbage, cbTotal);
pAllocHead = ((HEAD *)(headNew.pbBase + cbTotal - cbPadded));
pAllocHead[-1] = headNew;
AddToList(pAllocHead-1);
return pAllocHead;
}
/* P V R E A L L O C C O R E */
/*----------------------------------------------------------------------------
%%Function: PvReallocCore
%%Contact: lenoxb
Workhorse routine to move memory blocks
----------------------------------------------------------------------------*/
static LPVOID PvReallocCore (PVOID pvMem, DWORD cb, UINT uFlags)
{
LPVOID pvNew;
DWORD cbOld;
pvNew = (LPVOID) PvAllocateCore(uFlags, cb);
if (!pvNew)
return NULL;
cbOld = dbGlobalSize(pvMem);
if (cbOld>0 && cb>0)
memcpy(pvNew, pvMem, cbOld<cb ? cbOld : cb);
FreePvCore (pvMem);
return pvNew;
}
/* F R E E P V C O R E */
/*----------------------------------------------------------------------------
%%Function: FreePvCore
%%Contact: lenoxb
Workhourse routine to free memory blocks.
----------------------------------------------------------------------------*/
static void * FreePvCore (void* pvMem)
{
HEAD * phead;
if (pvMem)
{
phead = GetBlockHeader(pvMem);
if (phead->cLock != 0)
return pvMem;
RemoveFromList(phead);
VirtualFree(phead->pbBase, 0, MEM_RELEASE);
}
return NULL;
}
struct head* dbgHead(void)
{
struct head* pheadThis = phead;
if (pheadThis == NULL)
return NULL;
for (pheadThis=phead; pheadThis->pheadNext; pheadThis = pheadThis->pheadNext)
continue;
return pheadThis;
}
static void AddToList(struct head* pheadAdd)
{
EnterCriticalSection(&csMine);
pheadAdd->pheadNext = phead;
phead = pheadAdd;
LeaveCriticalSection(&csMine);
}
static void RemoveFromList(struct head* pheadRemove)
{
struct head* pheadThis;
struct head* pheadPrev;
BOOL fFoundNode = FALSE;
Assert(pheadRemove != NULL);
EnterCriticalSection(&csMine);
pheadPrev = NULL;
for (pheadThis = phead; pheadThis; pheadThis = pheadThis->pheadNext)
{
if (pheadThis == pheadRemove)
{
if (pheadPrev == NULL)
{
Assert(pheadThis == phead);
phead = pheadThis->pheadNext;
}
else
{
pheadPrev->pheadNext = pheadThis->pheadNext;
}
fFoundNode = TRUE;
goto LExit;
}
pheadPrev = pheadThis;
}
LExit:
LeaveCriticalSection(&csMine);
Assert(fFoundNode); // Not on the list? Never happens.
}
#else // !defined(DEBUG) && defined(NTX86) || defined (M_ALPHA)
void * WINAPI dbgCalloc(size_t c, size_t cb)
{
void *pMem = dbgMalloc(cb * c);
if (pMem)
{
memset(pMem, 0, cb * c);
}
return pMem;
}
#endif //defined(DEBUG) && defined(NTX86) || defined (M_ALPHA)