跨平台 C++ 程序崩溃调试与 Dump 文件分析
前言
C++ 程序在运行时可能会由于 空指针访问、数组越界、非法内存访问、栈溢出 等原因崩溃。为了分析崩溃原因,我们通常会生成 Dump 文件(Windows 的 .dmp,Linux 的 core,macOS 的 .crash),然后用调试工具分析。
1. Windows: MiniDump 生成 .dmp 文件
Windows 提供了 MiniDumpWriteDump() API 来生成 MiniDump 文件(.dmp),它可以记录程序崩溃时的内存、线程、异常信息等。
1.1 MiniDumpWriteDump() 介绍
BOOL MiniDumpWriteDump(HANDLE hProcess, // 进程句柄DWORD ProcessId, // 进程 IDHANDLE hFile, // Dump 文件句柄MINIDUMP_TYPE DumpType, // Dump 类型PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, // 异常信息 (可选)PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, // 额外数据 (可选)PMINIDUMP_CALLBACK_INFORMATION CallbackParam // 回调函数 (可选)
);
1.2 参数解析
| 参数 | 作用 |
|---|---|
hProcess | 进程句柄(用 GetCurrentProcess() 获取) |
ProcessId | 进程 ID(用 GetCurrentProcessId() 获取) |
hFile | 目标 Dump 文件的句柄(用 CreateFile() 创建) |
DumpType | Dump 类型(控制记录多少信息) |
ExceptionParam | 异常信息(用于捕获崩溃时的状态,可选) |
UserStreamParam | 额外数据(可为空) |
CallbackParam | 回调函数(可为空) |
1.3 Dump 类型(MINIDUMP_TYPE)
| 类型 | 值(十六进制) | 描述 |
|---|---|---|
| MiniDumpNormal | 0x00000000 | 默认值,仅包含基本信息(进程、线程、模块) |
| MiniDumpWithDataSegs | 0x00000001 | 记录全局变量数据段 |
| MiniDumpWithFullMemory | 0x00000002 | 完整 Dump,包含所有进程内存(文件较大) |
| MiniDumpWithHandleData | 0x00000004 | 记录所有句柄信息 |
| MiniDumpFilterMemory | 0x00000008 | 过滤一些私有的内存区域以减少 Dump 大小 |
| MiniDumpScanMemory | 0x00000010 | 扫描进程内存以获取更多信息 |
| MiniDumpWithUnloadedModules | 0x00000020 | 记录已卸载的模块 |
| MiniDumpWithIndirectlyReferencedMemory | 0x00000040 | 记录被指针间接引用的内存内容 |
| MiniDumpFilterModulePaths | 0x00000080 | 仅记录模块路径,不包含完整的模块数据 |
| MiniDumpWithProcessThreadData | 0x00000100 | 记录进程/线程额外信息 |
| MiniDumpWithPrivateReadWriteMemory | 0x00000200 | 记录进程私有的读写内存 |
| MiniDumpWithoutOptionalData | 0x00000400 | 不包含可选数据,减小 Dump 大小 |
| MiniDumpWithFullMemoryInfo | 0x00000800 | 记录完整的内存信息 |
| MiniDumpWithThreadInfo | 0x00001000 | 记录所有线程的详细信息 |
| MiniDumpWithCodeSegs | 0x00002000 | 记录代码段信息 |
| MiniDumpWithoutAuxiliaryState | 0x00004000 | 不包含辅助状态信息 |
| MiniDumpWithFullAuxiliaryState | 0x00008000 | 记录完整的辅助状态信息 |
| MiniDumpWithPrivateWriteCopyMemory | 0x00010000 | 记录写时复制(Copy-on-Write)的私有内存 |
| MiniDumpIgnoreInaccessibleMemory | 0x00020000 | 忽略无法访问的内存区域 |
| MiniDumpWithTokenInformation | 0x00040000 | 记录进程的 Token 信息(用于权限分析) |
| MiniDumpWithModuleHeaders | 0x00080000 | 记录模块的 PE 头信息 |
| MiniDumpFilterTriage | 0x00100000 | 仅记录用于故障诊断的最小数据集 |
| MiniDumpValidTypeFlags | 0x001FFFFF | 所有可用的 Dump 类型标志位(用于验证 Dump 类型) |
推荐使用 MiniDumpWithDataSegs | MiniDumpWithThreadInfo,可以更全面地分析崩溃原因。
1.4 自定义 Dump 文件存储路径
在 Windows 上,我们可以自定义 Dump 文件的存储路径,例如存放到 C:\Dumps\ 目录下:
std::string dumpPath = "C:\\Dumps\\crash_dump.dmp";
HANDLE hFile = CreateFileA(dumpPath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
确保 C:\Dumps\ 目录存在,否则 CreateFileA() 可能会失败。
1.5 Windows 代码示例
#include <windows.h>
#include <dbghelp.h>
#include <iostream>#pragma comment(lib, "dbghelp.lib")void CreateDump(const std::string& dumpPath, EXCEPTION_POINTERS* pExceptionInfo) {HANDLE hFile = CreateFileA(dumpPath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile != INVALID_HANDLE_VALUE) {MINIDUMP_EXCEPTION_INFORMATION dumpInfo;dumpInfo.ThreadId = GetCurrentThreadId();dumpInfo.ExceptionPointers = pExceptionInfo;dumpInfo.ClientPointers = TRUE;MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithDataSegs | MiniDumpWithThreadInfo, &dumpInfo, NULL, NULL);CloseHandle(hFile);}
}LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS* pExceptionInfo) {std::string dumpPath = "C:\\Dumps\\crash_dump.dmp";CreateDump(dumpPath, pExceptionInfo);return EXCEPTION_EXECUTE_HANDLER;
}int main() {SetUnhandledExceptionFilter(ExceptionHandler);// 触发崩溃int* p = nullptr;*p = 10;return 0;
}
1.6 Dump 分析
可以用 Visual Studio 或 WinDbg 打开 .dmp 文件,查看调用栈、崩溃地址等信息。
2. Linux: Core Dump 生成
Linux 默认会生成 core 文件,记录程序崩溃时的内存状态。
2.1 启用 Core Dump(需要命令启动)
ulimit -c unlimited # 允许生成 core dump 文件
2.2 自定义 Core Dump 存储路径
可以修改 /proc/sys/kernel/core_pattern 来改变 Core Dump 存放路径,例如:
echo "/tmp/core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern
这样崩溃后,Core Dump 文件将存放到 /tmp/ 目录,并包含程序名和进程 ID。
2.3 代码示例
#include <iostream>
#include <csignal>
#include <sys/resource.h>void EnableCoreDump() {struct rlimit core_limit = { RLIM_INFINITY, RLIM_INFINITY };setrlimit(RLIMIT_CORE, &core_limit);
}void Crash() {int* p = nullptr;*p = 42;
}int main() {EnableCoreDump();Crash();return 0;
}
2.4 Dump 生成路径
-
默认在当前目录 ./core
-
或 /var/lib/systemd/coredump/
-
可修改 /proc/sys/kernel/core_pattern
2.5 Dump 分析
gdb ./your_program core
bt # 查看调用栈
3. macOS: Crash Report(需要命令启动)
3.1 启用 Core Dump(需要命令启动)
macOS 也可能默认 禁用了 Core Dump,需要运行以下命令启用:
ulimit -c unlimited
3.2 自定义 Core Dump 存储路径
macOS 默认将 .crash 文件存放在 ~/Library/Logs/DiagnosticReports/,但可以使用 ulimit -c unlimited 后修改:
echo "/tmp/crash.%e.%p" | sudo tee /proc/sys/kernel/core_pattern
这样崩溃后,Crash Report 文件会存放到 /tmp/ 目录。
3.3 代码示例
#include <iostream>
#include <csignal>void Crash() {int* p = nullptr;*p = 42;
}int main() {signal(SIGSEGV, [](int signum) {std::cerr << "Segmentation fault caught!" << std::endl;exit(1);});Crash();return 0;
}
3.4 Dump 分析
lldb -c ~/Library/Logs/DiagnosticReports/YourApp.crash
bt # 查看调用栈
结论
参考表:如何判断崩溃原因
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
崩溃在 nullptr 访问 | 访问空指针 | assert(p != nullptr); |
| 崩溃在数组访问 | 数组越界 | 开启 ASan,检查索引 |
delete 崩溃 | 释放了已释放的内存 | nullptr 赋值后再 delete |
| 运行一段时间后崩溃 | 内存泄漏或数据竞争 | 启用 Valgrind 或 ThreadSanitizer |
| GUI 无响应 | 死锁或 UI 线程阻塞 | 检查 std::mutex 是否死锁 |
对比总结
| 平台 | 默认 Dump 目录 | 是否需要命令启动 | Dump 文件格式 | 代码生成 Dump | 触发 Dump 的方式 | 如何分析 Dump | 调试工具 |
|---|---|---|---|---|---|---|---|
| Windows | %LOCALAPPDATA%\CrashDumps\ 或 C:\Users\<用户名>\AppData\Local\CrashDumps\ | ❌ 无需命令 | .dmp | MiniDumpWriteDump() 生成 .dmp | 进程崩溃自动生成 或 手动调用 MiniDumpWriteDump() | WinDbg (!analyze -v),Visual Studio 直接打开 .dmp | WinDbg, Visual Studio |
| Linux | ./core 或 /var/lib/systemd/coredump/ | ✅ 需要 ulimit -c unlimited | core | setrlimit(RLIMIT_CORE, &core_limit) 生成 core | 进程崩溃(SIGSEGV 等)自动生成 或 gcore 手动触发 | gdb <程序> <core>,或 eu-stack -p core | gdb |
| macOS | ~/Library/Logs/DiagnosticReports/ | ✅ 需要 ulimit -c unlimited | .crash | signal(SIGSEGV, handler) 生成 .crash | 进程崩溃(SIGSEGV 等)自动生成 或 lldb -> process save-core 生成 | lldb -c <crash文件>,atos -o <可执行文件> -p <进程ID> | lldb, atos |
相关文章:
跨平台 C++ 程序崩溃调试与 Dump 文件分析
前言 C 程序在运行时可能会由于 空指针访问、数组越界、非法内存访问、栈溢出 等原因崩溃。为了分析崩溃原因,我们通常会生成 Dump 文件(Windows 的 .dmp,Linux 的 core,macOS 的 .crash),然后用调试工具分…...
缺陷VS质量:为何软件缺陷是质量属性的致命对立面?
为何说缺陷是质量的对立面? 核心逻辑:软件质量的定义是“满足用户需求的程度”,而缺陷会直接破坏这种满足关系。 对立性:缺陷的存在意味着软件偏离了预期行为(如功能错误、性能不足、安全性漏洞等)&#…...
伍[5],伺服电机,电流环,速度环,位置环
电流环、速度环和位置环是电机控制系统中常见的三个闭环控制环节,通常采用嵌套结构(内环→外环:电流环→速度环→位置环),各自负责不同层级的控制目标。以下是它们的详细说明及相互关系: 1. 电流环(最内环) 作用:控制电机的电流,间接控制输出转矩(τ=Kt⋅Iτ=Kt⋅…...
RuntimeError: CUDA error: device-side assert triggered
RuntimeError: CUDA error: device-side assert triggered 欢迎来到英杰社区,这里是博主英杰https://bbs.csdn.net/topics/617804998 原因: cuda运行可能是异步的(asynchronously),因此报错信息中提示的位置可能不准确…...
清华大学Deepseek第六版AIGC发展研究3.0(共186页,附PDF下载)
人工智能生成内容(AIGC)正以前所未有的速度改变我们的生活。 2024年底,清华大学新闻与传播学院与人工智能学院联合发布了《AIGC发展研究3.0版》,这份报告系统梳理了AIGC技术的突破性进展、应用场景及社会影响,并展望了…...
SpringBoot生成唯一ID的方式
1.为什么要生成唯一ID? 数据唯一性:每个记录都需要有一个独一无二的标识符来确保数据的唯一性。这可以避免重复的数据行,并有助于准确地查询、更新或删除特定的记录。 数据完整性:通过使用唯一ID,可以保证数据库中的数…...
通俗易懂的分类算法之K近邻详解
通俗易懂的分类算法之K近邻详解 用最通俗的语言和例子,来彻底理解 K近邻(K-Nearest Neighbors,简称 KNN) 这个分类算法。不用担心复杂的数学公式,我会用生活中的例子来解释,保证你一听就懂! 1.…...
CSDN markdown 操作指令等
CSDN markdown 操作指令等 页内跳转 [内容](#1) <div id"1"> </div>...
【linux】文件与目录命令 - uniq
文章目录 1. 基本用法2. 常用参数3. 用法举例4. 注意事项 uniq 命令用于过滤文本文件中相邻的重复行,并支持统计重复次数或仅保留唯一行。它通常与 sort 命令配合使用,因为 uniq 只识别相邻的重复行。 1. 基本用法 语法: uniq [选项] [输入…...
零信任沙箱:为网络安全筑牢“隔离墙”
在数字化浪潮汹涌澎湃的今天,网络安全如同一艘船在波涛汹涌的大海中航行,面临着重重挑战。数据泄露、恶意软件攻击、网络钓鱼等安全威胁层出不穷,让企业和个人用户防不胜防。而零信任沙箱,就像是一座坚固的“隔离墙”,…...
【金融量化】Ptrade中交易环境支持的业务类型
1. 普通股票买卖 • 特点: 普通股票买卖是最基础的交易形式,投资者通过买入和卖出上市公司的股票来获取收益。 ◦ 流动性高:股票市场交易活跃,买卖方便。 ◦ 收益来源多样:包括股价上涨的资本利得和公司分红。 ◦ 风险…...
【Java---数据结构】链表 LinkedList
1. 链表的概念 链表用于存储一系列元素,由一系列节点组成,每个节点包含两部分:数据域和指针域。 数据域:用于存储数据元素 指针域:用于指向下一个节点的地址,通过指针将各个节点连接在一起,形…...
紧跟 Web3 热潮,RuleOS 如何成为行业新宠?
Web3 热潮正以汹涌之势席卷全球。从金融领域的创新应用到供应链管理的变革,从社交媒体的去中心化尝试到游戏产业的全新玩法探索,Web3 凭借其去中心化、安全性和用户赋权等特性,为各个行业带来了前所未有的机遇。在这股热潮中,Rule…...
CC++的内存管理
目录 1、C/C内存划分 C语言的动态内存管理 malloc calloc realloc free C的动态内存管理 new和delete operator new函数和operator delete函数 new和delete的原理 new T[N]原理 delete[]的原理 1、C/C内存划分 1、栈:存有非静态局部变量、函数参数、返回…...
Spark核心之02:RDD、算子分类、常用算子
spark内存计算框架 一、目标 深入理解RDD弹性分布式数据集底层原理掌握RDD弹性分布式数据集的常用算子操作 二、要点 ⭐️1. RDD是什么 RDD(Resilient Distributed Dataset)叫做**弹性分布式数据集,是Spark中最基本的数据抽象,…...
【Resis实战分析】Redis问题导致页面timeout知识点分析
事故现象:前端页面返回timeout 事故回溯总结一句话: (1)因为大KEY调用量,随着白天自然流量趋势增长而增长,最终在业务高峰最高点期占满带宽使用100%。   (2&#x…...
单一职责原则(设计模式)
目录 问题: 定义: 解决: 方式 1:使用策略模式 示例:用户管理 方式 2:使用装饰者模式 示例:用户操作 方式 3:使用责任链模式 示例:用户操作链 总结 推荐 问题&a…...
生理信号概念
rPPG 信号(远程光电容积脉搏波信号) 原理: 基于光电容积脉搏波描记法,利用普通摄像头,在一定距离外捕捉人体皮肤表面因心脏泵血导致的血液容积变化引起的细微颜色变化,通过图像处理和信号分析算法提取心率…...
安卓内存泄露之DMA-BUF异常增长:Android Studio镜像引起DMA内存泄露
安卓内存泄露之DMA-BUF异常增长:Android Studio镜像引起DMA内存泄露 - Wesley’s Blog 今天用着安卓 14 的板子的时候突然系统卡死。 查看日志发现launcher都被干掉了 03-04 06:13:35.544 7872 8479 I ActivityManager: vis BFGS 18740: com.android.launcher3 (pid 8407) se…...
android13打基础: 控件checkbox
测试checkbox的activity // todo: 高级控件checkbox public class Ch4_CheckBoxActivity extends AppCompatActivityimplements CompoundButton.OnCheckedChangeListener {Overrideprotected void onCreate(Nullable Bundle savedInstanceState) {super.onCreate(savedInstance…...
图解CV中的交叉注意力:用QKV三兄弟搞定图像特征增强(附PyTorch代码示例)
图解CV中的交叉注意力:用QKV三兄弟搞定图像特征增强(附PyTorch代码示例) 在计算机视觉领域,注意力机制正逐渐成为提升模型性能的关键技术。不同于传统卷积操作的固定感受野,注意力机制赋予模型动态聚焦重要区域的能力。…...
揭秘APP签名信息:如何快速获取MD5、SHA1和SHA256值
1. 为什么需要获取APP签名信息? 当你下载一个APP时,有没有想过如何确认它真的是官方发布的版本?或者作为开发者,如何确保自己打包的APK没有被篡改?这些问题的答案都藏在APP的签名信息里。签名信息就像APP的"身份证…...
原神抽卡记录导出工具:一键备份分析你的抽卡历史数据
原神抽卡记录导出工具:一键备份分析你的抽卡历史数据 【免费下载链接】genshin-wish-export biuuu/genshin-wish-export - 一个使用Electron制作的原神祈愿记录导出工具,它可以通过读取游戏日志或代理模式获取访问游戏祈愿记录API所需的authKey。 项目…...
5分钟搞定ESP32开发:VSCode+ESP-IDF插件极简配置教程
5分钟极速搭建ESP32开发环境:VSCodeESP-IDF全流程指南 在物联网开发领域,ESP32凭借其出色的性价比和丰富的功能接口,已经成为智能硬件开发者的首选平台。但对于刚接触ESP32的开发者来说,传统的环境搭建过程往往充满挑战——从工具…...
3个简单步骤,用SMUDebugTool彻底解决AMD Ryzen系统稳定性问题
3个简单步骤,用SMUDebugTool彻底解决AMD Ryzen系统稳定性问题 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: htt…...
WebRtcStreamer避坑指南:解决RTSP视频流延迟高、卡顿的7个优化方案
WebRTCStreamer实战优化:7种方案彻底解决RTSP流媒体高延迟与卡顿问题 当我们在监控系统或视频会议中遇到画面卡成PPT、声音延迟到像看译制片时,那种抓狂感技术人员都懂。最近在部署某智慧园区项目时,我们通过WebRTCStreamer将200路RTSP监控流…...
【Android FWK】VR一体机全局菜单实战:从VirtualDisplay原理到系统级交互(上)
文章目录 一、从弹窗穿透到VR全局菜单 二、VirtualDisplay在VR中的适配原理 2.1 VR显示系统的特殊性 2.2 VR适配的核心代码 三、VR全局菜单的完整实现 3.1 系统架构设计 3.2 菜单呼出机制:手势+语音双重触发 3.3 菜单界面:适配VR的3D布局 3.4 系统交互:调节系统设置 四、VR环…...
解锁Stable Diffusion隐藏玩法:用ChatGPT批量生成动漫角色Prompt全攻略
从零到大师:ChatGPT与Stable Diffusion打造专属动漫角色的终极指南 在数字艺术创作领域,AI绘画工具正掀起一场前所未有的革命。想象一下,你脑海中那个独特的动漫角色形象,不再需要数月的美术训练就能实现——只需要正确的工具组合…...
5分钟解决PDF转Markdown痛点:Marker工具全场景应用指南
5分钟解决PDF转Markdown痛点:Marker工具全场景应用指南 【免费下载链接】marker 一个高效、准确的工具,能够将 PDF 和图像快速转换为 Markdown、JSON 和 HTML 格式,支持多语言和复杂布局处理,可选集成 LLM 提升精度,适…...
从零解析:富斯i6遥控器与STM32的IBUS协议通信实战
1. 为什么选择富斯i6遥控器与STM32通信 对于很多刚接触机器人或者智能小车开发的爱好者来说,无线控制模块的选择往往是个头疼的问题。市面上常见的方案要么价格昂贵,要么配置复杂,而富斯i6遥控器配合iA6B接收机恰好提供了一个低成本、高可靠性…...
