text: /*==========================================================================
   *
   *  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
   *
   ***************************************************************************/
  #undef WIN32_LEAN_AND_MEAN
  #define WIN32_LEAN_AND_MEAN
  #include <windows.h>
  #include "memalloc.h"
  #include "dpf.h"
  
  #define FREE_MEMORY_PATTERN 0xDEADBEEFUL
  #define RESPATH_D3D "Software\\Microsoft\\Direct3D"
  
  #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;
      LONG                lAllocID;
  } MEMTRACK, FAR *LPMEMTRACK;
  
  static LPMEMTRACK       lpHead;
  static LPMEMTRACK       lpTail;
  static LONG             lAllocCount;
  static LONG             lAllocID;
  static LONG             lBreakOnAllocID;
  static LONG             lBreakOnMemLeak;
  
  #if defined(_X86_)
  	#define MyGetReturnAddress(first) (LPVOID) *(DWORD *)(((LPBYTE)&first)-4)
  #else
  	#define MyGetReturnAddress(first) _ReturnAddress()
  #endif
  
  #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 = MyGetReturnAddress(first); \
  	pmt->dwPid = GetCurrentProcessId(); \
      pmt->lAllocID = lAllocID; \
  	if( lpHead == NULL ) \
  	{ \
  	    lpHead = lpTail = pmt; \
  	} \
  	else \
  	{ \
  	    lpTail->lpNext = pmt; \
  	    pmt->lpPrev = lpTail; \
  	    lpTail = pmt; \
  	} \
  	lptr = (LPVOID) (((LPBYTE) lptr) + sizeof( MEMTRACK )); \
  	lAllocCount++; \
      if( lAllocID == lBreakOnAllocID ) \
      { \
  	DebugBreak(); \
      } \
  	lAllocID++; \
      }
  
  #define DEBUG_TRACK_UPDATE_SIZE( s ) s += sizeof( MEMTRACK );
  
  #else
  
  #define DEBUG_TRACK( lptr, first )
  #define DEBUG_TRACK_UPDATE_SIZE( size )
  
  #endif
  
  #ifndef  __DXGUSEALLOC
  #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
  #endif  //!__DXGUSEALLOC
  
  /*
   * MemAlloc - allocate memory from our global pool
   */
  LPVOID __cdecl MemAlloc( UINT size )
  {
  #ifdef __USECRTMALLOC
      return calloc( size, 1 );
  #else /*__USECRTMALLOC */
      LPBYTE lptr;
  
      DEBUG_TRACK_UPDATE_SIZE( size );
      #ifdef  __DXGUSEALLOC
          #if DBG
              lptr = calloc( size, 1 );
          #else
              lptr = LocalAlloc( LPTR, size );
          #endif  //DBG
      #else 
          lptr = HeapAlloc( hHeap, HEAP_ZERO_MEMORY, size );
      #endif  //__DXGUSEALLOC
      DEBUG_TRACK( lptr, size );
  
      return lptr;
  #endif //__USECRTMALLOC
  
  } /* MemAlloc */
  
  #ifndef  __DXGUSEALLOC
  /*
   * MemSize - return size of object
   */
  UINT __cdecl MemSize( LPVOID lptr )
  {
  #ifdef DEBUG
      if (lptr)
      {
  	LPMEMTRACK  pmt;
  	lptr = (LPVOID) (((LPBYTE)lptr) - sizeof( MEMTRACK ));
  	pmt = lptr;
  	return pmt->dwSize;
      }
  #endif
      return (UINT)HeapSize(hHeap, 0, lptr);
  } /* MemSize */
  #endif  //!__DXGUSEALLOC
  
  /*
   * MemFree - free memory from our global pool
   */
  void MemFree( LPVOID lptr )
  {
  #ifdef __USECRTMALLOC
      free( lptr );
  #else /*__USECRTMALLOC */
      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: lAllocID=%ld dwSize=%08lx, lpAddr=%08lx", 
              pmt, pmt->lAllocID, pmt->dwSize, pmt->lpAddr );
  	    }
  	    else if( pmt->dwCookie != MCOOKIE )
  	    {
  		DPF( 1, "INVALID FREE! cookie=%08lx, ptr = %08lx", pmt->dwCookie, lptr );
  		DPF( 1, "%08lx: lAllocID=%ld dwSize=%08lx, lpAddr=%08lx", 
              pmt, pmt->lAllocID, pmt->dwSize, pmt->lpAddr );
  	    }
  	    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;
  		}
  
  		#ifndef NO_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 /* !NO_FILL_ON_MEMFREE */
  	    }
  	    lAllocCount--;
  	    if( lAllocCount < 0 )
  	    {
  		DPF( 1, "Too Many Frees!\n" );
  	    }
  	}
  	#endif
  
      #ifdef  __DXGUSEALLOC
          #if DBG
              free( lptr );
          #else
              LocalFree( lptr );
          #endif  //DBG
      #else 
  	HeapFree( hHeap, 0, lptr );
      #endif  // __DXGUSEALLOC
  
      }
  #endif /*__USECRTMALLOC */
  } /* MemFree */
  
  /*
   * MemReAlloc
   */
  LPVOID __cdecl MemReAlloc( LPVOID lptr, UINT size )
  {
  #ifdef __USECRTMALLOC
      return realloc( lptr, size );
  #else /* __USECRTMALLOC */
      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: lAllocID=%ld dwSize=%08lx, lpAddr=%08lx", 
              pmt, pmt->lAllocID, pmt->dwSize, pmt->lpAddr );
  	    }
  	}
      #endif
  
      #ifdef  __DXGUSEALLOC
          #if DBG
              new = realloc( lptr, size );
          #else //DBG
              new = LocalReAlloc( lptr, size, LMEM_MOVEABLE|LMEM_ZEROINIT );
          #endif  //DBG
      #else //__DXGUSEALLOC
      new = HeapReAlloc( hHeap, HEAP_ZERO_MEMORY, lptr, size );
      #endif  //__DXGUSEALLOC
  
      #ifdef DEBUG
      if (new != NULL)
      {
  	LPMEMTRACK pmt = new;
  
  	pmt->dwSize = size - sizeof( MEMTRACK );
  
  	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;
  #endif /* __USECRTMALLOC */
  } /* MemReAlloc */
  
  /*
   * MemInit - initialize the heap manager
   */
  BOOL MemInit( void )
  {
      HKEY hKey = (HKEY) NULL;
  #ifdef __USECRTMALLOC
      #include <crtdbg.h>
      int tmp = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
      tmp |= _CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF;
      _CrtSetDbgFlag(tmp);
  #else /* __USECRTMALLOC */
  #ifndef  __DXGUSEALLOC
      if( hHeap == NULL )
      {
  	hHeap = HeapCreate( HEAP_SHARED, 0x2000, 0 );
  	if( hHeap == NULL )
  	{
  	    return FALSE;
  	}
      }
  #endif  //!__DXGUSEALLOC
      #ifdef DEBUG
  	lAllocCount = 0;
  	lAllocID = 1;
      lBreakOnAllocID = 0;
      lBreakOnMemLeak = 0;
  	lpHead = NULL;
  	lpTail = NULL;
      if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey))
      {
          LONG result;
          DWORD dwType = REG_DWORD;
          DWORD dwSize = 4;
          DWORD value = 0;
          result =  RegQueryValueEx(hKey, "BreakOnAllocID", NULL, &dwType,
                                    (LPBYTE)(&value), &dwSize);
          if (result == ERROR_SUCCESS && dwType == REG_DWORD)
          {
              lBreakOnAllocID = value;
          }
          result =  RegQueryValueEx(hKey, "BreakOnMemLeak", NULL, &dwType,
                                    (LPBYTE)(&value), &dwSize);
          RegCloseKey(hKey);
          if (result == ERROR_SUCCESS && dwType == REG_DWORD)
          {
              lBreakOnMemLeak = value;
          }
      }
      #endif
  #endif /* __USECRTMALLOC */
      return TRUE;
  } /* MemInit */
  
  #ifdef DEBUG
  /*
   * MemState - finished with our heap manager
   */
  void MemState( void )
  {
      DPF( 6, "MemState" );
      #ifdef WIN95
      // Note: There is a well known leak of 8 bytes in Win9x, this is to discount it.
      if( lAllocCount > 1 )
      #else
      if( lAllocCount != 0 )
      #endif
      {
  	DPF( 0, "Memory still allocated!  Alloc count = %ld", lAllocCount );
  	DPF( 0, "Current Process (pid) = %08lx", GetCurrentProcessId() );
      if( lBreakOnMemLeak != 0 )
      {
          DebugBreak();
      }
      }
      if( lpHead != NULL )
      {
  	LPMEMTRACK      pmt;
  	DWORD		dwTotal = 0;
  	DWORD		pidCurrent = GetCurrentProcessId();
  	pmt = lpHead;
  	while( pmt != NULL )
  	{
  	    if( pidCurrent == pmt->dwPid )
  		dwTotal += pmt->dwSize;
  	    DPF( 0, "Memory Address: %08lx lAllocID=%ld dwSize=%08lx, ReturnAddr=%08lx (pid=%08lx)", 
                  (BYTE*)pmt + sizeof(MEMTRACK), // give the address that is returned 
                  pmt->lAllocID, 
                  pmt->dwSize, 
                  pmt->lpAddr, 
                  pmt->dwPid );
  	    pmt = pmt->lpNext;
  	}
  	DPF ( 0, "Total Memory Unfreed From Current Process = %ld bytes", dwTotal );
      }
  } /* MemState */
  #endif
  
  /*
   * MemFini - finished with our heap manager
   */
  void MemFini( void )
  {
  #ifdef __USECRTMALLOC
  #else /* __USECRTMALLOC */
      DPF( 2, "MemFini!" );
      #ifdef DEBUG
  	MemState();
      #endif
  #ifndef  __DXGUSEALLOC
      #if defined( WIN95 ) && defined( WANT_MEM16 )
  	freeSelectors();
      #endif
      if( hHeap )
      {
  	HeapDestroy( hHeap );
  	hHeap = NULL;
      }
  #endif  //!__DXGUSEALLOC
  #endif /* __USECRTMALLOC */
  } /* MemFini */
  