/*++ Copyright (c) 1990 Microsoft Corporation Module Name: memory.c Abstract: This module provides all the memory management functions for all spooler components Author: Krishna Ganugapati (KrishnaG) 03-Feb-1994 Revision History: --*/ #include "dswarn.h" #include #include #include #include #include #include #include #include "symhelp.h" #include "oledsdbg.h" #define WORD_ALIGN_DOWN(addr) ((LPBYTE)((DWORD)addr &= ~1)) #define DWORD_ALIGN_UP(size) ((size+3)&~3) #if DBG DWORD dwMemoryLog = 0; #define MAXDEPTH 10 typedef struct _ADSMEMTAG { DWORD Tag ; DWORD Size ; PVOID pvBackTrace[MAXDEPTH+1]; LPSTR pszSymbol[MAXDEPTH+1]; DWORD uDepth; LIST_ENTRY List ; } ADSMEMTAG, *PADSMEMTAG ; LIST_ENTRY ADsMemList ; DWORD ADsMemCount ; CRITICAL_SECTION ADsMemCritSect ; /*++ Routine Description: This function initializes the ADs mem tracking code. Must be call during DLL load an ONLY during DLL load. Arguments: None Return Value: None. --*/ VOID InitADsMem( VOID ) { InitializeCriticalSection(&ADsMemCritSect) ; InitializeListHead(&ADsMemList) ; ADsMemCount = 0 ; } /*++ Routine Description: This function asserts that the mem list is empty on exit. Arguments: None Return Value: None. --*/ VOID AssertADsMemLeaks( VOID ) { ADsAssert(IsListEmpty(&ADsMemList)) ; } #endif LPVOID AllocADsMem( DWORD cb ) /*++ Routine Description: This function will allocate local memory. It will possibly allocate extra memory and fill this with debugging information for the debugging version. Arguments: cb - The amount of memory to allocate Return Value: NON-NULL - A pointer to the allocated memory FALSE/NULL - The operation failed. Extended error status is available using GetLastError. --*/ { #if DBG DWORD cbNew ; PADSMEMTAG pMem ; ULONG ulHash; // // adjust size for our tag and one spare dword at end // and allocate the memory // cb = DWORD_ALIGN_UP(cb); cbNew = cb + ( sizeof(ADSMEMTAG) + sizeof(DWORD) ); pMem=(PADSMEMTAG)LocalAlloc(LPTR, cbNew); if (!pMem) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return 0; } // // fill in deadbeef at end and tag info. // and insert it into the ADsMemList // *(LPDWORD)((LPBYTE)pMem+cbNew-sizeof(DWORD)) = 0xdeadbeef; pMem->Tag = 0xB00FB00F ; pMem->Size = cb ; // // Capture a backtrace at this spot for debugging. // #if (defined(i386) && !defined(WIN95)) pMem->uDepth = RtlCaptureStackBackTrace( 0, MAXDEPTH, pMem->pvBackTrace, &ulHash ); #else pMem->uDepth = 0; #endif EnterCriticalSection(&ADsMemCritSect) ; InsertHeadList(&ADsMemList, &pMem->List) ; ADsMemCount++ ; LeaveCriticalSection(&ADsMemCritSect) ; // // skip past the mem tag // pMem++ ; return (LPVOID)(pMem); #else return(LocalAlloc(LPTR, cb)); #endif } BOOL FreeADsMem( LPVOID pMem ) { #if DBG DWORD cb; DWORD cbNew = 0; PADSMEMTAG pNewMem ; LPDWORD pRetAddr; DWORD i = 0; // // This apparently is a C++ requiremen - that you can call // delete on a null pointer and it should be handled // if (pMem == NULL) { return 0; } pNewMem = (PADSMEMTAG)pMem; pNewMem -- ; cb = pNewMem->Size; cbNew = cb + sizeof(DWORD) + sizeof(ADSMEMTAG); // // check the trailing deadbeef and remove from list // if (*(LPDWORD)(((LPBYTE)pNewMem) + cbNew - sizeof(DWORD)) != 0xdeadbeef) { ADsAssert(!"Freeing memory not allocated by AllocADsMem") ; return FALSE; } EnterCriticalSection(&ADsMemCritSect) ; RemoveEntryList(&pNewMem->List) ; ADsMemCount-- ; LeaveCriticalSection(&ADsMemCritSect) ; for (i = 0; i < pNewMem->uDepth; i++) { if (pNewMem->pszSymbol[i]) { LocalFree(pNewMem->pszSymbol[i]); } } // // Whack freed memory with known pattern // memset(pMem, 0x65, cb); return(LocalFree((LPVOID)pNewMem) == NULL); #else return(LocalFree(pMem) == NULL); #endif } LPVOID ReallocADsMem( LPVOID pOldMem, DWORD cbOld, DWORD cbNew ) { LPVOID pNewMem; pNewMem=AllocADsMem(cbNew); if (pOldMem && pNewMem) { memcpy(pNewMem, pOldMem, min(cbNew, cbOld)); FreeADsMem(pOldMem); } return pNewMem; } LPWSTR AllocADsStr( LPCWSTR pStr ) /*++ Routine Description: This function will allocate enough local memory to store the specified string, and copy that string to the allocated memory Arguments: pStr - Pointer to the string that needs to be allocated and stored Return Value: NON-NULL - A pointer to the allocated memory containing the string FALSE/NULL - The operation failed. Extended error status is available using GetLastError. --*/ { LPWSTR pMem; if (!pStr) return 0; if (pMem = (LPWSTR)AllocADsMem( wcslen(pStr)*sizeof(WCHAR) + sizeof(WCHAR) )) wcscpy(pMem, pStr); return pMem; } BOOL FreeADsStr( LPWSTR pStr ) { return pStr ? FreeADsMem(pStr) : FALSE; } BOOL ReallocADsStr( LPWSTR *ppStr, LPWSTR pStr ) { FreeADsStr(*ppStr); *ppStr=AllocADsStr(pStr); return TRUE; } #if DBG VOID DumpMemoryTracker( VOID ) { #if !defined(WIN95) && defined(_X86_) LIST_ENTRY* pEntry; ADSMEMTAG* pMem; BYTE* pTemp; DWORD i = 0; CHAR szSymbolPath[MAX_PATH+1]; DWORD dwCount = 0; pEntry = ADsMemList.Flink; if (!dwMemoryLog) { return; } if ( pEntry == &ADsMemList ) { OutputDebugStringA( "No Memory leaks found\n" ); } while( pEntry != &ADsMemList ) { CHAR szLeak[1024]; pTemp = (BYTE*)pEntry; pTemp = pTemp - sizeof(DWORD) - sizeof(DWORD) - sizeof(DWORD) - (sizeof(CHAR*) + sizeof(LPVOID))*( MAXDEPTH +1); pMem = (ADSMEMTAG*)pTemp; sprintf( szLeak, "[oleds] Memory leak!!! Addresss = %.8x Size = %ld \n", pMem + 1, pMem->Size ); OutputDebugStringA( szLeak ); for (i = 0; i < pMem->uDepth; i++) { dwCount = TranslateAddress( (ULONG)pMem->pvBackTrace[ i ], szSymbolPath, MAX_PATH ); szSymbolPath[dwCount] = '\0'; sprintf(szLeak, "%s\n",szSymbolPath); OutputDebugStringA( szLeak); } pEntry = pEntry->Flink; } #endif } #endif