📄 mmgr.cpp
字号:
{ if (au->prev) au->prev->next = au->next; if (au->next) au->next->prev = au->prev; } } // Re-insert it back into the hash table hashIndex = ((unsigned int) au->reportedAddress >> 4) & (hashSize - 1); if (hashTable[hashIndex]) hashTable[hashIndex]->prev = au; au->next = hashTable[hashIndex]; au->prev = NULL; hashTable[hashIndex] = au; } // Account for the new allocatin unit in our stats stats.totalReportedMemory += au->reportedSize; stats.totalActualMemory += au->actualSize; if (stats.totalReportedMemory > stats.peakReportedMemory) stats.peakReportedMemory = stats.totalReportedMemory; if (stats.totalActualMemory > stats.peakActualMemory) stats.peakActualMemory = stats.totalActualMemory; int deltaReportedSize = reportedSize - originalReportedSize; if (deltaReportedSize > 0) { stats.accumulatedReportedMemory += deltaReportedSize; stats.accumulatedActualMemory += deltaReportedSize; } // Prepare the allocation unit for use (wipe it with recognizable garbage) wipeWithPattern(au, unusedPattern, originalReportedSize); // If you hit this assert, then something went wrong, because the allocation unit was properly validated PRIOR to // the reallocation. This should not happen. m_assert(m_validateAllocUnit(au)); // Validate every single allocated unit in memory if (alwaysValidateAll) m_validateAllAllocUnits(); // Log the result if (alwaysLogAll) log("[~] ----> addr 0x%08X", (unsigned int) au->reportedAddress); // Resetting the globals insures that if at some later time, somebody calls our memory manager from an unknown // source (i.e. they didn't include our H file) then we won't think it was the last allocation. resetGlobals(); // Return the (reported) address of the new allocation unit #ifdef TEST_MEMORY_MANAGER log("[D] EXIT : m_reallocator()"); #endif return au->reportedAddress; } catch(const char *err) { // Deal with the errors log("[!] %s", err); resetGlobals(); #ifdef TEST_MEMORY_MANAGER log("[D] EXIT : m_reallocator()"); #endif return NULL; }}// ---------------------------------------------------------------------------------------------------------------------------------// Deallocate memory and track it// ---------------------------------------------------------------------------------------------------------------------------------void m_deallocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc, const unsigned int deallocationType, const void *reportedAddress){ try { #ifdef TEST_MEMORY_MANAGER log("[D] ENTER: m_deallocator()"); #endif // Log the request if (alwaysLogAll) log("[-] ----- %8s of addr 0x%08X by %s", allocationTypes[deallocationType], (unsigned int) reportedAddress, ownerString(sourceFile, sourceLine, sourceFunc)); // Go get the allocation unit sAllocUnit *au = findAllocUnit(reportedAddress); // If you hit this assert, you tried to deallocate RAM that wasn't allocated by this memory manager. m_assert(au != NULL); if (au == NULL) throw "Request to deallocate RAM that was never allocated"; // If you hit this assert, then the allocation unit that is about to be deallocated is damaged. But you probably // already know that from a previous assert you should have seen in validateAllocUnit() :) m_assert(m_validateAllocUnit(au)); // If you hit this assert, then this deallocation was made from a source that isn't setup to use this memory // tracking software, use the stack frame to locate the source and include our H file. m_assert(deallocationType != m_alloc_unknown); // If you hit this assert, you were trying to deallocate RAM that was not allocated in a way that is compatible with // the deallocation method requested. In other words, you have a allocation/deallocation mismatch. m_assert((deallocationType == m_alloc_delete && au->allocationType == m_alloc_new ) || (deallocationType == m_alloc_delete_array && au->allocationType == m_alloc_new_array) || (deallocationType == m_alloc_free && au->allocationType == m_alloc_malloc ) || (deallocationType == m_alloc_free && au->allocationType == m_alloc_calloc ) || (deallocationType == m_alloc_free && au->allocationType == m_alloc_realloc ) || (deallocationType == m_alloc_unknown ) ); // If you hit this assert, then the "break on dealloc" flag for this allocation unit is set. Interrogate the 'au' // variable to determine information about this allocation unit. m_assert(au->breakOnDealloc == false); // Wipe the deallocated RAM with a new pattern. This doen't actually do us much good in debug mode under WIN32, // because Microsoft's memory debugging & tracking utilities will wipe it right after we do. Oh well. wipeWithPattern(au, releasedPattern); // Do the deallocation free(au->actualAddress); // Remove this allocation unit from the hash table unsigned int hashIndex = ((unsigned int) au->reportedAddress >> 4) & (hashSize - 1); if (hashTable[hashIndex] == au) { hashTable[hashIndex] = au->next; } else { if (au->prev) au->prev->next = au->next; if (au->next) au->next->prev = au->prev; } // Remove this allocation from our stats stats.totalReportedMemory -= au->reportedSize; stats.totalActualMemory -= au->actualSize; stats.totalAllocUnitCount--; // Add this allocation unit to the front of our reservoir of unused allocation units memset(au, 0, sizeof(sAllocUnit)); au->next = reservoir; reservoir = au; // Resetting the globals insures that if at some later time, somebody calls our memory manager from an unknown // source (i.e. they didn't include our H file) then we won't think it was the last allocation. resetGlobals(); // Validate every single allocated unit in memory if (alwaysValidateAll) m_validateAllAllocUnits(); // If we're in the midst of static deinitialization time, track any pending memory leaks if (staticDeinitTime) dumpLeakReport(); } catch(const char *err) { // Deal with errors log("[!] %s", err); resetGlobals(); } #ifdef TEST_MEMORY_MANAGER log("[D] EXIT : m_deallocator()"); #endif}// ---------------------------------------------------------------------------------------------------------------------------------// -DOC- The following utilitarian allow you to become proactive in tracking your own memory, or help you narrow in on those tough// bugs.// ---------------------------------------------------------------------------------------------------------------------------------bool m_validateAddress(const void *reportedAddress){ // Just see if the address exists in our allocation routines return findAllocUnit(reportedAddress) != NULL;}// ---------------------------------------------------------------------------------------------------------------------------------bool m_validateAllocUnit(const sAllocUnit *allocUnit){ // Make sure the padding is untouched long *pre = (long *) allocUnit->actualAddress; long *post = (long *) ((char *)allocUnit->actualAddress + allocUnit->actualSize - paddingSize * sizeof(long)); bool errorFlag = false; for (unsigned int i = 0; i < paddingSize; i++, pre++, post++) { if (*pre != (long) prefixPattern) { log("[!] A memory allocation unit was corrupt because of an underrun:"); m_dumpAllocUnit(allocUnit, " "); errorFlag = true; } // If you hit this assert, then you should know that this allocation unit has been damaged. Something (possibly the // owner?) has underrun the allocation unit (modified a few bytes prior to the start). You can interrogate the // variable 'allocUnit' to see statistics and information about this damaged allocation unit. m_assert(*pre == (long) prefixPattern); if (*post != (long) postfixPattern) { log("[!] A memory allocation unit was corrupt because of an overrun:"); m_dumpAllocUnit(allocUnit, " "); errorFlag = true; } // If you hit this assert, then you should know that this allocation unit has been damaged. Something (possibly the // owner?) has overrun the allocation unit (modified a few bytes after the end). You can interrogate the variable // 'allocUnit' to see statistics and information about this damaged allocation unit. m_assert(*post == (long) postfixPattern); } // Return the error status (we invert it, because a return of 'false' means error) return !errorFlag;}// ---------------------------------------------------------------------------------------------------------------------------------bool m_validateAllAllocUnits(){ // Just go through each allocation unit in the hash table and count the ones that have errors unsigned int errors = 0; unsigned int allocCount = 0; for (unsigned int i = 0; i < hashSize; i++) { sAllocUnit *ptr = hashTable[i]; while(ptr) { allocCount++; if (!m_validateAllocUnit(ptr)) errors++; ptr = ptr->next; } } // Test for hash-table correctness if (allocCount != stats.totalAllocUnitCount) { log("[!] Memory tracking hash table corrupt!"); errors++; } // If you hit this assert, then the internal memory (hash table) used by this memory tracking software is damaged! The // best way to track this down is to use the alwaysLogAll flag in conjunction with STRESS_TEST macro to narrow in on the // offending code. After running the application with these settings (and hitting this assert again), interrogate the // memory.log file to find the previous successful operation. The corruption will have occurred between that point and this // assertion. m_assert(allocCount == stats.totalAllocUnitCount); // If you hit this assert, then you've probably already been notified that there was a problem with a allocation unit in a // prior call to validateAllocUnit(), but this assert is here just to make sure you know about it. :) m_assert(errors == 0); // Log any errors if (errors) log("[!] While validting all allocation units, %d allocation unit(s) were found to have problems", errors); // Return the error status return errors != 0;}// ---------------------------------------------------------------------------------------------------------------------------------// -DOC- Unused RAM calculation routines. Use these to determine how much of your RAM is unused (in bytes)// ---------------------------------------------------------------------------------------------------------------------------------unsigned int m_calcUnused(const sAllocUnit *allocUnit){ const unsigned long *ptr = (const unsigned long *) allocUnit->reportedAddress; unsigned int count = 0; for (unsigned int i = 0; i < allocUnit->reportedSize; i += sizeof(long), ptr++) { if (*ptr == unusedPattern) count += sizeof(long); } return count;}// ---------------------------------------------------------------------------------------------------------------------------------unsigned int m_calcAllUnused(){ // Just go through each allocation unit in the hash table and count the unused RAM unsigned int total = 0; for (unsigned int i = 0; i < hashSize; i++) { sAllocUnit *ptr = hashTable[i]; while(ptr) { total += m_calcUnused(ptr); ptr = ptr->next; } } return total;}// ---------------------------------------------------------------------------------------------------------------------------------// -DOC- The following functions are for logging and statistics reporting.// ---------------------------------------------------------------------------------------------------------------------------------void m_dumpAllocUnit(const sAllocUnit *allocUnit, const char *prefix){ log("[I] %sAddress (reported): %010p", prefix, allocUnit->reportedAddress); log("[I] %sAddress (actual) : %010p", prefix, allocUnit->actualAddress); log("[I] %sSize (reported) : 0x%08X (%s)", prefix, allocUnit->reportedSize, memorySizeString(allocUnit->reportedSize)); log("[I] %sSize (actual) : 0x%08X (%s)", prefix, allocUnit->actualSize, memorySizeString(allocUnit->actualSize)); log("[I] %sOwner : %s(%d)::%s", prefix, allocUnit->sourceFile, allocUnit->sourceLine, allocUnit->sourceFunc); log("[I] %sAllocation type : %s", prefix, allocationTypes[allocUnit->allocationType]); log("[I] %sAllocation number : %d", prefix, allocUnit->allocationNumber);}// ---------------------------------------------------------------------------------------------------------------------------------void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -