前几天,一直在纠结着一个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