windows下qt程序意外崩溃,生成dump文件的方法(OK,推荐)

本文介绍在Windows环境下,当QT程序意外崩溃时如何生成dump文件进行错误定位。通过在程序中添加特定代码,可以自动创建dump文件,便于后续分析和调试。

windows下qt程序意外崩溃,生成dump文件的方法

2019-08-04 10:53:01 颖妹子 阅读数 120更多

分类专栏: Qt C++ VS

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.youkuaiyun.com/weixin_38621214/article/details/98448657

程序运行一段时间之后,意外退出,没有提示任何出错信息,这种情况可能是内存泄漏,但是没有提示错误信息,很难定位到具体代码。我们可以生成dump文件,定位出错位置。

在工程中添加代码:

MiniDumper.h

#ifndef MINIDUMP_H
#define MINIDUMP_H
#include <Windows.h>
#include <DbgHelp.h>
// based on dbghelp.h
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
                                         CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
                                         CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
                                         CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
                                         );
#define MAX_WARNING_MESSAGE_PATH 1024
class MiniDumper
{
private:
    static LPCWSTR m_szAppName;
    static LPWSTR m_szAppVersion;
    static LPWSTR m_szAppBuildNumber;

    static WCHAR m_szMessageText[MAX_WARNING_MESSAGE_PATH];

    static LPWSTR m_szDumpFilePath;

    static LONG WINAPI TopLevelFilter( struct _EXCEPTION_POINTERS *pExceptionInfo );

public:
    MiniDumper( );
    ~MiniDumper();
    static void SetVersion(LPCWSTR szVersion);
    static void SetBuildNumber(LPCWSTR szBuildNumber);
    static void SetDumpFilePath(LPCWSTR szFilePath);
    static int SetWarningMessage(LPCWSTR szMessageText)
    {
        if(szMessageText)
        {
            int iLen = wcslen(szMessageText);
            if(iLen < MAX_WARNING_MESSAGE_PATH - MAX_PATH)
            {
                wcscpy(m_szMessageText,szMessageText);
                return 0;
            }
        }
        return 1;
    }
};


#endif

MiniDumper.cpp

#include <Windows.h>
#include "MiniDumper.h"
#include <QtDebug>

LPCWSTR MiniDumper::m_szAppName;

LPWSTR MiniDumper::m_szAppVersion;

LPWSTR MiniDumper::m_szAppBuildNumber;

WCHAR MiniDumper::m_szMessageText[MAX_WARNING_MESSAGE_PATH];

LPWSTR MiniDumper::m_szDumpFilePath;

#define DEFAULT_ENGLISH_MESSAGE_TEXT L"%s experienced an unknown error and had to exit. \nHowever, some error information has been saved in %s. \nPlease, email this file to <hassan_deldar@yahoo.com> if you would like to help us debug the problem."

#define MAX_DUMP_FILE_NUMBER 9999


//static int DUMP_TYPE_MINI = MiniDumpWithUnloadedModules;

//static int DUMP_TYPE_MIDD = MiniDumpWithUnloadedModules | MiniDumpWithIndirectlyReferencedMemory;

static int DUMP_TYPE_FULL = MiniDumpNormal | MiniDumpWithFullMemory | MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData;

//static int DUMP_TYPE_FULL = MiniDumpNormal;
//默认值是只有 MiniDumpNormal 文件比较小
//如果把所有的选项都加上, 文件很大, 本机调试也没关系


MiniDumper::MiniDumper()
{
    // if this assert fires then you have two instances of MiniDumper
    // which is not allowed
    Q_ASSERT( m_szAppName==NULL );

    m_szAppName = wcsdup(L"iLadarDataCollect");
    m_szAppVersion = wcsdup( L"CrashDump");
    m_szAppBuildNumber = wcsdup( L"0000");

    wcscpy(m_szMessageText,DEFAULT_ENGLISH_MESSAGE_TEXT);


    m_szDumpFilePath = NULL;
    ::SetUnhandledExceptionFilter( TopLevelFilter );
}

