1. 项目场景

本故事纯属虚构。
初入职场的小木,负责维护一个博客系统,后端采用C++编写,部署在Windows服务器上。刚刚熟悉完产品的小木,接到了后台服务的报警,服务器后端偶尔会程序崩溃。刚开始小木还有点慌张,脑子里面浮现出各种问题,这个是程序的bug吗?茫茫的代码如何寻找问题?log能看到线索吗?当冷静下来后,小木忽然想起前几天看的两篇文章<<Windbg调试----Windbg入门>>和<<Windows程序Dump收集>>,还没动手过呢,正好练习练习。

2. 收集Dump

首先小木想到了要定位到问题,得收集Dump。blogserver程序是64位程序,小木决定采用procdump64去收集dump。于是在产品服务器上运行了如下的命令, 将程序产生的dump生成到C:\dumps目录下。

procdump.exe -ma blogserver.exe -t -e -o C:\dumps

接下小木就是一边review以前的代码,一边等待着Crash的出现。终于有一天出现啦,procdump64输出了如下的信息:

[15:34:17] Exception: C0000005.ACCESS_VIOLATION
[15:34:17] Unhandled: C0000005.ACCESS_VIOLATION
[15:34:17] Dump 1 initiated: C:\dumps\blogserver.exe_201115_153417.dmp
[15:34:17] Dump 1 writing: Estimated dump file size is 42 MB.
[15:34:17] Dump 1 complete: 42 MB written in 0.2 seconds
[15:34:17] Dump count reached.

ACCESS_VIOLATION 看来是访问了不可访问的内存,估计做过C++代码编写的程序员都碰到过这种内存访问问题。 小木将程序dump拷贝到了自己的办公机器上,准备用预先安装好的Windbg64位进行分析。

3. Windbg分析

小木根据之前学习的内容,先用Windbg 加载dump。用k查看crash的堆栈,因为没有加载产品的符号信息,函数调用栈,没有显示出哪个函数调用导致程序crash了。这里补充一句,默认的产品发布采用Visual Studio Release模式发布,这个模式产品的符号信息将采用.pdb文件单独保存,保证自己的符号信息不被泄露。

3.1 符号信息加载

  1. 小木先将之前产品的符号信息blogserver.pdb拷贝到调试机器的C:\blogserversymbols目录下
  2. 创建一个微软的symbols的缓存目录C:\windowssymbols, 一般windows程序会加载很多微软的dll,而在分析crash的时候,也需要加载微软的symbols
  3. 使用命令添加产品的symbols目录: .sympath c:\blogserversymbols
  4. 使用命令添加了微软的symbols,并保存到指定的目录: .sympath+ srv*C:\windowssymbols*http://msdl.microsoft.com/download/symbols
  5. 运行重新加载symbols: .reload

以上的配置也可以保存到workspace中,以便下次继续使用。

3.2 寻找程序崩溃的代码

加载完symbols后,我们来看下程序调用栈:

