请看代码:(VS2005)
//free : int _tmain(int argc, _TCHAR* argv[]) { int *p=NULL; p= (int *)malloc(sizeof(int)); free(p);//单步跟进 } //来到这里。 extern "C" _CRTIMP void __cdecl free( void * pUserData ) { _free_dbg(pUserData, _NORMAL_BLOCK);//单步跟进 } //来到这里 extern "C" _CRTIMP void __cdecl _free_dbg( void * pUserData, int nBlockUse ) { /* lock the heap */ _mlock(_HEAP_LOCK); __try { /* allocate the block */ _free_dbg_nolock(pUserData, nBlockUse);//单步跟进 } __finally { /* unlock the heap */ _munlock(_HEAP_LOCK); } } //来到这里 extern "C" void __cdecl _free_dbg_nolock( void * pUserData, int nBlockUse ) {//这里检查了指针所指的堆空间,如果正确则调用void __cdecl _free_base (void * pBlock)释放堆空间 _CrtMemBlockHeader * pHead; RTCCALLBACK(_RTC_Free_hook, (pUserData, 0)); /* verify heap before freeing */ if (check_frequency > 0) if (check_counter == (check_frequency - 1)) { _ASSERTE(_CrtCheckMemory()); check_counter = 0; } else check_counter++; if (pUserData == NULL) return; /* check if the heap was not allocated by _aligned routines */ if ( nBlockUse == _NORMAL_BLOCK) { if ( CheckBytes((unsigned char*)((uintptr_t)pUserData & ~(sizeof(uintptr_t) -1)) -nAlignGapSize,_bAlignLandFill, nAlignGapSize)) { _RPT1(_CRT_ERROR, "The Block at 0x%p was allocated by aligned routines, use _aligned_free()", pUserData); errno = EINVAL; return; } } /* forced failure */ if ((_pfnAllocHook) && !(*_pfnAllocHook)(_HOOK_FREE, pUserData, 0, nBlockUse, 0L, NULL, 0)) { _RPT0(_CRT_WARN, "Client hook free failure./n"); return; } /* * If this ASSERT fails, a bad pointer has been passed in. It may be * totally bogus, or it may have been allocated from another heap. * The pointer MUST come from the 'local' heap. */ _ASSERTE(_CrtIsValidHeapPointer(pUserData)); /* get a pointer to memory block header */ pHead = pHdr(pUserData); // pUserData 0x003f92e0 void * // pHead 0x003f92c0 {pBlockHeaderNext=0x003f8f10 pBlockHeaderPrev=0x00000000 szFileName=0x00000000 <错误的指针> ...} _CrtMemBlockHeader * /* verify block type */ _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)); /* if we didn't already check entire heap, at least check this object */ if (!(_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)) { /* check no-mans-land gaps */ if (!CheckBytes(pHead->gap, _bNoMansLandFill, nNoMansLandSize)) _RPT3(_CRT_ERROR, "HEAP CORRUPTION DETECTED: before %hs block (#%d) at 0x%p./n" "CRT detected that the application wrote to memory before start of heap buffer./n", szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)], pHead->lRequest, (BYTE *) pbData(pHead)); if (!CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMansLandFill, nNoMansLandSize)) _RPT3(_CRT_ERROR, "HEAP CORRUPTION DETECTED: after %hs block (#%d) at 0x%p./n" "CRT detected that the application wrote to memory after end of heap buffer./n", szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)], pHead->lRequest, (BYTE *) pbData(pHead)); } RTCCALLBACK(_RTC_FuncCheckSet_hook,(0)); if (pHead->nBlockUse == _IGNORE_BLOCK) { _ASSERTE(pHead->nLine == IGNORE_LINE && pHead->lRequest == IGNORE_REQ); /* fill the entire block including header with dead-land-fill */ memset(pHead, _bDeadLandFill, sizeof(_CrtMemBlockHeader) + pHead->nDataSize + nNoMansLandSize); _free_base(pHead); RTCCALLBACK(_RTC_FuncCheckSet_hook,(1)); return; } /* CRT blocks can be freed as NORMAL blocks */ if (pHead->nBlockUse == _CRT_BLOCK && nBlockUse == _NORMAL_BLOCK) nBlockUse = _CRT_BLOCK; /* Error if freeing incorrect memory type */ _ASSERTE(pHead->nBlockUse == nBlockUse); /* keep track of total amount of memory allocated */ _lCurAlloc -= pHead->nDataSize; /* optionally reclaim memory */ if (!(_crtDbgFlag & _CRTDBG_DELAY_FREE_MEM_DF)) { /* remove from the linked list */ if (pHead->pBlockHeaderNext) { pHead->pBlockHeaderNext->pBlockHeaderPrev = pHead->pBlockHeaderPrev; } else { _ASSERTE(_pLastBlock == pHead); _pLastBlock = pHead->pBlockHeaderPrev; } if (pHead->pBlockHeaderPrev) { pHead->pBlockHeaderPrev->pBlockHeaderNext = pHead->pBlockHeaderNext; } else { _ASSERTE(_pFirstBlock == pHead); _pFirstBlock = pHead->pBlockHeaderNext; } /* fill the entire block including header with dead-land-fill */ memset(pHead, _bDeadLandFill, sizeof(_CrtMemBlockHeader) + pHead->nDataSize + nNoMansLandSize); _free_base(pHead);//跟进 } else { pHead->nBlockUse = _FREE_BLOCK; /* keep memory around as dead space */ memset(pbData(pHead), _bDeadLandFill, pHead->nDataSize); } RTCCALLBACK(_RTC_FuncCheckSet_hook,(1)); } //到达这里 void __cdecl _free_base (void * pBlock) { int retval = 0; if (pBlock == NULL) return; RTCCALLBACK(_RTC_Free_hook, (pBlock, 0)); #ifndef _WIN64 if ( __active_heap == __V6_HEAP ) { PHEADER pHeader; _mlock( _HEAP_LOCK ); __try { if ((pHeader = __sbh_find_block(pBlock)) != NULL) __sbh_free_block(pHeader, pBlock); } __finally { _munlock( _HEAP_LOCK ); } if (pHeader == NULL) { retval = HeapFree(_crtheap, 0, pBlock); if (retval == 0) { errno = _get_errno_from_oserr(GetLastError()); } } } #ifdef CRTDLL else if ( __active_heap == __V5_HEAP ) { __old_sbh_region_t *preg; __old_sbh_page_t * ppage; __old_page_map_t * pmap; _mlock(_HEAP_LOCK ); __try { if ( (pmap = __old_sbh_find_block(pBlock, &preg, &ppage)) != NULL ) __old_sbh_free_block(preg, ppage, pmap); } __finally { _munlock(_HEAP_LOCK ); } if (pmap == NULL) { retval = HeapFree(_crtheap, 0, pBlock); if (retval == 0) { errno = _get_errno_from_oserr(GetLastError()); } } } #endif /* CRTDLL */ else // __active_heap == __SYSTEM_HEAP #endif /* _WIN64 */ { retval = HeapFree(_crtheap, 0, pBlock);//这里不能跟进了。这是一个堆空间释放函数,第三个参数是传进来的堆块指针。 if (retval == 0) { errno = _get_errno_from_oserr(GetLastError()); } } } //到此,释放结束
依次检查后对堆空间进行释放。但是由于无法跟踪HeapFree(_crtheap, 0, pBlock)函数,感觉没有彻底解释清楚。不过大概原理以经出现。