MiniDumper::~MiniDumper()
{
}

void MiniDumper::SetVersion(LPCWSTR szVersion)
{
    if(szVersion)
    {
        free(m_szAppVersion);
        m_szAppVersion = wcsdup(szVersion);
    }
}

void MiniDumper::SetBuildNumber(LPCWSTR szBuildNumber)
{
    if(szBuildNumber)
    {
        free(m_szAppBuildNumber);
        m_szAppBuildNumber = wcsdup(szBuildNumber);
    }
}

void MiniDumper::SetDumpFilePath(LPCWSTR szFilePath)
{
    free(m_szDumpFilePath);
    m_szDumpFilePath = NULL;
    if(szFilePath != NULL)
    {
        m_szDumpFilePath = wcsdup(szFilePath);
    }
}

LONG MiniDumper::TopLevelFilter( struct _EXCEPTION_POINTERS *pExceptionInfo )
{

    LONG retval = EXCEPTION_CONTINUE_SEARCH;
    HWND hParent = NULL; // find a better value for your app

    // firstly see if dbghelp.dll is around and has the function we need
    // look next to the EXE first, as the one in System32 might be old
    // (e.g. Windows 2000)
    HMODULE hDll = NULL;
    WCHAR szDbgHelpPath[_MAX_PATH];

    if (GetModuleFileName( NULL, szDbgHelpPath, _MAX_PATH ))
    {
        WCHAR *pSlash = wcsrchr( szDbgHelpPath, L'\\');
        if (pSlash)
        {
            wcscpy( pSlash+1, L"DBGHELP.DLL" );
            hDll = ::LoadLibrary( szDbgHelpPath );

        }

        if (hDll==NULL)
        {
            // load any version we can
            hDll = ::LoadLibrary( L"DBGHELP.DLL");
        }

        LPCWSTR szResult = NULL;

        if (hDll)
        {
            MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );
            if (pDump)
            {
                WCHAR szDumpPath[_MAX_PATH];
                WCHAR szDumpRootPath[_MAX_PATH];
                WCHAR szScratch[_MAX_PATH];

                // work out a good place for the dump file

                if(m_szDumpFilePath == NULL)
                {
                    if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
                    {
                        WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
                        if (pSlash)
                        {
                            wcscpy(pSlash + 1, L"");
                            wcscpy(szDumpPath, szDbgHelpPath);
                        }
                    }
                    else if (!GetTempPath( _MAX_PATH, szDumpPath ))
                        wcscpy( szDumpPath, L"c:\\temp\\" );
                }
                else
                {
                    wcscpy( szDumpPath, m_szDumpFilePath );
                }
                wcscpy( szDumpRootPath, szDumpPath);

                //PrintDebug(L"[MiniDumper] Mini Dump file:[%s]",szDumpPath);

                // ask the user if they want to save a dump file
                //if (::MessageBox( NULL, _T("Something bad happened in your program, would you like to save a diagnostic file?"), m_szAppName, MB_YESNO )==IDYES)
                {
                    HANDLE hFile = INVALID_HANDLE_VALUE;
                    int i = 1;
                    WCHAR szFileNumber[_MAX_PATH];
                    while(hFile == INVALID_HANDLE_VALUE)
                    {
                        swprintf(szFileNumber, sizeof(szFileNumber), L"_%04d",i);
                        wcscpy( szDumpPath, szDumpRootPath);
                        wcscat( szDumpPath, m_szAppName );
                        wcscat( szDumpPath, L"_" );
                        wcscat( szDumpPath, m_szAppVersion);
                        wcscat( szDumpPath, L"_" );
                        wcscat( szDumpPath, m_szAppBuildNumber);
                        wcscat( szDumpPath, szFileNumber);
                        wcscat( szDumpPath, L".dmp" );
                        hFile = CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW,
                                            FILE_ATTRIBUTE_NORMAL, NULL );
                        i++;
                        if(i > MAX_DUMP_FILE_NUMBER)
                        {
                            hFile = CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
                                                FILE_ATTRIBUTE_NORMAL, NULL );
                            break;
                        }
                    }
                    // create the file

                    if (hFile!=INVALID_HANDLE_VALUE)
                    {
                        _MINIDUMP_EXCEPTION_INFORMATION ExInfo;

                        ExInfo.ThreadId = GetCurrentThreadId();
                        ExInfo.ExceptionPointers = pExceptionInfo;
                        ExInfo.ClientPointers = NULL;

                        // write the dump
                        BOOL bOK = pDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)DUMP_TYPE_FULL, &ExInfo, NULL, NULL );
                        if (bOK)
                        {
                            swprintf( szScratch, sizeof(szScratch), L"Saved dump file to '%s'", szDumpPath );
                            szResult = szScratch;
                            retval = EXCEPTION_EXECUTE_HANDLER;
                        }
                        else
                        {
                            swprintf( szScratch, sizeof(szScratch),L"Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError() );
                            szResult = szScratch;
                        }
                        CloseHandle(hFile);

                        WCHAR csOutMessage[MAX_WARNING_MESSAGE_PATH];
                        swprintf(csOutMessage, sizeof(csOutMessage), m_szMessageText, m_szAppName, szDumpPath);

                        //PrintError(_T("%s"), csOutMessage);
                        //MessageBoxW( NULL, csOutMessage, m_szAppName , MB_OK );
                        qDebug() << "Dump Crash file ...";
                    }
                    else
                    {
                        swprintf( szScratch, sizeof(szScratch),L"Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError() );
                        szResult = szScratch;
                    }
                }

            }
            else
            {
                szResult = L"DBGHELP.DLL too old";
            }
        }
        else
        {
            szResult = L"DBGHELP.DLL not found";
        }

        if (szResult)
        {
            //PrintDebug(_T("[MiniDumper] Mini Dump result:[%s]"),szResult);
        }

        return retval;
    }
}

