/* Copyright (C) 2003, 2004 Dave Bayer. Subject to the terms and conditions of the MIT License. */ #include #include #include #include "memory.h" /* undefine malloc and free */ #undef malloc #undef free /*, mallocN */ static int mallocN = 0; /* if MEMORYDEBUG is defined */ #if MEMORYDEBUG /*, EVERYN */ #define EVERYN 4096 /*, PAD */ #define PAD 32 /*, FILL */ #define FILL 1 /*, memRecord */ typedef struct memRecord { char *fileName; int lineNo; size_t size; int freed, ours; int count; void *p; struct memRecord *next; } memRecord; #define memN 4093 static memRecord *memRecordPool, *memRecordArray[memN], spare, *memRecordSpare = &spare; /*, memRecordNew */ static void memRecordNew( void *p, char *fileName, int lineNo, size_t size, int ours, int count ) { memRecord *r; int i; /* need spare for call to mallocDebug here */ if ( memRecordPool == 0 ) { memRecordPool = memRecordSpare; r = mallocDebug( 101 * sizeof( *r ), __FILE__, __LINE__, 1 ); for ( i=0; i<100; ++i ) { r->next = memRecordPool; memRecordPool = r++; } memRecordSpare = r; r->next = 0; } r = memRecordPool; memRecordPool = r->next; i = ( (int) p ) % memN; r->next = memRecordArray[i]; memRecordArray[i] = r; r->fileName = fileName; r->lineNo = lineNo; r->size = size; r->freed = 0; r->ours = ours; r->count = count; r->p = p; if ( count == 0 ) { /* debugging break */ i = 0; } } /*, clearMem */ static void clearMem( void *p, int from, int to ) { char *s, *t; for ( s=t=p, s+=from, t+=to; snext ) { if ( r->freed && checkMem( r->p, PAD, r->size + PAD )) abortMem( "memory written after free", r->count, r->fileName, r->lineNo ); if ( checkMem( r->p, 0, PAD ) || checkMem( r->p, r->size + PAD, r->size + 2*PAD )) abortMem( "memory written outside bounds", r->count, r->fileName, r->lineNo ); } } /*, mallocDebug */ void *mallocDebug( size_t size, char *fileName, int lineNo, int ours ) { void *p; static int count = 0; if ( ++count % EVERYN == 0 ) memoryVerifyDebug(); if ( !ours ) ++mallocN; p = malloc( size + 2*PAD ); if ( p == 0 ) abortMem( "malloc returned null", count, fileName, lineNo ); memRecordNew( p, fileName, lineNo, size, ours, count ); clearMem( p, 0, PAD ); clearMem( p, size + PAD, size + 2*PAD ); return p + PAD; } /*, freeDebug */ void freeDebug( void *p, char *fileName, int lineNo ) { memRecord *r; static int count = 0; int i; if ( ++count % EVERYN == 0 ) memoryVerifyDebug(); --mallocN; p -= PAD; i = ( (int) p ) % memN; for ( r=memRecordArray[i]; r!=0; r=r->next ) if ( r->p == p ) { if ( r->freed ) abortMem( "memory freed twice", r->count, fileName, lineNo ); r->freed = 1; if ( checkMem( p, 0, PAD ) || checkMem( p, r->size + PAD, r->size + 2*PAD )) abortMem( "memory written outside bounds", r->count, r->fileName, r->lineNo ); clearMem( p, PAD, r->size + PAD ); return; } abortMem( "non-malloc memory freed", r->count, fileName, lineNo ); } /*, mallocCountDebug */ void mallocCountDebug( void ) { memRecord *r, **pr; int i; memoryVerifyDebug(); if ( mallocN != 0 ) { printf( "malloc allocations in use = %d\n", mallocN ); for ( i=0, pr=memRecordArray; inext ) if ( !r->freed && !r->ours ) { printf( "\nmemory not freed: allocation %d, file \"%s\", line %d\n", r->count, r->fileName, r->lineNo ); return; } } } /* if MEMORYDEBUG is not defined */ #else /*, memoryVerifyCheck */ void memoryVerifyCheck( void ) { } /*, mallocCheck */ void *mallocCheck( size_t size ) { ++mallocN; return malloc( size ); } /*, freeCheck */ void freeCheck( void *p ) { --mallocN; free( p ); } /*, mallocCountCheck */ void mallocCountCheck( void ) { if ( mallocN != 0 ) printf( "malloc allocations in use = %d\n", mallocN ); } #endif