c++怎么把程序的异常堆栈信息输出到日志文件_CrashDump实现【附源码】

秋涛姑娘_4622

秋涛姑娘_4622

2026-03-27

312人浏览

原创

setunhandledexceptionfilter是windows下最轻量可靠的崩溃捕获方式,需在main/winmain开头注册,回调中禁用c++标准库,配合minidumpwritedump、stackwalk64及pdb解析堆栈;linux则用sigaction+backtrace+addr2line,注意编译选项与权限问题。

c++怎么把程序的异常堆栈信息输出到日志文件_crashdump实现【附源码】

Windows 下用 SetUnhandledExceptionFilter 捕获崩溃并写入日志

直接用系统 API 拦住未处理异常,是最轻量、最可靠的堆栈捕获方式。它不依赖调试器、不干扰 Release 构建,且能拿到崩溃瞬间的完整上下文。

常见错误现象:std::set_terminate 或 try/catch(...) 完全抓不到访问违规、栈溢出、非法指令这类 SEH 异常;日志里只看到“程序已停止工作”,没堆栈。

  • 必须在 main() 开头或 WinMain() 一开始就注册,晚了可能错过早期崩溃
  • 回调函数里禁止调用 C++ 标准库(如 std::ofstream、printf),避免重入或堆损坏;改用 WriteFile 或 OutputDebugStringA
  • 记得用 MiniDumpWriteDump 配合 dbghelp.dll 生成 .dmp 文件,纯文本堆栈在无符号信息时意义有限

用 StackWalk64 解析崩溃线程的调用栈

光有异常地址没用,得把地址转成函数名+文件行号,否则日志里全是 0x00007ff6a1b2c3f8 这种没法 debug 的值。

使用场景:你已经有崩溃线程的 CONTEXT 和模块信息,现在要逐帧回溯。

  • 必须加载对应模块的 PDB(不是 EXE 自带的,是编译时生成的 .pdb 文件),否则 SymFromAddr 返回空函数名
  • StackWalk64 要求传入正确的 CPU 架构标识(IMAGE_FILE_MACHINE_AMD64 或 IMAGE_FILE_MACHINE_I386),错一个就走不出第一帧
  • 别跳过 SymInitialize 的 fInvadeProcess = TRUE 参数,否则无法读取当前进程的模块符号

Linux 下用 backtrace + addr2line 替代方案

Windows 那套在 Linux 上跑不通,得换一套信号级捕获逻辑。核心是用 sigaction 拦住 SIGSEGV/SIGABRT,再用 GNU 扩展获取栈帧。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

性能影响:backtrace 本身很快,但后续符号解析(尤其 addr2line 外部调用)会阻塞主线程,线上服务慎用。

  • 编译时必须加 -g -rdynamic,否则 backtrace_symbols 只返回十六进制地址
  • addr2line -e your_program 0x401234 是离线解析推荐方式,比 dladdr 更准,尤其对内联函数和优化代码
  • 注意 fork() 后子进程继承信号处理,若用 system("addr2line..."),可能因 fork 失败静默丢堆栈

日志路径权限和多进程写入冲突怎么避

崩溃进程往往以受限权限运行(比如 Windows 服务跑在 LocalSystem,Linux 用 nobody 用户),直接往 C:\logs\crash.log 或 /var/log/app/ 写会失败——连打开文件句柄都返回 NULL。

容易踩的坑:用相对路径(如 "./crash.log"),结果日志写到未知目录,或者被杀毒软件拦截。

  • Windows 推荐写到 %LOCALAPPDATA%\YourApp\logs\,用 SHGetFolderPath 获取,确保用户有写权限
  • Linux 用 /tmp/yourapp_crash_$$($$ 是 pid),避免多实例覆盖;崩溃后由守护进程统一归档
  • 不要用 fopen(..., "a") 然后 fprintf —— 文件缓冲区可能未刷盘就进程终止;用 open(O_WRONLY|O_APPEND|O_CREAT) + write() 更可靠

符号解析和路径权限这两块,最容易在线上环境突然失效——本地测通不代表部署就稳。PDB 文件放哪、日志目录是否存在、SELinux 是否拦了 open,都得实机验证,不能只信开发机结果。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

2023.09.22

549

3

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

2024.03.01

1678

6

printf用法大全
printf用法大全

php中文网为大家提供printf用法大全,以及其他printf函数的相关文章、相关下载资源以及各种相关课程,供大家免费下载体验。

2023.06.20

788

5

fprintf和printf的区别
fprintf和printf的区别

fprintf和printf的区别在于输出的目标不同,printf输出到标准输出流,而fprintf输出到指定的文件流。根据需要选择合适的函数来进行输出操作。更多关于fprintf和printf的相关文章详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.28

1029

10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5827

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2508

6

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5827

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2508

6

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

4198

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习