|
|
//+---------------------------------------------------------------------------
//
// Microsoft Net Library System
// Copyright (C) Microsoft Corporation, 1996 - 1997.
//
// File: spy.cxx
//
// Contents: This file contains the implementation of the IMalloc Spy
// interface that uses the memory leak tracking stuff ported
// from Content Index to give stack traces of OLE memory
// allocations that are not freed. This class has been
// modified after copying from the TABLECOPY sample in oledb
// samples to make use of Content Index's heap tracking
// software.
//
// History: 10-05-97 srikants Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
/////////////////////////////////////////////////////////////////////////////
// Includes
//
/////////////////////////////////////////////////////////////////////////////
#include <spy.hxx>
#include <tracheap.h>
#include <alocdbg.hxx>
#if CIDBG==1 || DBG==1
DECLARE_DEBUG( heap ); #define heapDebugOut(x) heapInlineDebugOut x
/////////////////////////////////////////////////////////////////////////////
// Defines
//
/////////////////////////////////////////////////////////////////////////////
// AHeader + BUFFER + FOOTER
// FOOTER = TAILSIGNITURE
//All the header info must be ULONGs,
//so that the user buffer falls on a word boundary
//The tail must be a byte, since if it was a ULONG it would
//also require a word boundary, but the users buffer could
//be an odd number of bytes, so instead of rounding up, just use BYTE
const ULONG HEADSIZE = sizeof(AHeader); //HEADSIGNITURE
const ULONG TAILSIZE = sizeof(BYTE); //TAILSIGNITURE
const ULONG HEADERSIZE = ROUNDUP(HEADSIZE); const ULONG FOOTERSIZE = TAILSIZE;
const BYTE ALLOCSIGN = '$'; const BYTE FREESIGN = 'Z';
#define HEAD_OFFSET(pHeader) ((BYTE*)pHeader)
#define TAIL_OFFSET(pHeader) (USERS_OFFSET(pHeader)+ (AHeader *)pHeader->size)
#define USERS_OFFSET(pHeader) (HEAD_OFFSET(pHeader) + HEADERSIZE)
#define HEADER_OFFSET(pUserBuffer) ((BYTE*)(pUserBuffer) - HEADERSIZE)
#define TAIL_SIGNITURE(pHeader) (*(BYTE*)TAIL_OFFSET(pHeader))
static AllocArena * pAllocArena = (AllocArena *) -1;
/////////////////////////////////////////////////////////////////////////////
// CMallocSpy::CMallocSpy()
//
/////////////////////////////////////////////////////////////////////////////
CMallocSpy::CMallocSpy() : m_cRef( 1 ), // implicit AddRef()
m_cbRequest( 0 ) { }
/////////////////////////////////////////////////////////////////////////////
// CMallocSpy::~CMallocSpy()
//
/////////////////////////////////////////////////////////////////////////////
CMallocSpy::~CMallocSpy() { //Remove all the elements of the list
//CAllocList.RemoveAll();
}
/////////////////////////////////////////////////////////////////////////////
// BOOL CMallocSpy::Add
//
/////////////////////////////////////////////////////////////////////////////
BOOL CMallocSpy::Add(void* pv) { Win4Assert(pv);
//Add this element to the list
//CAllocList.AddTail(pv);
return TRUE; }
/////////////////////////////////////////////////////////////////////////////
// BOOL CMallocSpy::Remove
//
/////////////////////////////////////////////////////////////////////////////
BOOL CMallocSpy::Remove(void* pv) { Win4Assert(pv); //Remove this element from the list
//CAllocList.RemoveAt(CAllocList.Find(pv));
return TRUE; }
/////////////////////////////////////////////////////////////////////////////
// BOOL CMallocSpy::DumpLeaks
//
/////////////////////////////////////////////////////////////////////////////
BOOL CMallocSpy::DumpLeaks() { #if 0
ULONG ulTotalLeaked = 0;
//Display Leaks to the Output Window
while(!CAllocList.IsEmpty()) { //Obtain the pointer to the leaked memory
void* pUsersBuffer = CAllocList.RemoveHead(); Win4Assert(pUsersBuffer); void* pHeader = HEADER_OFFSET(pUsersBuffer); Win4Assert(pHeader);
//Make sure that the head/tail signitures are intact
if(HEAD_SIGNITURE(pHeader) != HEADSIGN) heapDebugOut((DEB_ERROR, "-- IMallocSpy HeadSigniture Corrupted! - 0x%08x, ID=%08lu, %lu bytes\n", pUsersBuffer, BUFFER_ID(pHeader), BUFFER_LENGTH(pHeader)));
if(TAIL_SIGNITURE(pHeader) != TAILSIGN) heapDebugOut((DEB_ERROR, "-- IMallocSpy TailSigniture Corrupted! - 0x%08x, ID=%08lu, %lu bytes\n", pUsersBuffer, BUFFER_ID(pHeader), BUFFER_LENGTH(pHeader)) );
ULONG ulSize = BUFFER_LENGTH(pHeader); ULONG ulID = BUFFER_ID(pHeader); heapDebugOut(( DEB_ERROR, "-- IMallocSpy LEAK! - 0x%08x, ID=%08lu, %lu bytes\n", pUsersBuffer, ulID, ulSize)); ulTotalLeaked += ulSize; }
if(ulTotalLeaked) heapDebugOut(( DEB_ERROR, "-- IMallocSpy Total LEAKED! - %lu bytes\n", ulTotalLeaked)); #endif // 0
return TRUE; }
/////////////////////////////////////////////////////////////////////////////
// HRESULT CMallocSpy::QueryInterface
//
/////////////////////////////////////////////////////////////////////////////
HRESULT CMallocSpy::QueryInterface(REFIID riid, void** ppIUnknown) { if(!ppIUnknown) return E_INVALIDARG; *ppIUnknown = NULL;
//IID_IUnknown
if(riid == IID_IUnknown) *ppIUnknown = this; //IDD_IMallocSpy
else if(riid == IID_IMallocSpy) *ppIUnknown = this; if(*ppIUnknown) { ((IUnknown*)*ppIUnknown)->AddRef(); return S_OK; }
return E_NOINTERFACE; }
/////////////////////////////////////////////////////////////////////////////
// ULONG CMallocSpy::AddRef
//
/////////////////////////////////////////////////////////////////////////////
ULONG CMallocSpy::AddRef() { return ++m_cRef; }
/////////////////////////////////////////////////////////////////////////////
// ULONG CMallocSpy::Release
//
/////////////////////////////////////////////////////////////////////////////
ULONG CMallocSpy::Release() { if(--m_cRef) return m_cRef;
heapDebugOut(( DEB_TRACE, "Releasing IMallocSpy\n" ));
delete this; return 0; }
/////////////////////////////////////////////////////////////////////////////
// ULONG CMallocSpy::PreAlloc
//
/////////////////////////////////////////////////////////////////////////////
SIZE_T CMallocSpy::PreAlloc(SIZE_T cbRequest) { //cbRequest is the orginal number of bytes requested by the user
//Store the users requested size
m_cbRequest = cbRequest;
//Return the total size requested, plus extra for header/footer
return (m_cbRequest + sizeof AHeader + 1); }
/////////////////////////////////////////////////////////////////////////////
// void* CMallocSpy::PostAlloc
//
/////////////////////////////////////////////////////////////////////////////
void* CMallocSpy::PostAlloc(void* pHeader) { //pHeader is the pointer to the head of the buffer, including the header
if (pHeader) { //Place the Size in the HEADER
((AHeader *)pHeader)->size = m_cbRequest; ((AHeader *)pHeader)->p = AllocArenaRecordAlloc( pAllocArena, m_cbRequest ); pHeader = (AHeader *)pHeader + 1;
//Place the TailSigniture in the HEADER
*((char *)pHeader + m_cbRequest ) = ALLOC_SIGNATURE;
//Set the UsersBuffer to a known char
memset(pHeader, ALLOCSIGN, m_cbRequest);
#ifdef FINDLEAKS
heapDebugOut((DEB_ITRACE, "-- IMallocSpy Alloc - 0x%08x, ID=%08lu, %lu bytes\n", pHeader, ulID, m_cbRequest)); #endif // FINDLEAKS
}
// Return the actual users buffer
return pHeader; }
/////////////////////////////////////////////////////////////////////////////
// void* CMallocSpy::PreFree
//
/////////////////////////////////////////////////////////////////////////////
void* CMallocSpy::PreFree(void* pUsersBuffer, BOOL fSpyed) { //pUsersBuffer is the users pointer to thier buffer, not the header
// Check for NULL
if(pUsersBuffer == NULL) return NULL;
//If this memory was alloced under IMallocSpy, need to remove it
if(fSpyed) { //Remove this pointer form the list
//Remove(pUsersBuffer);
AHeader *ap = (AHeader *)pUsersBuffer - 1;
switch( *((char *)pUsersBuffer + ap->size) ) { case ALLOC_SIGNATURE: break; case FREE_SIGNATURE: heapDebugOut((DEB_WARN, "Double deleted memory at %#x\n", pUsersBuffer )); AllocArenaDumpRecord( ap->p ); Win4Assert( !"Probable double delete" ); break; default: heapDebugOut((DEB_WARN, "Overrun memory at %#x\n", pUsersBuffer )); AllocArenaDumpRecord( ap->p ); Win4Assert( !"Probable overrun heap block" ); break; } *((char *)pUsersBuffer + ap->size) = FREE_SIGNATURE;
if ( 0 != ap->p ) AllocArenaRecordFree( ap->p, ap->size ); // memset( pUsersBuffer, FREESIGN, ap->size + HEADERSIZE );
pUsersBuffer = (void *) ap; }
//else
return pUsersBuffer; }
/////////////////////////////////////////////////////////////////////////////
// void CMallocSpy::PostFree
//
/////////////////////////////////////////////////////////////////////////////
void CMallocSpy::PostFree(BOOL fSpyed) { // Note the free or whatever
return; }
/////////////////////////////////////////////////////////////////////////////
// ULONG CMallocSpy::PreRealloc
//
/////////////////////////////////////////////////////////////////////////////
SIZE_T CMallocSpy::PreRealloc( void* pUsersBuffer, SIZE_T cbRequest, void** ppNewRequest, BOOL fSpyed) { Win4Assert(pUsersBuffer && ppNewRequest); //If this was alloced under IMallocSpy we need to adjust
//the size stored in the header
if(fSpyed) { AHeader *ap = (AHeader *)pUsersBuffer - 1;
//Find the start
*ppNewRequest = (void *) ap; //Store the new desired size
m_cbRequest = cbRequest; //Return the total size, including extra
return (m_cbRequest + sizeof AHeader + 1); }
//else
*ppNewRequest = pUsersBuffer; return cbRequest; }
/////////////////////////////////////////////////////////////////////////////
// void* CMallocSpy::PostRealloc
//
/////////////////////////////////////////////////////////////////////////////
void* CMallocSpy::PostRealloc(void* pHeader, BOOL fSpyed) { //If this buffer was alloced under IMallocSpy
if(fSpyed) {
AHeader *ap = (AHeader *)pHeader; void * pUsersBuffer = (AHeader *)pHeader + 1;
if ( m_cbRequest >= ap->size ) { switch( *((char *)pUsersBuffer + ap->size) ) { case ALLOC_SIGNATURE: break; case FREE_SIGNATURE: heapDebugOut((DEB_WARN, "Double deleted memory at %#x\n", pUsersBuffer )); AllocArenaDumpRecord( ap->p ); Win4Assert( !"Probable double delete" ); break; default: heapDebugOut((DEB_WARN, "Overrun memory at %#x\n", pUsersBuffer )); AllocArenaDumpRecord( ap->p ); Win4Assert( !"Probable overrun heap block" ); break; } } if ( 0 != ap->p ) AllocArenaRecordReAlloc( ap->p, ap->size, m_cbRequest );
ap->size = m_cbRequest;
// Position for the user's buffer.
pHeader = pUsersBuffer; //Place the TailSigniture in the HEADER
*((char *)pHeader + m_cbRequest ) = ALLOC_SIGNATURE; } //else
return pHeader; }
/////////////////////////////////////////////////////////////////////////////
// void* CMallocSpy::PreGetSize
//
/////////////////////////////////////////////////////////////////////////////
void* CMallocSpy::PreGetSize(void* pUsersBuffer, BOOL fSpyed) { if (fSpyed) { AHeader *ap = (AHeader *)pUsersBuffer - 1; return ap; }
return pUsersBuffer; }
/////////////////////////////////////////////////////////////////////////////
// ULONG CMallocSpy::PostGetSize
//
/////////////////////////////////////////////////////////////////////////////
SIZE_T CMallocSpy::PostGetSize(SIZE_T cbActual, BOOL fSpyed) { if (fSpyed) { return cbActual - HEADERSIZE - FOOTERSIZE; }
return cbActual; }
/////////////////////////////////////////////////////////////////////////////
// void* CMallocSpy::PreDidAlloc
//
/////////////////////////////////////////////////////////////////////////////
void* CMallocSpy::PreDidAlloc(void* pUsersBuffer, BOOL fSpyed) { if (fSpyed) { AHeader *ap = (AHeader *)pUsersBuffer - 1; return ap; }
return pUsersBuffer; }
/////////////////////////////////////////////////////////////////////////////
// BOOL CMallocSpy::PostDidAlloc
//
/////////////////////////////////////////////////////////////////////////////
BOOL CMallocSpy::PostDidAlloc(void* pRequest, BOOL fSpyed, BOOL fActual) { return fActual; }
/////////////////////////////////////////////////////////////////////////////
// void CMallocSpy::PreHeapMinimize
//
/////////////////////////////////////////////////////////////////////////////
void CMallocSpy::PreHeapMinimize() { // We don't do anything here
return; }
/////////////////////////////////////////////////////////////////////////////
// void CMallocSpy::PostHeapMinimize
//
/////////////////////////////////////////////////////////////////////////////
void CMallocSpy::PostHeapMinimize() { // We don't do anything here
return; }
/////////////////////////////////////////////////////////////////////////////
// Resgistration
//
/////////////////////////////////////////////////////////////////////////////
void MallocSpyRegister(CMallocSpy** ppCMallocSpy) { // CoInitializeEx(NULL, COINIT_MULTITHREADED);
Win4Assert(ppCMallocSpy);
// Win4Assert( !"Break In" );
//Allocate Interface
*ppCMallocSpy = new CMallocSpy(); //Constructor AddRef's
//Regisiter Interface
HRESULT hr = CoRegisterMallocSpy(*ppCMallocSpy); // Does an AddRef on Object
heapDebugOut(( DEB_WARN, "CoRegisterMallocSpy returned 0x%X\n", hr ));
if ( FAILED(hr) ) { (*ppCMallocSpy)->Release(); *ppCMallocSpy = 0; return; }
Win4Assert( pAllocArena == (AllocArena *) -1 ); if ( pAllocArena == (AllocArena *) -1 ) { pAllocArena = AllocArenaCreate( MEMCTX_TASK, "IMalloc allocator"); // atexit( HeapExit );
}
// CoUninitialize();
}
void MallocSpyUnRegister(CMallocSpy* pCMallocSpy) { // CoInitializeEx(NULL, COINIT_MULTITHREADED);
// Win4Assert();
CoRevokeMallocSpy(); //Does a Release on Object
// CoUninitialize();
}
void MallocSpyDump(CMallocSpy* pCMallocSpy) { Win4Assert(pCMallocSpy); pCMallocSpy->DumpLeaks(); }
#else
void MallocSpyRegister(CMallocSpy** ppCMallocSpy) { return; }; void MallocSpyUnRegister(CMallocSpy* pCMallocSpy) { return; }; void MallocSpyDump(CMallocSpy* pCMallocSpy) { return; };
#endif //CIDBG==1 || DBG==1
|