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.
 
 
 
 
 
 

930 lines
21 KiB

#include "hostenv.h"
#include "cmallspy.h"
#include "apglobal.h"
#define cbAlign 32
#define HEADERSIZE cbAlign // # of bytes of block header
#define TRAILERSIZE cbAlign // # of bytes of block trailer
static XCHAR g_rgchHead[] = XSTR("OLEAuto Mem Head"); // beginning of block signature
static XCHAR g_rgchTail[] = XSTR("OLEAuto Mem Tail"); // end of block signature
#define MEMCMP(PV1, PV2, CB) memcmp((PV1), (PV2), (CB))
#define MEMCPY(PV1, PV2, CB) memcpy((PV1), (PV2), (CB))
#define MEMSET(PV, VAL, CB) memset((PV), (VAL), (CB))
#define MALLOC(CB) GlobalLock(GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, CB))
CMallocSpy myMallocSpy;
UINT g_cHeapCheckInterval = 10; // only check full heap every 100 times.
//---------------------------------------------------------------------
// implementation of the debug allocator
//---------------------------------------------------------------------
CAddrNode32 FAR* CAddrNode32::m_pnFreeList = NULL;
// AddrNodes are allocated in blocks to reduce the number of allocations
// we do for these. Note, we get away with this because the addr nodes
// are never freed, so we can just allocate a block, and thread them
// onto the freelist.
//
#define MEM_cAddrNodes 128
void FAR* CAddrNode32::operator new(size_t /*cb*/)
{
CAddrNode32 FAR* pn;
if(m_pnFreeList == NULL)
{
pn = (CAddrNode32 FAR*)MALLOC(sizeof(CAddrNode32) * MEM_cAddrNodes);
for(int i = 1; i < MEM_cAddrNodes-1; ++i)
pn[i].m_pnNext = &pn[i+1];
pn[MEM_cAddrNodes-1].m_pnNext = m_pnFreeList;
m_pnFreeList = &pn[1];
}
else
{
pn = m_pnFreeList;
m_pnFreeList = pn->m_pnNext;
}
return pn;
}
void CAddrNode32::operator delete(void FAR* pv)
{
CAddrNode32 FAR *pn;
pn = (CAddrNode32 FAR*)pv;
pn->m_pnNext = m_pnFreeList;
m_pnFreeList = pn;
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::CMallocSpy
//
// Synopsis: Constructor
//
// Returns:
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
CMallocSpy::CMallocSpy(void)
{
m_cRef = 0;
m_fWantTrueSize = FALSE;
m_cAllocCalls = 0;
m_cHeapChecks = 0;
MEMSET(m_rganode, 0, sizeof(m_rganode));
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::~CMallocSpy
//
// Synopsis: Destructor
//
// Returns:
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
CMallocSpy::~CMallocSpy(void)
{
CheckForLeaks();
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::QueryInterface
//
// Synopsis: Only IUnknown and IMallocSpy are meaningful
//
// Arguments: [riid] --
// [ppUnk] --
//
// Returns: S_OK or E_NOINTERFACE
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
HRESULT CMallocSpy::QueryInterface(REFIID riid, LPVOID *ppUnk)
{
HRESULT hr = S_OK;
if (IsEqualIID(riid, IID_IUnknown))
{
*ppUnk = (IUnknown *) this;
}
else if (IsEqualIID(riid, IID_IMallocSpy))
{
*ppUnk = (IMalloc *) this;
}
else
{
*ppUnk = NULL;
return E_NOINTERFACE;
}
AddRef();
return hr;
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::AddRef
//
// Synopsis: Add a reference
//
// Returns: New reference count
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
ULONG CMallocSpy::AddRef(void)
{
return ++m_cRef;
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::Release
//
// Synopsis: Remove a reference
//
// Returns: The new reference count
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
ULONG CMallocSpy::Release(void)
{
ULONG cRef;
cRef = --m_cRef;
if (cRef == 0)
{
#if 0 // don't delete -- we're statically allocated
delete this;
#endif
}
return cRef;
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PreAlloc
//
// Synopsis: Called prior to OLE calling IMalloc::Alloc
//
// Arguments: [cbRequest] -- The number of bytes the caller of
// is requesting IMalloc::Alloc
//
// Returns: The count of bytes to actually allocate
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
SIZE_T CMallocSpy::PreAlloc(SIZE_T cbRequest)
{
HeapCheck();
return cbRequest + HEADERSIZE + TRAILERSIZE;
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PostAlloc
//
// Synopsis: Called after OLE calls IMalloc::Alloc
//
// Arguments: [pActual] -- The allocation returned by IMalloc::Alloc
//
// Returns: The allocation pointer to return to the caller of
// IMalloc::Alloc
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
void *CMallocSpy::PostAlloc(void *pActual)
{
IMalloc *pmalloc;
SIZE_T cbRequest;
HRESULT hresult;
XCHAR sz[20];
if (pActual == NULL) // if real alloc failed, then
return NULL; // propogate failure
if (FAILED(hresult = CoGetMalloc(MEMCTX_TASK, &pmalloc)))
{
apSPrintf(sz, XSTR("%lX"), hresult);
apLogFailInfo(XSTR("ERROR:CoGetMalloc failed!!!"), XSTR("NOEEROR"), sz, XSTR(""));
return(NULL);
}
m_fWantTrueSize = TRUE;
cbRequest = pmalloc->GetSize(pActual) - HEADERSIZE - TRAILERSIZE;
m_fWantTrueSize = FALSE;
pmalloc->Release();
// set header signature
MEMCPY(pActual, g_rgchHead, HEADERSIZE);
// set trailer signature
MEMCPY((BYTE *)pActual+HEADERSIZE+cbRequest, g_rgchTail, TRAILERSIZE);
// save info for leak detection
AddInst((BYTE *)pActual+HEADERSIZE, cbRequest);
// Return the allocation plus offset
return (void *) (((BYTE *) pActual) + HEADERSIZE);
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PreFree
//
// Synopsis: Called prior to OLE calling IMalloc::Free
//
// Arguments: [pRequest] -- The allocation to be freed
// [fSpyed] -- Whether it was allocated with a spy active
//
// Returns:
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
void *CMallocSpy::PreFree(void *pRequest, BOOL fSpyed)
{
HeapCheck();
if (pRequest == NULL)
{
return NULL;
}
// Undo the offset
if (fSpyed)
{
CAddrNode32 FAR* pn;
SIZE_T sizeToFree;
pn = FindInst(pRequest);
// check for attempt to operate on a pointer we didn't allocate
if(pn == NULL)
{
apLogFailInfo(XSTR("Attempt to free memory not allocated by this 32-bit test!"), XSTR(""), XSTR(""), XSTR(""));
}
// check the block we're freeing
VerifyHeaderTrailer(pn);
sizeToFree = pn->m_cb + HEADERSIZE + TRAILERSIZE;
DelInst(pRequest);
// mark entire block as invalid
MEMSET((BYTE *) pRequest - HEADERSIZE, '~', sizeToFree);
return (void *) (((BYTE *) pRequest) - HEADERSIZE);
}
else
{
return pRequest;
}
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PostFree
//
// Synopsis: Called after OLE calls IMalloc::Free
//
// Arguments: [fSpyed] -- Whether it was allocated with a spy active
//
// Returns:
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
void CMallocSpy::PostFree(BOOL /*fSpyed*/)
{
return;
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PreRealloc
//
// Synopsis: Called prior to OLE calling IMalloc::Realloc
//
// Arguments: [pRequest] -- The buffer to be reallocated
// [cbRequest] -- The requested new size of the buffer
// [ppNewRequest] -- Where to store the new buffer pointer
// to be reallocated
// [fSpyed] -- Whether it was allocated with a spy active
//
// Returns: The new size to actually be allocated
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
SIZE_T CMallocSpy::PreRealloc(void *pRequest, SIZE_T cbRequest, void **ppNewRequest, BOOL fSpyed)
{
HeapCheck();
if (fSpyed)
{
CAddrNode32 FAR* pn;
SIZE_T sizeToFree;
pn = FindInst(pRequest);
// check for attempt to operate on a pointer we didn't allocate
if(pn == NULL)
{
apLogFailInfo(XSTR("Attempt to reallocate memory not allocated by this 32-bit test!"), XSTR(""), XSTR(""), XSTR(""));
}
sizeToFree = pn->m_cb;
*ppNewRequest = (void *) (((BYTE *) pRequest) - HEADERSIZE);
m_pvRealloc = pRequest;
return cbRequest + HEADERSIZE + TRAILERSIZE;
}
else
{
*ppNewRequest = pRequest;
return cbRequest;
}
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PostRealloc
//
// Synopsis: Called after OLE calls IMalloc::Realloc
//
// Arguments: [pActual] -- Pointer to the reallocated buffer
// [fSpyed] -- Whether it was allocated with a spy active
//
// Returns: The buffer pointer to return
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
void *CMallocSpy::PostRealloc(void *pActual, BOOL fSpyed)
{
IMalloc *pmalloc;
SIZE_T cbRequest;
HRESULT hresult;
XCHAR sz[50];
if (pActual == NULL)
{
apLogFailInfo(XSTR("CMallocSpy::PostRealloc - Realloc of a block failed."), XSTR(""), XSTR(""), XSTR(""));
return NULL;
}
// Return the buffer with the header offset
if (fSpyed)
{
DelInst(m_pvRealloc);
if (FAILED(hresult = CoGetMalloc(MEMCTX_TASK, &pmalloc)))
{
apSPrintf(sz, XSTR("%lX"), hresult);
apLogFailInfo(XSTR("ERROR:CoGetMalloc failed!!!"), XSTR("NOEEROR"), sz, XSTR(""));
}
m_fWantTrueSize = TRUE;
cbRequest = pmalloc->GetSize(pActual) - HEADERSIZE - TRAILERSIZE;
m_fWantTrueSize = FALSE;
pmalloc->Release();
if (MEMCMP(pActual, g_rgchHead, HEADERSIZE) != 0)
{
MEMCPY(sz, pActual, HEADERSIZE);
sz[HEADERSIZE] = 0;
apLogFailInfo(XSTR("32-bit Memory header not intact!"), g_rgchHead, sz, XSTR(""));
}
// set new trailer signature
MEMCPY((BYTE *)pActual+HEADERSIZE+cbRequest, g_rgchTail, TRAILERSIZE);
// save info for leak detection
AddInst((BYTE *)pActual+HEADERSIZE, cbRequest);
return (void *) (((BYTE *) pActual) + HEADERSIZE);
}
else
{
return pActual;
}
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PreGetSize
//
// Synopsis: Called prior to OLE calling IMalloc::GetSize
//
// Arguments: [pRequest] -- The buffer whose size is to be returned
// [fSpyed] -- Whether it was allocated with a spy active
//
// Returns: The actual buffer with which to call IMalloc::GetSize
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
void *CMallocSpy::PreGetSize(void *pRequest, BOOL fSpyed)
{
HeapCheck();
if (fSpyed && !m_fWantTrueSize)
{
return (void *) (((BYTE *) pRequest) - HEADERSIZE);
}
else
{
return pRequest;
}
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PostGetSize
//
// Synopsis: Called after OLE calls IMalloc::GetSize
//
// Arguments: [cbActual] -- The result of IMalloc::GetSize
// [fSpyed] -- Whether it was allocated with a spy active
//
// Returns: The size to return to the IMalloc::GetSize caller
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
SIZE_T CMallocSpy::PostGetSize(SIZE_T cbActual, BOOL fSpyed)
{
if (fSpyed && !m_fWantTrueSize)
{
return cbActual - HEADERSIZE - TRAILERSIZE;
}
else
{
return cbActual;
}
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PreDidAlloc
//
// Synopsis: Called prior to OLE calling IMalloc::DidAlloc
//
// Arguments: [pRequest] -- The buffer whose allocation is being tested
// [fSpyed] -- Whether it was allocated with a spy active
//
// Returns: The buffer whose allocation is actually to be tested
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
void *CMallocSpy::PreDidAlloc(void *pRequest, BOOL fSpyed)
{
HeapCheck();
if (fSpyed)
{
return (void *) (((BYTE *) pRequest) - HEADERSIZE);
}
else
{
return pRequest;
}
}
//+---------------------------------------------------------------------
//
// Function: PostDidAlloc
//
// Synopsis: Called after OLE calls the IMalloc::DidAlloc
//
// Arguments: [pRequest] -- The passed allocation
// [fSpyed] -- Whether it was allocated with a spy active
// [fActual] -- The result of IMalloc::DidAlloc
//
// Returns: The result of IMalloc::DidAlloc
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
BOOL CMallocSpy::PostDidAlloc(void * /*pRequest*/, BOOL /*fSpyed*/, BOOL fActual)
{
return fActual;
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PreHeapMinimize
//
// Synopsis: Called prior to OLE calling the IMalloc::HeapMinimize
//
// Returns:
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
void CMallocSpy::PreHeapMinimize(void)
{
HeapCheck();
return;
}
//+---------------------------------------------------------------------
//
// Member: CMallocSpy::PostHeapMinimize
//
// Synopsis: Called after OLE calls the IMalloc::HeapMinimize
//
// Returns:
//
// History: 24-Oct-94 Created.
//
// Notes:
//
//----------------------------------------------------------------------
void CMallocSpy::PostHeapMinimize(void)
{
return;
}
//---------------------------------------------------------------------
// Instance table methods
//---------------------------------------------------------------------
VOID CMallocSpy::MemInstance()
{
++m_cAllocCalls;
}
/***
*PRIVATE CMallocSpy::AddInst
*Purpose:
* Add the given instance to the address instance table.
*
*Entry:
* pv = the instance to add
* nAlloc = the allocation passcount of this instance
*
*Exit:
* None
*
***********************************************************************/
void
CMallocSpy::AddInst(void FAR* pv, SIZE_T cb)
{
ULONG nAlloc;
UINT hash;
CAddrNode32 FAR* pn;
MemInstance();
nAlloc = m_cAllocCalls;
// DebAssert(pv != NULL, "");
pn = (CAddrNode32 FAR*)new FAR CAddrNode32();
// DebAssert(pn != NULL, "");
pn->m_pv = pv;
pn->m_cb = cb;
pn->m_nAlloc = nAlloc;
hash = HashInst(pv);
pn->m_pnNext = m_rganode[hash];
m_rganode[hash] = pn;
}
/***
*PRIVATE CMallocSpy::DelInst(void*)
*Purpose:
* Remove the given instance from the address instance table.
*
*Entry:
* pv = the instance to remove
*
*Exit:
* None
*
***********************************************************************/
void
CMallocSpy::DelInst(void FAR* pv)
{
CAddrNode32 FAR* FAR* ppn, FAR* pnDead;
for(ppn = &m_rganode[HashInst(pv)]; *ppn != NULL; ppn = &(*ppn)->m_pnNext)
{
if((*ppn)->m_pv == pv)
{
pnDead = *ppn;
*ppn = (*ppn)->m_pnNext;
delete pnDead;
return;
}
}
// didnt find the instance
// DebAssert(FALSE, "memory instance not found");
}
CAddrNode32 FAR*
CMallocSpy::FindInst(void FAR* pv)
{
CAddrNode32 FAR* pn;
for(pn = m_rganode[HashInst(pv)]; pn != NULL; pn = pn->m_pnNext)
{
if(pn->m_pv == pv)
return pn;
}
return NULL;
}
void
CMallocSpy::DumpInst(CAddrNode32 FAR* pn)
{
XCHAR szActual[128];
apSPrintf(szActual, XSTR("Block of %ld bytes leaked in test"), pn->m_cb);
apLogFailInfo(XSTR("Memory leaked on release of 32-bit test allocator!"), XSTR("no leak"), szActual, XSTR(""));
// Printf("[%lp] nAlloc=0x%lx size=0x%lx\n", pn->m_pv, pn->m_nAlloc, pn->m_cb);
}
/***
*PRIVATE BOOL IsEmpty
*Purpose:
* Answer if the address instance table is empty.
*
*Entry:
* None
*
*Exit:
* return value = BOOL, TRUE if empty, FALSE otherwise
*
***********************************************************************/
BOOL
CMallocSpy::IsEmpty()
{
UINT u;
for(u = 0; u < DIM(m_rganode); ++u)
{
if(m_rganode[u] != NULL) return FALSE; // something leaked
}
return TRUE;
}
/***
*PRIVATE CMallocSpy::DumpInstTable()
*Purpose:
* Print the current contents of the address instance table,
*
*Entry:
* None
*
*Exit:
* None
*
***********************************************************************/
void
CMallocSpy::DumpInstTable()
{
UINT u;
CAddrNode32 FAR* pn;
for(u = 0; u < DIM(m_rganode); ++u)
{
for(pn = m_rganode[u]; pn != NULL; pn = pn->m_pnNext)
{
VerifyHeaderTrailer(pn);
DumpInst(pn);
}
}
}
/***
*PRIVATE void CMallocSpy::VerifyHeaderTrailer()
*Purpose:
* Inspect allocations for signature overwrites.
*
*Entry:
* None
*
*Exit:
* return value = None.
*
***********************************************************************/
VOID CMallocSpy::VerifyHeaderTrailer(CAddrNode32 FAR* pn)
{
XCHAR sz[50];
XCHAR sz2[100];
if (MEMCMP((char FAR*)pn->m_pv + pn->m_cb, g_rgchTail, TRAILERSIZE) != 0)
{
// DumpInst(pn);
MEMCPY(sz, (char FAR*)pn->m_pv + pn->m_cb, TRAILERSIZE);
sz[TRAILERSIZE] = 0;
apSPrintf(sz2, XSTR("32-bit memory trailer corrupt on alloc of %ld bytes"), pn->m_cb);
apLogFailInfo(sz2, g_rgchTail, sz, XSTR(""));
apEndTest();
}
if (MEMCMP((char FAR*)pn->m_pv - HEADERSIZE, g_rgchHead, HEADERSIZE) != 0)
{
// DumpInst(pn);
MEMCPY(sz, (char FAR*)pn->m_pv - HEADERSIZE, HEADERSIZE);
sz[HEADERSIZE] = 0;
apSPrintf(sz2, XSTR("32-bit memory header corrupt on alloc of %ld bytes"), pn->m_cb);
apLogFailInfo(sz2, g_rgchHead, sz, XSTR(""));
apEndTest();
}
}
/***
*PRIVATE void CMallocSpy::HeapCheck()
*Purpose:
* Inspect allocations for signature overwrites.
*
*Entry:
* None
*
*Exit:
* return value = None.
*
***********************************************************************/
VOID CMallocSpy::HeapCheck()
{
UINT u;
CAddrNode32 FAR* pn;
if (m_cHeapChecks++ < g_cHeapCheckInterval)
{
return;
}
m_cHeapChecks = 0; // reset
for (u = 0; u < DIM(m_rganode); ++u)
{
for (pn = m_rganode[u]; pn != NULL; pn = pn->m_pnNext)
{
VerifyHeaderTrailer(pn);
}
}
}
void
CMallocSpy::CheckForLeaks()
{
if (!IsEmpty())
{
DumpInstTable();
apEndTest(); // make sure a failure get recorded
}
}
//---------------------------------------------------------------------
// Helper routines
//---------------------------------------------------------------------
STDAPI GetMallocSpy(IMallocSpy FAR* FAR* ppmallocSpy)
{
*ppmallocSpy = &myMallocSpy;
return NOERROR;
}