0:000> k# Child-SP          RetAddr               Call Site
00 00000001`08b2f4e8 00007ffb`62c05237     ucrtbase!strnlen+0x3c
01 00000001`08b2f4f0 00007ffb`62bebf65     ucrtbase!cgetws_s+0x3b37
02 00000001`08b2f520 00007ffb`62beaa7c     ucrtbase!_stdio_common_vfwscanf+0x3b15
03 00000001`08b2f570 00007ffb`62be9e7a     ucrtbase!_stdio_common_vfwscanf+0x262c
04 00000001`08b2f5a0 00007ffb`62be863b     ucrtbase!_stdio_common_vfwscanf+0x1a2a
05 00000001`08b2fac0 00007ffb`62beead1     ucrtbase!_stdio_common_vfwscanf+0x1eb
06 00000001`08b2faf0 00007ff6`78aa1c9f     ucrtbase!_stdio_common_vfprintf+0x81
07 00000001`08b2fb60 00007ff6`78aa1cf8     blogserver!_vfprintf_l+0x3f [c:\program files (x86)\windows kits\10\include\10.0.18362.0\ucrt\stdio.h @ 644]
08 00000001`08b2fba0 00007ff6`78aa15b3     blogserver!fprintf+0x48 [c:\program files (x86)\windows kits\10\include\10.0.18362.0\ucrt\stdio.h @ 839]
09 00000001`08b2fbf0 00007ff6`78aa1d59     blogserver!LogStr+0x33 [c:\personal\test\blogserver\blogserver.cpp @ 10]
0a 00000001`08b2fc30 00007ff6`78aa2054     blogserver!main+0x39 [c:\personal\test\blogserver\blogserver.cpp @ 16]
0b (Inline Function) --------`--------     blogserver!invoke_main+0x22 [d:\agent\_work\2\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 78]
0c 00000001`08b2fc90 00007ffb`653f4034     blogserver!__scrt_common_main_seh+0x10c [d:\agent\_work\2\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288]
0d 00000001`08b2fcd0 00007ffb`664a3691     kernel32!BaseThreadInitThunk+0x14
0e 00000001`08b2fd00 00000000`00000000     ntdll!RtlUserThreadStart+0x21

小木松了一口气,终于有点线索了,程序崩溃在函数LogStr,根据里面的行数提示,找到那段代码:

void LogStr(std::string strContent)
{fprintf(stdout, strContent.c_str());
}

刚松了一口气,小木又疑惑起来,这个函数是用来打印博客标题的log的,一直都用,也测试过,怎么会偶尔导致程序崩溃呢? 小木睁大眼睛,(也许在读文章的你已经知道到什么问题了),作为新手,就这么一行代码,还是没有找到原因。

3.3 真相大白

小木接着看,是不是这个log内容比较奇特呢,决定先看一看strContent的内容。
小木切到fprintf那个frame:

0:000> .frame 08
08 00000001`08b2fba0 00007ff6`78aa15b3     blogserver!fprintf+0x48 [c:\program files (x86)\windows kits\10\include\10.0.18362.0\ucrt\stdio.h @ 839]

然后再查看当前的参数内容,知道了strContentHello %sWindbg!

0:000> dv /t
struct _iobuf * _Stream = 0x00007ffb`62c584b8
char * _Format = 0x00000001`08b2fc60 "Hello %sWindbg!"
char * _ArgList = 0x00000001`08b2fc00 "Hello %sbg"
int _Result = 0n145947744

当看到%s的时候,小木的编程直觉,瞬间反应过来了,这个%s 是格化式字符串。而这句话fprintf(stdout, strContent.c_str()); 却将需要打印的strContent内容直接放在fprintf_Format参数中, 这样%s这个格式化串,将认为存在一个字符串参数,其实并没有,这样读取到的地址,将可能会出现ACCESS_VIOLATION.

真相大白了,小木身心舒适,程序员的成就感涌上心头,对着空气微微一笑。小木知道以后还会碰到棘手的问题去处理,所以决定继续努力学习,所谓“台上一分钟,台下十年功”。


最后是个人微信公众号,文章CSDN和微信公众号都会发,欢迎一起讨论。

