931 lines
21 KiB
C++
931 lines
21 KiB
C++
#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;
|
|
}
|