mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@1871 3b4a5df2-a311-0410-b5c6-a8a6f20db521
754 lines
19 KiB
C++
754 lines
19 KiB
C++
//**************************************************************************
|
|
//
|
|
// Filename : MemMan.cpp
|
|
//
|
|
// Purpose : function definitions for the memory manager
|
|
//
|
|
// Modification history :
|
|
//
|
|
// 11sep96:HJH - Creation
|
|
// 29may97:ARM - Fix & improve MemDebugCounter handling, logging of
|
|
// MemAlloc/MemFree, and reporting of any errors
|
|
//
|
|
//**************************************************************************
|
|
|
|
//**************************************************************************
|
|
//
|
|
// Includes
|
|
//
|
|
//**************************************************************************
|
|
|
|
//#ifdef JA2_PRECOMPILED_HEADERS
|
|
// #include "JA2 SGP ALL.H"
|
|
//#elif defined( WIZ8_PRECOMPILED_HEADERS )
|
|
// #include "WIZ8 SGP ALL.H"
|
|
//#else
|
|
#include "types.h"
|
|
#include <windows.h>
|
|
#include <malloc.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "MemMan.h"
|
|
#include "Debug.h"
|
|
#include <stdio.h>
|
|
#ifdef _DEBUG
|
|
#include <crtdbg.h>
|
|
#endif
|
|
//#endif
|
|
|
|
#ifdef _DEBUG
|
|
//#define DEBUG_MEM_LEAKS // turns on tracking of every MemAlloc and MemFree!
|
|
#endif
|
|
|
|
//**************************************************************************
|
|
//
|
|
// Variables
|
|
//
|
|
//**************************************************************************
|
|
|
|
#ifdef JA2
|
|
#include "mousesystem.h"
|
|
#include "MessageBoxScreen.h"
|
|
STR16 gzJA2ScreenNames[] =
|
|
{
|
|
L"EDIT_SCREEN",
|
|
L"SAVING_SCREEN",
|
|
L"LOADING_SCREEN",
|
|
L"ERROR_SCREEN",
|
|
L"INIT_SCREEN",
|
|
L"GAME_SCREEN",
|
|
L"ANIEDIT_SCREEN",
|
|
L"PALEDIT_SCREEN",
|
|
L"DEBUG_SCREEN",
|
|
L"MAP_SCREEN",
|
|
L"LAPTOP_SCREEN",
|
|
L"LOADSAVE_SCREEN",
|
|
L"MAPUTILITY_SCREEN",
|
|
L"FADE_SCREEN",
|
|
L"MSG_BOX_SCREEN",
|
|
L"MAINMENU_SCREEN",
|
|
L"AUTORESOLVE_SCREEN",
|
|
L"SAVE_LOAD_SCREEN",
|
|
L"OPTIONS_SCREEN",
|
|
L"SHOPKEEPER_SCREEN",
|
|
L"SEX_SCREEN",
|
|
L"GAME_INIT_OPTIONS_SCREEN",
|
|
L"DEMO_EXIT_SCREEN",
|
|
L"INTRO_SCREEN",
|
|
L"CREDIT_SCREEN",
|
|
#ifdef JA2BETAVERSION
|
|
L"AIVIEWER_SCREEN",
|
|
L"QUEST_DEBUG_SCREEN",
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
#ifdef EXTREME_MEMORY_DEBUGGING
|
|
typedef struct MEMORY_NODE
|
|
{
|
|
PTR pBlock;
|
|
struct MEMORY_NODE *next, *prev;
|
|
UINT8 *pCode;
|
|
UINT32 uiSize;
|
|
}MEMORY_NODE;
|
|
|
|
MEMORY_NODE *gpMemoryHead = NULL;
|
|
MEMORY_NODE *gpMemoryTail = NULL;
|
|
UINT32 guiMemoryNodes = 0;
|
|
UINT32 guiTotalMemoryNodes = 0;
|
|
#endif
|
|
|
|
static BOOLEAN gfMemDebug = TRUE;
|
|
// debug variable for total memory currently allocated
|
|
UINT32 guiMemTotal = 0;
|
|
UINT32 guiMemAlloced = 0;
|
|
UINT32 guiMemFreed = 0;
|
|
UINT32 MemDebugCounter = 0;
|
|
BOOLEAN fMemManagerInit = FALSE;
|
|
|
|
//**************************************************************************
|
|
//
|
|
// Function Prototypes
|
|
//
|
|
//**************************************************************************
|
|
|
|
void DebugPrint( void );
|
|
|
|
//**************************************************************************
|
|
//
|
|
// Functions
|
|
//
|
|
//**************************************************************************
|
|
|
|
//**************************************************************************
|
|
//
|
|
// MemInit
|
|
//
|
|
//
|
|
//
|
|
// Parameter List :
|
|
// Return Value :
|
|
// Modification history :
|
|
//
|
|
// 12sep96:HJH ->modified for use by Wizardry
|
|
//
|
|
//**************************************************************************
|
|
|
|
BOOLEAN InitializeMemoryManager( void )
|
|
{
|
|
// Register the memory manager with the debugger
|
|
RegisterDebugTopic(TOPIC_MEMORY_MANAGER, "Memory Manager");
|
|
MemDebugCounter = 0;
|
|
guiMemTotal = 0;
|
|
guiMemAlloced = 0;
|
|
guiMemFreed = 0;
|
|
fMemManagerInit = TRUE;
|
|
|
|
#ifdef EXTREME_MEMORY_DEBUGGING
|
|
gpMemoryHead = NULL;
|
|
gpMemoryTail = NULL;
|
|
guiMemoryNodes = 0;
|
|
guiTotalMemoryNodes = 0;
|
|
#endif
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
//**************************************************************************
|
|
//
|
|
// MemDebug
|
|
//
|
|
// To set whether or not we should print debug info.
|
|
//
|
|
// Parameter List :
|
|
// Return Value :
|
|
// Modification history :
|
|
//
|
|
// 12sep96:HJH ->modified for use by Wizardry
|
|
//
|
|
//**************************************************************************
|
|
|
|
void MemDebug( BOOLEAN f )
|
|
{
|
|
gfMemDebug = f;
|
|
}
|
|
|
|
//**************************************************************************
|
|
//
|
|
// MemShutdown
|
|
//
|
|
// Shuts down the memory manager.
|
|
//
|
|
// Parameter List :
|
|
// Return Value :
|
|
// Modification history :
|
|
//
|
|
// 12sep96:HJH ->modified for use by Wizardry
|
|
//
|
|
//**************************************************************************
|
|
|
|
void ShutdownMemoryManager( void )
|
|
{
|
|
if ( MemDebugCounter != 0 )
|
|
{
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String(" "));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("***** WARNING - WARNING - WARNING *****"));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("***** WARNING - WARNING - WARNING *****"));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("***** WARNING - WARNING - WARNING *****"));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String(" "));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String(" >>>>> MEMORY LEAK DETECTED!!! <<<<< "));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("%d memory blocks still allocated", MemDebugCounter ));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("%d bytes memory total STILL allocated", guiMemTotal ));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("%d bytes memory total was allocated", guiMemAlloced));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("%d bytes memory total was freed", guiMemFreed));
|
|
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String(" "));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("***** WARNING - WARNING - WARNING *****"));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("***** WARNING - WARNING - WARNING *****"));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("***** WARNING - WARNING - WARNING *****"));
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String(" "));
|
|
|
|
#ifndef EXTREME_MEMORY_DEBUGGING
|
|
#ifdef JA2BETAVERSION
|
|
{
|
|
FILE *fp;
|
|
fp = fopen( "MemLeakInfo.txt", "a" );
|
|
if( fp )
|
|
{
|
|
fprintf( fp, "\n\n" );
|
|
fprintf( fp, ">>>>> MEMORY LEAK DETECTED!!! <<<<<\n" );
|
|
fprintf( fp, " %d bytes memory total was allocated\n", guiMemAlloced );
|
|
fprintf( fp, "- %d bytes memory total was freed\n", guiMemFreed );
|
|
fprintf( fp, "_______________________________________________\n" );
|
|
fprintf( fp, "%d bytes memory total STILL allocated\n", guiMemTotal );
|
|
fprintf( fp, "%d memory blocks still allocated\n", MemDebugCounter );
|
|
fprintf( fp, "guiScreenExitedFrom = %S\n", gzJA2ScreenNames[ gMsgBox.uiExitScreen ] );
|
|
fprintf( fp, "\n\n" );
|
|
}
|
|
fclose( fp );
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
UnRegisterDebugTopic( TOPIC_MEMORY_MANAGER, "Memory Manager Un-initialized" );
|
|
|
|
fMemManagerInit = FALSE;
|
|
}
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
PTR MemAllocReal( UINT32 uiSize, const STR8 pcFile, INT32 iLine )
|
|
{
|
|
PTR ptr;
|
|
|
|
if( !uiSize )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if ( !fMemManagerInit )
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("MemAlloc: Warning -- Memory manager not initialized -- Line %d in %s", iLine, pcFile) );
|
|
|
|
|
|
ptr = _malloc_dbg( uiSize, _NORMAL_BLOCK, pcFile, iLine );
|
|
if (ptr != NULL)
|
|
{
|
|
guiMemTotal += uiSize;
|
|
guiMemAlloced += uiSize;
|
|
MemDebugCounter++;
|
|
}
|
|
else
|
|
{
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("MemAlloc failed: %d bytes (line %d file %s)", uiSize, iLine, pcFile) );
|
|
}
|
|
|
|
#ifdef DEBUG_MEM_LEAKS
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_1, String("MemAlloc %p: %d bytes (line %d file %s)", ptr, uiSize, iLine, pcFile) );
|
|
#endif
|
|
|
|
return( ptr );
|
|
}
|
|
|
|
|
|
void MemFreeReal( PTR ptr, const STR8 pcFile, INT32 iLine )
|
|
{
|
|
UINT32 uiSize;
|
|
|
|
if ( !fMemManagerInit )
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("MemFree: Warning -- Memory manager not initialized -- Line %d in %s", iLine, pcFile) );
|
|
|
|
if (ptr != NULL)
|
|
{
|
|
uiSize = _msize(ptr);
|
|
guiMemTotal -= uiSize;
|
|
guiMemFreed += uiSize;
|
|
_free_dbg( ptr, _NORMAL_BLOCK );
|
|
|
|
#ifdef DEBUG_MEM_LEAKS
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_1, String("MemFree %p: %d bytes (line %d file %s)", ptr, uiSize, iLine, pcFile) );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("MemFree ERROR: NULL ptr received (line %d file %s)", iLine, pcFile) );
|
|
}
|
|
|
|
// count even a NULL ptr as a MemFree, not because it's really a memory leak, but because it is still an error of some
|
|
// sort (nobody should ever be freeing NULL pointers), and this will help in tracking it down if the above DbgMessage
|
|
// is not noticed.
|
|
MemDebugCounter--;
|
|
}
|
|
|
|
|
|
PTR MemReallocReal( PTR ptr, UINT32 uiSize, const STR8 pcFile, INT32 iLine )
|
|
{
|
|
PTR ptrNew;
|
|
UINT32 uiOldSize = 0;
|
|
|
|
|
|
if ( !fMemManagerInit )
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("MemRealloc: Warning -- Memory manager not initialized -- Line %d in %s", iLine, pcFile) );
|
|
|
|
if(ptr != NULL)
|
|
{
|
|
uiOldSize = _msize(ptr);
|
|
guiMemTotal -= uiOldSize;
|
|
guiMemFreed += uiOldSize;
|
|
MemDebugCounter--;
|
|
}
|
|
|
|
// Note that the ptr changes to ptrNew...
|
|
ptrNew = _realloc_dbg( ptr, uiSize, _NORMAL_BLOCK, pcFile, iLine );
|
|
if (ptrNew == NULL)
|
|
{
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("MemReAlloc failed: ptr %d, %d->%d bytes (line %d file %s)", ptr, uiOldSize, uiSize, iLine, pcFile) );
|
|
if ( uiSize != 0 )
|
|
{
|
|
// ptr is left untouched, so undo the math above
|
|
guiMemTotal += uiOldSize;
|
|
guiMemFreed -= uiOldSize;
|
|
MemDebugCounter++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_MEM_LEAKS
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_1, String("MemRealloc %p: Resizing %d bytes to %d bytes (line %d file %s) - New ptr %p", ptr, uiOldSize, uiSize, iLine, pcFile, ptrNew ) );
|
|
#endif
|
|
|
|
guiMemTotal += uiSize;
|
|
guiMemAlloced += uiSize;
|
|
MemDebugCounter++;
|
|
}
|
|
|
|
return( ptrNew );
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
PTR MemAllocLocked( UINT32 uiSize )
|
|
{
|
|
PTR ptr;
|
|
|
|
if ( !fMemManagerInit )
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("MemAllocLocked: Warning -- Memory manager not initialized!!! ") );
|
|
|
|
|
|
ptr = VirtualAlloc( NULL, uiSize, MEM_COMMIT, PAGE_READWRITE );
|
|
|
|
if ( ptr )
|
|
{
|
|
VirtualLock( ptr, uiSize );
|
|
|
|
guiMemTotal += uiSize;
|
|
guiMemAlloced += uiSize;
|
|
MemDebugCounter++;
|
|
}
|
|
else
|
|
{
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("MemAllocLocked failed: %d bytes", uiSize) );
|
|
}
|
|
|
|
#ifdef DEBUG_MEM_LEAKS
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_1, String("MemAllocLocked %p: %d bytes", ptr, uiSize) );
|
|
#endif
|
|
|
|
return( ptr );
|
|
}
|
|
|
|
|
|
void MemFreeLocked( PTR ptr, UINT32 uiSize )
|
|
{
|
|
if ( !fMemManagerInit )
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("MemFreeLocked: Warning -- Memory manager not initialized!!! ") );
|
|
|
|
|
|
if (ptr != NULL)
|
|
{
|
|
VirtualUnlock( ptr, uiSize );
|
|
VirtualFree( ptr, uiSize, MEM_RELEASE );
|
|
|
|
guiMemTotal -= uiSize;
|
|
guiMemFreed += uiSize;
|
|
}
|
|
else
|
|
{
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_0, String("MemFreeLocked ERROR: NULL ptr received, size %d", uiSize) );
|
|
}
|
|
|
|
// count even a NULL ptr as a MemFree, not because it's really a memory leak, but because it is still an error of some
|
|
// sort (nobody should ever be freeing NULL pointers), and this will help in tracking it down if the above DbgMessage
|
|
// is not noticed.
|
|
MemDebugCounter--;
|
|
|
|
#ifdef DEBUG_MEM_LEAKS
|
|
DbgMessage( TOPIC_MEMORY_MANAGER, DBG_LEVEL_1, String("MemFreeLocked %p", ptr) );
|
|
#endif
|
|
}
|
|
|
|
|
|
//**************************************************************************
|
|
//
|
|
// MemGetFree
|
|
//
|
|
//
|
|
//
|
|
// Parameter List :
|
|
// Return Value :
|
|
// Modification history :
|
|
//
|
|
// ??sep96:HJH ->modified for use by Wizardry
|
|
//
|
|
//**************************************************************************
|
|
|
|
UINT32 MemGetFree( void )
|
|
{
|
|
MEMORYSTATUS ms;
|
|
|
|
ms.dwLength = sizeof(MEMORYSTATUS);
|
|
GlobalMemoryStatus( &ms );
|
|
|
|
return( ms.dwAvailPhys );
|
|
}
|
|
|
|
|
|
//**************************************************************************
|
|
//
|
|
// MemGetTotalSystem
|
|
//
|
|
//
|
|
//
|
|
// Parameter List :
|
|
// Return Value :
|
|
// Modification history :
|
|
//
|
|
// May98:HJH ->Carter
|
|
//
|
|
//**************************************************************************
|
|
|
|
UINT32 MemGetTotalSystem( void )
|
|
{
|
|
MEMORYSTATUS ms;
|
|
|
|
ms.dwLength = sizeof(MEMORYSTATUS);
|
|
GlobalMemoryStatus( &ms );
|
|
|
|
return( ms.dwTotalPhys );
|
|
}
|
|
|
|
|
|
//**************************************************************************
|
|
//
|
|
// MemCheckPool
|
|
//
|
|
//
|
|
//
|
|
// Parameter List :
|
|
// Return Value :
|
|
// Modification history :
|
|
//
|
|
// 23sep96:HJH ->modified for use by Wizardry
|
|
//
|
|
//**************************************************************************
|
|
|
|
BOOLEAN MemCheckPool( void )
|
|
{
|
|
BOOLEAN fRet = TRUE;
|
|
|
|
#ifdef _DEBUG
|
|
|
|
fRet = _CrtCheckMemory();
|
|
Assert( fRet );
|
|
|
|
#endif
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
#ifdef EXTREME_MEMORY_DEBUGGING
|
|
|
|
PTR MemAllocXDebug( UINT32 size, const STR8 szCodeString, INT32 iLineNum, void *pSpecial )
|
|
{
|
|
PTR ptr;
|
|
UINT16 usLength;
|
|
UINT8 str[70];
|
|
UINT8 *pStr;
|
|
|
|
if( !size )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if( !pSpecial )
|
|
{
|
|
ptr = malloc( size );
|
|
}
|
|
else
|
|
{
|
|
ptr = pSpecial;
|
|
}
|
|
|
|
if( ptr )
|
|
{
|
|
// Set into video object list
|
|
if( gpMemoryHead )
|
|
{ //Add node after tail
|
|
gpMemoryTail->next = (MEMORY_NODE*)malloc( sizeof( MEMORY_NODE ) );
|
|
Assert( gpMemoryTail->next ); //out of memory?
|
|
gpMemoryTail->next->prev = gpMemoryTail;
|
|
gpMemoryTail->next->next = NULL;
|
|
gpMemoryTail = gpMemoryTail->next;
|
|
}
|
|
else
|
|
{ //new list
|
|
gpMemoryHead = (MEMORY_NODE*)malloc( sizeof( MEMORY_NODE ) );
|
|
Assert( gpMemoryHead ); //out of memory?
|
|
gpMemoryHead->prev = gpMemoryHead->next = NULL;
|
|
gpMemoryTail = gpMemoryHead;
|
|
}
|
|
|
|
//record the code location of the calling creating function.
|
|
pStr = strrchr( szCodeString, '\\' );
|
|
pStr++;
|
|
sprintf( str, "%s -- line(%d)", pStr, iLineNum );
|
|
usLength = strlen( str ) + 1;
|
|
gpMemoryTail->pCode = (UINT8*)malloc( usLength );
|
|
memset( gpMemoryTail->pCode, 0, usLength );
|
|
strcpy( gpMemoryTail->pCode, str );
|
|
|
|
//record the size
|
|
gpMemoryTail->uiSize = size;
|
|
|
|
//Set the hVObject into the node.
|
|
gpMemoryTail->pBlock = ptr;
|
|
|
|
guiMemoryNodes++;
|
|
guiTotalMemoryNodes++;
|
|
}
|
|
return( ptr );
|
|
}
|
|
|
|
void MemFreeXDebug( PTR ptr, const STR8 szCodeString, INT32 iLineNum, void *pSpecial )
|
|
{
|
|
MEMORY_NODE *curr;
|
|
|
|
if( ptr )
|
|
{
|
|
curr = gpMemoryHead;
|
|
while( curr )
|
|
{
|
|
if( curr->pBlock == ptr )
|
|
{ //Found the node, so detach it and delete it.
|
|
|
|
if( !pSpecial )
|
|
{
|
|
free( ptr );
|
|
}
|
|
|
|
if( curr == gpMemoryHead )
|
|
{ //Advance the head, because we are going to remove the head node.
|
|
gpMemoryHead = gpMemoryHead->next;
|
|
}
|
|
if( curr == gpMemoryTail )
|
|
{ //Back up the tail, because we are going to remove the tail node.
|
|
gpMemoryTail = gpMemoryTail->prev;
|
|
}
|
|
//Detach the node from the vobject list
|
|
if( curr->next )
|
|
{ //Make the prev node point to the next
|
|
curr->next->prev = curr->prev;
|
|
}
|
|
if( curr->prev )
|
|
{ //Make the next node point to the prev
|
|
curr->prev->next = curr->next;
|
|
}
|
|
//The node is now detached. Now deallocate it.
|
|
free( curr );
|
|
curr = NULL;
|
|
guiMemoryNodes--;
|
|
return;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
PTR MemReallocXDebug( PTR ptr, UINT32 size, const STR8 szCodeString, INT32 iLineNum, void *pSpecial )
|
|
{
|
|
MEMORY_NODE *curr;
|
|
PTR ptrNew;
|
|
UINT16 usLength;
|
|
UINT8 str[70];
|
|
UINT8 *pStr;
|
|
|
|
if( !ptr && size )
|
|
{
|
|
return MemAllocXDebug( size, szCodeString, iLineNum, pSpecial );
|
|
}
|
|
|
|
curr = gpMemoryHead;
|
|
while( curr )
|
|
{
|
|
if( curr->pBlock == ptr )
|
|
{
|
|
// Note that the ptr changes to ptrNew...
|
|
if( !pSpecial )
|
|
{
|
|
ptrNew = realloc( ptr, size );
|
|
}
|
|
else
|
|
{
|
|
ptrNew = pSpecial;
|
|
}
|
|
|
|
if( ptrNew )
|
|
{
|
|
curr->pBlock = ptrNew;
|
|
curr->uiSize = size;
|
|
|
|
free( curr->pCode );
|
|
|
|
//record the code location of the calling creating function.
|
|
pStr = strrchr( szCodeString, '\\' );
|
|
pStr++;
|
|
sprintf( str, "%s -- line(%d)", pStr, iLineNum );
|
|
usLength = strlen( str ) + 1;
|
|
curr->pCode = (UINT8*)malloc( usLength );
|
|
memset( curr->pCode, 0, usLength );
|
|
strcpy( curr->pCode, str );
|
|
}
|
|
else
|
|
{
|
|
ptr = ptr;
|
|
}
|
|
return ptrNew;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
typedef struct DUMPFILENAME
|
|
{
|
|
UINT8 str[70];
|
|
}DUMPFILENAME;
|
|
|
|
void DumpMemoryInfoIntoFile( UINT8 *filename, BOOLEAN fAppend )
|
|
{
|
|
MEMORY_NODE *curr;
|
|
FILE *fp;
|
|
DUMPFILENAME *pCode;
|
|
UINT32 *puiCounter, *puiSize;
|
|
UINT8 tempCode[ 70 ];
|
|
UINT32 i, uiUniqueID, uiTotalKbWasted = 0, uiBytesRemainder = 0;
|
|
BOOLEAN fFound;
|
|
|
|
if( fAppend )
|
|
{
|
|
fp = fopen( filename, "a" );
|
|
}
|
|
else
|
|
{
|
|
fp = fopen( filename, "w" );
|
|
}
|
|
Assert( fp );
|
|
|
|
if( !guiMemoryNodes )
|
|
{
|
|
fprintf( fp, "NO MEMORY LEAKS DETECTED! CONGRATULATIONS!\n" );
|
|
fclose( fp );
|
|
return;
|
|
}
|
|
|
|
//Allocate enough strings and counters for each node.
|
|
pCode = (DUMPFILENAME*)malloc( sizeof( DUMPFILENAME ) * guiMemoryNodes );
|
|
memset( pCode, 0, sizeof( DUMPFILENAME ) * guiMemoryNodes );
|
|
puiSize = (UINT32*)malloc( 4 * guiMemoryNodes );
|
|
memset( puiSize, 0, 4 * guiMemoryNodes );
|
|
puiCounter = (UINT32*)malloc( 4 * guiMemoryNodes );
|
|
memset( puiCounter, 0, 4 * guiMemoryNodes );
|
|
|
|
//Loop through the list and record every unique filename and count them
|
|
uiUniqueID = 0;
|
|
curr = gpMemoryHead;
|
|
while( curr )
|
|
{
|
|
strcpy( tempCode, curr->pCode );
|
|
fFound = FALSE;
|
|
for( i = 0; i < uiUniqueID; i++ )
|
|
{
|
|
if( !_stricmp( tempCode, pCode[i].str ) )
|
|
{ //same string
|
|
fFound = TRUE;
|
|
(puiCounter[ i ])++;
|
|
(puiSize[ i ]) += curr->uiSize;
|
|
break;
|
|
}
|
|
}
|
|
if( !fFound )
|
|
{
|
|
strcpy( pCode[i].str, tempCode );
|
|
(puiSize[ i ]) += curr->uiSize;
|
|
(puiCounter[ i ])++;
|
|
uiUniqueID++;
|
|
}
|
|
curr = curr->next;
|
|
}
|
|
|
|
//Now dump the info.
|
|
fprintf( fp, "--------------------------------------------------------------------------------\n" );
|
|
fprintf( fp, "%d unique memory allocation locations exist in %d memory nodes\n", uiUniqueID, guiMemoryNodes );
|
|
fprintf( fp, "--------------------------------------------------------------------------------\n" );
|
|
for( i = 0; i < uiUniqueID; i++ )
|
|
{
|
|
fprintf( fp, "%d occurrences of %s (total size %d bytes)\n", puiCounter[i], pCode[i].str, puiSize[i] );
|
|
uiBytesRemainder += puiSize[i];
|
|
if( uiBytesRemainder >= 1024 )
|
|
{
|
|
uiTotalKbWasted += uiBytesRemainder/1024;
|
|
uiBytesRemainder %= 1024;
|
|
}
|
|
}
|
|
fprintf( fp, "--------------------------------------------------------------------------------\n" );
|
|
fprintf( fp, "%dKB of memory total wasn't cleaned up!\n", uiTotalKbWasted );
|
|
fprintf( fp, "--------------------------------------------------------------------------------\n" );
|
|
|
|
fclose( fp );
|
|
|
|
//Free all memory associated with this operation.
|
|
free( pCode );
|
|
free( puiCounter );
|
|
free( puiSize );
|
|
}
|
|
|
|
BOOLEAN _AddAndRecordMemAlloc( UINT32 size, UINT32 uiLineNum, UINT8 *pSourceFile )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#endif
|