/*** mem.c - Memory Manager * * Microsoft Confidential * Copyright (C) Microsoft Corporation 1993-1994 * All Rights Reserved. * * Author: * Benjamin W. Slivka * * History: * 10-Aug-1993 bens Initial version * 11-Aug-1993 bens Lift code from STOCK.EXE win app * 12-Aug-1993 bens Get strings from memory.msg * 01-Sep-1993 bens Add NULL pointer checks to MMAssert and MMStrDup * 18-Mar-1994 bens Make sure non-assert build works; rename * 18-May-1994 bens Allow turning off MemCheckHeap() in debug build * (it can really, really slow things down!) * * Functions: * MemAlloc - Allocate memory block * MemFree - Free memory block * MemStrDup - Duplicate string to new memory block * * Functions available in ASSERT build: * MemAssert - Assert that pointer was allocated by MemAlloc * MemCheckHeap - Check entire memory heap * MemGetSize - Return allocated size of memory block * MemSetCheckHeap - Control whether MemCheckHeap is done on every * every MemAlloc and MemFree! */ #include #include #include #include "types.h" #include "asrt.h" #ifdef ASSERT // Must be after asrt.h! #include "mem.h" #include "mem.msg" /*** MEMSIG - memory signature * * This is placed at the front and end of every dynamic memory * alloction in DEBUG builds. The pointer has to be unaligned for * RISC machines. */ typedef ULONG MEMSIG; /* ms - memory signature */ typedef MEMSIG UNALIGNED *PMEMSIG; /* pms */ #define msHEAD 0x12345678L // Head signature #define msTAIL 0x87654321L // Tail signature #define msBAD 0L // Bad signature #define cmsTAIL 2 // Number of tail signatures typedef struct mh_t { MEMSIG ms; // Head signature (msHEAD) unsigned cb; // Size of user block struct mh_t *pmhNext; // Next block struct mh_t *pmhPrev; // Previous block // char ach[?]; // User block; length is cb // MEMSIG ms[cmsTAIL]; // Tail signature area (msTAIL...) } MEMHDR; /* mh - memory header */ typedef MEMHDR *PMEMHDR; /* pmh */ #define PMHFromPV(pv) ((PMEMHDR)((char *)pv - sizeof(MEMHDR))) #define PVFromPMH(pmh) ((void *)((char *)pmh+sizeof(MEMHDR))) STATIC PMEMHDR pmhList=NULL; // List of memory blocks STATIC BOOL fDoCheckHeap=TRUE; // TRUE => check heap regularly void MemSetCheckHeap(BOOL f) { fDoCheckHeap = f; } void MMCheckHeap(char *pszFile, int iLine) { PMEMHDR pmh; for (pmh = pmhList; pmh != NULL; pmh = pmh->pmhNext) MMAssert(PVFromPMH(pmh),pszFile,iLine); } void MMAssert(void *pv, char *pszFile, int iLine) { int i; PMEMHDR pmh; PMEMSIG pms; AssertSub(pv!=NULL,pszFile,iLine); pmh = PMHFromPV(pv); if ((void *)pmh > pv) { // Pointer wrapped AssertForce(pszMEMERR_NULL_POINTER,pszFile,iLine); } // Test head signature if (pmh->ms != msHEAD) { AssertForce(pszMEMERR_BAD_HEAD_SIG,pszFile,iLine); } // Test tail signatures pms = (PMEMSIG)( (char *)pmh + sizeof(MEMHDR) + pmh->cb ); for (i=0; ipmhPrev != NULL) { // pmh is not at front of list // before: a->p->? pmh->pmhPrev->pmhNext = pmh->pmhNext; // after: a->? } else { // pmh is at front of list // before: list->p->? pmhList = pmh->pmhNext; // after: list->? } // Make next block point to previous block if (pmh->pmhNext != NULL) { // pmh is not at end of list // before: ?<-p<->a pmh->pmhNext->pmhPrev = pmh->pmhPrev; // after: ?<-a } // Obliterate signature pmh->ms = msBAD; // Free memory free((char *)pmh); } void *MMAlloc(unsigned cb, char *pszFile, int iLine) { unsigned cbAlloc; int i; PMEMHDR pmh; PMEMSIG pms; if (fDoCheckHeap) { MMCheckHeap(pszFile,iLine); } // Solves alignment problems on the RISCs cb = (cb+3) & ~3; cbAlloc = cb+sizeof(MEMHDR)+sizeof(MEMSIG)*cmsTAIL; pmh = malloc(cbAlloc); if (pmh != NULL) { pmh->ms = msHEAD; // Store head signature pmh->cb = cb; // Store size of user block // Add block to front of list (Easiest code!) if (pmhList != NULL) { // List is not empty pmhList->pmhPrev = pmh; // Point old top block back at us } pmh->pmhNext = pmhList; // Next element is old top block pmh->pmhPrev = NULL; // We are first, so no prev block pmhList = pmh; // Make ourselves first // Fill in tail signatures pms = (PMEMSIG)( (char *)pmh + sizeof(MEMHDR) + pmh->cb ); for (i=0; ipmhNext) { pch = PVFromPMH(pmh); printf("%5d %04x %s\n",pmh->cb,(unsigned)pch,pch); } return NULL; */ } } char *MMStrDup(char *pch, char *pszFile, int iLine) { unsigned cb; char *pchDst; //** Make sure pointer is not null. // NOTE: pch does not have to be a string we dynamically allocated! AssertSub(pch!=NULL,pszFile,iLine); cb = strlen(pch)+1; // Count NUL terminator pchDst = MMAlloc(cb,pszFile,iLine); // Alloc new copy if (pchDst != NULL) { // Success memcpy(pchDst,pch,cb); // Copy string } return pchDst; // Return string copy } int MemGetSize(void *pv) { PMEMHDR pmh; MMAssert(pv,__FILE__,__LINE__); pmh = PMHFromPV(pv); return pmh->cb; } #endif // !ASSERT