int CMemLeakDetector::CrtAllocHook(int allocType, void *userData, size_t size, int blockType, long requestNumber, const unsigned char *filename, int lineNumber) { #ifdef _DEBUG UNREFERENCED_PARAMETER(size); UNREFERENCED_PARAMETER(filename); UNREFERENCED_PARAMETER(lineNumber); bool trackAllocation = true; // do not memory tracking on crt blocks or if detection is disabled for this thread if(blockType == _CRT_BLOCK) trackAllocation = false; // get the current debug flag bits, only track debug allocations // INFO: The _CrtSetDbgFlag does NOT store its flags thread local! // Therefore if one thread deactivates memory tracking, an allocation in another thread could not be tracked. // This MFC default usage behavior and must be implemented, otherwise many MFC memory leak will be reported. // The function does not affect applications without MFC, because this flag is not used by applications without MFC. int debugFlags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); if(!(debugFlags & _CRTDBG_ALLOC_MEM_DF)) trackAllocation = false; // prevent the current thread from re-entering on allocs/reallocs/frees // that we or the CRT do internally to record the data we collect. if(trackAllocation) { // handle the allocation request switch(allocType) { case _HOOK_ALLOC: g_MemLeakDetector.TrackAllocInfo(requestNumber, 0); break; case _HOOK_FREE: g_MemLeakDetector.RemoveAllocInfo(pHdr(userData)->lRequest); break; case _HOOK_REALLOC: g_MemLeakDetector.RemoveAllocInfo(pHdr(userData)->lRequest); g_MemLeakDetector.TrackAllocInfo(requestNumber, 0); break; } } if(g_MemLeakDetector.m_OldHook) return g_MemLeakDetector.m_OldHook(blockType, userData, size, blockType, requestNumber, filename, lineNumber); #endif // _DEBUG return TRUE; }
void operator delete( void *pUserData ) { _CrtMemBlockHeader * pHead; RTCCALLBACK(_RTC_Free_hook, (pUserData, 0)); if (pUserData == NULL) return; _mlock(_HEAP_LOCK); /* block other threads */ __TRY /* get a pointer to memory block header */ pHead = pHdr(pUserData); /* verify block type */ _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)); _free_dbg( pUserData, pHead->nBlockUse ); __FINALLY _munlock(_HEAP_LOCK); /* release other threads */ __END_TRY_FINALLY return; }
void _vm_free( void *ptr ) #endif { if (!ptr) { #ifndef NDEBUG mprintf(("Why are you trying to free a NULL pointer? [%s(%d)]\n", clean_filename(filename), line)); #else mprintf(("Why are you trying to free a NULL pointer?\n")); #endif return; } #ifndef NDEBUG _CrtMemBlockHeader* phd = pHdr(ptr); int nSize = phd->nDataSize; TotalRam -= nSize; if (Cmdline_show_mem_usage) unregister_malloc(filename, nSize, ptr); #endif _free_dbg(ptr, _NORMAL_BLOCK); }
_CrtMemBlockHeader* get_head() { // New blocks are added to the head of the list void* p = malloc(1); _CrtMemBlockHeader* hdr = pHdr(p); free(p); return hdr; }
void *_vm_realloc( void *ptr, int size, int quiet ) #endif { // if this is the first time it's used then we need to malloc it first if (ptr == NULL) return vm_malloc(size); void* ret_ptr = NULL; #ifndef NDEBUG // Unregistered the previous allocation _CrtMemBlockHeader* phd = pHdr(ptr); int nSize = phd->nDataSize; TotalRam -= nSize; if (Cmdline_show_mem_usage) unregister_malloc(filename, nSize, ptr); #endif ret_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, __FILE__, __LINE__); if (ret_ptr == NULL) { mprintf(("realloc failed!!!!!!!!!!!!!!!!!!!\n")); if (quiet && (size > 0) && (ptr != NULL)) { // realloc doesn't touch the original ptr in the case of failure so we could still use it return NULL; } Error(LOCATION, "Out of memory. Try closing down other applications, increasing your\n" "virtual memory size, or installing more physical RAM.\n"); } #ifndef NDEBUG TotalRam += size; // register this allocation if (Cmdline_show_mem_usage) register_malloc(size, filename, line, ret_ptr); #endif return ret_ptr; }
void _vm_free( void *ptr ) #endif { if ( !ptr ) { return; } #ifndef NDEBUG _CrtMemBlockHeader *phd = pHdr(ptr); int nSize = phd->nDataSize; TotalRam -= nSize; if(Cmdline_show_mem_usage) unregister_malloc(filename, nSize, ptr); #endif _free_dbg(ptr,_NORMAL_BLOCK); }
static int CrtAllocHook(int nAllocType, void * pvData, size_t nSize, int nBlockUse, long lRequest, const unsigned char * szFileName, int nLine) { if (nBlockUse == _CRT_BLOCK) { return TRUE; } if (!g_inAllocHook) { g_inAllocHook = true; if (nAllocType == _HOOK_ALLOC) { StoreAlloc(pvData, nSize, lRequest, (g_newFile[0]) ? g_newFile : (const char*)szFileName, "", (g_newFile[0]) ? g_newLine : nLine); } else if (nAllocType == _HOOK_FREE) { if (_CrtIsValidHeapPointer(pvData)) { _CrtMemBlockHeader* pHead = pHdr(pvData); lRequest = pHead->lRequest; } RemoveAlloc(pvData, nSize, lRequest); } // clear the new caller g_newFile = ""; g_inAllocHook = false; } return TRUE; }
/*** *void operator delete() - delete a block in the debug heap * *Purpose: * Deletes any type of block. * *Entry: * void *pUserData - pointer to a (user portion) of memory block in the * debug heap * *Return: * <void> * *******************************************************************************/ void operator delete( void *pUserData ) { _CrtMemBlockHeader * pHead; if (pUserData == NULL) return; _mlock(_HEAP_LOCK); /* block other threads */ /* get a pointer to memory block header */ pHead = pHdr(pUserData); /* verify block type */ _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)); _free_dbg( pUserData, pHead->nBlockUse ); _munlock(_HEAP_LOCK); /* release other threads */ return; }
int __cdecl MyAllocHook( int nAllocType, void * pvData, size_t nSize, int nBlockUse, long lRequest, const char * szFileName, int nLine ) { // char *operation[] = { "", "allocating", "re-allocating", "freeing" }; // char *blockType[] = { "Free", "Normal", "CRT", "Ignore", "Client" }; if ( nBlockUse == _CRT_BLOCK ) // Ignore internal C runtime library allocations return( TRUE ); _ASSERT( ( nAllocType > 0 ) && ( nAllocType < 4 ) ); _ASSERT( ( nBlockUse >= 0 ) && ( nBlockUse < 5 ) ); if ( nAllocType == 3 ) { _CrtMemBlockHeader *phd = pHdr(pvData); nSize = phd->nDataSize; } // mprintf(( "Total RAM = %d\n", TotalRam )); mprintf(( "Memory operation in %s, line %d: %s a %d-byte '%s' block (# %ld)\n", szFileName, nLine, operation[nAllocType], nSize, blockType[nBlockUse], lRequest )); if ( pvData != NULL ) mprintf(( " at %X", pvData )); mprintf(("\n" )); return( TRUE ); // Allow the memory operation to proceed }
unsigned int allocation_id (void* ptr) { return static_cast<unsigned int>(pHdr(ptr)->lRequest); }
size_t size (void* ptr) { return ptr ? pHdr(ptr)->nDataSize : 0; }
bool is_free (void* ptr) { return pHdr(ptr)->nBlockUse == _FREE_BLOCK; }
bool is_normal (void* ptr) { return pHdr(ptr)->nBlockUse == _NORMAL_BLOCK; }
bool is_crt (void* ptr) { return pHdr(ptr)->nBlockUse == _CRT_BLOCK; }
void CMemLeakDetector::ReportLeaks() { #ifdef _DEBUG // hooks must be disabled for reporting assert(!m_HooksEnabled); if(m_AllocInfoMap.size() > 0) { // start reporting m_Reporter->WriteHeader(static_cast<uintx>(m_AllocInfoMap.size())); // we'r accessing heap-internal structures so synchronize via heap lock LOCK_HEAP // We employ a simple trick here to get a pointer to the first allocated // block: just allocate a new block and get the new block's memory header. // This works because the most recently allocated block is always placed at // the head of the allocated list. We can then walk the list from head to // tail. For each block still in out allocation list search for the entry // in the crt list. #if defined(PLATFORM_WINDOWS) char *pHeap = new char; _CrtMemBlockHeader *pHeader = pHdr(pHeap)->pBlockHeaderNext; delete(pHeap); #endif // search through all alloc entries for(AllocInfoMap::iterator iter = m_AllocInfoMap.begin(); iter != m_AllocInfoMap.end(); ++iter) { AllocInfo& info = (*iter).second; uintx request = (*iter).first; #if defined(PLATFORM_WINDOWS) // search for entry in the crt list _CrtMemBlockHeader *pNext = pHeader; while(pNext && pNext->lRequest != request) pNext = pNext->pBlockHeaderNext; // write memory leak infos if(pNext && pNext->lRequest == request) m_Reporter->WriteLeak(request, pbData(pNext), static_cast<uintx>(pNext->nDataSize), info.m_CallstackSize, info.m_Callstack, info.m_ModuleReference, &m_ModuleInfoVector[0]); else m_Reporter->WriteLeak(request, NULL, 0, info.m_CallstackSize, info.m_Callstack, info.m_ModuleReference, &m_ModuleInfoVector[0]); #else // restore old malloc functions //RestoreHooks(); m_Reporter->WriteLeak(request, reinterpret_cast<void*>(request), info.m_Size, info.m_CallstackSize, info.m_Callstack, info.m_ModuleReference, NULL); // set hooking functions //SaveHooks(); //InstallHooks(); #endif } UNLOCK_HEAP // finished reporting m_Reporter->WriteFooter(); } #endif // _DEBUG }
int catchMemoryAllocHook(int allocType, void *userData, size_t size, int blockType, long requestNumber, const unsigned char *filename, // Can't be UNICODE int lineNumber) { _CrtMemBlockHeader *pCrtHead; long prevRequestNumber; #ifdef UNICODE wchar_t Wname[1024] ; Wname[0] = '\0' ; #endif // internal C library internal allocations if ( blockType == _CRT_BLOCK ) { return( TRUE ); } // check if someone has turned off mem tracing // CRT memory tracking can be turned off by the app. MFC sometimes does this temporarily. if ((( _CRTDBG_ALLOC_MEM_DF & _crtDbgFlag) == 0) && ( ( allocType == _HOOK_ALLOC) || ( allocType == _HOOK_REALLOC))) { if (pfnOldCrtAllocHook) { pfnOldCrtAllocHook(allocType, userData, size, blockType, requestNumber, filename, lineNumber); } return TRUE; } // protect if mem trace is not initialized if (g_pMemTrace == NULL) { if (pfnOldCrtAllocHook) { pfnOldCrtAllocHook(allocType, userData, size, blockType, requestNumber, filename, lineNumber); } return TRUE; } // protect internal mem trace allocs if (g_pMemTrace->isLocked) { if (pfnOldCrtAllocHook) { pfnOldCrtAllocHook(allocType, userData, size, blockType, requestNumber, filename, lineNumber); } return( TRUE); } // lock the function g_pMemTrace->isLocked = true; // #ifdef UNICODE int len ; if (NULL != filename) { len = strlen((char *)filename) + 1 ; MultiByteToWideChar(CP_ACP, 0, (char *)filename, len, Wname, len) ; } else len = 0 ; #else #define Wname (char*)filename #endif if (allocType == _HOOK_ALLOC) { g_pMemTrace->addMemoryTrace((void *) requestNumber, size, Wname, lineNumber); } else if (allocType == _HOOK_REALLOC) { if (_CrtIsValidHeapPointer(userData)) { pCrtHead = pHdr(userData); prevRequestNumber = pCrtHead->lRequest; // //if (pCrtHead->nBlockUse == _IGNORE_BLOCK) //{ // if (pfnOldCrtAllocHook) // { // pfnOldCrtAllocHook(allocType, userData, size, blockType, requestNumber, filename, lineNumber); // } // goto END; //} g_pMemTrace->redoMemoryTrace((void *) requestNumber, (void *) prevRequestNumber, size, Wname, lineNumber); } } else if (allocType == _HOOK_FREE) { if (_CrtIsValidHeapPointer(userData)) { pCrtHead = pHdr(userData); requestNumber = pCrtHead->lRequest; // //if (pCrtHead->nBlockUse == _IGNORE_BLOCK) //{ // if (pfnOldCrtAllocHook) // { // pfnOldCrtAllocHook(allocType, userData, size, blockType, requestNumber, filename, lineNumber); // } // goto END; //} g_pMemTrace->removeMemoryTrace((void *) requestNumber, userData); } } //END: // unlock the function g_pMemTrace->isLocked = false; return TRUE; }
void* next_pointer (void* ptr) { return get_pointer(pHdr(ptr)->pBlockHeaderNext); }
unsigned int allocation_line (void* ptr) { return static_cast<unsigned int>(pHdr(ptr)->nLine); }
const char* allocation_filename(void* ptr) { return pHdr(ptr)->szFileName; }
bool is_client (void* ptr) { return pHdr(ptr)->nBlockUse == _CLIENT_BLOCK; }
bool is_ignore (void* ptr) { return pHdr(ptr)->nBlockUse == _IGNORE_BLOCK; }