You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
500 lines
11 KiB
500 lines
11 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: memalloc.c
|
|
* Content: allocates memory
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 20-jan-95 craige initial implementation
|
|
* 27-feb-95 craige don't call HeapFree with NULL, it is a huge time sink
|
|
* 29-mar-95 craige memory tracker
|
|
* 01-apr-95 craige happy fun joy updated header file
|
|
* 06-apr-95 craige made stand-alone
|
|
* 22-may-95 craige added MemAlloc16
|
|
* 12-jun-95 craige added MemReAlloc
|
|
* 18-jun-95 craige deadlock joy: don't take DLL csect here
|
|
* 26-jul-95 toddla added MemSize and fixed MemReAlloc
|
|
* 29-feb-96 colinmc added optional debugging code to blat a a specific
|
|
* bit pattern over freed memory
|
|
* 08-oct-96 ketand change debug message to give a total for the terminating
|
|
* process
|
|
* 22-dec-00 aarono use process heap in retail (whistler b#190380)
|
|
*
|
|
***************************************************************************/
|
|
#undef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include "memalloc.h"
|
|
#include "newdpf.h"
|
|
|
|
#define FREE_MEMORY_PATTERN 0xDEADBEEFUL
|
|
|
|
#ifdef WIN95
|
|
#ifdef NOSHARED
|
|
#define HEAP_SHARED 0
|
|
#else
|
|
#define HEAP_SHARED 0x04000000 // put heap in shared memory
|
|
#endif
|
|
#else
|
|
#define HEAP_SHARED 0
|
|
#endif
|
|
|
|
static HANDLE hHeap = NULL; // handle to shared heap for this DLL
|
|
|
|
/*
|
|
* memory track struct and list
|
|
*/
|
|
#ifdef DEBUG
|
|
#define MCOOKIE 0xbaaabaaa
|
|
#define MCOOKIE_FREE 0xbabababa
|
|
typedef struct _MEMTRACK
|
|
{
|
|
DWORD dwCookie;
|
|
struct _MEMTRACK FAR *lpNext;
|
|
struct _MEMTRACK FAR *lpPrev;
|
|
DWORD dwSize;
|
|
LPVOID lpAddr;
|
|
DWORD dwPid;
|
|
} MEMTRACK, FAR *LPMEMTRACK;
|
|
|
|
static LPMEMTRACK lpHead;
|
|
static LPMEMTRACK lpTail;
|
|
static LONG lAllocCount;
|
|
static LONG lBytesAlloc;
|
|
|
|
#define DEBUG_TRACK( lptr, first ) \
|
|
if( lptr == NULL ) \
|
|
{ \
|
|
DPF( 1, "Alloc of size %u FAILED!", size ); \
|
|
} \
|
|
else \
|
|
{ \
|
|
LPMEMTRACK pmt; \
|
|
pmt = (LPMEMTRACK) lptr; \
|
|
pmt->dwSize = size - sizeof( MEMTRACK ); \
|
|
pmt->dwCookie = MCOOKIE; \
|
|
pmt->lpAddr = _ReturnAddress(); \
|
|
pmt->dwPid = GetCurrentProcessId(); \
|
|
if( lpHead == NULL ) \
|
|
{ \
|
|
lpHead = lpTail = pmt; \
|
|
} \
|
|
else \
|
|
{ \
|
|
lpTail->lpNext = pmt; \
|
|
pmt->lpPrev = lpTail; \
|
|
lpTail = pmt; \
|
|
} \
|
|
lptr = (LPVOID) (((LPBYTE) lptr) + sizeof( MEMTRACK )); \
|
|
lAllocCount++; \
|
|
lBytesAlloc+=pmt->dwSize;\
|
|
{ \
|
|
IN_WRITESTATS InWS; \
|
|
memset((PVOID)&InWS,0xFF,sizeof(IN_WRITESTATS)); \
|
|
InWS.stat_USER3=lBytesAlloc; \
|
|
DbgWriteStats(&InWS); \
|
|
} \
|
|
}
|
|
|
|
#define DEBUG_TRACK_UPDATE_SIZE( s ) s += sizeof( MEMTRACK );
|
|
|
|
#else
|
|
|
|
#define DEBUG_TRACK( lptr, first )
|
|
#define DEBUG_TRACK_UPDATE_SIZE( size )
|
|
|
|
#endif
|
|
|
|
|
|
#if defined( WIN95 ) && defined( WANT_MEM16 )
|
|
|
|
extern DWORD _stdcall MapLS( LPVOID ); // flat -> 16:16
|
|
extern void _stdcall UnMapLS( DWORD ); // unmap 16:16
|
|
|
|
typedef struct SELLIST {
|
|
struct SELLIST *link;
|
|
LPBYTE base;
|
|
WORD sel;
|
|
} SELLIST, *LPSELLIST;
|
|
|
|
static LPSELLIST lpSelList;
|
|
|
|
/*
|
|
* MemAlloc16
|
|
*
|
|
* Allocate some memory, and return a 16:16 pointer to that memory
|
|
*
|
|
* NOTE: ASSUMES WE ARE IN THE DLL CRITICAL SECTION!
|
|
*/
|
|
LPVOID __cdecl MemAlloc16( UINT size, LPDWORD p16 )
|
|
{
|
|
LPBYTE lptr;
|
|
LPSELLIST psel;
|
|
DWORD diff;
|
|
|
|
DEBUG_TRACK_UPDATE_SIZE( size );
|
|
lptr = HeapAlloc( hHeap, HEAP_ZERO_MEMORY, size );
|
|
DEBUG_TRACK( lptr, size );
|
|
if( lptr == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* try to find an existing selector that maps this area
|
|
*/
|
|
psel = lpSelList;
|
|
while( psel != NULL )
|
|
{
|
|
if( psel->base <= lptr )
|
|
{
|
|
diff = lptr - psel->base;
|
|
if( diff+size < 0xf000 )
|
|
{
|
|
*p16 = ((DWORD)psel->sel << 16l) + diff;
|
|
return lptr;
|
|
}
|
|
}
|
|
psel = psel->link;
|
|
}
|
|
|
|
/*
|
|
* no selector found, create a new one
|
|
*/
|
|
psel = HeapAlloc( hHeap, HEAP_ZERO_MEMORY, sizeof( SELLIST ));
|
|
if( psel == NULL )
|
|
{
|
|
return NULL;
|
|
}
|
|
psel->sel = HIWORD( MapLS( lptr ) );
|
|
DPF( 2, "$$$$$$ New selector allocated: %04x", psel->sel );
|
|
psel->base = lptr;
|
|
psel->link = lpSelList;
|
|
lpSelList = psel;
|
|
*p16 = ((DWORD) psel->sel) << 16l;
|
|
|
|
return lptr;
|
|
|
|
} /* MemAlloc16 */
|
|
|
|
/*
|
|
* GetPtr16
|
|
*/
|
|
LPVOID GetPtr16( LPVOID ptr )
|
|
{
|
|
DWORD diff;
|
|
DWORD p16;
|
|
LPSELLIST psel;
|
|
LPBYTE lptr;
|
|
|
|
lptr = ptr;
|
|
|
|
psel = lpSelList;
|
|
while( psel != NULL )
|
|
{
|
|
if( psel->base <= lptr )
|
|
{
|
|
diff = lptr - psel->base;
|
|
if( diff <= 0xf000 )
|
|
{
|
|
p16 = ((DWORD)psel->sel << 16l) + diff;
|
|
return (LPVOID) p16;
|
|
}
|
|
}
|
|
psel = psel->link;
|
|
}
|
|
DPF( 1, "ERROR: NO 16:16 PTR for %08lx", lptr );
|
|
return NULL;
|
|
|
|
} /* GetPtr16 */
|
|
|
|
/*
|
|
* freeSelectors
|
|
*/
|
|
static void freeSelectors( void )
|
|
{
|
|
LPSELLIST psel;
|
|
LPSELLIST link;
|
|
|
|
psel = lpSelList;
|
|
while( psel != NULL )
|
|
{
|
|
link = psel->link;
|
|
DPF( 2, "$$$$$$ Freeing selector %04x", psel->sel );
|
|
UnMapLS( ((DWORD)psel->sel) << 16l );
|
|
HeapFree( hHeap, 0, psel );
|
|
psel = link;
|
|
}
|
|
lpSelList = NULL;
|
|
|
|
} /* freeSelectors */
|
|
#endif
|
|
|
|
/*
|
|
* MemAlloc - allocate memory from our global pool
|
|
*/
|
|
LPVOID __cdecl MemAlloc( UINT size )
|
|
{
|
|
LPBYTE lptr;
|
|
|
|
DEBUG_TRACK_UPDATE_SIZE( size );
|
|
lptr = HeapAlloc( hHeap, HEAP_ZERO_MEMORY, size );
|
|
DEBUG_TRACK( lptr, size );
|
|
|
|
return lptr;
|
|
|
|
} /* MemAlloc */
|
|
|
|
/*
|
|
* MemSize - return size of object
|
|
*/
|
|
UINT_PTR __cdecl MemSize( LPVOID lptr )
|
|
{
|
|
#ifdef DEBUG
|
|
if (lptr)
|
|
{
|
|
LPMEMTRACK pmt;
|
|
lptr = (LPVOID) (((LPBYTE)lptr) - sizeof( MEMTRACK ));
|
|
pmt = lptr;
|
|
return pmt->dwSize;
|
|
}
|
|
#endif
|
|
return HeapSize(hHeap, 0, lptr);
|
|
|
|
} /* MemSize */
|
|
|
|
/*
|
|
* MemFree - free memory from our global pool
|
|
*/
|
|
void MemFree( LPVOID lptr )
|
|
{
|
|
if( lptr != NULL )
|
|
{
|
|
#ifdef DEBUG
|
|
{
|
|
/*
|
|
* get real pointer and unlink from chain
|
|
*/
|
|
LPMEMTRACK pmt;
|
|
lptr = (LPVOID) (((LPBYTE)lptr) - sizeof( MEMTRACK ));
|
|
pmt = lptr;
|
|
|
|
if( pmt->dwCookie == MCOOKIE_FREE )
|
|
{
|
|
DPF( 1, "FREE OF FREED MEMORY! ptr=%08lx", pmt );
|
|
DPF( 1, "%08lx: dwSize=%08lx, lpAddr=%08lx", pmt, pmt->dwSize, pmt->lpAddr );
|
|
DEBUG_BREAK();
|
|
}
|
|
else if( pmt->dwCookie != MCOOKIE )
|
|
{
|
|
DPF( 1, "INVALID FREE! cookie=%08lx, ptr = %08lx", pmt->dwCookie, lptr );
|
|
DPF( 1, "%08lx: dwSize=%08lx, lpAddr=%08lx", pmt, pmt->dwSize, pmt->lpAddr );
|
|
DEBUG_BREAK();
|
|
}
|
|
else
|
|
{
|
|
pmt->dwCookie = MCOOKIE_FREE;
|
|
if( pmt == lpHead && pmt == lpTail )
|
|
{
|
|
lpHead = NULL;
|
|
lpTail = NULL;
|
|
}
|
|
else if( pmt == lpHead )
|
|
{
|
|
lpHead = pmt->lpNext;
|
|
lpHead->lpPrev = NULL;
|
|
}
|
|
else if( pmt == lpTail )
|
|
{
|
|
lpTail = pmt->lpPrev;
|
|
lpTail->lpNext = NULL;
|
|
}
|
|
else
|
|
{
|
|
pmt->lpPrev->lpNext = pmt->lpNext;
|
|
pmt->lpNext->lpPrev = pmt->lpPrev;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
lBytesAlloc -= pmt->dwSize;
|
|
{
|
|
IN_WRITESTATS InWS;
|
|
memset((PVOID)&InWS,0xFF,sizeof(IN_WRITESTATS));
|
|
InWS.stat_USER3=lBytesAlloc;
|
|
DbgWriteStats(&InWS);
|
|
}
|
|
#endif
|
|
|
|
#ifdef FILL_ON_MEMFREE
|
|
{
|
|
LPDWORD lpMem;
|
|
DWORD dwPat;
|
|
DWORD dwSize;
|
|
|
|
dwSize = pmt->dwSize;
|
|
lpMem = (LPDWORD)( (LPBYTE)lptr + sizeof( MEMTRACK ) );
|
|
while (dwSize >= sizeof(DWORD))
|
|
{
|
|
*lpMem++ = FREE_MEMORY_PATTERN;
|
|
dwSize -= sizeof(DWORD);
|
|
}
|
|
if (dwSize != 0UL)
|
|
{
|
|
dwPat = FREE_MEMORY_PATTERN;
|
|
memcpy(lpMem, &dwPat, dwSize);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
lAllocCount--;
|
|
if( lAllocCount < 0 )
|
|
{
|
|
DPF( 1, "Too Many Frees!\n" );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
HeapFree( hHeap, 0, lptr );
|
|
|
|
}
|
|
|
|
} /* MemFree */
|
|
|
|
/*
|
|
* MemReAlloc
|
|
*/
|
|
LPVOID __cdecl MemReAlloc( LPVOID lptr, UINT size )
|
|
{
|
|
LPVOID new;
|
|
|
|
DEBUG_TRACK_UPDATE_SIZE( size );
|
|
#ifdef DEBUG
|
|
if( lptr != NULL )
|
|
{
|
|
LPMEMTRACK pmt;
|
|
lptr = (LPVOID) (((LPBYTE)lptr) - sizeof( MEMTRACK ));
|
|
pmt = lptr;
|
|
if( pmt->dwCookie != MCOOKIE )
|
|
{
|
|
DPF( 1, "INVALID REALLOC! cookie=%08lx, ptr = %08lx", pmt->dwCookie, lptr );
|
|
DPF( 1, "%08lx: dwSize=%08lx, lpAddr=%08lx", pmt, pmt->dwSize, pmt->lpAddr );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
new = HeapReAlloc( hHeap, HEAP_ZERO_MEMORY, lptr, size );
|
|
|
|
#ifdef DEBUG
|
|
if (new != NULL)
|
|
{
|
|
LPMEMTRACK pmt = new;
|
|
|
|
lBytesAlloc -= pmt->dwSize;
|
|
|
|
pmt->dwSize = size - sizeof( MEMTRACK );
|
|
|
|
lBytesAlloc += pmt->dwSize;
|
|
|
|
{
|
|
IN_WRITESTATS InWS;
|
|
memset((PVOID)&InWS,0xFF,sizeof(IN_WRITESTATS));
|
|
InWS.stat_USER3=lBytesAlloc;
|
|
DbgWriteStats(&InWS);
|
|
}
|
|
|
|
if( lptr == (LPVOID)lpHead )
|
|
lpHead = pmt;
|
|
else
|
|
pmt->lpPrev->lpNext = pmt;
|
|
|
|
if( lptr == (LPVOID)lpTail )
|
|
lpTail = pmt;
|
|
else
|
|
pmt->lpNext->lpPrev = pmt;
|
|
|
|
new = (LPVOID) (((LPBYTE)new) + sizeof(MEMTRACK));
|
|
}
|
|
#endif
|
|
return new;
|
|
|
|
} /* MemReAlloc */
|
|
|
|
/*
|
|
* MemInit - initialize the heap manager
|
|
*/
|
|
BOOL MemInit( void )
|
|
{
|
|
if( hHeap == NULL )
|
|
{
|
|
#ifdef DEBUG
|
|
hHeap = HeapCreate( HEAP_SHARED, 0x2000, 0 );
|
|
#else
|
|
hHeap = GetProcessHeap();
|
|
#endif
|
|
if( hHeap == NULL )
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
lAllocCount = 0;
|
|
lBytesAlloc = 0;
|
|
lpHead = NULL;
|
|
lpTail = NULL;
|
|
#endif
|
|
return TRUE;
|
|
|
|
} /* MemInit */
|
|
|
|
#ifdef DEBUG
|
|
/*
|
|
* MemState - finished with our heap manager
|
|
*/
|
|
void MemState( void )
|
|
{
|
|
DPF( 2, "MemState" );
|
|
if( lAllocCount != 0 )
|
|
{
|
|
DPF( 1, "Memory still allocated! Alloc count = %ld", lAllocCount );
|
|
DPF( 1, "Current Process (pid) = %08lx", GetCurrentProcessId() );
|
|
}
|
|
if( lpHead != NULL )
|
|
{
|
|
LPMEMTRACK pmt;
|
|
DWORD dwTotal = 0;
|
|
DWORD pidCurrent = GetCurrentProcessId();
|
|
pmt = lpHead;
|
|
while( pmt != NULL )
|
|
{
|
|
if( pidCurrent == pmt->dwPid )
|
|
dwTotal += pmt->dwSize;
|
|
DPF( 1, "%08lx: dwSize=%08lx, lpAddr=%08lx (pid=%08lx)", pmt, pmt->dwSize, pmt->lpAddr, pmt->dwPid );
|
|
pmt = pmt->lpNext;
|
|
}
|
|
DPF ( 1, "Total Memory Unfreed From Current Process = %ld bytes", dwTotal );
|
|
}
|
|
} /* MemState */
|
|
#endif
|
|
|
|
/*
|
|
* MemFini - finished with our heap manager
|
|
*/
|
|
void MemFini( void )
|
|
{
|
|
DPF( 2, "MemFini!" );
|
|
#ifdef DEBUG
|
|
MemState();
|
|
#endif
|
|
#if defined( WIN95 ) && defined( WANT_MEM16 )
|
|
freeSelectors();
|
|
#endif
|
|
if( hHeap )
|
|
{
|
|
#ifdef DEBUG
|
|
HeapDestroy( hHeap );
|
|
#endif
|
|
hHeap = NULL;
|
|
}
|
|
} /* MemFini */
|