如何检测c 内存泄漏检测的位置/类构造函数内谨慎使用ZeroMemory函数

I am using
to verify the validity of some Windows executables with the following function, called in a loop from _tmain:
int signature_is_valid(const wchar_t *filepath) {
GUID guid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
WINTRUST_FILE_INFO file_info = { 0 };
WINTRUST_DATA
file_info.cbStruct = sizeof(file_info);
file_info.pcwszFilePath =
file_info.hFile = NULL;
file_info.pgKnownSubject = NULL;
ZeroMemory(&wd, sizeof(wd));
wd.cbStruct = sizeof(wd);
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_REVOCATION_CHECK_NONE;
wd.dwUnionChoice = WTD_CHOICE_FILE;
wd.dwStateAction = 0;
wd.pFile = &file_
wd.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | WTD_CACHE_ONLY_URL_RETRIEVAL;
return 0 == WinVerifyTrust(NULL, &guid, &wd);
However, with every loop the memory keeps growing, a sure sign of a memory leak.
Is there a problem with my understanding of the API or is the WinVerifyTrust function actually leaking? I am testing this on a Windows XP Professional SP3 system.
Here is some output from umdh:
472 allocs BackTraceAD1
5) BackTraceAD1 allocations
ntdll!RtlDebugAllocateHeap+
ntdll!RtlAllocateHeapSlowly+
ntdll!RtlAllocateHeap+00000E64
kernel32!LocalAlloc+
CRYPT32!operator new+
CRYPT32!I_CryptCreateLruEntry+
CRYPT32!CreateAuthRootAutoUpdateMatchCaches+
CRYPT32!CCertChainEngine::FindAuthRootAutoUpdateMatchingCtlEntries+0000004D
CRYPT32!CChainPathObject::GetAuthRootAutoUpdateUrlStore+
CRYPT32!CChainPathObject::CChainPathObject+0000030E
CRYPT32!ChainCreatePathObject+
CRYPT32!CCertIssuerList::AddIssuer+0000006A
CRYPT32!CChainPathObject::FindAndAddIssuersFromStoreByMatchType+
CRYPT32!CChainPathObject::FindAndAddIssuersByMatchType+
CRYPT32!CChainPathObject::FindAndAddIssuers+
CRYPT32!CChainPathObject::CChainPathObject+
CRYPT32!ChainCreatePathObject+
CRYPT32!CCertIssuerList::AddIssuer+0000006A
CRYPT32!CChainPathObject::FindAndAddIssuersFromCacheByMatchType+
CRYPT32!CChainPathObject::FindAndAddIssuersByMatchType+
CRYPT32!CChainPathObject::FindAndAddIssuers+
CRYPT32!CChainPathObject::CChainPathObject+
CRYPT32!ChainCreatePathObject+
CRYPT32!CCertChainEngine::CreateChainContextFromPathGraph+0000019E
CRYPT32!CCertChainEngine::GetChainContext+
CRYPT32!CertGetCertificateChain+
WINTRUST!_WalkChain+0000019C
WINTRUST!WintrustCertificateTrust+
WINTRUST!_VerifyTrust+
WINTRUST!WinVerifyTrust+0000004E
SigTest!signature_is_valid+000000DD
2 allocs BackTraceBB3
0) BackTraceBB3 allocations
ntdll!RtlDebugAllocateHeap+
ntdll!RtlAllocateHeapSlowly+
ntdll!RtlAllocateHeap+00000E64
kernel32!LocalAlloc+
CRYPT32!PkiDefaultCryptAlloc+
CRYPT32!CertFindCertificateInCRL+
cryptnet!MicrosoftCertDllVerifyRevocation+
CRYPT32!I_CryptRemainingMilliseconds+0000021B
CRYPT32!CertVerifyRevocation+
CRYPT32!CChainPathObject::CalculateRevocationStatus+
CRYPT32!CChainPathObject::CalculateAdditionalStatus+
CRYPT32!CCertChainEngine::CreateChainContextFromPathGraph+
CRYPT32!CCertChainEngine::GetChainContext+
CRYPT32!CertGetCertificateChain+
WINTRUST!_WalkChain+0000019C
WINTRUST!WintrustCertificateTrust+
WINTRUST!_VerifyTrust+
WINTRUST!WinVerifyTrust+0000004E
SigTest!signature_is_valid+000000DD
SigTest!wmain+
SigTest!__tmainCRTStartup+
SigTest!wmainCRTStartup+0000000F
kernel32!BaseProcessStart+
It seems to me that the CRYPT32 functions are the ones leaking... or I'm missing something.
Here is the memory evolution for some thousand loops:
解决方案 YES. If you have a low enough version of the crypt32.dll file there is a very annoying memory leak.
and install hotfix KB2641690 for fix
本文地址: &
我使用使用以下函数验证一些Windows可执行文件的有效性,在 _tmain 中循环调用:
int signature_is_valid(const wchar_t * filepath){ GUID guid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
WINTRUST_FILE_INFO file_info = {0};
WINTRUST_DATA
file_info.cbStruct = sizeof(file_info);
file_info.pcwszFilePath =
file_info.hFile = NULL;
file_info.pgKnownSubject = NULL;
ZeroMemory(& wd,sizeof(wd));
wd.cbStruct = sizeof(wd);
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_REVOCATION_CHECK_NONE;
wd.dwUnionChoice = WTD_CHOICE_FILE;
wd.dwStateAction = 0;
wd.pFile =& file_
wd.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | WTD_CACHE_ONLY_URL_RETRIEVAL;
return 0 == WinVerifyTrust(NULL,& guid,&wd); }
然而,随着每个循环,内存不断增长,泄漏。
我有理解 API 有问题,或者是 WinVerifyTrust 函数实际泄漏?我在 Windows XP Professional SP3 系统上测试此项。
编辑: / p>
以下是 umdh 的一些输出:
180)472 allocs BackTraceAD1
+ 467(472
5)BackTraceAD1分配
ntdll!RtlDebugAllocateHeap +
ntdll! RtlAllocateHeapSlowly +
NTDLL!RtlAllocateHeap + 00000E64
KERNEL32!LocalAlloc +
CRYPT32!new操作符+
CRYPT32!I_CryptCreateLruEntry +
CRYPT32!CreateAuthRootAutoUpdateMatchCaches +
CRYPT32!CCertChainEngine :: FindAuthRootAutoUpdateMatchingCtlEntries + 0000004D
CRYPT32!CChainPathObject :: GetAuthRootAutoUpdateUrlStore +
CRYPT32!CChainPathObject :: CChainPathObject + 0000030E
CRYPT32!ChainCreatePathObject +
CRYPT32! !!!!CCertIssuerList :: AddIssuer + 0000006A
CRYPT32 CChainPathObject :: FindAndAddIssuersFromStoreByMatchType +
CRYPT32 CChainPathObject :: FindAndAddIssuersByMatchType +
CRYPT32 CChainPathObject :: FindAndAddIssuers +
CRYPT32 CChainPathObject: !!!!CChainPathObject +
CRYPT32 ChainCreatePathObject +
CRYPT32 CCertIssuerList :: AddIssuer + 0000006A
CRYPT32 CChainPathObject :: FindAndAddIssuersFromCacheByMatchType +
CRYPT32 CChainPathObject :: FindAndAddIssuersByMatchType +
CRYPT32!CChainPathObject :: FindAndAddIssuers +
CRYPT32!CChainPathObject :: CChainPathObject +
CRYPT32!ChainCreatePathObject +
CRYPT32!CCertChainEngine :: CreateChainContextFromPathGraph + 0000019E
CRYPT32! CCertChainEngine :: GetChainContext +
CRYPT32!CertGetCertificateChain +
WINTRUST!_WalkChain + 0000019C
WINTRUST!WintrustCertificateTrust +
WINTRUST!_VerifyTrust +
WINTRUST!WinVerifyTrust + 0000004E
SigTest!signature_is_valid + 000000DD
0)2 allocs BackTraceBB3
0)BackTraceBB3分配
ntdll !RtlDebugAllocateHeap +
NTDLL!RtlAllocateHeapSlowly +
NTDLL!RtlAllocateHeap + 00000E64
KERNEL32!LocalAlloc +
CRYPT32!PkiDefaultCryptAlloc +
CRYPT32!CertFindCertificateInCRL +
cryptnet!MicrosoftCertDllVerifyRevocation +
CRYPT32!I_CryptRemainingMilliseconds + 0000021B
CRYPT32!CertVerifyRevocation +
CRYPT32!CChainPathObject :: CalculateRevocationStatus +
CRYPT32!CChainPathObject :: CalculateAdditionalStatus +
CRYPT32!CCertChainEngine :: CreateChainContextFromPathGraph +
CRYPT32!CCertChainEngine :: GetChainContext +
CRYPT32!CertGetCertificateChain +
WINTRUST!_WalkChain + 0000019C
WINTRUST!WintrustCertificateTrust +
WINTRUST!_VerifyTrust +
WINTRUST!WinVerifyTrust + 0000004E
SigTest!signature_is_valid + 000000DD
SigTest!wmain +
SigTest!__ tmainCRTStartup +
SigTest!wmainCRTStartup + 0000000F
kernel32!BaseProcessStart +
code> CRYPT32 函数正在泄漏...或者我缺少了一些东西。
这里是几千个循环的内存演化:
解决方案 是的。如果你有一个足够低的版本的crypt32.dll文件有一个非常讨厌的内存泄漏。
并安装修补程序KB2641690修复
本文地址: &
扫一扫关注官方微信作者:Ac_Von
博客地址:http://www.cnblogs.com/vongang/
文章地址:http://www.cnblogs.com/vongang/archive//2122076.html
结构体能自由组装数据,是一种很常见的数据打包方法。
当我们定义一个结构体后,没有初始化就使用,就会使用到垃圾数据,而且这种错误很难发现。
在编程时对于定义的任何变量,我们最好都先初始化。
除了使用memset和ZeroMemory之外,有没有更简单的方法初始化呢?
因为有时候每定义一个结构体,就使用一次memset,这样很繁琐,同时有时候也需要给结构体中的一些变量赋一些非0的默认值。
我这里总结三种方法,如果大家有什么好的方法,不妨加上去:
1、结构体的构造函数中初始化。
2、继承模板类初始化
3、定义时初始化
一、在结构体构造函数中初始化
在C++中,结构体与类在使用上已没有本质上的区别了,所以可以使用类似构造函数的形式来初始化,如下代码所示:
&&struct Stu&{&&int&&nN&&bool&bS&&char&szName[20];&&char&szEmail[100];
& //构造函数初始化
&&Stu()&&{nNum = 0;&&&bSex =&&&memset(szName,0,sizeof(szName));&&&memset(szEmail,0,sizeof(szEmail));
你可能已经发现了,如果结构体中有大量成员,一个个赋值,相当麻烦。那么你可以这样写:
&struct Stu&{&&int&&nN&&bool&bS&&char&szName[20];&&char&szEmail[100];
&&//构造函数初始化&&Stu()&&{&&& memset(this,0,sizeof(Stu));&&&& //或者是下面的格式&&&& //memset(&nNum,0,sizeof(Stu));
如果在结构体中分配了指针,并且指针指向一个堆内存,那么就在析构函数中释放,以上便是在构造函数中初始化。
二、继承模板类初始化
首先定义一个模板基类:template&&typename&T&&class&ZeroStruct&{&public:&&&&&ZeroStruct()&&&&&{&&&&&&&&&memset(this,0,sizeof(T));&&&&&}&};
之后定义的结构体都继承于此模板类。&
&&&&struct&Stu:ZeroStruct&Stu&&&&&&{&&&&&&&&&int&&&&&&&&nN&&&&&&&&&bool&&&&bS&&&&&&&&&char&&&&szName[20];&&&&&&&&&char&&&&szEmail[100];&&&&&};
这样也能实现初始化。
三、定义时初始化
&&&&struct&Stu&&&&&{&&&&&&&&&int&&&&&&&&nN&&&&&&&&&bool&&&&bS&&&&&&&&&char&&&&szName[20];&&&&&&&&&char&&&&szEmail[100];&&&&&};&//定义时初始化&Stu stu1 = {0};
在有的结构体中,第一个成员表示结构体的大小,那么就可以这样初始化:
&struct Stu&{int nS //结构体大小&&int&&nN&&bool&bS&&char&szName[20];&&char&szEmail[100];&};
&Stu stu1 = {sizeof(Stu),0};
后面的0,可以省略掉,直接写成:Stu stu1 = {sizeof(Stu)};后面自动会用0填充。
总结分析:
以上三种,是据我所知的初始化结构体方法。
前面两种,实际上已经把结构体给类化了,和类的使用差不多。第三种,是纯粹的结构体的写法。
如果用途仅仅限定为结构体,我建议不要加上构造函数,也不要继承于那个模板类,因为这个时候结构体实际上已经是类了。在定义结构体时,将无法使用第三种方式去初始化,当然,此时也不需要初始化了。
看看微软定义的结构体,基本上都没有构造函数和析构函数。因为结构体的意义很明确,它仅仅是对数据的一个包装,如果加上了方法,其意义就变了。
阅读(...) 评论()匿名用户不能发表回复!|2009年7月 总版技术专家分月排行榜第二2009年3月 总版技术专家分月排行榜第二2009年1月 总版技术专家分月排行榜第二2005年7月 总版技术专家分月排行榜第二2005年5月 总版技术专家分月排行榜第二2005年3月 总版技术专家分月排行榜第二
优秀小版主2015年8月优秀小版主2015年9月优秀小版主2015年5月优秀小版主2015年2月论坛优秀版主
匿名用户不能发表回复!|下次自动登录
现在的位置:
& 综合 & 正文
VC环境下检查内存泄漏memory leak的方法
通过改写delete new方法,我们可以记录内存分配的地址,数量。因此,也就可以知道哪此内存在程序结束后没有释放。
将如下代码改存放为trace.cpp ,将trace.cpp放入要检测的工程。运行Debug调试程序,在Debug的输出里会有提示信息。
/**********************************************************************Trace alloc-----------Purpose:
Implement a allocation check routine that reports the whole
callstack for each leaked allocation.
Based on the code for ExtendedTrace written by
Zoltan Csizmadia, .
Erik Rydgren, .
1/ Define DETECT_LEAKS in the project settings under
C++/preprocessor.
If you want checking of overwrites then define DETECT_OVERWRITES
in the project settings. Change the frequency of the checks by
altering the NML_CHECK_EVERY define in tracealloc.cpp.
2/ Compile.
If you get multiple defined symbols (overloaded new and delete)
add linker switch /FORCE:MULTIPLE on the exe and make sure the
tracealloc new and delete is the ones used. If not, reorder the
included libraries until they do.
**********************************************************************/
#if defined(_DEBUG) && defined(WIN32) //&& defined(DETECT_LEAKS)
#include &windows.h&#include &tchar.h&#include &iostream&#include &ImageHlp.h&#include &string&#include &assert.h&
typedef std::basic_string&TCHAR, char_traits&TCHAR& &
// Setup how much buffer is used for a single path fetch, increase if you get AV's during leak dump (4096 is plenty though)#define BUFFERSIZE 4096
// Define how many levels of callstack that should be fetched for each allocation.// Each level costs 2*sizof(ULONG) bytes / allocation.#define MAXSTACK 5
// Define size of no mans land#define NO_MANS_LAND_SIZE 16
// Define frequency of no mans land checking#define NML_CHECK_EVERY 1000
#pragma comment( lib, "imagehlp.lib" )
void GetStackTrace(HANDLE hThread, ULONG ranOffsets[][2], ULONG nMaxStack );void WriteStackTrace(ULONG ranOffsets[][2], ULONG nMaxStack, tcstring& roOut);void* TraceAlloc(size_t nSize);void TraceDealloc(void* poMem);
void OutputDebugStringFormat( LPCTSTR lpszFormat, ... ){ TCHAR
lpszBuffer[BUFFERSIZE]; va_list
va_start( fmtList, lpszFormat ); _vstprintf( lpszBuffer, lpszFormat, fmtList ); va_end( fmtList );
::OutputDebugString( lpszBuffer );}
// Unicode safe char* -& TCHAR* conversionvoid PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut ){#if defined(UNICODE)||defined(_UNICODE)
ULONG index = 0;
PCSTR lpAct = lpszIn;
for( ; ; lpAct++ ) {
lpszOut[index++] = (TCHAR)(*lpAct);
if ( *lpAct == 0 ) } #else
// This is trivial
strcpy( lpszOut, lpszIn );#endif}
// Let's figure out the path for the symbol files// Search path= ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%/System32;" + lpszIniPath// Note: There is no size check for lpszSymbolPath!void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath ){ CHAR lpszPath[BUFFERSIZE];
// Creating the default path
// ".;%_NT_SYMBOL_PATH%;%_NT_ALTERNATE_SYMBOL_PATH%;%SYSTEMROOT%;%SYSTEMROOT%/System32;" strcpy( lpszSymbolPath, "." );
// environment variable _NT_SYMBOL_PATH if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) ) {
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszPath ); }
// environment variable _NT_ALTERNATE_SYMBOL_PATH if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) ) {
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszPath ); }
// environment variable SYSTEMROOT if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) ) {
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszPath );
strcat( lpszSymbolPath, ";" );
// SYSTEMROOT/System32
strcat( lpszSymbolPath, lpszPath );
strcat( lpszSymbolPath, "" ); }
// Add user defined path if ( lpszIniPath != NULL )
if ( lpszIniPath[0] != '/0' )
strcat( lpszSymbolPath, ";" );
strcat( lpszSymbolPath, lpszIniPath );
// Uninitialize the loaded symbol filesBOOL UninitSymInfo(){ return SymCleanup( GetCurrentProcess() );}
// Initializes the symbol filesBOOL InitSymInfo( PCSTR lpszInitialSymbolPath ){ CHAR
lpszSymbolPath[BUFFERSIZE];
symOptions = SymGetOptions();
symOptions |= SYMOPT_LOAD_LINES;
symOptions &= ~SYMOPT_UNDNAME; SymSetOptions( symOptions );
// Get the search path for the symbol files InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath );
return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE);}
// Get the module name from a given addressBOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule ){ BOOL
ret = FALSE; IMAGEHLP_MODULE
::ZeroMemory( &moduleInfo, sizeof(moduleInfo) ); moduleInfo.SizeOfStruct = sizeof(moduleInfo);
if ( SymGetModuleInfo( GetCurrentProcess(), (DWORD)address, &moduleInfo ) ) {
// Got it!
PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule );
ret = TRUE; } else
// Not found
_tcscpy( lpszModule, _T("?") ); }
// Get function prototype and parameter info from ip address and stack addressBOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol ){ BOOL
ret = FALSE; DWORD
dwDisp = 0; DWORD
dwSymSize = 10000;
lpszUnDSymbol[BUFFERSIZE]=_T("?"); CHAR
lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?"; LPTSTR
lpszParamSep = NULL; LPCTSTR
lpszParsed = lpszUnDS PIMAGEHLP_SYMBOL
pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
::ZeroMemory( pSym, dwSymSize ); pSym-&SizeOfStruct = dwSymS pSym-&MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL);
// Set the default to unknown _tcscpy( lpszSymbol, _T("?") );
// Get symbol info for IP if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) ) {
// Make the symbol readable for humans
UnDecorateSymbolName( pSym-&Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
UNDNAME_COMPLETE |
UNDNAME_NO_THISTYPE |
UNDNAME_NO_SPECIAL_SYMS |
UNDNAME_NO_MEMBER_TYPE |
UNDNAME_NO_MS_KEYWORDS |
UNDNAME_NO_ACCESS_SPECIFIERS );
// Symbol information is ANSI string
PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol );
// I am just smarter than the symbol file
if ( _tcscmp(lpszUnDSymbol, _T("")) == 0 )
_tcscpy(lpszUnDSymbol, _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)"));
if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 )
_tcscpy(lpszUnDSymbol, _T("main(int,TCHAR * *)"));
if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 )
_tcscpy(lpszUnDSymbol, _T("mainCRTStartup()"));
if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 )
_tcscpy(lpszUnDSymbol, _T("wmain(int,TCHAR * *,TCHAR * *)"));
if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 )
_tcscpy(lpszUnDSymbol, _T("wmainCRTStartup()"));
lpszSymbol[0] = _T('/0');
// Let's go through the stack, and modify the function prototype, and insert the actual
// parameter values from the stack
if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL)
ULONG index = 0;
for( ; ; index++ )
lpszParamSep = _tcschr( lpszParsed, _T(',') );
if ( lpszParamSep == NULL )
*lpszParamSep = _T('/0');
_tcscat( lpszSymbol, lpszParsed );
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) );
lpszParsed = lpszParamSep + 1;
lpszParamSep = _tcschr( lpszParsed, _T(')') );
if ( lpszParamSep != NULL )
*lpszParamSep = _T('/0');
_tcscat( lpszSymbol, lpszParsed );
_stprintf( lpszSymbol + _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) );
lpszParsed = lpszParamSep + 1;
_tcscat( lpszSymbol, lpszParsed );
ret = TRUE; }
GlobalFree( pSym );
// Get source file name and line number from IP address// The output format is: "sourcefile(linenumber)" or//
"modulename!address" or//
"address"BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo ){ BOOL
ret = FALSE; IMAGEHLP_LINE
lineI DWORD
lpszFileName[BUFFERSIZE] = _T(""); TCHAR
lpModuleInfo[BUFFERSIZE] = _T("");
_tcscpy( lpszSourceInfo, _T("?(?)") );
::ZeroMemory( &lineInfo, sizeof( lineInfo ) ); lineInfo.SizeOfStruct = sizeof( lineInfo );
if ( SymGetLineFromAddr( GetCurrentProcess(), address, &dwDisp, &lineInfo ) ) {
// Got it. Let's use "sourcefile(linenumber)" format
PCSTR2LPTSTR( lineInfo.FileName, lpszFileName );
_stprintf( lpszSourceInfo, _T("%s(%d)"), lpszFileName, lineInfo.LineNumber );
ret = TRUE; } else {
// There is no source file information.
// Let's use the "modulename!address" format
GetModuleNameFromAddress( address, lpModuleInfo );
if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('/0'))
// There is no modulename information. :((
// Let's use the "address" format
_stprintf( lpszSourceInfo, _T("0x%08X"), lpModuleInfo, address );
_stprintf( lpszSourceInfo, _T("%s!0x%08X"), lpModuleInfo, address );
ret = FALSE; } }
void GetStackTrace(HANDLE hThread, ULONG ranOffsets[][2], ULONG nMaxStack ){ STACKFRAME
callS BOOL
bR CONTEXT TCHAR
symInfo[BUFFERSIZE] = _T("?"); TCHAR
srcInfo[BUFFERSIZE] = _T("?"); HANDLE
hProcess = GetCurrentProcess();
// If it's not this thread, let's suspend it, and resume it at the end if ( hThread != GetCurrentThread() )
if ( SuspendThread( hThread ) == -1 )
// whaaat ?!
OutputDebugStringFormat( _T("Call stack info(thread=0x%X) failed./n") );
::ZeroMemory( &context, sizeof(context) ); context.ContextFlags = CONTEXT_FULL;
if ( !GetThreadContext( hThread, &context ) ) {
OutputDebugStringFormat( _T("Call stack info(thread=0x%X) failed./n") ); }
::ZeroMemory( &callStack, sizeof(callStack) ); callStack.AddrPC.Offset
= context.E callStack.AddrStack.Offset = context.E callStack.AddrFrame.Offset = context.E callStack.AddrPC.Mode
= AddrModeF callStack.AddrStack.Mode
= AddrModeF callStack.AddrFrame.Mode
= AddrModeF
for( ULONG index = 0; ; index++ )
bResult = StackWalk(
IMAGE_FILE_MACHINE_I386,
&callStack,
SymFunctionTableAccess,
SymGetModuleBase,
// Ignore the first two levels (it's only TraceAlloc and operator new anyhow)
if ( index & 3 )
// Break if we have fetched nMaxStack levels
if ( index-3 == nMaxStack)
// If we are at the top of the stackframe then break.
if( !bResult || callStack.AddrFrame.Offset == 0) {
ranOffsets[index-3][0] = 0;
ranOffsets[index-3][1] = 0;
// Remember program counter and frame pointer
ranOffsets[index-3][0] = callStack.AddrPC.O
ranOffsets[index-3][1] = callStack.AddrFrame.O }
if ( hThread != GetCurrentThread() )
ResumeThread( hThread );}
void WriteStackTrace(ULONG ranOffsets[][2], ULONG nMaxStack, tcstring& roOut){ TCHAR
symInfo[BUFFERSIZE] = _T("?"); TCHAR
srcInfo[BUFFERSIZE] = _T("?");
for (ULONG index = 0; index & nMaxStack && ranOffsets[index][0] != 0 && ranOffsets[index][1] != 0; index++) {
GetFunctionInfoFromAddresses( ranOffsets[index][0], ranOffsets[index][1], symInfo );
GetSourceInfoFromAddress( ranOffsets[index][0], srcInfo );
roOut += _T("
roOut += srcI
roOut += _T(" : ");
roOut += symI
roOut += _T("/n");
struct sdAllocBlock {
unsigned long nMagicN
sdAllocBlock* poN
sdAllocBlock* poP
ULONG anStack[MAXSTACK][2];
char pzNoMansLand[NO_MANS_LAND_SIZE];
sdAllocBlock()
void Init() {
nMagicNumber = 0x;
void Disconnect() {
if (poNext != this) {
poNext-&poPrev = poP
poPrev-&poNext = poN
void ConnectTo(sdAllocBlock* poPos) {
Disconnect();
poPrev = poP
poNext = poPos-&poN
poPos-&poNext-&poPrev =
poPos-&poNext =
void LeakDump(tcstring& roOut);
class CS {
CRITICAL_SECTIONpublic:
CS() { InitializeCriticalSection(&cs); }
operator CRITICAL_SECTION& () { }};
class Guard {
CRITICAL_SECTION&public:
Guard(CRITICAL_SECTION& rcs)
: rcs(rcs) { EnterCriticalSection(&rcs); }
~Guard() { LeaveCriticalSection(&rcs); }};
class cLeakDetector{public:
cLeakDetector() {
InitSymInfo(NULL);
~cLeakDetector() {
LeakDump(leaks);
OutputDebugString(leaks.c_str());
UninitSymInfo();
static unsigned int nNumAllocs = 0;static unsigned int nCurrentAllocs = 0;static unsigned int nMaxConcurrent = 0;
CS& Gate() {
static CS}
sdAllocBlock& Head(){
static cLeakDetector oD
static sdAllocBlock oH
return oH}
class cInitializer {
public: cInitializer() { Head(); }; } oI
void LeakDump(tcstring& roOut){
Guard at(Gate());
TCHAR buffer[65];
sdAllocBlock* poBlock = Head().poN
while (poBlock != &Head()) {
WriteStackTrace(poBlock-&anStack, MAXSTACK, stack);
bool bIsKnownLeak =
// afxMap leaks is MFC. Not ours.
if (stack.find(_T(": afxMap")) != tcstring::npos)
bIsKnownLeak =
if (!bIsKnownLeak) {
roOut += _T("Leak of ");
roOut += _itot(poBlock-&nSize, buffer, 10);
roOut += _T(" bytes detected:/n");
roOut += _T("/n");
poBlock = poBlock-&poN
roOut += _T("Memory statistics/n-----------------/n");
roOut += _T("Total allocations: ");
roOut += _itot(nNumAllocs, buffer, 10);
roOut += _T("/n");
roOut += _T("Max concurrent allocations: ");
roOut += _itot(nMaxConcurrent, buffer, 10);
roOut += _T("/n");}
bool AssertMem(char* m, char c, size_t s){
for (size_t i = 0; i & i++)
if (m[i] != c)
return i &=}
void CheckNoMansLand(){
Guard at(Gate());
sdAllocBlock* poBlock = Head().poN
while (poBlock != &Head()) {
if (!AssertMem(poBlock-&pzNoMansLand, 0x55, NO_MANS_LAND_SIZE)) {
bool MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD =
WriteStackTrace(poBlock-&anStack, MAXSTACK, stack);
assert(MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD);
char* pzNoMansLand = ((char*)poBlock) + sizeof(sdAllocBlock) + poBlock-&nS
if (!AssertMem(pzNoMansLand, 0x55, NO_MANS_LAND_SIZE)) {
bool MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_TAIL =
WriteStackTrace(poBlock-&anStack, MAXSTACK, stack);
assert(MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_TAIL);
poBlock = poBlock-&poN
void* TraceAlloc(size_t nSize){
Guard at(Gate());
nNumAllocs++;#ifdef DETECT_OVERWRITES
if (nNumAllocs % NML_CHECK_EVERY == 0) {
CheckNoMansLand();
sdAllocBlock* poBlock = (sdAllocBlock*) malloc(nSize + sizeof(sdAllocBlock) + NO_MANS_LAND_SIZE);
poBlock-&Init();
poBlock-&nSize = nS
char* pzNoMansLand = ((char*)poBlock) + sizeof(sdAllocBlock) + poBlock-&nS
memset(poBlock-&pzNoMansLand, 0x55, NO_MANS_LAND_SIZE);
memset(pzNoMansLand, 0x55, NO_MANS_LAND_SIZE);
GetStackTrace(GetCurrentThread(), poBlock-&anStack, MAXSTACK );
poBlock-&ConnectTo(&Head());
nCurrentAllocs++;
if (nCurrentAllocs & nMaxConcurrent)
nMaxConcurrent = nCurrentA
return (void*)(((char*) poBlock) + sizeof(sdAllocBlock));}
void TraceDealloc(void* poMem){
Guard at(Gate());
if (!poMem) // delete NULL; = do nothing
sdAllocBlock* poBlock = (sdAllocBlock*) ((char*)poMem - sizeof(sdAllocBlock));
char* pzNoMansLand = ((char*)poBlock) + sizeof(sdAllocBlock) + poBlock-&nS
if (poBlock-&nMagicNumber != 0x) {
// Whupps, something fishy is going on
// Validate the address against our list of allocated blocks
sdAllocBlock* poLoopBlock = Head().poN
while (poLoopBlock != &Head() && poLoopBlock != poBlock)
poLoopBlock = poLoopBlock-&poN
if (poLoopBlock == &Head()) {
// Hell we didn't allocate this block.
// Just free the memory and hope for the best.
free(poMem);
bool MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD =
assert(MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD);
else if (!AssertMem(poBlock-&pzNoMansLand, 0x55, NO_MANS_LAND_SIZE)) {
bool MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD =
assert(MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD);
else if (!AssertMem(pzNoMansLand, 0x55, NO_MANS_LAND_SIZE)) {
bool MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_TAIL =
assert(MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_TAIL);
poBlock-&Disconnect();
free(poBlock);
nCurrentAllocs--;
// Take over global new and deletevoid* operator new(size_t s){
return TraceAlloc(s);}
void* operator new[](size_t s){
return TraceAlloc(s);}
void operator delete(void* pMem){
TraceDealloc(pMem);}
void operator delete[] (void* pMem){
TraceDealloc(pMem);}
// And then some crap for taking over MFC allocations.void* __cdecl operator new(size_t s, LPCSTR lpszFileName, int nLine){
return TraceAlloc(s);}
void* __cdecl operator new[](size_t s, LPCSTR lpszFileName, int nLine){
return TraceAlloc(s);}
void __cdecl operator delete(void* pMem, LPCSTR /* lpszFileName */, int /* nLine */){
TraceDealloc(pMem);}
void __cdecl operator delete[](void* pMem, LPCSTR /* lpszFileName */, int /* nLine */){
TraceDealloc(pMem);}
【上篇】【下篇】

我要回帖

更多关于 vs 内存泄漏检测工具 的文章

 

随机推荐