这样的bug能发现真不容易啊,花了我两天时间才找到
2010-12-18 02:34
537 查看
前几天,一直在纠结着一个bug,直到昨天我才搞定了这个bug,在这儿有必要记录一下这个虽小却大的问题。bug是这样的,我申请了一块内存(见@1),在使用完了之后释放这个内存空间的时候(在@4)却一直报错误::“HEAP CORRUPTION DETECTED: after Normal block (#48) at 0x000032E90.CRT detected that the application wrote to memory after end of heap buffer.”
在网上找了好多资料,也没有找到具体的应对办法,但是极有可能是在某处错用了内存所导致的。不过,却找到一个用来检查内存有没有访问越界的好东西--- _ASSERTE( _CrtCheckMemory( ) )。
在msdn上,对于函数 _CrtCheckMemory( )的解释是:
Confirms the integrity of the memory blocks allocated in the debug heap (debug version only).
The _CrtCheckMemory function validates memory allocated by the debug heap manager by verifying the underlying base heap and inspecting every memory block. If an error or memory inconsistency is encountered in the underlying base heap, the debug header information, or the overwrite buffers, _CrtCheckMemory generates a debug report with information describing the error condition. When _DEBUG is not defined, calls to _CrtCheckMemory are removed during preprocessing.
The behavior of _CrtCheckMemory can be controlled by setting the bit fields of the _crtDbgFlag flag using the _CrtSetDbgFlag function. Turning the _CRTDBG_CHECK_ALWAYS_DF bit field ON results in _CrtCheckMemory being called every time a memory allocation operation is requested. Although this method slows down execution, it is useful for catching errors quickly. Turning the _CRTDBG_ALLOC_MEM_DF bit field OFF causes _CrtCheckMemory to not verify the heap and immediately return TRUE.
所以我在好多代码中都加入了 _ASSERTE( _CrtCheckMemory( ) )块,用于提前检查可能出现的内存使用错误。结果还真在代码中发现了一些端倪。在下面摘录的代码中,检查块中@2没有报错,但是在@3中报错,说明错误只能在这两者之间了,范围缩小了就好办了。在这之间只有snprintf可疑了(@5),通过仔细查看_snprintf_s所传递的参数,才发现第二个参数我是直接传入了nBuffersize, 事实上,我在传第一个缓冲区指针参数中,已经有了一些偏移了,(即pBuffer+nReadCount),所以,buBufferSize必须减掉偏移的那一部分,不然就会访问越界,从而造成错误。
BTW,下面的代码中@5处,是修改了之后的代码。
运行一下,果真问题没了。呵呵,happy!!
PCHAR pBuffer = new CHAR[DEFAULT_BUFFER_SIZE*DEFAULT_BUFFER_NUM] ; // @1
_ASSERTE( _CrtCheckMemory( ) );
.......
int nBufferSize = DEFAULT_BUFFER_SIZE * DEFAULT_BUFFER_NUM;
ULONGLONG nReadCount ;
CString strWords ;
int nLen ;
// 写入文件头 --- {{
nReadCount = sizeof(UINT) ; // 预留四个byte来表示文件头的大小
// @1 软件信息
_ASSERTE( _CrtCheckMemory( ) ); // @2
strWords = SOFTWARE_INFO ;
nLen = _snprintf_s(pBuffer+nReadCount,nBufferSize-nReadCount,_TRUNCATE ,"%s/0",strWords) ; // @5
nReadCount += (nLen+1) ;
_ASSERTE( _CrtCheckMemory( ) ); //@3
........
// 释放内存
SAFEDELETE(pBuffer) ; // @4
Jekkay Hu, 胡杨
2010-12-6
在网上找了好多资料,也没有找到具体的应对办法,但是极有可能是在某处错用了内存所导致的。不过,却找到一个用来检查内存有没有访问越界的好东西--- _ASSERTE( _CrtCheckMemory( ) )。
在msdn上,对于函数 _CrtCheckMemory( )的解释是:
Confirms the integrity of the memory blocks allocated in the debug heap (debug version only).
The _CrtCheckMemory function validates memory allocated by the debug heap manager by verifying the underlying base heap and inspecting every memory block. If an error or memory inconsistency is encountered in the underlying base heap, the debug header information, or the overwrite buffers, _CrtCheckMemory generates a debug report with information describing the error condition. When _DEBUG is not defined, calls to _CrtCheckMemory are removed during preprocessing.
The behavior of _CrtCheckMemory can be controlled by setting the bit fields of the _crtDbgFlag flag using the _CrtSetDbgFlag function. Turning the _CRTDBG_CHECK_ALWAYS_DF bit field ON results in _CrtCheckMemory being called every time a memory allocation operation is requested. Although this method slows down execution, it is useful for catching errors quickly. Turning the _CRTDBG_ALLOC_MEM_DF bit field OFF causes _CrtCheckMemory to not verify the heap and immediately return TRUE.
所以我在好多代码中都加入了 _ASSERTE( _CrtCheckMemory( ) )块,用于提前检查可能出现的内存使用错误。结果还真在代码中发现了一些端倪。在下面摘录的代码中,检查块中@2没有报错,但是在@3中报错,说明错误只能在这两者之间了,范围缩小了就好办了。在这之间只有snprintf可疑了(@5),通过仔细查看_snprintf_s所传递的参数,才发现第二个参数我是直接传入了nBuffersize, 事实上,我在传第一个缓冲区指针参数中,已经有了一些偏移了,(即pBuffer+nReadCount),所以,buBufferSize必须减掉偏移的那一部分,不然就会访问越界,从而造成错误。
BTW,下面的代码中@5处,是修改了之后的代码。
运行一下,果真问题没了。呵呵,happy!!
PCHAR pBuffer = new CHAR[DEFAULT_BUFFER_SIZE*DEFAULT_BUFFER_NUM] ; // @1
_ASSERTE( _CrtCheckMemory( ) );
.......
int nBufferSize = DEFAULT_BUFFER_SIZE * DEFAULT_BUFFER_NUM;
ULONGLONG nReadCount ;
CString strWords ;
int nLen ;
// 写入文件头 --- {{
nReadCount = sizeof(UINT) ; // 预留四个byte来表示文件头的大小
// @1 软件信息
_ASSERTE( _CrtCheckMemory( ) ); // @2
strWords = SOFTWARE_INFO ;
nLen = _snprintf_s(pBuffer+nReadCount,nBufferSize-nReadCount,_TRUNCATE ,"%s/0",strWords) ; // @5
nReadCount += (nLen+1) ;
_ASSERTE( _CrtCheckMemory( ) ); //@3
........
// 释放内存
SAFEDELETE(pBuffer) ; // @4
Jekkay Hu, 胡杨
2010-12-6
相关文章推荐
- 半天时间找到原因却仍未解决的Bug
- 发现hao123主页上面的时间有一个bug
- 花了一天时间,发现一个隐藏巨深的BUG
- 大家有没有发现ListCtrl的LVN_ITEMCHANGED时间为什么连续响应3次,是不是vc的bug,急!!!
- IDC 的调查发现开发人员的37%的时间花在解决BUG上
- 编译libtorrent,花了两天时间,才找到合适版本并编译例子通过
- [难忘的找BUG]一行代码花去我两天时间
- 大家有没有发现ListCtrl的LVN_ITEMCHANGED时间为什么连续响应3次,是不是vc的bug,急!!!
- 半天时间找到原因却仍未解决的Bug
- 当程序员发现BUG时,这反应绝了,你是不是这样的程序员
- 发现CSDN,文章分类有个bug
- 好工作是这样找到的-当代大学生的求职理念/求职面试该找谁
- mysql插入int字段可以使用单引号包含?今天改东西无意发现时间字段成int类型了,而且update这个字段用单引号包含,于是在MySQL上测试下能运行,求解
- Xdite:永葆热情的上瘾式学习法(套路王:每天总结自己,反省自己的作息规律,找到自己的幸运时间、幸运方法,倒霉时间、倒霉方法。幸运是与注意力挂钩的。重复才能让自己登峰造极,主动去掉运气部分来训练自己。游戏吸引自己的几个原因非常适合训练自己)good
- 全局记录程序片段的运行时间 正确找到程序逻辑耗时多的断点
- 偶然的错误发现一个bug,引人深思的null
- 第七天:poj1009(题目读不懂,读懂了模拟时间超限,看来找到规律才是王道)
- 我用4年时间解决了Python GIL的一个bug...
- //杨氏矩阵 有一个二维数组. 数组的每行从左到右是递增的,每列从上到下是递增的. 在这样的数组中查找一个数字是否存在。 时间复杂度小于O(N);
- 发现微软VS工具的一个问题,不知算不算是BUG