跨平台 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…...
FF14副本动画跳过插件终极指南:3分钟告别冗长等待
FF14副本动画跳过插件终极指南:3分钟告别冗长等待 【免费下载链接】FFXIV_ACT_CutsceneSkip 项目地址: https://gitcode.com/gh_mirrors/ff/FFXIV_ACT_CutsceneSkip 你是否曾在《最终幻想14》国服副本中,看着那些无法跳过的动画感到无比焦虑&…...
VideoDownloadHelper:三分钟掌握浏览器视频下载技巧,告别观看限制
VideoDownloadHelper:三分钟掌握浏览器视频下载技巧,告别观看限制 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 你是…...
别再死记硬背了!用Verilog/SystemVerilog手把手教你理解Decoder、Mux和Selector的电路本质
从Verilog代码反推Decoder与Mux的硬件本质:写给会看电路图但写不出代码的工程师 当你第一次在教科书上看到2-4解码器的门级电路图时,是否觉得那些与门排列得像积木一样整齐?但当你打开编辑器准备用Verilog实现时,却发现大脑一片空…...
工业视觉系统选型实战:CCD相机与镜头参数计算全解析
1. 项目概述:从“神坛”到“工具箱”的CCD相机与镜头选型 在自动化视觉检测、精密测量和机器视觉领域,CCD工业相机和镜头的选型与参数计算,常常被新手工程师视为一个“黑箱”或“玄学”问题。客户一问到“这个系统能看多清楚?”、…...
三步搞定Windows和Office永久激活:KMS_VL_ALL_AIO智能激活全攻略
三步搞定Windows和Office永久激活:KMS_VL_ALL_AIO智能激活全攻略 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows系统频繁弹出激活提示而烦恼吗?Office突然…...
3步解锁开源字体编辑器:从零基础到专业字体设计师的蜕变之路
3步解锁开源字体编辑器:从零基础到专业字体设计师的蜕变之路 【免费下载链接】fontforge Free (libre) font editor for Windows, Mac OS X and GNULinux 项目地址: https://gitcode.com/gh_mirrors/fo/fontforge FontForge是一款跨平台的开源字体编辑器&…...
Cadence SKILL脚本实战:5分钟搞定TESTKEY原理图批量创建(附完整代码)
Cadence SKILL脚本实战:5分钟搞定TESTKEY原理图批量创建(附完整代码) 在集成电路设计领域,TESTKEY(测试结构)的创建是验证工艺模型和器件特性的基础工作。传统手动放置器件的方式不仅效率低下,还…...
逆向实战:用WT-JS_DEBUG_V1.8.3快速定位并导出AES加密参数到Python
逆向工程实战:从浏览器到Python的AES加密参数高效迁移指南 在数据采集和接口分析领域,遇到前端加密是再常见不过的挑战。特别是当网站采用AES加密时,如何快速提取关键参数并复用到Python脚本中,成为许多开发者头疼的问题。本文将…...
SAP SD新手避坑指南:交货工厂和装运点配置错了,小心订单发不出去!
SAP SD配置实战:交货工厂与装运点配置错误的深度排查手册 当销售订单在SAP系统中卡在发货环节时,背后往往隐藏着交货工厂(Plant)与装运点(Shipping Point)的配置逻辑问题。这类错误不仅会导致业务流程中断&…...
什么是数字员工?AI销冠系统与AI提效软件系统在提升销售效率中的关键角色是什么?
数字员工成为一种新兴的AI销售工具,正在为企业优化业务流程和提升运营效率提供巨大助力。这些智能化的虚拟职员能够处理大量的客户咨询,全天候地维护客户关系,显著减少了人力资源的消耗。依靠AI销冠系统,这些数字员工除了实时分析…...
