|
|
//////////////////////////////////////////////////////
#include <comdef.h>
#include "..\jcomheap\jcomheap.h"
#include <tchar.h>
#include <crtdbg.h>
//
//#ifdef _DEBUG
//#define DBG_NEW new(_NORMAL_BLOCK,__FILE__,__LINE__)
//#define new DBG_NEW
//#endif
void test_empty()
{
CoInitialize(0);
jComHeap* ch = new jComHeap;
ch->Init();
CoUninitialize();
ch->Report(__FILE__, __LINE__);
delete ch;
}
void test_1alloc0free()
{
CoInitialize(0);
jComHeap* ch = new jComHeap;
ch->Init();
void *p = CoTaskMemAlloc(128);
CoUninitialize();
ch->Report(__FILE__, __LINE__);
delete ch;
}
void test_1alloc1free()
{
CoInitialize(0);
jComHeap* ch = new jComHeap;
ch->Init();
void *p = CoTaskMemAlloc(128);
CoTaskMemFree(p);
CoUninitialize();
ch->Report(__FILE__, __LINE__);
delete ch;
}
void test_2alloc1free()
{
CoInitialize(0);
jComHeap* ch = new jComHeap;
ch->Init();
void *p = CoTaskMemAlloc(128);
p = CoTaskMemAlloc(28);
CoTaskMemFree(p);
CoUninitialize();
ch->Report(__FILE__, __LINE__);
delete ch;
}
void test_1alloc1realloc1free()
{
CoInitialize(0);
jComHeap* ch = new jComHeap;
ch->Init();
void *p = CoTaskMemAlloc(128);
p = CoTaskMemRealloc(p, 5001);
CoTaskMemFree(p);
CoUninitialize();
ch->Report(__FILE__, __LINE__);
delete ch;
}
void test_1alloc1realloc0free()
{
CoInitialize(0);
jComHeap* ch = new jComHeap;
ch->Init();
void *p = CoTaskMemAlloc(128);
p = CoTaskMemRealloc(p, 5000);
CoUninitialize();
ch->Report(__FILE__, __LINE__);
delete ch;
}
void test_1bstr1free()
{
CoInitialize(0);
jComHeap* ch = new jComHeap;
ch->Init();
BSTR bstr = SysAllocString(L"bob");
SysFreeString(bstr);
CoUninitialize();
ch->Report(__FILE__, __LINE__);
delete ch;
}
void test_1bstr0free()
{
CoInitialize(0);
jComHeap* ch = new jComHeap;
ch->Init();
BSTR bstr = SysAllocString(L"bob");
CoUninitialize();
ch->Report(__FILE__, __LINE__);
delete ch;
}
void test_1bstr1realloc1free()
{
CoInitialize(0);
jComHeap* ch = new jComHeap;
ch->Init();
BSTR bstr = SysAllocString(L"bob");
SysReAllocStringLen(&bstr, L"ted", 21); //actual alloc is 48 bytes (2 * 21 rounded to the next 16 byte paragraph)
SysFreeString(bstr);
CoUninitialize();
ch->Report(__FILE__, __LINE__);
delete ch;
}
void test_1bstr1realloc0free()
{
CoInitialize(0);
jComHeap* ch = new jComHeap;
ch->Init();
BSTR bstr = SysAllocString(L"bob");
SysReAllocStringLen(&bstr, L"ted", 21); //actual alloc is 48 bytes (2 * 21 rounded to the next 16 byte paragraph)
CoUninitialize();
ch->Report(__FILE__, __LINE__);
delete ch;
}
int main()
{
//set the memory leak dump at the end of the exe run.
#ifdef _DEBUG
int flag;
flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
flag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(flag);
_CrtSetBreakAlloc(-1);
// int* x = new int;
#endif
test_1bstr1free();
test_1alloc1realloc1free();
test_1alloc1free();
test_1bstr1realloc1free();
test_empty();
//leaks from here on; only 1 leak allowed!
//test_1alloc0free();
//test_2alloc1free();
//test_1alloc1realloc0free();
//test_1bstr0free();
test_1bstr1realloc0free();
//untested:
// // occasionally use a bad ptr, potentially corrupting the heap
// DWORD *pdw = LPDWORD(p) + 10;
// *(--pdw) = 12;
// while (pdw >= LPDWORD(p)); // highly defective statement!
return 0;
}
|
|
|
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\arrizza\Debug]
"jComHeap"=dword:00000002
|
|
|
#pragma warning(disable: 4786) //identifier was truncated to '255' characters in the debug info
#include <crtdbg.h>
#include "common.h"
#include "allocationmap.h"
#pragma warning(disable: 4291) //xxx : no matching operator delete found;
void AllocationMap::ClearAll()
{
ALLOCINFOP ai;
for (iterator p = begin(); p != end(); p++)
{
ai =(*p).second;
_ASSERTE(ai);
destroymem(ai);
}
clear();
}
ALLOCINFOP AllocationMap::Add(unsigned long size, void* pAdjusted, AllocNumberHandler& allocnum)
{
ALLOCINFOP ai = (*this)[pAdjusted];
if (ai == 0)
{
ai = new (0,0) ALLOCINFO(size, pAdjusted, allocnum);
(*this)[pAdjusted] = ai;
}
else
ai->ResetAlloc(size, pAdjusted, allocnum);
return ai;
}
ALLOCINFOP AllocationMap::FreeRequest(void* pRequest)
{
ALLOCINFOP ai = (*this)[pRequest];
if (ai == 0)
HeapTrace(_T("ERROR! Free: has not been allocated: 0X%p\n"), pRequest);
else
ai->SetFree();
return ai;
}
|
|
|
#pragma once
#include <map>
#include <functional>
using std::less;
using std::map;
#include "allocinfo.h"
#include "allocator.h"
#include "allocnumberhandler.h"
typedef map<const void*, ALLOCINFOP, less<const void*>, MyAllocator > BaseMap;
class AllocationMap : public BaseMap
{
public:
void ClearAll();
ALLOCINFOP Add(unsigned long size, void* pAdjusted, AllocNumberHandler& allocnum);
ALLOCINFOP FreeRequest(void* pRequest);
};
|
|
|
#include "allocator.h"
#include "common.h"
using namespace std;
char* MyAllocator::_Charalloc(size_type _N)
{
return (char*) new (0,0) char[_N];
}
MyAllocator::pointer MyAllocator::allocate(size_type _N, const void *)
{
return (pointer) new (0,0) char [_N * sizeof(value_type)];
}
void MyAllocator::construct(pointer _P, const_reference _V)
{
new ((void *)_P) value_type(_V);
}
void MyAllocator::deallocate(void *_P, size_type)
{
//destroymem(_P);
}
void MyAllocator::destroy(pointer _P)
{
deallocate(_P , 0);
}
|
|
|
#pragma once
#include "allocinfo.h"
#include <memory>
using std::allocator;
//------------------
//-- used to allocate map memory on to a separate heap
class MyAllocator : public allocator<ALLOCINFOP>
{
public:
char * _Charalloc(size_type _N);
pointer allocate(size_type _N, const void *);
void construct(pointer _P, const_reference _V);
void deallocate(void *_P, size_type);
void destroy(pointer _P);
} ;
|
|
|
//#define WIN32_LEAN_AND_MEAN
//#include <windows.h>
#include <crtdbg.h>
#include "allocinfo.h"
ALLOCINFO::ALLOCINFO(unsigned long lastalloc, void* v, unsigned long allocnum)
: inuse(false), numallocs(0), numfrees(0), size(0), val(0), allocnumber(0)
{
ResetAlloc(lastalloc, v, allocnum);
}
void ALLOCINFO::ResetAlloc(unsigned long lastalloc, void* v, unsigned long allocnum)
{
_ASSERTE(!inuse && "alloced memory is already in use");
numallocs++;
inuse = true;
size = lastalloc;
val = v;
allocnumber = allocnum;
}
void ALLOCINFO::SetFree()
{
_ASSERTE(inuse && "memory was not in use");
inuse = false;
numfrees++;
}
|
|
|
#pragma once
//---------
//-- contains individual node information
class ALLOCINFO
{
public:
ALLOCINFO(unsigned long lastalloc, void* v, unsigned long allocnum);
void ResetAlloc(unsigned long lastalloc, void* v, unsigned long allocnum);
void SetFree();
bool inuse;
unsigned long numallocs;
unsigned long numfrees;
unsigned long size;
void* val;
unsigned long allocnumber;
private:
ALLOCINFO(); //no default ctor
ALLOCINFO(const ALLOCINFO&); //no copy ctor
} ;
typedef ALLOCINFO* ALLOCINFOP;
|
|
|
#include "allocnumberhandler.h"
AllocNumberHandler::AllocNumberHandler()
: m_BreakAllocNumber(-1), m_lAllocNumber(0)
{
}
AllocNumberHandler::operator unsigned long ()
{
return m_lAllocNumber;
}
void AllocNumberHandler::Increment()
{
m_lAllocNumber++;
if (m_lAllocNumber == m_BreakAllocNumber)
{
_asm int 3;
}
}
void AllocNumberHandler::BreakOn(unsigned long num)
{
m_BreakAllocNumber = num;
}
|
|
|
#pragma once
class AllocNumberHandler
{
public:
AllocNumberHandler();
operator unsigned long ();
void Increment();
void BreakOn(unsigned long num);
private:
unsigned long m_BreakAllocNumber;
unsigned long m_lAllocNumber; //the current allocation number
} ;
|
|
|
#include <crtdbg.h>
#include "arenaheader.h"
const unsigned long SIGNATURE = 0x1BADABBAL;
//------------------------------------------------------------------------
// write signature and alloc size
void ArenaHeader::Set(void *ptr, unsigned long dwAllocSize)
{
if (ptr == 0) return;
ArenaHeader& arena = *((ArenaHeader *)ptr);
arena.m_dwSignature = SIGNATURE;
arena.m_dwAllocSize = dwAllocSize;
}
// helper function to verify and return the prepended
// header (or null if failure)
ArenaHeader* ArenaHeader::Get(void *ptr)
{
ArenaHeader *result = 0;
if (ptr)
{
result = (ArenaHeader *)((char*)ptr - Size());
_ASSERTE(result->m_dwSignature == SIGNATURE && "The heap is corrupted");
}
return result;
}
unsigned long ArenaHeader::Size()
{
return sizeof(ArenaHeader);
}
|
|
|
#pragma once
struct ArenaHeader
{
static void Set(void *ptr, unsigned long dwAllocSize);
static ArenaHeader* Get(void *ptr);
static unsigned long Size();
unsigned long m_dwAllocSize;
private:
unsigned long m_dwSignature;
};
|
|
|
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
#include <crtdbg.h>
#include "comheapregistry.h"
static const TCHAR* const HeapKey = _T("jComHeap");
static const TCHAR* const DebugKey = _T("SOFTWARE\\arrizza\\Debug");
class HDRegistry::Private
{
public:
HKEY hKey;
DWORD dwCount;
DWORD dwValue;
} ;
HDRegistry::HDRegistry() : impl(* new HDRegistry::Private())
{
Init();
}
HDRegistry::~HDRegistry()
{
RegCloseKey(impl.hKey);
delete &impl;
}
int HDRegistry::GetOption()
{
impl.dwCount = sizeof(DWORD);
DWORD dwType = 0;
impl.dwValue = 0;
LONG rc = RegQueryValueEx(impl.hKey,
HeapKey,
0,
&dwType,
(PBYTE)&impl.dwValue,
&impl.dwCount);
if (rc != ERROR_SUCCESS)
SetOptionKey();
return (int) impl.dwValue;
}
void HDRegistry::Init()
{
impl.dwCount = 0;
LONG rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
DebugKey,
0,
0,
REG_OPTION_NON_VOLATILE,
KEY_WRITE|KEY_READ,
0,
&impl.hKey,
&impl.dwCount);
_ASSERTE(rc == ERROR_SUCCESS);
}
void HDRegistry::SetOptionKey()
{
impl.dwValue = 0;
//trace mask is not there so set up a default value of 0
LONG rc = RegSetValueEx(impl.hKey,
HeapKey,
NULL,
REG_DWORD,
(LPBYTE)&impl.dwValue,
sizeof(impl.dwValue));
_ASSERTE(rc == ERROR_SUCCESS);
}
|
|
|
#pragma once
class HDRegistry
{
public:
HDRegistry();
~HDRegistry();
int GetOption();
private:
void Init();
void SetOptionKey();
private:
class Private;
Private& impl;
} ;
|
|
|
#include <crtdbg.h>
#pragma warning(disable: 4786) //identifier was truncated to '255' characters in the debug info
#include "comheapspy.h"
#include "allocinfo.h"
#include "common.h"
#include "reporter.h"
#include "arenaheader.h"
#include "allocnumberhandler.h"
class ComHeapSpy::Private
{
public:
Private(bool sumonly)
{
Reset();
mReporter.SummaryOnly(sumonly);
}
AllocNumberHandler AllocNumber; //a property??
void Free(void* p)
{
mReporter.ReportFree(mMap.FreeRequest(p));
}
void Alloc(void* pActual, void* pAdjusted)
{
AllocNumber.Increment();
mReporter.ReportAlloc(mMap.Add(m_cbLastAlloc, pAdjusted, AllocNumber), pActual);
}
void Realloc(void* pOriginal, void* pActual, void* pAdjusted)
{
Free(pOriginal);
AllocNumber.Increment();
mReporter.ReportRealloc(mMap.Add(m_cbLastAlloc, pAdjusted, AllocNumber), pActual, m_pvLastRealloc);
}
void Reset()
{
m_cbLastAlloc = 0;
m_pvLastRealloc = 0;
mMap.ClearAll();
}
void Report(const char* fname, long lineno)
{
mReporter.Set(fname, lineno);
mReporter.ReportOn(mMap);
}
void Summary(const char* fname, long lineno)
{
mReporter.Set(fname, lineno);
mReporter.SummaryOf(mMap);
}
unsigned long m_cbLastAlloc; //size of last allocation
void* m_pvLastAlloc; //pointer to last realloced memory
void* m_pvLastRealloc; //pointer to last realloced memory
private:
Reporter mReporter;
AllocationMap mMap;
bool m_summaryonly; //flag indicates whether to print individual allocs/frees
} ;
//------------------------------------------------------------------------
// initialize data members
ComHeapSpy::ComHeapSpy(bool sumonly)
: impl(* new ComHeapSpy::Private(sumonly))
{
Reset();
}
//------------------------------------------------------------------------
ComHeapSpy::~ComHeapSpy()
{
delete &impl;
}
void ComHeapSpy::BreakOnAllocNumber(unsigned long num)
{
impl.AllocNumber.BreakOn(num);
}
//------------------------------------------------------------------------
HRESULT ComHeapSpy::Revoke()
{
return ::CoRevokeMallocSpy();
}
//------------------------------------------------------------------------
HRESULT ComHeapSpy::Register()
{
return ::CoRegisterMallocSpy(this);
}
//------------------------------------------------------------------------
void ComHeapSpy::Reset()
{
impl.Reset();
}
//------------------------------------------------------------------------
//-- report any leaks
void ComHeapSpy::Report(const char* fname, long lineno)
{
impl.Report(fname, lineno);
}
//------------------------------------------------------------------------
void ComHeapSpy::Summary(const char* fname, long lineno)
{
impl.Summary(fname, lineno);
}
// IUnknown Methods ////////////////////
//------------------------------------------------------------------------
STDMETHODIMP ComHeapSpy::QueryInterface(REFIID riid, void**ppv)
{
if (riid == IID_IUnknown || riid == IID_IMallocSpy)
LPUNKNOWN(*ppv = (IMallocSpy*)this)->AddRef();
else
*ppv = 0;
return ResultFromScode(*ppv ? S_OK : E_NOINTERFACE);
}
//------------------------------------------------------------------------
// this object is global and doesn't hold server, so punt
STDMETHODIMP_(ULONG) ComHeapSpy::AddRef()
{
return 1;
}
//------------------------------------------------------------------------
STDMETHODIMP_(ULONG) ComHeapSpy::Release()
{
return 0;
}
// IMallocSpy Methods //////////////////
//------------------------------------------------------------------------
// PreAlloc reserves space for our arena header
//
STDMETHODIMP_(ULONG) ComHeapSpy::PreAlloc(ULONG cbRequest)
{
impl.m_cbLastAlloc = cbRequest;
return cbRequest + ArenaHeader::Size();
}
//------------------------------------------------------------------------
// PostAlloc writes the arena header and updates the alloc count
STDMETHODIMP_(void*) ComHeapSpy::PostAlloc(void *pActual)
{
LPBYTE pAdjusted = LPBYTE(pActual);
if (pActual) // alloc succeeded
{
// write arena header
ArenaHeader::Set(pActual, impl.m_cbLastAlloc);
pAdjusted += ArenaHeader::Size();
impl.Alloc(pActual, pAdjusted);
}
return pAdjusted;
}
//------------------------------------------------------------------------
// PreFree verifies the header, and adjusts the alloc count
STDMETHODIMP_(void*) ComHeapSpy::PreFree(void *pRequest, BOOL fSpyed)
{
LPBYTE pAdjusted = LPBYTE(pRequest);
if (pRequest && fSpyed) // it is definitely ours
{
ArenaHeader *phdr = ArenaHeader::Get(pRequest);
pAdjusted -= ArenaHeader::Size();
impl.Free(pRequest);
}
return pAdjusted;
}
//------------------------------------------------------------------------
// PostFree gets called after the task allocator overwrites
// our block, so there is very little we can do
STDMETHODIMP_(void) ComHeapSpy::PostFree(BOOL fSpyed)
{
}
//------------------------------------------------------------------------
// PreRealloc must verify the header, subtract the old size
// from the alloc count, and cache the arguments for PostRealloc
STDMETHODIMP_(ULONG) ComHeapSpy::PreRealloc(void *pRequest, ULONG cbRequest,
void **ppNewRequest, BOOL fSpyed)
{
LPBYTE pNewRequest = LPBYTE(pRequest);
if (fSpyed) // it is ours
{
// cache the pointer for PostRealloc
impl.m_pvLastRealloc = pRequest;
impl.m_cbLastAlloc = cbRequest;
cbRequest += ArenaHeader::Size();
if (pRequest) // genuine realloc
pNewRequest -= ArenaHeader::Size();
}
*ppNewRequest = pNewRequest;
return cbRequest;
}
//------------------------------------------------------------------------
// Post realloc must adjust the alloc count and write the
// new arena header if succeeded
STDMETHODIMP_(void*) ComHeapSpy::PostRealloc(void *pActual, BOOL fSpyed)
{
LPBYTE pAdjusted = LPBYTE(pActual);
if (!fSpyed) return pAdjusted;
if (pActual == 0) return pAdjusted;
ArenaHeader::Set(pActual, impl.m_cbLastAlloc);
pAdjusted += ArenaHeader::Size();
impl.Realloc(impl.m_pvLastRealloc, pActual, pAdjusted);
return pAdjusted;
}
//------------------------------------------------------------------------
// PreGetSize simply needs to shear off and verify the header
STDMETHODIMP_(void*) ComHeapSpy::PreGetSize(void *pRequest, BOOL fSpyed)
{
LPBYTE pAdjusted = LPBYTE(pRequest);
if (fSpyed && pRequest && ArenaHeader::Get(pRequest)) // it is ours and valid
pAdjusted -= ArenaHeader::Size();
return pAdjusted;
}
//------------------------------------------------------------------------
// PostGetSize adjusts the size reported by ArenaHeader::Size()
STDMETHODIMP_(ULONG) ComHeapSpy::PostGetSize(ULONG cbActual, BOOL fSpyed)
{
return fSpyed ? (cbActual - ArenaHeader::Size()) : cbActual;
}
//------------------------------------------------------------------------
// PreDidAlloc simply needs to shear off and verify the header
STDMETHODIMP_(void*) ComHeapSpy::PreDidAlloc(void *pRequest, BOOL fSpyed)
{
LPBYTE pAdjusted = LPBYTE(pRequest);
if (fSpyed && pRequest && ArenaHeader::Get(pRequest)) // it is ours and valid
pAdjusted -= ArenaHeader::Size(); // adjust pAdjusted pointer
return pAdjusted;
}
//------------------------------------------------------------------------
STDMETHODIMP_(int) ComHeapSpy::PostDidAlloc(void *pRequest, BOOL fSpyed, int fActual)
{
return fActual;
}
//------------------------------------------------------------------------
STDMETHODIMP_(void) ComHeapSpy::PreHeapMinimize(void)
{
}
//------------------------------------------------------------------------
STDMETHODIMP_(void) ComHeapSpy::PostHeapMinimize(void)
{
}
|
|
|
#pragma once
#include <comdef.h>
//----------------------------------------------------------------------
//-- the extension of the IMallocSpy callback
class ComHeapSpy : public IMallocSpy
{
public:
virtual ~ComHeapSpy();
ComHeapSpy(bool sum);
HRESULT Register();
HRESULT Revoke();
void Reset();
void BreakOnAllocNumber(unsigned long num);
void Report(const char* fname, long lineno);
void Summary(const char* fname, long lineno);
private:
ComHeapSpy(); //no default ctor
ComHeapSpy(const ComHeapSpy&); //no copy
ComHeapSpy& operator=(const ComHeapSpy&); //no assignment
class Private;
Private& impl;
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, void**ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IMallocSpy methods
STDMETHODIMP_(ULONG) PreAlloc(ULONG cbRequest);
STDMETHODIMP_(void*) PostAlloc(void *pActual);
STDMETHODIMP_(void*) PreFree(void *pRequest, BOOL fSpyed);
STDMETHODIMP_(void) PostFree(BOOL fSpyed);
STDMETHODIMP_(ULONG) PreRealloc(void *pRequest, ULONG cbRequest, void **ppNewRequest, BOOL fSpyed);
STDMETHODIMP_(void*) PostRealloc(void *pActual, BOOL fSpyed);
STDMETHODIMP_(void*) PreGetSize(void *pRequest, BOOL fSpyed);
STDMETHODIMP_(ULONG) PostGetSize(ULONG cbActual, BOOL fSpyed);
STDMETHODIMP_(void*) PreDidAlloc(void *pRequest, BOOL fSpyed);
STDMETHODIMP_(int) PostDidAlloc(void *pRequest, BOOL fSpyed, int fActual);
STDMETHODIMP_(void) PreHeapMinimize(void);
STDMETHODIMP_(void) PostHeapMinimize(void);
};
|
|
|
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <crtdbg.h>
#include <tchar.h>
#include <stdio.h>
#include "common.h"
//----------------------------------------------------------------------
//-- use this new to get all comheap allocations into the private heap
//-- typical call is new (0,0) xxx
//-- putting all heapdet. memory onto a private heap keeps it from showing up
//-- on the crtdbg reports
static HANDLE _ghHeap = 0;
void* operator new(size_t size, void*, int)
{
if (_ghHeap == 0)
{
_ghHeap = HeapCreate(0, 65535, 0);
_ASSERTE(_ghHeap);
}
_ASSERTE(size >= 0);
if (size < 0)
size = 0;
return HeapAlloc(_ghHeap, 0, size);
}
//----------------------------------------------------------------------
//-- frees the memory
void destroymem(void *p)
{
if (!p) return;
_ASSERTE(_ghHeap);
BOOL wrc = HeapFree(_ghHeap, 0, p);
_ASSERTE(wrc);
}
//----------------------------------------------------------------------
//-- the common trace line facility
void HeapTrace(LPCTSTR lpszFormat, ...)
{
static int count = 0;
va_list args;
va_start(args, lpszFormat);
TCHAR szBuffer[2048];
int nBuf = _vstprintf(szBuffer, lpszFormat, args);
_ASSERTE(nBuf < sizeof(szBuffer)/sizeof(TCHAR));
OutputDebugString(szBuffer);
va_end(args);
//OutputDebugString has trouble with large volumes of lines
//doing a context switch every so often seems to help
count++;
if (count > 100)
{
Sleep(1);
count = 0;
}
}
|
|
|
#pragma once
#include <tchar.h>
//----------------------------------------------------------------------
//-- use this new to get all comheap allocations into the private heap
//-- typical call is new (0,0) xxx
//-- putting all heapdet. memory onto a private heap keeps it from showing up
//-- on the crtdbg reports
void* operator new(size_t size, void*, int);
void destroymem(void *p);
//----------------------------------------------------------------------
//-- the common trace line facility
void HeapTrace(const TCHAR* const lpszFormat, ...);
|
|
|
//////////////////////////////////////////////////////
//
// HeapDet.cpp - Copyright 1995, Don Box
// modifications and additions by John Arrizza
//
// Simple IMallocSpy to track allocation byte count
#include <crtdbg.h>
#include "jcomheap.h"
#include "comheapregistry.h"
#include "common.h"
#include "comheapspy.h"
#pragma warning(disable: 4291) //no matching operator delete found
//------------------------------------------------------------------------
class jComHeap::CHState
{
public:
bool traceit;
ComHeapSpy* spy;
CHState() : traceit(false), sumonly(false), spy(0)
{
}
~CHState()
{
if (spy == 0) return;
if (spy->Revoke() == S_OK)
{
spy->~ComHeapSpy();
destroymem(spy);
}
spy = 0;
}
void Init()
{
GetOptionsFromRegistry();
if (!traceit) return;
// declare a spy object and register it
if (!spy)
CreateCoComHeap();
spy->Reset();
}
private:
bool sumonly;
void GetOptionsFromRegistry()
{
traceit = false; //be pessimistic
sumonly = false;
#ifdef _DEBUG
HDRegistry reg;
DWORD val = reg.GetOption();
if (val == 0)
return;
traceit = true;
if (val == 1)
sumonly = true;
#endif
}
void CreateCoComHeap()
{
spy = new (0, 0) ComHeapSpy(sumonly);
_ASSERTE(spy);
spy->Register();
}
} ;
//------------------------------------------------------------------------
jComHeap::jComHeap()
: m_state(* new (0,0) jComHeap::CHState)
{
}
//------------------------------------------------------------------------
jComHeap::~jComHeap()
{
m_state.~CHState();
}
//------------------------------------------------------------------------
void jComHeap::Init()
{
m_state.Init();
}
//------------------------------------------------------------------------
void jComHeap::Report(const char* fname, long lineno)
{
if (!m_state.traceit) return;
_ASSERTE(m_state.spy);
m_state.spy->Report(fname, lineno);
}
//------------------------------------------------------------------------
void jComHeap::Summary(const char* fname, long lineno)
{
if (!m_state.traceit) return;
_ASSERTE(m_state.spy);
m_state.spy->Summary(fname, lineno);
}
//------------------------------------------------------------------------
void jComHeap::Clear()
{
if (!m_state.traceit) return;
_ASSERTE(m_state.spy);
m_state.spy->Reset();
}
void jComHeap::BreakOnAllocNumber(long num)
{
_ASSERTE(m_state.spy);
m_state.spy->BreakOnAllocNumber(num);
}
|
|
|
//////////////////////////////////////////////////////
// Original code Copyright 1995, Don Box
// modified by John Arrizza
#pragma once
#pragma comment(lib, "jComHeap.lib")
class jComHeap
{
public:
jComHeap();
~jComHeap();
void Init();
void Report(const char *fname, long lineno); //all outstanding mem allocs
void Summary(const char *fname, long lineno); //just the totals
void Clear();
void BreakOnAllocNumber(long num);
private:
jComHeap& operator=(const jComHeap& ); //not allowed
jComHeap(const jComHeap&); //not allowed
class CHState;
CHState& m_state;
} ;
|
|
|
#pragma warning(disable: 4786) //identifier was truncated to '255' characters in the debug info
#include <algorithm>
using std::sort;
#include "common.h"
#include "reporter.h"
#include "allocationmap.h"
Reporter::Reporter()
{
mSummaryOnly = false;
}
void Reporter::Set(const char* f, long l)
{
fname = f;
lineno = l;
}
void Reporter::SummaryOnly(bool sumonly)
{
mSummaryOnly = sumonly;
}
void Reporter::ReportOn(AllocationMap& H)
{
IterateOver(H);
WritePrefix();
if (mStats.IsNoLeaks())
{
WriteNoLeaksFound();
return;
}
WriteLeakMessage();
ReportLeaks(H);
HeapTrace(_T("jComHeap: Report -------- Done\n"));
}
void Reporter::SummaryOf(AllocationMap& H)
{
IterateOver(H);
WritePrefix();
if (mStats.IsNoLeaks())
WriteNoLeaksFound();
else
WriteLeakMessage();
}
void Reporter::WritePrefix()
{
HeapTrace(_T("%s(%ld) : jComHeap: "), fname, lineno);
}
void Reporter::WriteNoLeaksFound(bool writetotals)
{
HeapTrace(_T("no leaks found. "));
if (writetotals)
mStats.Report();
HeapTrace(_T("\n"));
}
void Reporter::WriteLeakMessage()
{
HeapTrace(_T("LEAKS! "));
mStats.Report();
HeapTrace(_T("\n"));
}
void Reporter::CopyTo(AllocationMap& H, VEC& v)
{
for(AllocationMap::iterator p = H.begin(); p != H.end(); p++)
v.push_back((*p).second);
}
void Reporter::Sort(VEC& v)
{
//sort the vector by allocation number
sort(v.begin(), v.end(), local_less());
}
void Reporter::ReportLeaks(AllocationMap& H)
{
//since the map can't be sorted, create a vector from the map
VEC v;
CopyTo(H, v);
Sort(v);
IterateOver(v);
}
void Reporter::IterateOver(VEC& v)
{
mStats.Reset();
for(VEC::iterator it = v.begin(); it != v.end(); ++it)
{
VEC::value_type ai = *it;
if (!ai) continue;
if(ai->inuse)
ReportUnfreedBlock(ai);
mStats.BumpTotals(ai);
}
}
void Reporter::IterateOver(AllocationMap& H)
{
mStats.Reset();
for(AllocationMap::iterator it = H.begin(); it != H.end(); ++it)
{
ALLOCINFOP ai =(*it).second;
if(!ai) continue;
if(ai->inuse)
mStats.BumpUnfreed(ai);
mStats.BumpTotals(ai);
}
}
void Reporter::ReportUnfreedBlock(ALLOCINFOP ai)
{
HeapTrace(_T("----- [%6ld] alloc: 0x%p size=%ld bytes \n"),
(long) ai->allocnumber, ai->val, ai->size);
TCHAR widebuf[200] = _T("");
TCHAR bytebuf[200] = _T("");
long bstrlen = 0;
PrintToBuffers(ai, bytebuf, widebuf, bstrlen);
HeapTrace(_T("----- as Data: %s\n"), bytebuf);
HeapTrace(_T("----- as bstr: len=%-4ld bytes <%s>\n"), bstrlen, widebuf);
mStats.BumpUnfreed(ai);
}
void Reporter::PrintToBuffers(ALLOCINFOP ai, TCHAR* bytebuf, TCHAR* widebuf, long& bstrlen)
{
char* b;
unsigned int i;
//save up to 160 bytes of info into the buffers
for(i = 0, b = (char*)ai->val; i < 160 && i < 1 + ai->size; i++, b++)
{
//save the memory as raw data
if(i < 30)
_stprintf(&bytebuf[_tcslen(bytebuf)], _T("%02.2X "), (*b) & 0xFF);
//save the memory as wide chars
if(i >= 4 && i % 2 == 0 && i < (ai->size + 1 - 4))
_stprintf(&widebuf[_tcslen(widebuf)], _T("%C"), _istprint(*b) ? *b : 0x0001);
}
bstrlen = *((long *)ai->val);
}
void Reporter::ReportAlloc(ALLOCINFOP ai, void* pActual)
{
if (mSummaryOnly) return;
HeapTrace(_T("jComHeap:: Alloc {%6ld} %s at 0X%p, %5u bytes\n"),
(long) ai->allocnumber, (pActual != 0 ? _T("succeeded") : _T("failed")),
ai->val, ai->size);
}
void Reporter::ReportRealloc(ALLOCINFOP ai, void* pActual, void* pOriginal)
{
if (mSummaryOnly) return;
HeapTrace(_T("jComHeap:: Realloc{%6ld} %s at 0X%p, %5u bytes (old ptr 0X%p)\n"),
(long) ai->allocnumber,
(pActual != 0 ? _T("succeeded") : _T("failed")),
ai->val, ai->size,
pOriginal);
}
void Reporter::ReportFree(ALLOCINFOP ai)
{
if (mSummaryOnly) return;
HeapTrace(_T("jComHeap:: Free {%6ld} succeeded at 0X%p, %5u bytes\n"),
(long) ai->allocnumber,
ai->val, ai->size);
}
|
|
|
#pragma once
#include <functional>
#include <vector>
using std::vector;
using std::binary_function;
#include <tchar.h>
#include "allocinfo.h"
#include "allocationmap.h"
#include "stats.h"
class Reporter
{
public:
Reporter();
void Set(const char* f, long l);
void SummaryOnly(bool sumonly);
void ReportOn(AllocationMap& H);
void SummaryOf(AllocationMap& H);
void ReportAlloc(ALLOCINFOP ai, void* pActual);
void ReportRealloc(ALLOCINFOP ai, void* pActual, void* pOriginal);
void ReportFree(ALLOCINFOP ai);
private:
typedef vector<ALLOCINFOP, MyAllocator> VEC;
struct local_less : public binary_function<ALLOCINFOP,ALLOCINFOP,bool>
{
bool operator()(const ALLOCINFOP __x, const ALLOCINFOP __y) const { return __x->allocnumber < __y->allocnumber; }
};
void WritePrefix();
void WriteNoLeaksFound(bool writetotals = false);
void WriteLeakMessage();
void CopyTo(AllocationMap& H, VEC& v);
void Sort(VEC& v);
void ReportLeaks(AllocationMap& H);
void IterateOver(VEC& v);
void IterateOver(AllocationMap& H);
void ReportUnfreedBlock(ALLOCINFOP ai);
void PrintToBuffers(ALLOCINFOP ai, TCHAR* bytebuf, TCHAR* widebuf, long& bstrlen);
bool mSummaryOnly;
const char* fname;
long lineno;
Stats mStats;
} ;
|
|
|
#include "stats.h"
#include "common.h"
void Stats::Report()
{
HeapTrace(_T("Total %ld bytes unfreed in %ld allocation(s)"),
total, unfreedcount);
}
bool Stats::IsNoLeaks()
{
return totalallocs == totalfrees;
}
void Stats::Reset()
{
total = 0;
unfreedcount = 0;
totalallocs = 0;
totalfrees = 0;
}
void Stats::BumpTotals(ALLOCINFOP ai)
{
totalallocs += ai->numallocs;
totalfrees += ai->numfrees;
}
void Stats::BumpUnfreed(ALLOCINFOP ai)
{
total += ai->size;
unfreedcount++;
}
|
|
|
#pragma once
#include "allocinfo.h"
class Stats
{
public:
long total;
long unfreedcount;
long totalallocs;
long totalfrees;
void Report();
bool IsNoLeaks();
void Reset();
void BumpTotals(ALLOCINFOP ai);
void BumpUnfreed(ALLOCINFOP ai);
};
|