> 文章列表 > 【创作赢红包】C++程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题的排查

【创作赢红包】C++程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题的排查

【创作赢红包】C++程序调用IsBadReadPtr或IsBadWritePtr引发内存访问违例问题的排查

目录

1、问题描述

2、VS中看不到有效的信息,尝试使用Windbg去分析

3、使用Windbg分析

4、最后


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N2N8https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N2N8https://blog.csdn.net/chenlycly/article/details/125529931       最近在用VS调试程序时老是遇到程序一启动就报错的问题,严重影响软件新功能的开发进度,于是就详细地研究了一下。经分析,发现是因为程序依赖的某个比较老的第三方库调用了IsBadReadPtr和IsBadWritePtr这两个微软已经废弃的老接口导致的。下面将整个问题的分析过程分享出来,以供大家借鉴或参考。 

1、问题描述

        某天,在Visual Studio(以下简称VS)中调试Debug版本程序,刚启动调试就弹出如下的报错提示框:

报出0xC0000005内存访问违例,是在读取某个内存地址时发生了内存读违例(试图去访问一个不应该或者没权限访问的内存)。

       因为当前是在VS中进行Debug调试,所以可以直接切换到call stack函数调用堆栈页面去查看此时的函数调用堆栈:

但并没有看到有效的函数调用堆栈,只能在堆栈中看到异常发生在kernel32.dll系统库模块中。这个有点奇怪,之前几天启动Debug调试时都是正常的,为啥今天突然会报错,并且是必现的。 

2、VS中看不到有效的信息,尝试使用Windbg去分析

        同样的代码,同样的底层dll库,为啥不同时间点表现不一致呢(有时报异常,有时又不报异常)?经尝试发现,在VS的调试状态下,多次按下F5继续运行之后,可以将这个异常跳过去。所以,这个报错不是致命性的异常,是可以跳过去的,然后程序还可以继续运行。

       除了多次按下F5将异常跳过,也可以在弹出的报错提示窗口中,勾除掉“引发此异常类型时中断“,下次就不会再报这类异常了:

       一般当我们在VS中看不到有效的异常上下文信息(比如有效的函数调用堆栈)时,可以尝试使用Windbg直接启动程序或者将Windbg附加到已经运行的目标进程上,看看能否看到有效的函数调用堆栈信息等信息。

       对于本案例,报错是发生在程序启动时,所以需要使用Windbg启动目标程序,这样Windbg才能感知到启动时的异常。因为异常发生在程序启动的过程中,要等目标程序启动起来后再将Windbg附加到目标进程上,时机上就晚了。 

3、使用Windbg分析,发现是调用IsBadReadPtr导致的

       于是用Windbg启动Debug版本的exe程序,启动后,Windbg果然监测到0xC0000005内存访问违例异常,如下所示:

从上图可以看到是调用kernel32!IsBadReadPtr接口触发的,然后输入kn命令查看此时的函数调用堆栈,从堆栈中可以看到是底层的HKCommand模块中的HKGetSerialNum接口中调用了IsBadReadPtr。可以执行g命令将此异常跳过去,但会多次报该异常(应该是多次调用了IsBadReadPtr函数),多次g就可以了。

       对于IsBadReadPtr,有经验的人可能知道这个系统API,同类型的API接口还有IsBadWritePtr。在以前,IsBadReadPtr用来判断目标内存地址是否可读,IsBadWritePtr用来判断目标内存地址是否可写,但现在这两个函数已经被微软官方废弃了,已经达不到预定的作用了,不要再使用了!可以在微软在线MSDN上查看到这两个API函数的说明:

这两个API函数已经被废弃了,不建议再使用了,这两个函数不能判断出目标地址是否可读可写。

       在本问题中,是HKCommand.dll库中函数内部调用了IsBadReadPtr接口,这个HKCommand.dll库是第三方安全相关的库,这个库比较老(可能是好几年前的库),在老版本库的代码中调用IsBadReadPtr或者IsBadWritePtr是有可能的。

       调用IsBadReadPtr或者IsBadWritePtr接口,会触发调试器(VS、Windbg等)异常中断下来,但这个异常不是致命的,可以跳过去(在VS中点继续运行,在Windbg中输入g命令继续运行),程序仍然可以继续运行!

有些异常是致命的,程序无法恢复正常运行;有的异常则是不致命的,可以跳过去,程序还可以继续运行。

4、最后

       本文简单介绍了由IsBadReadPtr函数调用引发异常的排查过程,整个分析过程也相对比较简单,主要给大家提供一个借鉴或参考。