今早一回到公司,测试的同事就反映,昨晚程序运行一段时间后闪退了。。。。闪退???额,好吧,幸好我有加写DUMP的代码,示例如下:
LONG WINAPI UnhandledExceptionFunction(_EXCEPTION_POINTERS* pExceptionInfo)
{
SYSTEMTIME st;
GetLocalTime(&st);
CString time_now = _T("");
time_now.Format(_T("%04d_%02d_%02d_%02d_%02d_%03d.dmp"), st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
CString dump_file_path = GetRootPath(); //获取程序所在的文件夹的路径
dump_file_path += _T("dump/");
CreateDirectory(dump_file_path, NULL);
dump_file_path += time_now;
HANDLE hDumpFile = CreateFile(dump_file_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
dumpInfo.ExceptionPointers = pExceptionInfo;
dumpInfo.ThreadId = GetCurrentThreadId();
dumpInfo.ClientPointers = TRUE;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
CloseHandle(hDumpFile);
return 1;
}
只要在程序的Main函数中加上
SetUnhandledExceptionFilter(UnhandledExceptionFunction);
就行了。但是一查看测试同事手上的软件时。。。。DUMP呢???没有生成!什么鬼!于是我去找了找“程序闪退,没有生成DUMP文件”之类的资料,于是找到了这篇博客:https://blog.csdn.net/liaozhilong88/article/details/80595757。先感谢这位博主的整理与分享。
(2020年4月3号更新:下面说的方式是错的,是错的,是错的,不要学这个逗比的博主的写法!!!到了最近我才知道这篇博客的代码的作用,今天会写一篇新的博客来说一下,这篇博客也不会删除,留下来嘲讽自己,让自己记住当年自己是多么的逗比。下面的代码可以用,没错的,现在大家知道这个博主有多逗比了吧。出现问题的估计是我那个程序里面的代码,而不是下面这个函数的代码。
顺便提一下,下面这个函数的做法是把SetUnhandledExceptionFilter函数的地址替换为0x33 0xC0 0xC2 0x04 0x00这句指令以达到屏蔽SetUnhandledExceptionFilter函数的结果,这句指令的作用究竟是什么,我到现在都不知道,但是直接使用下面这个函数的代码绝对是不行,程序会直接死掉。如果想知道如何才能成功屏蔽SetUnhandledExceptionFilter函数,如果想知道这样做的具体原理可以去看本人最新写的博客:https://blog.csdn.net/u012104827/article/details/106099271,看一下就懂了。)
(2020年5月30号更新:感谢biewenwoaaaa这位朋友的努力,找到了下面这个指令的功能了,详细请看网址:https://stackoverflow.com/questions/3010626/how-do-i-patch-a-windows-api-at-runtime-so-that-it-to-returns-0-in-x64。根据这个网址的说法,33 C0 C2 04 00这个指令的功能为XOR EAX,EAX; RET 4 ,但是为什么会导致我之前程序抛出异常呢?我是没想通,周一回去公司看看再说。)
原来SetUnhandledExceptionFilter是无法捕获printf等CRT函数的异常的,于是我加上了下面的代码后,开始了测试
void DisableSetUnhandledExceptionFilter()
{
void* addr = (void*)GetProcAddress(LoadLibrary(_T("kernel32.dll")), "SetUnhandledExceptionFilter");
if (addr != NULL)
{
unsigned char code[16];
int size = 0;
code[size++] = 0x33;
code[size++] = 0xC0;
code[size++] = 0xC2;
code[size++] = 0x04;
code[size++] = 0x00;
DWORD dwOldFlag, dwTempFlag;
VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);
WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);
VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);
}
}
上面这个函数使用方法如下所示
SetUnhandledExceptionFilter(UnhandledExceptionFunction);
DisableSetUnhandledExceptionFilter();
我先注释掉DisableSetUnhandledExceptionFilter();这句代码,并在其后面加上pritf(NULL);这句代码,如下所示
SetUnhandledExceptionFilter(UnhandledExceptionFunction);
//DisableSetUnhandledExceptionFilter();
printf(NULL);
然后运行程序,发现DUMP的确没有生成。于是我把DisableSetUnhandledExceptionFilter();的注释去掉,如下所示
SetUnhandledExceptionFilter(UnhandledExceptionFunction);
DisableSetUnhandledExceptionFilter();
printf(NULL);
再次运行程序,发现生成了DUMP,问题解决。
以上就是我对“程序闪退,没有生成DUMP文件”的一点总结。至于程序究竟是不是因为CRT的异常出现闪退,还得等测试的同事再次重现异常才可以,希望这次能捕捉到DUMP吧。