在main.cpp中添加如下代码:

    MiniDumper dump;

 程序意外退出时,在debug或者release下生成dump文件,如下图所示:

双击dmp文件,用vs打开。点击下图中红色箭头指向的“使用 仅限本机进行调试”,即可定位到出错的地方。

 

 

<think>首先,用户的问题是:“我想在基于QT的环境中使用yum安装或配置valgrind请问如何通过yum在QT开发环境中安装和配置valgrind”。用户指定了“参考站内引用”,引用内容是关于在CentOS系统上安装工具的问题,特别是提到了yum安装devtoolset,cpplint的配置,以及QT开发环境的搭建。用户的关键点是“基于QT的环境”,指的是QT开发环境,并且想安装valgrind通过yum。valgrind是一个内存泄露检测工具,常用于调试程序。引用中:-[1]提到在CentOS7.6上使用yum安装devtoolset-9,这对于x86和Arm非Qt环境没问题,但ArmQt5环境不支持。这表明在Qt环境下可能会有兼容性问题。-[2]是关于cpplint的安装和配置,与valgrind无关。-[3]是关于在CentOS6.5上安装nginx,无关。-[4]是关于QT5Linux开发环境搭建,提到了调试模式的使用,但没直接说valgrind。用户之前的指令强调了系统级规则:-所有行内数学表达式用$...$(但用户问题中没有数学内容)。-独立公式用$$...$$。-LaTeX语法正确。-使用中文回答。-生成相关问题。-在引用的段落末尾添加引用标识,如[^n]。我的回答需要结构清晰,帮助用户逐步解决问题。我需要确保回答真实可靠。核心问题:在QT开发环境中通过yum安装和配置valgrind。-OS:假设是CentOS,因为这些引用都提到了CentOS。引用[1]明确是CentOS7.6,并且是x86或Arm。-QT环境:引用[1]提到了ArmCentOS7.6的Qt5环境,说yum安装devtoolset-9有问题。这可能暗示在Qt环境下可能有特定问题。-valgrind:这是一个工具,常用于调试,支持在Linux上使用。步骤分析:1.**安装valgrind**:使用yum安装valgrind应该很简单。在CentOS上,标准命令是`yuminstallvalgrind`。-引用[1]提到在yum安装devtoolset-9时有兼容性问题,但valgrind是独立的工具,可能没同样问题。valgrind在yum仓库中通常可用。2.**配置valgrind**:安装后,配置通常是环境设置,比如在Qt项目中调用valgrind来调试程序。-valgrind的基本配置可能不需要额外步骤,但集成到Qt开发中可能需要。3.**Qt环境集成**:-QtCreator(IDE)支持外部工具。用户可以配置QtCreator来运行valgrind作为调试工具。-参考引用[4],提到在Qt中使用调试模式检测coredumps,类似于valgrind的功能。-具体步骤:在QtCreator中,用户可以添加valgrind作为自定义工具。现在,构建回答:-**结构清晰**:逐步说明如何安装和配置。-**参考引用**:引用中提到了Arm和Qt5环境的问题。在回答中,我需要提到可能的兼容性问题。-引用[1]:"对于ArmCentOS7.6的Qt5环境则无法支持"–如果用户是Arm架构,并且是Qt5,安装valgrind可能有类似问题?valgrind是工具,不是编译工具链,所以可能ok。但需要小心。-**添加引用标识**:在回答中引用相关部分时添加[^1]等。回答大纲:1.**介绍valgrind**:解释valgrind是什么和用途。2.**安装步骤**:使用yum安装valgrind。3.**配置和集成到Qt环境**:如何在QtCreator中使用valgrind。4.**潜在问题**:基于引用[1],讨论在特定环境下的兼容性问题。5.**结束**:添加相关问题。详细步骤:-安装valgrind:-`sudoyuminstallvalgrind`-在Qt环境中使用:-打开QtCreator。-添加valgrind作为外部工具。-例如:在"Tools">"External">"Configure"添加新的工具。-命令设置为valgrind,参数根据程序设置。-验证:运行一个Qt程序通过valgrind来检测内存错误。潜在问题:-如果OS是ArmCentOS7.6的Qt环境,引用[1]说有devtoolset问题。valgrind可能依赖某些库。建议用户检查yum是否成功安装。-安装后,如果valgrind崩溃或报错,可能需要调试。添加引用标识:-在提到兼容性问题时,参考引用[1]。最后,生成相关问题:-相关问题部分:基于用户需求,提出相关的问题。-例如:如何验证valgrind是否工作?如何在Qt中调试内存泄露?等等。用中文回答。</think> ### 在QT开发环境中使用yum安装和配置Valgrind Valgrind是一个内存调试和性能分析工具,常用于检测内存泄漏、非法内存访问等错误。针对您基于QT的开发环境(如CentOS系统),通过yum安装和配置Valgrind的步骤如下。我会参考站内引用的相关内容,重点注意兼容性问题(如在Arm架构的QT环境中可能出现的问题),并分步解释过程。 #### 步骤1: 检查系统环境和预配置 在安装前,确认您的系统版本和架构(如x86或Arm),因为引用[1]提到在**Arm CentOS7.6的QT5环境可能不支持某些yum安装方式**[^1]。 - **检查系统信息**: 运行命令: ```bash lsb_release -a # 查看CentOS版本 uname -m # 查看架构(x86_64或aarch64) ``` - **更新yum仓库**: 确保yum源是最新的,以避免安装失败: ```bash sudo yum update -y ``` - **注意事项**: - 如果您的环境是Arm架构的CentOS7.6(如aarch64),确保已安装基本开发工具: ```bash sudo yum groupinstall "Development Tools" -y ``` - 引用[1]指出在Arm QT5环境中,yum安装特定库可能有问题[^1]。Valgrind本身可能无此问题,但安装后需验证。 #### 步骤2: 使用yum安装Valgrind Valgrind在CentOS标准仓库中可用,安装命令如下: ```bash sudo yum install valgrind -y ``` - **安装验证**: 运行命令检查版本: ```bash valgrind --version # 输出类似"valgrind-3.15.0" ``` 如果安装失败(尤其在Arm QT5环境),错误可能源于系统依赖。可尝试安装兼容层或更新仓库: - 引用[1]提到利用Yum SCL源安装devtoolset(如devtoolset-9)[^1],但仅建议在非QT环境或x86架构使用。若必须,执行: ```bash sudo yum install centos-release-scl -y # 安装SCL源[^1] sudo yum install devtoolset-9 -y # 安装后启用环境:scl enable devtoolset-9 bash ``` 之后重试安装Valgrind。但需注意,在QT环境中,这可能干扰编译链。 #### 步骤3: 配置Valgrind集成到QT开发环境 Valgrind安装后,需在QT Creator(Qt IDE)中配置调试工具。以下基于引用[4],其中提到QT调试模式能检测core dump位置,而Valgrind可扩展此功能以分析内存问题[^4]。 - **配置QT Creator外部工具**: 1. 打开QT Creator,进入"Tools" > "External" > "Configure..."。 2. 添加新工具,例如命名为"Valgrind内存检测"。 3. 设置参数: - **Executable**: `/usr/bin/valgrind` - **Arguments**: `--leak-check=full --track-origins=yes --error-exitcode=1 ./your_qt_app` (替换`your_qt_app`为您的可执行文件路径) - **Working Directory**: 指定项目编译输出目录(如`/path/to/build-folder`) 4. 保存后,在"Tools"菜单中调用此工具运行QT程序。 - **测试Valgrind功能**: - 创建一个简单的QT测试程序(如一个有内存泄漏的按钮应用)。 - 在QT Creator的构建配置中选择"Debug"模式(引用[4]提到调试模式可断点捕捉coredump[^4])。 - 启动配置的Valgrind工具,分析输出日志中的内存泄漏报告。 - **常用参数调优**: - 使用`--suppressions=/path/to/suppressions`忽略已知错误(如QT内部库的伪阳性)。 - 在QT项目的`.pro`文件中添加条件编译选项,避免与valgrind冲突: ```makefile CONFIG(debug, debug|release) { QMAKE_CXXFLAGS += -g -O0 # 确保调试符号存在 } ``` #### 步骤4: 验证与常见问题处理 - **验证安装**: 运行测试命令检查Valgrind: ```bash valgrind --tool=memcheck ls -l # 分析ls命令的内存使用,应无错误 ``` - **潜在问题解决方案**: - **安装失败**:在Arm QT环境中,尝试从源码编译Valgrind(非yum方式): ```bash wget https://sourceware.org/pub/valgrind/valgrind-3.20.0.tar.bz2 tar -xvjf valgrind-3.20.0.tar.bz2 cd valgrind-3.20.0 ./configure make sudo make install ``` - **Valgrind崩溃**:引用[4]强调QT调试直接断在挂点[^4],但Valgrind可能与QT库冲突。添加`--trace-children=yes`监控子进程,或升级到最新的Valgrind版本。 - **内存报告不准确**:检查系统内核版本(需≥3.0),并确保Valgrind版本与QT兼容。 #### 总结 通过yum安装Valgrind在x86架构或非QT环境较简单,但在Arm CentOS7.6的QT5环境可能需额外验证[^1]。安装后,在QT Creator中配置外部工具可实现内存检测调试。此方法可靠,引用[4]的调试实践可用于指导优化配置[^4]。如果您遇到特定错误,请提供详细日志以便进一步诊断。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值