前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >程序Crash了却无法捕获正确的函数调用栈?

程序Crash了却无法捕获正确的函数调用栈?

作者头像
河边一枝柳
发布2021-08-06 15:03:52
9670
发布2021-08-06 15:03:52
举报

问题描述

曾经碰到一种奇怪的Crash场景:Windows程序Crash,每次用windbg attach或者ntsd/cdb产生dump,总是不能捕获到程序出错时候的栈,而且crash的时候只能看到少数甚至只剩一个线程的信息,而这个仅有的一些线程函数调用栈,也并不是导致程序Crash的地方。

问题分析

首先确认Dump选项是进程的全部信息;也检查了写Dump的时候系统的资源充足(CPU,Memory等)。大家平时碰到的Crash,大多数都是非法资源的访问,实际上还有一种可能存在的场景,就是进程被Kill/Terminate掉,此时捕获的Dump信息不一定是程序出错时候的栈。

那么程序被Kill/Terminate掉有两种可能性一种是外部程序(包含Taskmanager),还有一种是程序内部调用TerminateProcess等API。可以先通过笔者之前写过的文章<<我的程序被谁干掉了?>>,用gflag配置查找到程序退出的原因,如果是外部程序Kill了当前的进程,那么找到程序名称,也便有了线索;如果是当前进程调用了API自动退出呢? 本文便是讲述这种场景下的分析方法。

程序自己调用退出进程API,有以下几种可能性:

  1. 当前程序显式地调用了exit, TerminateProcess, ExitProcess等API。对于这种API的调用,一般产品中会很少,也可以通过搜索代码查找到可能的地方。
  2. 比较隐晦的一些场景,并不是自己编写的程序代码显示的调用退出进程API,而是由于一些API调用或者异常处理导致的:
    1. 比如微软的安全函数,strcpy_s在VS2005中比如当目标buffer空间不够就会调用TerminateProcess. (笔者此时查看VS2015版本,默认行为已经不会调用了TerminateProcess,而是返回错误,微软也是在各位程序员采坑的情况下不断的优化自己的CRT库)
    2. 在抛出异常Unwind过程中,会调用一些局部变量的析构函数,如果此时再次抛出异常,也会调用TerminateProcess. (所以不建议在析构函数中抛出异常)
    3. 等等......

既然明确了这个场景后,有个麻烦的事情,程序中有很多地方,包括第三方库都会调用strcpy_s等这类函数,而且异常处理的地方也有很多,很难通过代码审查找到问题所在,更有可能的是,还有其他的退出进程的调用场景没有列出来。下一章节将分享一种常见的分析方法。

Windbg+TerminateProcess断点分析问题

本案例以VS2005中strcpy_s目标buffer不足为例触发TerminateProcess。使用Windbg调试器附加到进程之后,在TerminateProcess处设置断点,并且运行程序(有时候也设置断点在ntdll!ZwTerminateProcesskernel32!TerminateProcesskernelbase!TerminateProcesskernel32!ExitProcess,或者kernelbase!ExitProcess):

代码语言:javascript
复制
0:000> bp KERNELBASE!TerminateProcess
0:000> g
Breakpoint 0 hit
eax=ffffffff ebx=00000000 ecx=779877e4 edx=002de8b8 esi=00000001 edi=00000000
eip=7790f210 esp=053ffc14 ebp=053ffca4 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
KERNELBASE!TerminateProcess:
7790f210 8bff            mov     edi,edi

当程序运行到断点TerminateProcess处,查看函数调用栈,就可以找到程序出错的地方了。如下,可以找到函数调用关系为fun->strcpy_s

代码语言:javascript
复制
0:001> kv
ChildEBP RetAddr  Args to Child              
0537fc00 7790f23c ffffffff c000000d 0537fca4 ntdll!ZwTerminateProcess (FPO: [2,0,0])
0537fc10 00401410 ffffffff c000000d 00000022 KERNELBASE!TerminateProcess+0x2c (FPO: [Non-Fpo])
0537ff4c 0040108d 00000000 00000000 00000000 testforiceking!_invoke_watson+0xe6 (FPO: [Non-Fpo]) (CONV: cdecl) [f:\sp\vctools\crt_bld\self_x86\crt\src\invarg.c @ 185]
0537ff70 00401014 0537ff87 00000001 0041218c testforiceking!strcpy_s+0x29 (FPO: [3,0,4]) (CONV: cdecl) [f:\sp\vctools\crt_bld\self_x86\crt\src\tcscpy_s.inl @ 18]
0537ff88 7796336a 00000000 0537ffd4 77e99f72 testforiceking!Fun+0x14 (FPO: [Non-Fpo]) (CONV: stdcall) [d:\vsproject\testforme\testforiceking\test.cpp @ 11]
0537ff94 77e99f72 00000000 7dfe5d2b 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
0537ffd4 77e99f45 00401000 00000000 ffffffff ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
0537ffec 00000000 00401000 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一个程序员的修炼之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题描述
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档