我用StackWalk函数在程序崩溃的时候得到栈信息,在debug版本下面还好,release版本下面只能得到一部分,请问怎么解决呢
debug版本看起来像这个样子
-MyExe.exe 0x0400015 + 0x0C
-MFC80d.dll 0x0700152 + 0x120
而release版本没有MFC80.dll这一行另外kernel32.dll里面的函数调用也没有得到,我看迅雷,qq都能得到kernel32.dll里面的栈
谢谢
debug版本看起来像这个样子
-MyExe.exe 0x0400015 + 0x0C
-MFC80d.dll 0x0700152 + 0x120
而release版本没有MFC80.dll这一行另外kernel32.dll里面的函数调用也没有得到,我看迅雷,qq都能得到kernel32.dll里面的栈
谢谢
adplus之类的工具都可以
迅雷5 5.7.2.371
———————————–
Type: EXCEPTION_UNCATCH_THROW
Address: 0×7C812A5B
Error: [3536][asyn_io_manager] unknownCall stack:
0×7C800000[12A5B] kernel32.dll: RaiseException[+52](-536838143,1,1,21036956)
0×21350000[10FA0] download_interface.dll: debug_p2p_pipe_simulate_remote_choke_local[+45D0](11364736,1429560,1243148,11364736)
0×7C800000[B683] kernel32.dll: GetModuleFileNameA[+1B4](0,0,0,0)
Release版是不调用这个的,当然你看不到这个了
2.用dump抓 crash文件核对map 去查代码
在blog上整理了网上的几篇文章。blog.csdn.net/alicehyxx
dumper.h#ifndef __DUMPER_H__
#define __DUMPER_H__#include <time.h>
#include <string>
#include <windows.h>
#include <dbghelp.h>#pragma comment(lib,"dbghelp.lib")class CDumper
{
public:
CDumper(void);
~CDumper(void); static int OnError(LPEXCEPTION_POINTERS pException);
static std::string FormateDateTime(time_t t);
static const char* GetRootPath(void);
static void Test(void);
};#endif //__DUMPER_H__
dumper.cpp#include "stdafx.h"
#include "dumper.h"CDumper::CDumper(void)
{
}CDumper::~CDumper(void)
{
}int CDumper::OnError(LPEXCEPTION_POINTERS pException)
{
LONG ret = EXCEPTION_CONTINUE_SEARCH;
std::string strTime = CDumper::FormateDateTime(time(NULL));
std::string strRootPath = CDumper::GetRootPath();
std::string strFileName = strRootPath + "\\crash" + strTime + ".dmp";
HANDLE hFile = ::CreateFile( strFileName.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile!=INVALID_HANDLE_VALUE)
{
MINIDUMP_EXCEPTION_INFORMATION ExInfo = {0}; ExInfo.ThreadId = ::GetCurrentThreadId();
ExInfo.ExceptionPointers = pException;
ExInfo.ClientPointers = NULL; // write the dump
if (!MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL) )
{
//MessageBox(NULL, "write dumpfile error.", "Error", MB_ICONQUESTION|MB_OK);
::CloseHandle(hFile);
return EXCEPTION_EXECUTE_HANDLER;
}
::CloseHandle(hFile);
} return EXCEPTION_EXECUTE_HANDLER;
}std::string CDumper::FormateDateTime(time_t t)
{
char szData[128] = {0};
tm* ptm = localtime(&t);
sprintf(szData, "%d-%.2d-%.2d %.2d-%.2d-%.2d", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
return szData;
}const char* CDumper::GetRootPath(void)
{
static char szPath[MAX_PATH];
static bool bFirstTime = true; if(bFirstTime)
{
bFirstTime = false;
GetModuleFileName(NULL, szPath, sizeof(szPath));
char *p = strrchr(szPath, '\\');
*p = '\0';
} return szPath;
}
void CDumper::Test(void)
{
#ifndef _DEBUG
__try
{
#endif
char *p = NULL; *p = 1;#ifndef _DEBUG
}
__except(CDumper::OnError(GetExceptionInformation()))
{ }
#endif}
main.cpp
#include "stdafx.h"#include "Dumper.h"int main()
{
#ifndef _DEBUG
__try
{
#endif
char *p = NULL; *p = 1;#ifndef _DEBUG
}
__except(CDumper::OnError(GetExceptionInformation()))
{ }
#endif return 0;
} 1. 程序崩溃的话会在exe当前目录生成类似crash2009-07-24 17-16-45.dmp的文件2. 双击文件会用VS打开。直接F5 定位到崩溃的位置。3. 注意exe目录需要放好对应的pdb文件。否则可能无法定位。也就是说你发布一个程序以后你要保存对应的pdb文件和对应的源码。4. vs2005以上版本默认是不打开。在C/C++ -> Code Generation -> Enable C++ Exceptions -> set Yes With SEH Exceptions (/EHa) 5. 那个sethandle啥啥啥的有问题。不是每次都能输出的。相对而言这个比那个药稳定一些。6. LZ不加分实在说不过去。大家说呢。
__try
{
}
__except()
{
}处理异常,在_try 块中不能存在C++对象。。#include "stdafx.h"
#include "Dumper.h"class A
{
int m_nStep;
int* m_pTest;public:
A(void) : m_nStep(0),m_pTest(NULL)
{
m_pTest = new int;
}; ~A(void)
{
if(m_pTest != NULL)
{
delete m_pTest;
m_pTest = NULL;
}
};
};int main()
{
#ifndef _DEBUG
__try
{
#endif
char *p = NULL; *p = 1; A value;#ifndef _DEBUG
}
__except(CDumper::OnError(GetExceptionInformation()))
{ }
#endif return 0;
}
Release模式下编译将报错。。
#include "Dumper.h"class A
{
public:
int m_nStep;
int* m_pTest;public:
A(void) : m_nStep(0),m_pTest(NULL)
{
m_pTest = new int;
}; ~A(void)
{
if(m_pTest != NULL)
{
delete m_pTest;
m_pTest = NULL;
}
}; static A* Create()
{
return new A;
}
void Test(void)
{ }
};int main()
{
#ifndef _DEBUG
__try
{
#endif
char *p = NULL; *p = 1;
A *value = A::Create();
value->Test();#ifndef _DEBUG
}
__except(CDumper::OnError(GetExceptionInformation()))
{ }
#endif return 0;
}
这样的确可以解决编译的问题,但我提出两点:
1、既然可能发生异常,而new了一个对象,很可能导致内存泄漏。2、__try __except 捕获的异常只是当前线程的,在__try块中创建线程并触发异常,是捕获不到的。
函数SetUnhandledExceptionFilter设置的异常处理函数,可以捕获由设置线程创建的所有线程的异常。
如下代码异常未捕获。
#include <Windows.h>
#include "Dumper.h"
#include <iostream>
using namespace std;DWORD WINAPI ThreadProc(
LPVOID lpParameter
)
{
cout << "Thread Start" << endl; char *p = NULL;
*p = 1; cout << "Thread Stop" << endl;
return 0;
}class A
{
public:
int m_nStep;
int* m_pTest;public:
A(void) : m_nStep(0),m_pTest(NULL)
{
m_pTest = new int;
}; ~A(void)
{
if(m_pTest != NULL)
{
delete m_pTest;
m_pTest = NULL;
}
}; static A* Create()
{
return new A;
} void Test(void)
{
cout << "A::Test" << endl;
}
};int main()
{
#ifndef _DEBUG
__try
{
#endif
A *value = A::Create();
value->Test(); //char *p = NULL;
//*p = 1; DWORD dwThreadID;
::CreateThread(NULL,0,ThreadProc,NULL,0,&dwThreadID); EXCEPTION_INT_DIVIDE_BY_ZERO
#ifndef _DEBUG
}
__except(CDumper::OnError(GetExceptionInformation()))
{
cout << "OnError" << endl;
}
#endif system("pause"); return 0;
}
宏功能:
依据版本进行头文件的选择
\-------------------------------------------------------------------------------*/
#if (_WIN32_WINNT>=0x0501)
#include <DbgHelp.h>
#else
#include "DbgHelp.h"
#endif#include "ExceptionByJade.h"
#pragma comment(lib,"DbgHelp")
CExceptionByJade::CExceptionByJade(DWORD dwCode,std::string szFun,LPEXCEPTION_POINTERS lpException)
:m_dwCode(dwCode),m_szFun(szFun)
{
memcpy(&m_tgException,lpException,sizeof(EXCEPTION_POINTERS));
}CExceptionByJade::CExceptionByJade(DWORD dwCode,std::string szFun,CComBSTR cError)
:m_dwCode(dwCode),m_szFun(szFun)
{
m_cError = cError;
ZeroMemory(&m_tgException,sizeof(EXCEPTION_POINTERS));
}CExceptionByJade::CExceptionByJade(std::string szFun) : m_szFun(szFun)
{
ZeroMemory(&m_tgException,sizeof(EXCEPTION_POINTERS));
}CExceptionByJade::CExceptionByJade(DWORD dwCode,std::string szFun)
: m_szFun(szFun),m_dwCode(dwCode)
{
ZeroMemory(&m_tgException,sizeof(EXCEPTION_POINTERS));
}CExceptionByJade::CExceptionByJade(void) : m_dwCode(0)
{
ZeroMemory(&m_tgException,sizeof(EXCEPTION_POINTERS));
}CExceptionByJade::~CExceptionByJade(void)
{
ZeroMemory(&m_tgException,sizeof(EXCEPTION_POINTERS));
}
DWORD CExceptionByJade::DumpFile(LPCTSTR lpFile,BOOL bExcept,DWORD dwOption)
{
HANDLE hThis = GetCurrentProcess();
DWORD dwId = GetCurrentProcessId();
MINIDUMP_EXCEPTION_INFORMATION tgExcpetion = { 0 };
HANDLE hFile = CreateFile(lpFile,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL
,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile == INVALID_HANDLE_VALUE)
return GetLastError();
tgExcpetion.ClientPointers = TRUE;
tgExcpetion.ThreadId = GetCurrentThreadId();
memcpy(&tgExcpetion.ExceptionPointers,&m_tgException,sizeof(EXCEPTION_POINTERS));
switch(dwOption)
{
case 0:
if(bExcept)
MiniDumpWriteDump(hThis,dwId,hFile,MiniDumpNormal,&tgExcpetion,NULL,NULL);
else
MiniDumpWriteDump(hThis,dwId,hFile,MiniDumpNormal,NULL,NULL,NULL);
break;
}
return 0;
}DWORD CExceptionByJade::FormatMsg(std::wstring &szMsg,USHORT usPrimaryLang,USHORT usSubLang)
{
LPVOID lpMsgBuf = NULL;
DWORD dwLang = MAKELANGID(usPrimaryLang,usSubLang) , dwRetVal = 0;
dwRetVal = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL,m_dwCode,dwLang,(LPTSTR) &lpMsgBuf,0,NULL);
if(!dwRetVal) return GetLastError();
szMsg = (WCHAR*)lpMsgBuf;
LocalFree(lpMsgBuf);
return 0;
}
#if !defined(__JADE_EXCEPTION_H_)
#define __JADE_EXCEPTION_H_class CExceptionByJade
{
public:
/*****************************************************************************\
函数名称:CExceptionByJade
函数功能:异常类型对象构造函数
参数:
input:
DWORD dwCode 异常信息代号
std::string szFun 异常函数名称
LPEXCEPTION_POINTERS lpException 异常信息结构
返回值:
无
异常类型:
无
\*****************************************************************************/
CExceptionByJade(DWORD dwCode,std::string szFun,LPEXCEPTION_POINTERS lpException);
/*****************************************************************************\
函数名称:CExceptionByJade
函数功能:异常类型对象构造函数
参数:
input:
DWORD dwCode 异常信息代号
std::string szFun 异常函数名称
CComBSTR cError 错误信息描述串
返回值:
无
异常类型:
无
\*****************************************************************************/
CExceptionByJade(DWORD dwCode,std::string szFun,CComBSTR cError);
/*****************************************************************************\
函数名称:CExceptionByJade
函数功能:异常类型对象构造函数
参数:
input:
std::string szFun 异常函数名称
返回值:
无
异常类型:
无
\*****************************************************************************/
CExceptionByJade(std::string szFun);
CExceptionByJade(DWORD dwCode,std::string szFun);
CExceptionByJade(void);
~CExceptionByJade(void);
public:
/*****************************************************************************\
函数名称:DumpFile
函数功能:将异常环境最小调试信息记录文件
参数:
input:
LPCTSTR lpFile 生成的文件完全路径
BOOL bExcept 环境调试信息是否包含异常信息结构
DWORD dwOption Dump选项该参数保留
返回值:
0 —— 正常值
非0 —— 错误代号
\*****************************************************************************/
DWORD DumpFile(LPCTSTR lpFile,BOOL bExcept,DWORD dwOption = 0);
/*****************************************************************************\
函数名称:FormatMsg
函数功能:查询错误代号在该系统下的信息描述
参数:
input:
USHORT usPrimaryLang 主要语言类型代号
USHORT usSubLange 语言种类描述
output:
std::wstring &szMsg 错误代号在该系统下的字符描述
返回值:
0 —— 正常值
非0 —— 错误代号
\*****************************************************************************/
DWORD FormatMsg(std::wstring &szMsg,USHORT usPrimaryLang,USHORT usSubLang);
/*****************************************************************************\
函数名称:ErrorCode
函数功能:得到错误代号
参数:
input:
无
output:
无
返回值:
错误代号
\*****************************************************************************/
DWORD ErrorCode(void);
/*****************************************************************************\
函数名称:GetRecord
函数功能:得到异常记录
参数:
input:
EXCEPTION_RECORD *lpRecord 异常记录指针
DWORD dwLen lpRecord长度
output:
无
返回值:
0 —— 正常值
非0 —— 错误代号
\*****************************************************************************/
DWORD GetRecord(EXCEPTION_RECORD *lpRecord,DWORD dwLen);
/*****************************************************************************\
函数名称:GetFunName
函数功能:异常函数描述
参数:
input:
无
output:
std::string &szFun 异常函数描述符
返回值:
无
\*****************************************************************************/
void GetFunName(std::string &szFun);
/*****************************************************************************\
函数名称:Install
函数功能:C++异常处理转换为SEH
参数:
input:
无
output:
无
返回值:
无
异常类型:
无
\*****************************************************************************/
void Install(void) throw();
protected:
inline static void TranslatorSEH(UINT unCode,LPEXCEPTION_POINTERS lptgInfo);
private:
EXCEPTION_POINTERS m_tgException;
DWORD m_dwCode;
CComBSTR m_cError;
std::string m_szFun;
};inline void CExceptionByJade::GetFunName(std::string &szFun)
{
szFun = m_szFun;
}inline DWORD CExceptionByJade::ErrorCode(void)
{
return m_dwCode;
}inline void CExceptionByJade::Install(void) throw()
{
_set_se_translator(TranslatorSEH);
}inline void CExceptionByJade::TranslatorSEH(UINT unCode,LPEXCEPTION_POINTERS lptgInfo)
{
throw CExceptionByJade(unCode,"TranslatorSEH",lptgInfo);
}inline DWORD CExceptionByJade::GetRecord(EXCEPTION_RECORD *lpRecord,DWORD dwLen)
{
if(IsBadWritePtr(lpRecord,sizeof(EXCEPTION_POINTERS)))
return -1;
if(IsBadReadPtr(lpRecord,sizeof(EXCEPTION_POINTERS)))
return -1;
memcpy(lpRecord,&m_tgException.ExceptionRecord,sizeof(EXCEPTION_POINTERS));
return 0;
}#endif /*__JADE_EXCEPTION_H_H*/
1. 内存管理应该是用户自己管理的。程序退出了。内存就不存在泄漏。内存管理和异常处理应该没什么关系的。2. __try __except 捕获的异常是针对当前作用域。跟线程没关系。新启的线程没加__try。3. 可以用SetUnhandledExceptionFilter。现在开发基本上都是模块化,不是很提倡跨线程处理别人的异常。另:使用的时候感觉这个不是很稳定。90%以上情况都正常。极少数情况无法捕获。这让人很尴尬。因为不是必现,具体原因没排查出来。如果有知道原因的,麻烦告诉我一下。