如何定位导致程序异常退出的Bug?

3 篇文章 4 订阅

一 引言

  我们写代码的时候经常会遇到一些Bug导致程序异常退出,比如访问了空指针。在大多数情况下,我们能够根据经验和IDE本身提供的调试功能来定位问题,并找到解决方案。但最近在工作中遇到了一个问题,一个提供后台服务的程序在运行不等时间后例如30分钟,一个小时或其它时间后会异常退出。一时,毫无头绪,因为代码里面嵌入了其它同事写的模块,虽然很怀疑是同事引起的,但是没有证据就没有底气啊。百度了很多解决办法后,最终选择下面的方案,最终证明是同事模块引起的。 以下内容是我整理网友的解决方案,加以自己的简单封装,下面就对这种利用Dump文件进行程序异常分析的方式进行简介。

二 Dump文件

来自百度百科:

Dump文件是进程内存镜像。可以把程序的执行状态通过调试器保存到dump文件中。Dump文件是用来给驱动程序编写人员调试驱动程序用的,这种文件必须用专用工具软件打开,比如使用WinDbg打开。

我的解释:dump文件可以保存程序的运行信息,Windows下程序奔溃退出后会调用一个被注册过的处理函数,我们就可以在这个函数里面生成dump文件,保存现场,然后利用WinDbg Preview进行分析,可以查看当时调用堆栈,确定程序最后调用了哪个函数导致了没有出来,引起程序异常崩溃。

三 如何在程序崩溃时生成Dump文件

  SetUnhandledExceptionFilter函数是Win32API的异常捕获函数,在程式异常结束前。会调用该函数注冊的回调函数,这样就能在进程终止前运行指定的代码,达到比如保存数据的功能。其实在程序奔溃时我们也可以给予一个用户提示等,下面写出我简单封装的一个类WinDebug,使用的时候调用install即可,该类在程序崩溃时会在当前目录生成Debug.dmp,如果需要其它功能用户可自行更改handler函数。使用时不要忘记链接DbgHelp.lib!!!

WinDebug.h:

#pragma once

#include <Windows.h>
#include <DbgHelp.h>


class WinDebug
{
public:
	static void install();

private:
	static long handler(_EXCEPTION_POINTERS* pException);
};

WinDebug.cpp:

#include "WinDebug.h"
#include <QDebug>


void WinDebug::install()
{
	SetUnhandledExceptionFilter(&WinDebug::handler);
}

long WinDebug::handler(_EXCEPTION_POINTERS* pException)
{
    HANDLE hDumpFile = CreateFile(L"Debug.dmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hDumpFile != INVALID_HANDLE_VALUE)
	{
		MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
		dumpInfo.ExceptionPointers = pException;
		dumpInfo.ThreadId = GetCurrentThreadId();
		dumpInfo.ClientPointers = true;

		MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
	}

	return EXCEPTION_EXECUTE_HANDLER;
}

main.cpp:

#include <QApplication>
#include "WinDebug.h"
#include "mainwindow.h"
#include <QPainter>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    WinDebug::install();

    QPainter* p;
    p->drawLine(0, 0, 100, 100);

    MainWindow w;
    w.show();

    return a.exec();
}

注意:p是空指针,程序会异常退出。

四 Pdb文件

PDB文件是在编译工程的时候产生的,它是和对应的模块(exe或dll)一起生成出来的。pdb文件可以使用一些特有的pdb阅读器打开。如果想把PDB文件转换成TXT文件查看,可以使用专用转换器转换。如果想根据dump文件分析程序是在哪一行崩溃的就必须要有pdb文件,debug下会自动生成pdb文件。那么Release程序如何生成pdb文件呢?Qt工程可以在pro文件中加上

QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO /DEBUG

VS工程做如下设置:

1.

2.

这样就能在Release下生成PDB文件了。

五 利用WinDbg Preview分析dump文件

 WinDbg Preview可以在微软的应用商店和官网下载,这里不再赘述。请自行下载安装!

1.打开WinDbg Preview,界面如下

2.加载dump文件,点击文件,然后点击Open dump file,加载进去刚刚生成的Debug.dmp

3. 设置pdb和源码路径,点击文件->Settings,选择Debugging settings,设置好source path 和 symbol path(pdb文件路径)

4.此时主界面如下:

5. 输入 !analyze -v 或者点击上面的提示,此时会加载一些信息并打印出分析结果,查看STACK_TEXT即可查看程序异常退出前的堆栈信息。

6.我们可以看到上述函数调用过程,最后进去了QPainter::drawLines,这和我们预期的是一致的,这个函数导致了程序崩溃。

五 写在最后

  以上只是简单的程序崩溃处理,如果有更加方便简洁的方式也请各位同仁不吝赐教,最后也是感谢网友的无私分享,方有我这篇拙作。


                                                                                                                                                                                                                                                                             四时最好是三月,一去不回唯少年。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值