Windbg分析程序崩溃实践相关推荐

  1. Windbg分析dump崩溃

    首先抓dump.在任务管理器->进程里面进行抓dump. 然后需要的原材料有dump.源码.pdb 打开windbg把源码路径和pdb路径添加进去. 需要打开的窗口包括线程窗口(Processe ...

  2. linux程序崩溃时调用链,Linux 获取并分析程序崩溃时的调用堆栈

    下面是一个小例子,说明了程序出现段错误时,如何打印程序的堆栈信息. #include #include #include #include static void WidebrightSegvHand ...

  3. Linux程序崩溃分析(一)

    引言 我们在做Linux开发时,常常会遇到程序崩溃的问题,这时会用gdb或者通过查看反汇编的方式去对程序进行分析,接下来,我们从底层的角度,去讲述如何分析程序崩溃的原因. 一.常见BUG 在进行分析前 ...

  4. windbg分析崩溃dmp

    首先我们收集了程序崩溃的dump文件,然后将dump文件拖拽到windbg下,然后依次如下命令: 1.设置符号路径:.sympath srv*C:\symbols*http://msdl.micros ...

  5. 记一次 .NET 某医疗器械 程序崩溃分析

    一:背景 1.讲故事 前段时间有位朋友在微信上找到我,说他的程序偶发性崩溃,让我帮忙看下怎么回事,上面给的压力比较大,对于这种偶发性崩溃,比较好的办法就是利用 AEDebug 在程序崩溃的时候自动抽一 ...

  6. 程序崩溃 分析工具_程序分析工具| 软件工程

    程序崩溃 分析工具 A program analysis tool implies an automatic tool that takes the source code or the execut ...

  7. java 崩溃监控,求大神分析drwtsn32 监控javaee程序崩溃日记

    当前位置:我的异常网» J2EE » 求大神分析drwtsn32 监控javaee程序崩溃日记 求大神分析drwtsn32 监控javaee程序崩溃日记 www.myexceptions.net  网 ...

  8. C语言常见的程序崩溃问题分析

    文章目录 1. 常见的程序崩溃示例 2. 执行结果分析 1. 常见的程序崩溃示例 常见的崩溃类型有以下几种: 对空指针指向的内存非法写操作 对空指针指向的内存非法读操作 除0操作 大的临时变量或者递归 ...

  9. 揪出“凶手”——实战WinDbg分析电脑蓝屏原因

    http://www.appinn.com/blue-screen-search-code/ 蓝屏代码查询器 – 找出蓝屏的元凶 11 文章标签: windows / 系统 / 蓝屏. 蓝屏代码查询器 ...

最新文章

  1. MS SQL专用管理员连接DAC
  2. Hibernate Session的delete()方法
  3. 进程间的通信方式:简介
  4. 解决pycharm安装包过程出现的问题:module 'pip' has no attribute 'main'
  5. axure怎么做5秒倒计时_装修隔音怎么做,进屋秒变“静音”模式
  6. 打破场景边界,PDFlux助你多领域表格提取
  7. python读取数据库数据类型_Python实现从SQL型数据库读写dataframe型数据的方法【基于pandas】...
  8. (软件工程复习核心重点)第十二章软件项目管理-第二节:进度计划
  9. 关于Jquery EasyUI中的DataGrid服务器端分页随记
  10. 【Anychat】理解POCO
  11. Visio实用技巧总结
  12. 一文吃透等额本息及其应用
  13. CTF-网络信息安全攻防学习平台(脚本关)
  14. python手机版下载-手机python下载
  15. 学3DMAX主要就业方向是什么?
  16. 计算机开机桌面空白,电脑开机桌面一片空白是怎么回事?
  17. 明日边缘:愈演愈烈的POS机网络犯罪
  18. 使用预装Win10的戴尔电脑最新恢复出厂设置方法
  19. 178页7万字智慧乡村大数据平台建设项目解决方案2022
  20. WinForm DataGridView实时更新表格数据

热门文章

  1. 库卡机器人外部紧急关断已按_东莞市库卡机器人系统维修中心
  2. 北大本科小妹妹:在北大“卷”了三年,才明白的四个道理…
  3. IT内审那点事之内部审核工作流程
  4. 2G|3G|4G网络速率知识普及
  5. 深度学习Week9-YOLOv5-C3模块实现(Pytorch)
  6. C++基础——抽象基类(ABC)
  7. 股票个人交易接口怎样导入excel 数据?
  8. Photoshop 基础知识 与 常用 快捷键
  9. 3.5mm 耳机插座 5脚
  10. oc调用python_引用ios-和引用ios相关的内容-阿里云开发者社区