VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931 最近遇到一个主程序启动报错的问题,在Visual Studio中启动调试会报出异常,点开call stack函数调用堆栈页面却看不到有效的函数调用堆栈。后来尝试使用Windbg启动主程序进行调试,报出异常时Windbg中却看到了完整的函数调用堆栈。这个问题也正是借助Windbg的动态调试解决的,今天就来分享一下该问题完整的排查分析过程。
1、Visual Studio中看不到有效的函数调用堆栈
在给新人搭建项目在Debug下的运行调试环境时,先是拷贝了底层各个模块的Debug版本dll库,将项目中需要编译的工程添加到解决方案中进行编译,最后在Visual Studio中启动Debug下主程序的调试,结果主程序还没启动起来就报错了,弹出如下报错提示框:
提示框中显示的错误描述信息为:Access violation executing location 0x00000000,即执行0x00000000地址时产生了访问违例,这个0x00000000是代码段的地址,很有可能是call了这个无效的代码段地址引发的访问违例。
于是切换到Call Stack函数调用堆栈页面,去查看此时的函数调用堆栈。但并没有看到有效的函数调用堆栈,如下所示:
看不到有效的函数调用堆栈,这个问题就不好分析了。难道是底层的dll库之间不匹配导致的?亦或是Debug版本的dll库与Release版本的dll混用导致的?
2、使用Windbg调试运行主程序,看到了有效的函数调用堆栈
Visual Studio调试状态下看不到有效的函数调用堆栈,于是想尝试使用Windbg启动主程序调试运行,看看在发生异常时能否看到有效的信息。使用Windbg打开目标主程序开始调试,Windbg确实捕获到了异常,中断了下来。于是输入kn命令,查看到如下的函数调用堆栈:
Windbg确实很强大啊,Windbg中看到了发生异常时的完整函数调用堆栈。从上图可以看到,异常崩溃发生在mediaxxx.dll模块中。因为没有pdb文件,所以函数调用堆栈中只能看到崩溃发生在mediaxxx.dll模块中,看不到具体的函数名。
于是输入lm vm mediaxxx*命令去查看mediaxxx.dll文件的时间戳:
该dll库的时间戳为:2022年8月3日15时45分09秒,该时间就是mediaxxx.dll库文件编译生成的时间,按照这个时间点到版本服务器上查找对应时间的pdb文件。取来pdb文件后,将pdb文件的路径添加到Windbg中(在添加页面记得勾选Reload选项),然后重新输入kn,看到了详细的函数名,如下:
看到问题是发生在initgloble函数的553行代码上:
J:\media\media\source\video\videocom.cpp @ 553
此外,还能看到该函数位于哪个cpp文件中。
3、根据函数名和行号去查看对应的C++源码,定位问题
于是将完整的函数调用堆栈发给维护mediaxxx.dll库的同事,根据显示的函数名和行号,去查看C++源码,看看出问题的代码是啥样子的。
查看到如下的这行代码:
这里的m_pHWDec_Startup变量应该是个函数指针,此处通过该指针中保存的函数地址,去调用对应的函数的。于是搜索给m_pHWDec_Startup指针变量赋值的地方,找到了如下的代码:
根据同事提示,此处是从uniplay.dll库中动态获取PLAYXX_Startup函数地址,赋值给m_pHWDec_Startup函数指针变量的。
所以,调用uniplay.dll中的接口是通过动态加载库的方式去操作的,很有可能是主程序的路径中缺少uniplay.dll库文件导致PLAYXX_Startup函数获取失败,所以m_pHWDec_Startup函数指针为空,这样代码中去call了这个空指针,所以出现了“Access violation executing location 0x00000000”异常。经查看,主程序的路径中确实是没有uniplay.dll库文件的,手动将该库拷贝到主程序的目录中就没问题了。
4、总结
在使用Visual Studio等IDE工具调试C++代码的过程中遇到了异常,如果看不到有用的信息或线索,可以尝试使用Windbg等调试工具去动态调试目标程序,看看发生异常时能否看到有用的内容。
类似的问题,以前我们也遇到过,当代码中发生Stack overflow线程栈溢出时,Visual Studio会直接停止调试,退出调试状态,这样也就看不到异常发生的函数调用堆栈了。但用Windbg动态调试目标进程时发生线程栈溢出,则可以看到完整的函数调用堆栈。本文恰好是另一个实例。
版权归原作者 dvlinker 所有, 如有侵权,请联系我们删除。