最近有个用户遇到程序Crash问题,但我们的机器都不能重现,于是在网上搜了一把,发现有个MSJExceptionHandler类还比较好用,故整理了一下供大家参考。
这个类的使用方法很简单,只要把这个类加入到你的工程(不管是MFC,com,dll都可以)中一起编译就可以了,由于在这个类的实现文件中把定义了一个全局的类对象,所以不用加入任何代码,连#include都不需要。
一、VS2005创建一个基于对话框的工程testCrash
1.将msjexhnd.h和msjexhnd.cpp加入到这个工程
此时编译程序会提示错误fatal error C1010: unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source?
2.工程中选中msjexhnd.cpp右键>属性,在c/c++>Precompiled Headers>Create/Use Precompiled Headers选择Not Using Precompiled Headers,Ok
编译程序,成功。
3.首先设置工程为Release编译,然后选中工程右键>属性,在c/c++>Output Files>Assembler Output选择Assembly, Machine Code and Source (/FAcs).
这个选项将为每个源文件(*.cpp)生成机器码、汇编码和源代码的对应表,可以在“Release”目录下找到和查看这些文件。
然后在Linker>Debugging>Generate Map File选择Yes (/MAP),这个选项将生成编译后的函数地址和函数名的对应表。
点击ok后rebuild此工程,可以在Release目录找到testCrash.map,testCrashDlg.cod
4.在工程中加入测试代码,并重新编译程序
void CtestCrashDlg::OnBnClickedOk()
{
// TODO: Add your control notification handler code here
int *p=NULL;
*p = 0; //给空指针赋值
OnOK();
}
二、查找Crash
1.运行testCrash.exe,点击ok按钮,程序crash
此时会在exe同一目录下生成文件 testCrash.RPT,你可以自己定义此文件位置及名字,具体看MSJExceptionHandler的构造函数。
2.用文本方式打开testCrash.RPT,可以看到这一行
Fault address: 00401452 01:00000452 d:\myown\test\testcrash\release\testCrash.exe
注意01:00000452就是程序崩溃的地址
3.打开testCrash.map,可以找到
0001:00000450 ?OnBnClickedOk@CtestCrashDlg@@QAEXXZ 00401450 f testCrashDlg.obj
0001:00000460 ?Create@CDialog@@UAEHIPAVCWnd@@@Z 00401460 f i testCrashDlg.obj
由于崩溃地址是01:00000452,大于0001:00000450,小于0001:00000460,所以可以肯定是CtestCrashDlg::OnBnClickedOk里崩溃。
并且相对地址是 00000452-00000450=2(16进制),代码对应在testCrashDlg.cod因为最后面显示的是testCrashDlg.obj
4.打开testCrashDlg.cod,找到
; COMDAT ?OnBnClickedOk@CtestCrashDlg@@QAEXXZ
_TEXT SEGMENT
?OnBnClickedOk@CtestCrashDlg@@QAEXXZ PROC ; CtestCrashDlg::OnBnClickedOk, COMDAT
; _this$ = ecx
; 155 : // TODO: Add your control notification handler code here
; 156 : int *p=NULL;
00000 33 c0 xor eax, eax
; 157 : *p = 0;
00002 89 00 mov DWORD PTR [eax], eax
; 158 : OnOK();
前面带分号的是注释,不带的是汇编代码,汇编代码前面5位数是代码在此函数的相对地址,00002就是偏移2,正是我们要找的崩溃的地方。
它上面的一行是注释实际的源代码; 157 : *p = 0;
好,终于找到元凶!