www.pudn.com > EZW_.rar > MEMCHK.C
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Adapted/reformated to suit my own coding style. Some changes to the * printing. Also the defintion that enable/disable the memory checker. * Added a few functions and definitions. * * Mow-Song, Ng 2/9/2002 * msng@mmu.edu.my * http://www.pesona.mmu.edu.my/~msng * * I do not claim copyright to the code, but if you use them or modify them, * please drop me a mail. * */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* Original code from LiftPack */ /* * -*- Mode: ANSI C -*- * $Id: memchk.c,v 1.7 1996/11/18 18:49:11 fernande Exp $ * $Header: /sgi.acct/sweldens/cvs/liftpack/Util/memchk.c,v 1.7 * 1996/11/18 18:49:11 fernande Exp $ * Author: M. A. Sridhar * Modified: Gabriel Fernandez * * This file has a memory leak checker which keeps track of all the * allocations and deallocations in order to see if some previously * allocated memory is not freed at the end of the execution of the * code. * The functions included are malloc, calloc, realloc, and free. * * NOTE: It is important tht this program is not combined with any * other memory handler, because a list of allocations and * deallocations is kept with every call to 'malloc', 'calloc', * 'realloc', and 'free'. If 'free' is used to deallocate a * memory segment allocated with other function that the ones in * this file, the program will segment fault because is trying to * delete a list entry which does not exists. */ /* do not edit anything above this line */ #include#include "memchk.h" #undef calloc #undef realloc #undef malloc #undef free #include #include typedef unsigned long uLong; typedef unsigned char uChar; uLong magic_cookie = 0xf9a42bb1; /* Used to indicate "allocated" state */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ struct BlockHeader { uLong marker; long time; struct BlockHeader* prev; struct BlockHeader* next; char* file; long lineNo; long size; #ifdef DOUBLE uChar dummy[4]; /* pad structure to a power of two */ #endif }; /* --------------------- Static variables --------------------------------- */ static struct BlockHeader* _AllocListHead = 0; /* Head of list of */ /* allocated blocks */ static struct BlockHeader* _AllocListTail = 0; /* Tail of list of */ /* allocated blocks */ static short _LeakCheckerActive = 0; static long _Time = 0; /* Clock: ticks on every new and */ /* delete */ static long _MaxMem = 0; /* Max memory used so far */ static long _CurrentAlloc = 0; /* Amount of memory currently */ /* allocated */ static long _BeginTime = 0; /* Time at which leack checker was */ /* instantiated */ /*------------------------------------------------------------------------- */ /* code */ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* * Calloc function: same as Malloc, but initializes the content with * zeros. */ void *Calloc ( size_t n, size_t s, int line_no, char *file_name ) { size_t size = n*s; uChar *buffer = (uChar *)Malloc ( size, line_no, file_name ); int i; for ( i=0 ; i<(int)size ; i++ ) buffer[i] = 0; return buffer; } /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* * Realloc function: reallocates a contiguous segment of memory using * the same pointer variable. */ void *Realloc ( void *p, size_t s, int line_no, char *file_name ) { uChar *newp; struct BlockHeader* q; /* Check for integrity of memory in p */ q = (struct BlockHeader*) ( (uChar*) p - sizeof (struct BlockHeader)); if (q->marker != magic_cookie && _LeakCheckerActive) fprintf (stderr, "Realloc(%8lx): memory corrupted", (long)p); /* Allocate new segment and copy p into it */ newp = (uChar *)Malloc ( s, line_no, file_name ); newp = (uChar *)memcpy (newp, p, (size_t)q->size); /* Free p and return new segment */ Free (p); return (void *)newp; } /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* * Malloc function: uses a linked list to keep track of all the memory * segments that have been allocated so far. It * includes information about the size of the segment, * the file where the allocation was done, the line * where the function was called, and the order in * which the call was executed. */ void* Malloc (size_t n, int line_no, char* file_name) { struct BlockHeader* q; long size; uChar* p; if (n == 0) return NULL; size = (long)n; /* Allocate extra bytes */ p = (uChar*) malloc (n + sizeof (struct BlockHeader)); if (!p) { fprintf (stderr, "Malloc(): allocating %u bytes: no memory!", n); exit (1); } _CurrentAlloc += (long)n; if (_CurrentAlloc > _MaxMem) _MaxMem = _CurrentAlloc; q = (struct BlockHeader*) p; /* Put a magic marker */ q->marker = magic_cookie; q->time = _Time++; q->size = size; q->file = file_name; q->lineNo = (long)line_no; memset (p + sizeof(struct BlockHeader), '\02', (unsigned int) size); /* Uninitialized allocated memory has 02 in it */ /* Insert at tail of allocated list */ if (_AllocListTail) { _AllocListTail->next = q; q->prev = _AllocListTail; q->next = 0; _AllocListTail = q; } else { _AllocListHead = _AllocListTail = q; q->prev = q->next = 0; } return p + sizeof(struct BlockHeader); } /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* * Free function: frees previously allocated memory and puts 03 in * it to verify later on. The entry in the linked list * is removed and all the other entries are reorganized. */ void Free (void* p) { struct BlockHeader* q; if ( p == NULL ) fprintf (stderr, "Free(%8lx): empty memory\n", (long)p); q = (struct BlockHeader*) ( (uChar*) p - sizeof (struct BlockHeader)); if (q->marker != magic_cookie && _LeakCheckerActive) fprintf (stderr, "Free(%8lx): memory corrupted\n", (long)p); _CurrentAlloc -= q->size; if (_AllocListHead) { if (q->prev) q->prev->next = q->next; if (q->next) q->next->prev = q->prev; if (q == _AllocListHead) _AllocListHead = q->next; if (q == _AllocListTail) _AllocListTail = q->prev; memset (q, '\03', (unsigned int) (sizeof(struct BlockHeader) + (unsigned int)q->size)); /* Freed memory has 03 in it */ } free (q); _Time++; } /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* * PrintLeaks function: this routine prints the content of the linked * list with all the information about memory * allocated so far. If everything that was * allocated was freed, then the list should be * empty and nothing should be printed. */ int PrintLeaks () { #ifdef __MEMCHK_ENABLE_ struct BlockHeader* q = _AllocListHead; long count = 0; fprintf (stderr, "\nMemory status:\n" "--------------\n"); fprintf(stderr, "Max:%d Current:%d\n", MaxMemory(), CurrentMemoryAllocated()); while (q) { if (q->time >= _BeginTime) count++; q = q->next; } if (count) { q = _AllocListHead; while (q) { if (q->time >= _BeginTime) { /* Only output if the allocation occurred after the leak */ /* checker was created */ fprintf (stderr, "Time: %ld Address: %08x Size: %ld line %d file '%s'\n", q->time, (unsigned long)q, q->size, (int)q->lineNo, q->file); } q = q->next; } return 1; } else{ fprintf(stderr, "No allocated memory.\n"); return 0; } #else return 0; #endif } /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* * FreeLeaks functions: frees intermediate allocated memory that cannot * be free'd by any other mean since an unexpected * error has occurred. */ void FreeLeaks () { #ifdef __MEMCHK_ENABLE_ struct BlockHeader* q = _AllocListHead; struct BlockHeader* tmp; long count = 0; while (q) { if (q->time >= _BeginTime) count++; q = q->next; } if (count) { q = _AllocListHead; while (q) { tmp = q->next; if (q->time >= _BeginTime) { /* Only free if the allocation occurred after the leak */ /* checker was created */ free (q); } q = tmp; } } _AllocListHead = _AllocListTail = 0; _CurrentAlloc = 0; #endif } /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* * MaxMemory functions: returns the maximum memory used so far. * */ long MaxMemory() { #ifdef __MEMCHK_ENABLE_ return _MaxMem; #else return 0; #endif } /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ /* * MaxMemory functions: returns the maximum memory used so far. * */ long CurrentMemoryAllocated() { #ifdef __MEMCHK_ENABLE_ return _CurrentAlloc; #else return 0; #endif } /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/