/** \file memorycheck.cpp \brief Includefile (!) for heap tracking The routines here can be included into the main programs for finding heap related problems. */ /*************************************************************************** memorycheck.cpp - description ------------------- begin : Wed Nov 29 2000 copyright : (C) 2000 by Martin Bickel email : bickel@asc-hq.org ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifdef MEMCHK int blockNum = 0; int operationID = 0; int errorNum = 0; int breakOnFree = 0; const int infoblocksize = 3; bool memchk_initialized = false; bool memchk_reallyComplete = false; // this variable is intended to be set by the debugger int memchk_breakOnOp = -1; // this variable is intended to be set by the debugger void memchkError ( ) { errorNum++; fprintf(stderr, "memchkError !\n"); } class Block { public: int start; int stop; int userStart; int size; int allocated; int freed; int allocatedOP; int freedOP; }; Block blocks[1000000]; void* verifyblock ( int tp, Block* b ) { int error = 0; int* tmpi = (int*) b->start; if ( tp != -1 ) if ( tmpi[0] != tp ) error++; // for example: allocated with new ; freed with delete[] /* if ( tmpi[1] != (int) tmpi) { memchkError(); #ifdef logging logtofile ( "memory check: verifyblock : error A at address %x", p ); #endif } */ int amt = tmpi[2]; for ( int i = 0; i < 25; i++ ) { if ( tmpi[infoblocksize + i] != 0x12345678) { memchkError(); #ifdef logging logtofile ( "memory check: verifyblock : error C at address %x", p ); #endif } if ( tmpi[infoblocksize + i + (amt+3)/4 + 25] != 0x87654321 ) { memchkError(); #ifdef logging logtofile ( "memory check: verifyblock : error D at address %x", p ); #endif } } return tmpi; } void verifyallblocks ( void ) { for ( int i = 0; i < blockNum; i++ ) if ( !blocks[i].freed ) verifyblock ( -1, &blocks[i] ); } void* memchkAlloc ( int tp, size_t amt ) { if ( ! memchk_initialized ) { memset ( blocks, 0, sizeof ( blocks )); memchk_initialized = true; } if ( memchk_reallyComplete ) verifyallblocks(); Block& b = blocks[ blockNum++ ]; if ( blockNum >= 1000000 ) memchkError(); b.size = amt + (50+infoblocksize) * 4; b.allocated++; if ( operationID == memchk_breakOnOp ) memchkError(); b.allocatedOP = operationID++; void* tmp = malloc ( b.size+4 ); b.start = (int) tmp; b.stop = b.start + b.size; for ( int i = 0; i < blockNum-1; i++ ) { if ( !blocks[i].freed ) { if ( b.start >= blocks[i].start && b.start < blocks[i].stop ) memchkError(); if ( b.stop >= blocks[i].start && b.stop < blocks[i].stop ) memchkError(); if ( blocks[i].start < b.start && blocks[i].stop > b.stop ) memchkError(); } } int* tmpi = (int*) tmp; /* if ( (int) tmpi == 0x1bb2138 || (int) tmpi == 0x1bcf178 ) error++; */ tmpi[0] = tp; if ( 4 < infoblocksize ) tmpi[4] = (int) tmp; if ( 2 < infoblocksize ) tmpi[2] = amt; if ( 3 < infoblocksize ) tmpi[3] = b.allocatedOP; if ( 1 < infoblocksize ) tmpi[1] = blockNum-1; for ( int i = 0; i < 25; i++ ) { tmpi[infoblocksize + i] = 0x12345678; tmpi[infoblocksize + i + (amt+3)/4 + 25] = 0x87654321; } void* p = &tmpi[25+infoblocksize]; b.userStart = (int) p; return p; } void memchkFree ( int tp, void* buf ) { if ( breakOnFree == (int) buf ) memchkError(); Block* b = NULL; for ( int i = blockNum-1; i>= 0 ; i-- ) if ( blocks[i].userStart == (int) buf ) { b = &blocks[i]; break; } if ( b ) { if ( memchk_reallyComplete ) verifyallblocks(); void* tmpi = verifyblock ( tp, b ); if ( b->freed > 0 ) memchkError(); if ( b->allocated <= 0 ) memchkError(); if ( operationID == memchk_breakOnOp ) memchkError(); b->freed++; b->freedOP = operationID++; free ( tmpi ); } else free ( buf ); } void *operator new( size_t amt ) { return( memchkAlloc( 100, amt ) ); } void operator delete( void *p ) { if ( p ) memchkFree( 100, p ); } void *operator new []( size_t amt ) { return( memchkAlloc( 102, amt ) ); } void operator delete []( void *p ) { if ( p ) memchkFree( 102, p ); } void* asc_malloc ( size_t size ) { void* tmp = memchkAlloc ( 104, size ); return tmp; } void asc_free ( void* p ) { memchkFree ( 104, p ); } #else void* asc_malloc ( size_t size ) { void* tmp = malloc ( size ); #ifdef _DOS_ if ( tmp == NULL ) new_new_handler(); #else if ( tmp == NULL ) fatalError("Out of memory!"); #endif return tmp; } void asc_free ( void* p ) { free ( p ); } #endif