跨平台 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…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
