近日跟踪分析一个程序,其特征为,在运行过程中,可以毫无征兆的随心所欲的崩溃,而且无论是debug跟踪还是dump分析,出错的地方的代码都是完全没问题。
经过排除了所有可能的外部链接的各种lib库带入的问题的原因后,问题重新回归到应用程序代码上来,经过反复定位,由于程序最终出错都是发生在另外一个稳定可靠的lib库在执行某代码功能时分配内存时报“HEAP: Free Heap block 44734b8 modified at 4473580 after it was freed”这类错误,字面上就是说,有一段heap堆内存被错误的在已经释放后又被操作了,即俗称的C/C++万年老大难“野指针”问题。
这种问题一般发生在内存被重复释放(释放后指向这块内存的指针又被使用,然后在另一个地方又被释放),或者哪块内存被“越界”操作了(数组只有10,却写了11的位置)等等情况下,但操作系统的机制决定了代码在执行这些操作时,它不报错,直到这块内存又被人使用时,好了,它bi的一下崩掉了,但这时候通过回溯函数调用堆栈stack只能看到正常执行内存分配的场景,也就是你通过正常的调试跟踪和抓dump根本没用,原先想用之前在linux下分配内存泄漏的memleak函数库来分析处理(它的原理就是替换系统所有malloc, free等函数,在执行这些操作时记录一下分配和释放并定时或手工打印出来,这样程序跑一段时间,如果有哪个分配的内存应该释放的但还能在打印日志里看到,这块内存就是泄漏了),但考虑到一来这是linux下的库要移植,另外这个windows程序大量调用了外部lib库,全部替换成memleak进行内存分配处理工作量太大,寻找现有方案。
好在这个问题不是我一家遇到,微软MSDN上已经有相应工具提供(不过网上的大量日志已经过时,下载不到),类似工具有Gflags(包含在Debugging Tools for Windows里)及其它类似工具,可以通过下载windows SDK安装时选择安装这个工具就可以找到,然后这个工具是一个命令行,通过gflags.exe /p /enable xxxx.exe /full打开(当然还有一些额外参数,这次调试工作里没用到),通过gflags.exe /p /disable xxxx.exe关闭,其实它没做什么复杂工作,只是修改一个注册表项,修改了操作系统的Heap堆内存的分配机制。
其核心原理简单分析了一下就是,原先malloc只是在heap堆里分配一块内存,然后free后还给系统,但gflags操作后,这个程序再申请内存时,除了原有一块内存,还会紧接它又分配一块额外的内存但标识为noaccess不允许访问的,而且free后也同样给这块内存打上noaccess标识,这样,再重复上面我们描述的问题,如果出现内存已经释放后又来用它(写它),立即就会触发异常崩溃,同样,如果想越界访问超出已分配内存大小的区域,也会立即触发崩溃,这样,这方便我们立即定位到真正的问题点,而不是等到内存再次被申请时才发现内存异常了,一般能够让你立即发现问题了——本次调试的程序最终发现问题点出在一个动态分配的数据结构在通过windows消息发送到接收端时,错误地将整个消息大小当成某一个字符串大小而进行了尾部设置为0的内存写操作,最终导致了libcurl这个内存大户在频繁分配内存执行curl_easy_perform时频繁导致程序崩溃,一直错怪了libcurl以为它不稳定,最终还是跟它毫不相关的另一个位置的代码的一个小小的p[n] = ‘\0’配值操作导致了整个程序的不稳定。
这类问题一般要么不遇到,遇到就会让人心慌失眠头痛情况差……………………希望上文能帮助你解脱痛苦,啊吧啊吧~~~