Qt环境生成dump解决异常崩溃

背景

对于经常使用C/C++的伙伴来说,程序有问题动不动就罢工崩溃的问题简直不能太熟悉了。比如本地测试通过打包发布的release版本Qt程序,在客户环境下仍可能出现异常崩溃的问题。一般通过客户反馈以及分析系统运行日志,问题基本都能够得到快速解决。但总会有些bug很难定位,这种情况下通过生成dump文件,结合winDbg程序定位问题将是一个很好的解决方式。

内容新增

-------------------------------------------------------------------分割线----------------------------------------------------------
VS作为宇宙第一IDE,名声在外自然要利用起来。对于编写Qt程序,QtCreator还是最香的。但VS的强大的调试能力还是无出其右。对于疑难问题,将QT程序移植到VS环境运行调试,是可以直接跳转到问题代码行的,这也是不错的可行方法。
-------------------------------------------------------------------分割线----------------------------------------------------------

具体操作

一、生成dump文件

在QtCreator中默认不支持生成dump文件,且发行版release模式不含调试信息,因此这里需要进行以下两步设置。

1.在.pro文件中添加如下语句,来产生调试信息以及pdb文件

QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
QMAKE_LFLAGS_RELEASE = $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO
LIBS += -lDbgHelp

2.程序文件中添加可以产生dump文件的代码。代码直接复制可用,不再讲解含义

LONG crashHandler(EXCEPTION_POINTERS *pException)
{
    QString curDataTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
    QString dumpName = curDataTime + ".dmp";

    HANDLE dumpFile = CreateFile((LPCWSTR)QString("./" + dumpName).utf16(),GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if(dumpFile != INVALID_HANDLE_VALUE)
    {
        MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
        dumpInfo.ExceptionPointers = pException;
        dumpInfo.ThreadId = GetCurrentThreadId();
        dumpInfo.ClientPointers = TRUE;

        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),dumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
        CloseHandle(dumpFile);
    }
    else
    {
        qDebug() << "dumpFile not vaild";
    }
    
    return EXCEPTION_EXECUTE_HANDLER;
}

//防止CRT(C runtime)函数报错可能捕捉不到
void DisableSetUnhandledExceptionFilter()
{
    void* addr = (void*)GetProcAddress(LoadLibrary(L"kernel32.dll"), "SetUnhandledExceptionFilter");
    if(addr)
    {
        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);
    }
}

int main(int argc, char *argv[])
{
    //注冊异常捕获函数
    SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)crashHandler);
    DisableSetUnhandledExceptionFilter();

    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

3.清除并重新qmake运行,产生pdb文件以及运行程序。此种情况下应用程序崩溃将会预定位置产生dump文件。

二、使用dump文件

1.假设此时程序崩溃得到dump文件,打开winDbg软件(需要自行下载,安装很简单),分别设置源代码路径、pdb文件路径、dump路径,确定后软件跳转至分析界面。
Qt环境生成dump解决异常崩溃_第1张图片
2.点击自动分析(!anasyle -v),产生堆栈信息,之后可以查看到出错的源代码行数
Qt环境生成dump解决异常崩溃_第2张图片

注意事项

以上提供了一个解决异常崩溃的思路,不是终极解决方案,虽然无法保证100%解决问题,但是可能会有奇效,个人建议还是逻辑分析为主,问题基本都能解决,还能锻炼分析能力,避免再写类似bug。

注意点如下:
1.应保证打包的exe,pdb,源代码版本一致,否则调试可能有偏差。
2.dump文件不保证一定产生,可能有些错误捕捉不到。
3.!anasyle -v自动分析后,大部分时候可以直接定位到出错行数,很直观。但也存在找不到行数的情况,但是有清晰的堆栈信息可以帮助分析问题。

你可能感兴趣的