00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 #define __MEMWATCH_C 1
00098
00099 #ifdef MW_NOCPP
00100 #define MEMWATCH_NOCPP
00101 #endif
00102 #ifdef MW_STDIO
00103 #define MEMWATCH_STDIO
00104 #endif
00105
00106
00107
00108
00109
00110 #include <stdio.h>
00111 #include <stdlib.h>
00112 #include <stdarg.h>
00113 #include <string.h>
00114 #include <signal.h>
00115 #include <setjmp.h>
00116 #include <time.h>
00117 #include <limits.h>
00118 #include "memwatch.h"
00119
00120 #ifndef toupper
00121 #include <ctype.h>
00122 #endif
00123
00124 #if defined(WIN32) || defined(__WIN32__)
00125 #define MW_HAVE_MUTEX 1
00126 #include <windows.h>
00127 #endif
00128
00129 #if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
00130 #define MW_HAVE_MUTEX 1
00131 #include <pthread.h>
00132 #endif
00133
00134
00135
00136
00137
00138
00139 #define VERSION "2.71"
00140 #define CHKVAL(mw) (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line)
00141 #define FLUSH() mwFlush()
00142 #define TESTS(f,l) if(mwTestAlways) (void)mwTestNow(f,l,1)
00143 #define PRECHK 0x01234567L
00144 #define POSTCHK 0x76543210L
00145 #define mwBUFFER_TO_MW(p) ( (mwData*) (void*) ( ((char*)p)-mwDataSize-mwOverflowZoneSize ) )
00146
00147
00148 #define MW_NML 0x0001
00149
00150 #ifdef _MSC_VER
00151 #define COMMIT "c"
00152 #else
00153 #define COMMIT ""
00154 #endif
00155
00156 #ifdef __cplusplus
00157 #define CPPTEXT "++"
00158 #else
00159 #define CPPTEXT ""
00160 #endif
00161
00162 #ifdef MEMWATCH_STDIO
00163 #define mwSTDERR stderr
00164 #else
00165 #define mwSTDERR mwLog
00166 #endif
00167
00168 #ifdef MW_HAVE_MUTEX
00169 #define MW_MUTEX_INIT() mwMutexInit()
00170 #define MW_MUTEX_TERM() mwMutexTerm()
00171 #define MW_MUTEX_LOCK() mwMutexLock()
00172 #define MW_MUTEX_UNLOCK() mwMutexUnlock()
00173 #else
00174 #define MW_MUTEX_INIT()
00175 #define MW_MUTEX_TERM()
00176 #define MW_MUTEX_LOCK()
00177 #define MW_MUTEX_UNLOCK()
00178 #endif
00179
00180
00181
00182
00183
00184
00185 #ifndef mwBYTE_DEFINED
00186 # if CHAR_BIT != 8
00187 # error need CHAR_BIT to be 8!
00188 # else
00189 typedef unsigned char mwBYTE;
00190 # define mwBYTE_DEFINED 1
00191 # endif
00192 #endif
00193
00194 #if defined(ULONGLONG_MAX) || defined(ULLONG_MAX) || defined(_UI64_MAX) || defined(ULONG_LONG_MAX)
00195 # define mw64BIT 1
00196 # define mwROUNDALLOC_DEFAULT 8
00197 #else
00198 # if UINT_MAX <= 0xFFFFUL
00199 # define mw16BIT 1
00200 # define mwROUNDALLOC_DEFAULT 2
00201 # else
00202 # if ULONG_MAX > 0xFFFFFFFFUL
00203 # define mw64BIT 1
00204 # define mwROUNDALLOC_DEFAULT 8
00205 # else
00206 # define mw32BIT 1
00207 # define mwROUNDALLOC_DEFAULT 4
00208 # endif
00209 # endif
00210 #endif
00211
00212
00213
00214
00215
00216 #ifndef mwROUNDALLOC
00217 # define mwROUNDALLOC mwROUNDALLOC_DEFAULT
00218 #endif
00219
00220 #ifndef mwDWORD_DEFINED
00221 #if ULONG_MAX == 0xFFFFFFFFUL
00222 typedef unsigned long mwDWORD;
00223 #define mwDWORD_DEFINED "unsigned long"
00224 #endif
00225 #endif
00226
00227 #ifndef mwDWORD_DEFINED
00228 #if UINT_MAX == 0xFFFFFFFFUL
00229 typedef unsigned int mwDWORD;
00230 #define mwDWORD_DEFINED "unsigned int"
00231 #endif
00232 #endif
00233
00234 #ifndef mwDWORD_DEFINED
00235 #if USHRT_MAX == 0xFFFFFFFFUL
00236 typedef unsigned short mwDWORD;
00237 #define mwDWORD_DEFINED "unsigned short"
00238 #endif
00239 #endif
00240
00241 #ifndef mwBYTE_DEFINED
00242 #error "can't find out the correct type for a 8 bit scalar"
00243 #endif
00244
00245 #ifndef mwDWORD_DEFINED
00246 #error "can't find out the correct type for a 32 bit scalar"
00247 #endif
00248
00249
00250
00251
00252
00253
00254 typedef struct mwData_ mwData;
00255 struct mwData_ {
00256 mwData* prev;
00257 mwData* next;
00258 const char* file;
00259 long count;
00260 long check;
00261 #if 0
00262 long crc;
00263 #endif
00264 size_t size;
00265 int line;
00266 unsigned flag;
00267 };
00268
00269
00270 typedef struct mwStat_ mwStat;
00271 struct mwStat_ {
00272 mwStat* next;
00273 const char* file;
00274 long total;
00275 long num;
00276 long max;
00277 long curr;
00278 int line;
00279 };
00280
00281
00282 typedef struct mwGrabData_ mwGrabData;
00283 struct mwGrabData_ {
00284 mwGrabData* next;
00285 int type;
00286 char blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ];
00287 };
00288
00289 typedef struct mwMarker_ mwMarker;
00290 struct mwMarker_ {
00291 void *host;
00292 char *text;
00293 mwMarker *next;
00294 int level;
00295 };
00296
00297 #if defined(WIN32) || defined(__WIN32__)
00298 typedef HANDLE mwMutex;
00299 #endif
00300
00301 #if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
00302 typedef pthread_mutex_t mwMutex;
00303 #endif
00304
00305
00306
00307
00308
00309 static int mwInited = 0;
00310 static int mwInfoWritten = 0;
00311 static int mwUseAtexit = 0;
00312 static FILE* mwLog = NULL;
00313 static int mwFlushing = 0;
00314 static int mwStatLevel = MW_STAT_DEFAULT;
00315 static int mwNML = MW_NML_DEFAULT;
00316 static int mwFBI = 0;
00317 static long mwAllocLimit = 0L;
00318 static int mwUseLimit = 0;
00319
00320 static long mwNumCurAlloc = 0L;
00321 static mwData* mwHead = NULL;
00322 static mwData* mwTail = NULL;
00323 static int mwDataSize = 0;
00324 static unsigned char mwOverflowZoneTemplate[] = "mEmwAtch";
00325 static int mwOverflowZoneSize = mwROUNDALLOC;
00326
00327 static void (*mwOutFunction)(int) = NULL;
00328 static int (*mwAriFunction)(const char*) = NULL;
00329 static int mwAriAction = MW_ARI_ABORT;
00330
00331 static char mwPrintBuf[MW_TRACE_BUFFER+8];
00332
00333 static unsigned long mwCounter = 0L;
00334 static long mwErrors = 0L;
00335
00336 static int mwTestFlags = 0;
00337 static int mwTestAlways = 0;
00338
00339 static FILE* mwLogB1 = NULL;
00340 static int mwFlushingB1 = 0;
00341
00342 static mwStat* mwStatList = NULL;
00343 static long mwStatTotAlloc = 0L;
00344 static long mwStatMaxAlloc = 0L;
00345 static long mwStatNumAlloc = 0L;
00346 static long mwStatCurAlloc = 0L;
00347 static long mwNmlNumAlloc = 0L;
00348 static long mwNmlCurAlloc = 0L;
00349
00350 static mwGrabData* mwGrabList = NULL;
00351 static long mwGrabSize = 0L;
00352
00353 static void * mwLastFree[MW_FREE_LIST];
00354 static const char *mwLFfile[MW_FREE_LIST];
00355 static int mwLFline[MW_FREE_LIST];
00356 static int mwLFcur = 0;
00357
00358 static mwMarker* mwFirstMark = NULL;
00359
00360 static FILE* mwLogB2 = NULL;
00361 static int mwFlushingB2 = 0;
00362
00363 #ifdef MW_HAVE_MUTEX
00364 static mwMutex mwGlobalMutex;
00365 #endif
00366
00367
00368
00369
00370
00371 static void mwAutoInit( void );
00372 static FILE* mwLogR( void );
00373 static void mwLogW( FILE* );
00374 static int mwFlushR( void );
00375 static void mwFlushW( int );
00376 static void mwFlush( void );
00377 static void mwIncErr( void );
00378 static void mwUnlink( mwData*, const char* file, int line );
00379 static int mwRelink( mwData*, const char* file, int line );
00380 static int mwIsHeapOK( mwData *mw );
00381 static int mwIsOwned( mwData* mw, const char* file, int line );
00382 static int mwTestBuf( mwData* mw, const char* file, int line );
00383 static void mwDefaultOutFunc( int );
00384 static void mwWrite( const char* format, ... );
00385 static void mwLogFile( const char* name );
00386 static size_t mwFreeUp( size_t, int );
00387 static const void *mwTestMem( const void *, unsigned, int );
00388 static int mwStrCmpI( const char *s1, const char *s2 );
00389 static int mwTestNow( const char *file, int line, int always_invoked );
00390 static void mwDropAll( void );
00391 static const char *mwGrabType( int type );
00392 static unsigned mwGrab_( unsigned kb, int type, int silent );
00393 static unsigned mwDrop_( unsigned kb, int type, int silent );
00394 static int mwARI( const char* text );
00395 static void mwStatReport( void );
00396 static mwStat* mwStatGet( const char*, int, int );
00397 static void mwStatAlloc( size_t, const char*, int );
00398 static void mwStatFree( size_t, const char*, int );
00399 static int mwCheckOF( const void * p );
00400 static void mwWriteOF( void * p );
00401 static char mwDummy( char c );
00402 #ifdef MW_HAVE_MUTEX
00403 static void mwMutexInit( void );
00404 static void mwMutexTerm( void );
00405 static void mwMutexLock( void );
00406 static void mwMutexUnlock( void );
00407 #endif
00408
00409
00410
00411
00412
00413 void mwInit( void ) {
00414 time_t tid;
00415
00416 if( mwInited++ > 0 ) return;
00417
00418 MW_MUTEX_INIT();
00419
00420
00421 if( mwLogR() == NULL ) mwLogFile( "memwatch.log" );
00422 if( mwLogR() == NULL ) {
00423 int i;
00424 char buf[32];
00425
00426
00427
00428 for( i=1; i<100; i++ ) {
00429 sprintf( buf, "memwat%02d.log", i );
00430 mwLogFile( buf );
00431 if( mwLogR() != NULL ) break;
00432 }
00433 }
00434
00435
00436 mwStatList = NULL;
00437 mwStatTotAlloc = 0L;
00438 mwStatCurAlloc = 0L;
00439 mwStatMaxAlloc = 0L;
00440 mwStatNumAlloc = 0L;
00441 mwNmlCurAlloc = 0L;
00442 mwNmlNumAlloc = 0L;
00443
00444
00445 mwDataSize = sizeof(mwData);
00446 while( mwDataSize % mwROUNDALLOC ) mwDataSize ++;
00447
00448
00449 if( !mwInfoWritten ) {
00450 mwInfoWritten = 1;
00451 (void) time( &tid );
00452 mwWrite(
00453 "\n============="
00454 " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh "
00455 "=============\n");
00456 mwWrite( "\nStarted at %s\n", ctime( &tid ) );
00457
00458
00459 mwWrite( "Modes: " );
00460 #ifdef mwNew
00461 mwWrite( "C++ " );
00462 #endif
00463 #ifdef __STDC__
00464 mwWrite( "__STDC__ " );
00465 #endif
00466 #ifdef mw16BIT
00467 mwWrite( "16-bit " );
00468 #endif
00469 #ifdef mw32BIT
00470 mwWrite( "32-bit " );
00471 #endif
00472 #ifdef mw64BIT
00473 mwWrite( "64-bit " );
00474 #endif
00475 mwWrite( "mwDWORD==(" mwDWORD_DEFINED ")\n" );
00476 mwWrite( "mwROUNDALLOC==%d sizeof(mwData)==%d mwDataSize==%d\n",
00477 mwROUNDALLOC, sizeof(mwData), mwDataSize );
00478
00479
00480
00481 #ifdef _MSC_VER
00482 mwWrite( "Compiled using Microsoft C" CPPTEXT
00483 " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 );
00484 #endif
00485
00486
00487
00488 #ifdef __BORLANDC__
00489 mwWrite( "Compiled using Borland C"
00490 #ifdef __cplusplus
00491 "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 );
00492 #else
00493 " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 );
00494 #endif
00495 #endif
00496
00497
00498
00499 #ifdef __WATCOMC__
00500 mwWrite( "Compiled using Watcom C %d.%02d ",
00501 __WATCOMC__/100, __WATCOMC__%100 );
00502 #ifdef __FLAT__
00503 mwWrite( "(32-bit flat model)" );
00504 #endif
00505 mwWrite( "\n" );
00506 #endif
00507
00508
00509 mwWrite( "\n" );
00510 FLUSH();
00511 }
00512
00513 if( mwUseAtexit ) (void) atexit( mwAbort );
00514 return;
00515 }
00516
00517 void mwAbort( void ) {
00518 mwData *mw;
00519 mwMarker *mrk;
00520 char *data;
00521 time_t tid;
00522 int c, i, j;
00523 int errors;
00524
00525 tid = time( NULL );
00526 mwWrite( "\nStopped at %s\n", ctime( &tid) );
00527
00528 if( !mwInited )
00529 mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" );
00530
00531
00532 mwDropAll();
00533
00534
00535 while( mwFirstMark ) {
00536 mrk = mwFirstMark->next;
00537 mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text );
00538 free( mwFirstMark->text );
00539 free( mwFirstMark );
00540 mwFirstMark = mrk;
00541 mwErrors ++;
00542 }
00543
00544
00545 errors = 0;
00546 while( mwHead != NULL && errors < 3 ) {
00547 if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) {
00548 if( errors < 3 )
00549 {
00550 errors ++;
00551 mwWrite( "internal: NML/unfreed scan restarting\n" );
00552 FLUSH();
00553 mwHead = mwHead;
00554 continue;
00555 }
00556 mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" );
00557 FLUSH();
00558 break;
00559 }
00560 mwFlushW(0);
00561 if( !(mwHead->flag & MW_NML) ) {
00562 mwErrors++;
00563 data = ((char*)mwHead)+mwDataSize;
00564 mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ",
00565 mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+mwOverflowZoneSize );
00566 if( mwCheckOF( data ) ) {
00567 mwWrite( "[underflowed] ");
00568 FLUSH();
00569 }
00570 if( mwCheckOF( (data+mwOverflowZoneSize+mwHead->size) ) ) {
00571 mwWrite( "[overflowed] ");
00572 FLUSH();
00573 }
00574 mwWrite( " \t{" );
00575 j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size;
00576 for( i=0;i<16;i++ ) {
00577 if( i<j ) mwWrite( "%02X ",
00578 (unsigned char) *(data+mwOverflowZoneSize+i) );
00579 else mwWrite( ".. " );
00580 }
00581 for( i=0;i<j;i++ ) {
00582 c = *(data+mwOverflowZoneSize+i);
00583 if( c < 32 || c > 126 ) c = '.';
00584 mwWrite( "%c", c );
00585 }
00586 mwWrite( "}\n" );
00587 mw = mwHead;
00588 mwUnlink( mw, __FILE__, __LINE__ );
00589 free( mw );
00590 }
00591 else {
00592 data = ((char*)mwHead) + mwDataSize + mwOverflowZoneSize;
00593 if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) {
00594 mwErrors++;
00595 mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
00596 mwHead->count, data + mwOverflowZoneSize, mwHead->file, mwHead->line );
00597 FLUSH();
00598 }
00599 mwNmlNumAlloc --;
00600 mwNmlCurAlloc -= mwHead->size;
00601 mw = mwHead;
00602 mwUnlink( mw, __FILE__, __LINE__ );
00603 free( mw );
00604 }
00605 }
00606
00607 if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc );
00608 if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc );
00609
00610
00611 mwStatReport();
00612 FLUSH();
00613
00614 mwInited = 0;
00615 mwHead = mwTail = NULL;
00616 if( mwErrors )
00617 fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors);
00618 mwLogFile( NULL );
00619 mwErrors = 0;
00620
00621 MW_MUTEX_TERM();
00622
00623 }
00624
00625 void mwTerm( void ) {
00626 if( mwInited == 1 )
00627 {
00628 mwAbort();
00629 return;
00630 }
00631 if( !mwInited )
00632 mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n");
00633 else
00634 mwInited --;
00635 }
00636
00637 void mwStatistics( int level )
00638 {
00639 mwAutoInit();
00640 if( level<0 ) level=0;
00641 if( mwStatLevel != level )
00642 {
00643 mwWrite( "statistics: now collecting on a %s basis\n",
00644 level<1?"global":(level<2?"module":"line") );
00645 mwStatLevel = level;
00646 }
00647 }
00648
00649 void mwAutoCheck( int onoff ) {
00650 mwAutoInit();
00651 mwTestAlways = onoff;
00652 if( onoff ) mwTestFlags = MW_TEST_ALL;
00653 }
00654
00655 void mwSetOutFunc( void (*func)(int) ) {
00656 mwAutoInit();
00657 mwOutFunction = func;
00658 }
00659
00660 static void mwWriteOF( void *p )
00661 {
00662 int i;
00663 unsigned char *ptr;
00664 ptr = (unsigned char*) p;
00665 for( i=0; i<mwOverflowZoneSize; i++ )
00666 {
00667 *(ptr+i) = mwOverflowZoneTemplate[i%8];
00668 }
00669 return;
00670 }
00671
00672 static int mwCheckOF( const void *p )
00673 {
00674 int i;
00675 const unsigned char *ptr;
00676 ptr = (const unsigned char *) p;
00677 for( i=0; i<mwOverflowZoneSize; i++ )
00678 {
00679 if( *(ptr+i) != mwOverflowZoneTemplate[i%8] )
00680 return 1;
00681 }
00682 return 0;
00683 }
00684
00685 int mwTest( const char *file, int line, int items ) {
00686 mwAutoInit();
00687 mwTestFlags = items;
00688 return mwTestNow( file, line, 0 );
00689 }
00690
00691
00692
00693
00694
00695 int mwTestBuffer( const char *file, int line, void *p ) {
00696 mwData* mw;
00697
00698 mwAutoInit();
00699
00700
00701 mw = (mwData*) mwBUFFER_TO_MW( p );
00702
00703 if( mwIsOwned( mw, file, line ) ) {
00704 return mwTestBuf( mw, file, line );
00705 }
00706 return 1;
00707 }
00708
00709 void mwBreakOut( const char* cause ) {
00710 fprintf(mwSTDERR, "breakout: %s\n", cause);
00711 mwWrite("breakout: %s\n", cause );
00712 return;
00713 }
00714
00715
00716
00717
00718 void * mwMark( void *p, const char *desc, const char *file, unsigned line ) {
00719 mwMarker *mrk;
00720 unsigned n, isnew;
00721 char *buf;
00722 int tot, oflow = 0;
00723 char wherebuf[128];
00724
00725 mwAutoInit();
00726 TESTS(NULL,0);
00727
00728 if( desc == NULL ) desc = "unknown";
00729 if( file == NULL ) file = "unknown";
00730
00731 tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line );
00732 if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; }
00733
00734 if( p == NULL ) {
00735 mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc );
00736 return p;
00737 }
00738
00739 if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) )
00740 {
00741 mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n",
00742 file, line, mwFirstMark, desc );
00743 return p;
00744 }
00745
00746 for( mrk=mwFirstMark; mrk; mrk=mrk->next )
00747 {
00748 if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) )
00749 {
00750 mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n",
00751 file, line, mrk, mrk->next, desc );
00752 return p;
00753 }
00754 if( mrk->host == p ) break;
00755 }
00756
00757 if( mrk == NULL ) {
00758 isnew = 1;
00759 mrk = (mwMarker*) malloc( sizeof( mwMarker ) );
00760 if( mrk == NULL ) {
00761 mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
00762 return p;
00763 }
00764 mrk->next = NULL;
00765 n = 0;
00766 }
00767 else {
00768 isnew = 0;
00769 n = strlen( mrk->text );
00770 }
00771
00772 n += strlen( wherebuf );
00773 buf = (char*) malloc( n+3 );
00774 if( buf == NULL ) {
00775 if( isnew ) free( mrk );
00776 mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
00777 return p;
00778 }
00779
00780 if( isnew ) {
00781 memcpy( buf, wherebuf, n+1 );
00782 mrk->next = mwFirstMark;
00783 mrk->host = p;
00784 mrk->text = buf;
00785 mrk->level = 1;
00786 mwFirstMark = mrk;
00787 }
00788 else {
00789 strcpy( buf, mrk->text );
00790 strcat( buf, ", " );
00791 strcat( buf, wherebuf );
00792 free( mrk->text );
00793 mrk->text = buf;
00794 mrk->level ++;
00795 }
00796
00797 if( oflow ) {
00798 mwIncErr();
00799 mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
00800 }
00801 return p;
00802 }
00803
00804 void* mwUnmark( void *p, const char *file, unsigned line ) {
00805 mwMarker *mrk, *prv;
00806 mrk = mwFirstMark;
00807 prv = NULL;
00808 while( mrk ) {
00809 if( mrk->host == p ) {
00810 if( mrk->level < 2 ) {
00811 if( prv ) prv->next = mrk->next;
00812 else mwFirstMark = mrk->next;
00813 free( mrk->text );
00814 free( mrk );
00815 return p;
00816 }
00817 mrk->level --;
00818 return p;
00819 }
00820 prv = mrk;
00821 mrk = mrk->next;
00822 }
00823 mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p );
00824 return p;
00825 }
00826
00827
00828
00829
00830
00831
00832 static int mwARI( const char *estr ) {
00833 char inbuf[81];
00834 int c;
00835 fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr);
00836 (void) fgets(inbuf,sizeof(inbuf),stdin);
00837 for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ;
00838 c = inbuf[c];
00839 if( c == 'R' || c == 'r' ) {
00840 mwBreakOut( estr );
00841 return MW_ARI_RETRY;
00842 }
00843 if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE;
00844 return MW_ARI_ABORT;
00845 }
00846
00847
00848 int mwAriHandler( const char *estr ) {
00849 mwAutoInit();
00850 return mwARI( estr );
00851 }
00852
00853
00854 void mwSetAriFunc( int (*func)(const char *) ) {
00855 mwAutoInit();
00856 mwAriFunction = func;
00857 }
00858
00859
00860
00861
00862
00863 void* mwMalloc( size_t size, const char* file, int line) {
00864 size_t needed;
00865 mwData *mw;
00866 char *ptr;
00867 void *p;
00868
00869 mwAutoInit();
00870
00871 MW_MUTEX_LOCK();
00872
00873 TESTS(file,line);
00874
00875 mwCounter ++;
00876 needed = mwDataSize + mwOverflowZoneSize*2 + size;
00877 if( needed < size )
00878 {
00879
00880 return NULL;
00881 }
00882
00883
00884 if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) {
00885 mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
00886 mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc );
00887 mwIncErr();
00888 FLUSH();
00889 MW_MUTEX_UNLOCK();
00890 return NULL;
00891 }
00892
00893 mw = (mwData*) malloc( needed );
00894 if( mw == NULL ) {
00895 if( mwFreeUp(needed,0) >= needed ) {
00896 mw = (mwData*) malloc(needed);
00897 if( mw == NULL ) {
00898 mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed );
00899 mwIncErr();
00900 FLUSH();
00901 }
00902 }
00903 if( mw == NULL ) {
00904 mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n",
00905 mwCounter, file, line, (long)size, mwStatCurAlloc );
00906 mwIncErr();
00907 FLUSH();
00908 MW_MUTEX_UNLOCK();
00909 return NULL;
00910 }
00911 }
00912
00913 mw->count = mwCounter;
00914 mw->prev = NULL;
00915 mw->next = mwHead;
00916 mw->file = file;
00917 mw->size = size;
00918 mw->line = line;
00919 mw->flag = 0;
00920 mw->check = CHKVAL(mw);
00921
00922 if( mwHead ) mwHead->prev = mw;
00923 mwHead = mw;
00924 if( mwTail == NULL ) mwTail = mw;
00925
00926 ptr = ((char*)mw) + mwDataSize;
00927 mwWriteOF( ptr );
00928 ptr += mwOverflowZoneSize;
00929 p = ptr;
00930 memset( ptr, MW_VAL_NEW, size );
00931 ptr += size;
00932 mwWriteOF( ptr );
00933
00934 mwNumCurAlloc ++;
00935 mwStatCurAlloc += (long) size;
00936 mwStatTotAlloc += (long) size;
00937 if( mwStatCurAlloc > mwStatMaxAlloc )
00938 mwStatMaxAlloc = mwStatCurAlloc;
00939 mwStatNumAlloc ++;
00940
00941 if( mwStatLevel ) mwStatAlloc( size, file, line );
00942
00943 MW_MUTEX_UNLOCK();
00944 return p;
00945 }
00946
00947 void* mwRealloc( void *p, size_t size, const char* file, int line) {
00948 int oldUseLimit, i;
00949 mwData *mw;
00950 char *ptr;
00951
00952 mwAutoInit();
00953
00954 if( p == NULL ) return mwMalloc( size, file, line );
00955 if( size == 0 ) { mwFree( p, file, line ); return NULL; }
00956
00957 MW_MUTEX_LOCK();
00958
00959
00960 mw = (mwData*) mwBUFFER_TO_MW( p );
00961 if( mwIsOwned( mw, file, line ) ) {
00962
00963
00964 if( mw->flag & MW_NML )
00965 {
00966 mwIncErr();
00967 if( *((unsigned char*)(mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML )
00968 {
00969 mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
00970 mwCounter, file, line, mw );
00971 }
00972 goto check_dbl_free;
00973 }
00974
00975
00976 if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) {
00977 TESTS(file,line);
00978 mwCounter ++;
00979 mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
00980 mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc );
00981 mwIncErr();
00982 FLUSH();
00983 MW_MUTEX_UNLOCK();
00984 return NULL;
00985 }
00986
00987
00988 oldUseLimit = mwUseLimit;
00989 mwUseLimit = 0;
00990 ptr = (char*) mwMalloc( size, file, line );
00991 if( ptr != NULL ) {
00992 if( size < mw->size )
00993 memcpy( ptr, p, size );
00994 else
00995 memcpy( ptr, p, mw->size );
00996 mwFree( p, file, line );
00997 }
00998 mwUseLimit = oldUseLimit;
00999 MW_MUTEX_UNLOCK();
01000 return (void*) ptr;
01001 }
01002
01003
01004
01005
01006 check_dbl_free:
01007 for(i=0;i<MW_FREE_LIST;i++) {
01008 if( mwLastFree[i] == p ) {
01009 mwIncErr();
01010 mwWrite( "realloc: <%ld> %s(%d), %p was"
01011 " freed from %s(%d)\n",
01012 mwCounter, file, line, p,
01013 mwLFfile[i], mwLFline[i] );
01014 FLUSH();
01015 MW_MUTEX_UNLOCK();
01016 return NULL;
01017 }
01018 }
01019
01020
01021 mwIncErr();
01022 mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n",
01023 mwCounter, file, line, p );
01024 FLUSH();
01025 MW_MUTEX_UNLOCK();
01026 return NULL;
01027 }
01028
01029 char *mwStrdup( const char* str, const char* file, int line ) {
01030 size_t len;
01031 char *newstring;
01032
01033 MW_MUTEX_LOCK();
01034
01035 if( str == NULL ) {
01036 mwIncErr();
01037 mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n",
01038 mwCounter, file, line );
01039 FLUSH();
01040 MW_MUTEX_UNLOCK();
01041 return NULL;
01042 }
01043
01044 len = strlen( str ) + 1;
01045 newstring = (char*) mwMalloc( len, file, line );
01046 if( newstring != NULL ) memcpy( newstring, str, len );
01047 MW_MUTEX_UNLOCK();
01048 return newstring;
01049 }
01050
01051 void mwFree( void* p, const char* file, int line ) {
01052 int i;
01053 mwData* mw;
01054 char buffer[ sizeof(mwData) + (mwROUNDALLOC*3) + 64 ];
01055
01056
01057 if( file == NULL ) {
01058 mwFree_( p );
01059 MW_MUTEX_UNLOCK();
01060 return;
01061 }
01062
01063 mwAutoInit();
01064
01065 MW_MUTEX_LOCK();
01066 TESTS(file,line);
01067 mwCounter ++;
01068
01069
01070 if( p == NULL ) {
01071 mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n",
01072 mwCounter, file, line );
01073 FLUSH();
01074 MW_MUTEX_UNLOCK();
01075 return;
01076 }
01077
01078
01079 mw = (mwData*) mwBUFFER_TO_MW( p );
01080
01081 if( mwIsOwned( mw, file, line ) ) {
01082 (void) mwTestBuf( mw, file, line );
01083
01084
01085 if( mw->flag & MW_NML )
01086 {
01087 if( *(((unsigned char*)mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML )
01088 {
01089 mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
01090 mwCounter, file, line, mw );
01091 }
01092 goto check_dbl_free;
01093 }
01094
01095
01096 mwNumCurAlloc --;
01097 mwStatCurAlloc -= (long) mw->size;
01098 if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line );
01099
01100
01101 if( mwNML ) {
01102 mw->flag |= MW_NML;
01103 mwNmlNumAlloc ++;
01104 mwNmlCurAlloc += (long) mw->size;
01105 memset( ((char*)mw)+mwDataSize+mwOverflowZoneSize, MW_VAL_NML, mw->size );
01106 }
01107 else {
01108
01109 mwUnlink( mw, file, line );
01110 memset( mw, MW_VAL_DEL,
01111 mw->size + mwDataSize+mwOverflowZoneSize+mwOverflowZoneSize );
01112 if( mwFBI ) {
01113 memset( mw, '.', mwDataSize + mwOverflowZoneSize );
01114 sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line );
01115 strncpy( (char*)(void*)mw, buffer, mwDataSize + mwOverflowZoneSize );
01116 }
01117 free( mw );
01118 }
01119
01120
01121 mwLFfile[ mwLFcur ] = file;
01122 mwLFline[ mwLFcur ] = line;
01123 mwLastFree[ mwLFcur++ ] = p;
01124 if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0;
01125
01126 MW_MUTEX_UNLOCK();
01127 return;
01128 }
01129
01130
01131 check_dbl_free:
01132 for(i=0;i<MW_FREE_LIST;i++) {
01133 if( mwLastFree[i] == p ) {
01134 mwIncErr();
01135 mwWrite( "double-free: <%ld> %s(%d), %p was"
01136 " freed from %s(%d)\n",
01137 mwCounter, file, line, p,
01138 mwLFfile[i], mwLFline[i] );
01139 FLUSH();
01140 MW_MUTEX_UNLOCK();
01141 return;
01142 }
01143 }
01144
01145
01146 mwIncErr();
01147 mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n",
01148 mwCounter, file, line, p );
01149 FLUSH();
01150 MW_MUTEX_UNLOCK();
01151 return;
01152 }
01153
01154 void* mwCalloc( size_t a, size_t b, const char *file, int line ) {
01155 void *p;
01156 size_t size = a * b;
01157 p = mwMalloc( size, file, line );
01158 if( p == NULL ) return NULL;
01159 memset( p, 0, size );
01160 return p;
01161 }
01162
01163 void mwFree_( void *p ) {
01164 MW_MUTEX_LOCK();
01165 TESTS(NULL,0);
01166 MW_MUTEX_UNLOCK();
01167 free(p);
01168 }
01169
01170 void* mwMalloc_( size_t size ) {
01171 MW_MUTEX_LOCK();
01172 TESTS(NULL,0);
01173 MW_MUTEX_UNLOCK();
01174 return malloc( size );
01175 }
01176
01177 void* mwRealloc_( void *p, size_t size ) {
01178 MW_MUTEX_LOCK();
01179 TESTS(NULL,0);
01180 MW_MUTEX_UNLOCK();
01181 return realloc( p, size );
01182 }
01183
01184 void* mwCalloc_( size_t a, size_t b ) {
01185 MW_MUTEX_LOCK();
01186 TESTS(NULL,0);
01187 MW_MUTEX_UNLOCK();
01188 return calloc( a, b );
01189 }
01190
01191 void mwFlushNow( void ) {
01192 if( mwLogR() ) fflush( mwLogR() );
01193 return;
01194 }
01195
01196 void mwDoFlush( int onoff ) {
01197 mwFlushW( onoff<1?0:onoff );
01198 if( onoff ) if( mwLogR() ) fflush( mwLogR() );
01199 return;
01200 }
01201
01202 void mwLimit( long lim ) {
01203 TESTS(NULL,0);
01204 mwWrite("limit: old limit = ");
01205 if( !mwAllocLimit ) mwWrite( "none" );
01206 else mwWrite( "%ld bytes", mwAllocLimit );
01207 mwWrite( ", new limit = ");
01208 if( !lim ) {
01209 mwWrite( "none\n" );
01210 mwUseLimit = 0;
01211 }
01212 else {
01213 mwWrite( "%ld bytes\n", lim );
01214 mwUseLimit = 1;
01215 }
01216 mwAllocLimit = lim;
01217 FLUSH();
01218 }
01219
01220 void mwSetAriAction( int action ) {
01221 MW_MUTEX_LOCK();
01222 TESTS(NULL,0);
01223 mwAriAction = action;
01224 MW_MUTEX_UNLOCK();
01225 return;
01226 }
01227
01228 int mwAssert( int exp, const char *exps, const char *fn, int ln ) {
01229 int i;
01230 char buffer[MW_TRACE_BUFFER+8];
01231 if( exp ) {
01232 return 0;
01233 }
01234 mwAutoInit();
01235 MW_MUTEX_LOCK();
01236 TESTS(fn,ln);
01237 mwIncErr();
01238 mwCounter++;
01239 mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
01240 if( mwAriFunction != NULL ) {
01241 sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps );
01242 i = (*mwAriFunction)(buffer);
01243 switch( i ) {
01244 case MW_ARI_IGNORE:
01245 mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter );
01246 MW_MUTEX_UNLOCK();
01247 return 0;
01248 case MW_ARI_RETRY:
01249 mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter );
01250 MW_MUTEX_UNLOCK();
01251 return 1;
01252 }
01253 }
01254 else {
01255 if( mwAriAction & MW_ARI_IGNORE ) {
01256 mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
01257 MW_MUTEX_UNLOCK();
01258 return 0;
01259 }
01260 fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps );
01261 }
01262
01263 FLUSH();
01264 (void) mwTestNow( fn, ln, 1 );
01265 FLUSH();
01266
01267 if( mwAriAction & MW_ARI_NULLREAD ) {
01268
01269
01270 FLUSH();
01271
01272 i = *((int*)NULL);
01273 mwDummy( (char)i );
01274
01275 }
01276
01277 MW_MUTEX_UNLOCK();
01278 exit(255);
01279
01280
01281
01282
01283 return 0;
01284
01285 }
01286
01287 int mwVerify( int exp, const char *exps, const char *fn, int ln ) {
01288 int i;
01289 char buffer[MW_TRACE_BUFFER+8];
01290 if( exp ) {
01291 return 0;
01292 }
01293 mwAutoInit();
01294 MW_MUTEX_LOCK();
01295 TESTS(fn,ln);
01296 mwIncErr();
01297 mwCounter++;
01298 mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
01299 if( mwAriFunction != NULL ) {
01300 sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps );
01301 i = (*mwAriFunction)(buffer);
01302 if( i == 0 ) {
01303 mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter );
01304 MW_MUTEX_UNLOCK();
01305 return 0;
01306 }
01307 if( i == 1 ) {
01308 mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter );
01309 MW_MUTEX_UNLOCK();
01310 return 1;
01311 }
01312 }
01313 else {
01314 if( mwAriAction & MW_ARI_NULLREAD ) {
01315
01316
01317 FLUSH();
01318
01319 i = *((int*)NULL);
01320 mwDummy( (char)i );
01321
01322 }
01323 if( mwAriAction & MW_ARI_IGNORE ) {
01324 mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
01325 MW_MUTEX_UNLOCK();
01326 return 0;
01327 }
01328 fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps );
01329 }
01330 FLUSH();
01331 (void) mwTestNow( fn, ln, 1 );
01332 FLUSH();
01333 MW_MUTEX_UNLOCK();
01334 exit(255);
01335
01336
01337
01338
01339 return 0;
01340
01341 }
01342
01343 void mwTrace( const char *format, ... ) {
01344 int tot, oflow = 0;
01345 va_list mark;
01346
01347 mwAutoInit();
01348 MW_MUTEX_LOCK();
01349 TESTS(NULL,0);
01350 if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
01351
01352 va_start( mark, format );
01353 tot = vsprintf( mwPrintBuf, format, mark );
01354 va_end( mark );
01355 if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; }
01356 for(tot=0;mwPrintBuf[tot];tot++)
01357 (*mwOutFunction)( mwPrintBuf[tot] );
01358 if( oflow ) {
01359 mwIncErr();
01360 mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
01361 }
01362
01363 FLUSH();
01364 MW_MUTEX_UNLOCK();
01365 }
01366
01367
01368
01369
01370
01371
01372 unsigned mwGrab( unsigned kb ) {
01373 TESTS(NULL,0);
01374 return mwGrab_( kb, MW_VAL_GRB, 0 );
01375 }
01376
01377 unsigned mwDrop( unsigned kb ) {
01378 TESTS(NULL,0);
01379 return mwDrop_( kb, MW_VAL_GRB, 0 );
01380 }
01381
01382 static void mwDropAll() {
01383 TESTS(NULL,0);
01384 (void) mwDrop_( 0, MW_VAL_GRB, 0 );
01385 (void) mwDrop_( 0, MW_VAL_NML, 0 );
01386 if( mwGrabList != NULL )
01387 mwWrite( "internal: the grab list is not empty after mwDropAll()\n");
01388 }
01389
01390 static const char *mwGrabType( int type ) {
01391 switch( type ) {
01392 case MW_VAL_GRB:
01393 return "grabbed";
01394 case MW_VAL_NML:
01395 return "no-mans-land";
01396 default:
01397
01398 ;
01399 }
01400 return "<unknown type>";
01401 }
01402
01403 static unsigned mwGrab_( unsigned kb, int type, int silent ) {
01404 unsigned i = kb;
01405 mwGrabData *gd;
01406 if( !kb ) i = kb = 65000U;
01407
01408 for(;kb;kb--) {
01409 if( mwUseLimit &&
01410 (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) {
01411 if( !silent ) {
01412 mwWrite("grabbed: all allowed memory to %s (%u kb)\n",
01413 mwGrabType(type), i-kb);
01414 FLUSH();
01415 }
01416 return i-kb;
01417 }
01418 gd = (mwGrabData*) malloc( sizeof(mwGrabData) );
01419 if( gd == NULL ) {
01420 if( !silent ) {
01421 mwWrite("grabbed: all available memory to %s (%u kb)\n",
01422 mwGrabType(type), i-kb);
01423 FLUSH();
01424 }
01425 return i-kb;
01426 }
01427 mwGrabSize += (long) sizeof(mwGrabData);
01428 gd->next = mwGrabList;
01429 memset( gd->blob, type, sizeof(gd->blob) );
01430 gd->type = type;
01431 mwGrabList = gd;
01432 }
01433 if( !silent ) {
01434 mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) );
01435 FLUSH();
01436 }
01437 return i;
01438 }
01439
01440 static unsigned mwDrop_( unsigned kb, int type, int silent ) {
01441 unsigned i = kb;
01442 mwGrabData *gd,*tmp,*pr;
01443 const void *p;
01444
01445 if( mwGrabList == NULL && kb == 0 ) return 0;
01446 if( !kb ) i = kb = 60000U;
01447
01448 pr = NULL;
01449 gd = mwGrabList;
01450 for(;kb;) {
01451 if( gd == NULL ) {
01452 if( i-kb > 0 && !silent ) {
01453 mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb);
01454 FLUSH();
01455 }
01456 return i-kb;
01457 }
01458 if( gd->type == type ) {
01459 if( pr ) pr->next = gd->next;
01460 kb --;
01461 tmp = gd;
01462 if( mwGrabList == gd ) mwGrabList = gd->next;
01463 gd = gd->next;
01464 p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type );
01465 if( p != NULL ) {
01466 mwWrite( "wild pointer: <%ld> %s memory hit at %p\n",
01467 mwCounter, mwGrabType(type), p );
01468 FLUSH();
01469 }
01470 mwGrabSize -= (long) sizeof(mwGrabData);
01471 free( tmp );
01472 }
01473 else {
01474 pr = gd;
01475 gd = gd->next;
01476 }
01477 }
01478 if( !silent ) {
01479 mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) );
01480 FLUSH();
01481 }
01482 return i;
01483 }
01484
01485
01486
01487
01488
01489 void mwNoMansLand( int level ) {
01490 mwAutoInit();
01491 TESTS(NULL,0);
01492 switch( level ) {
01493 case MW_NML_NONE:
01494 (void) mwDrop_( 0, MW_VAL_NML, 0 );
01495 break;
01496 case MW_NML_FREE:
01497 break;
01498 case MW_NML_ALL:
01499 (void) mwGrab_( 0, MW_VAL_NML, 0 );
01500 break;
01501 default:
01502 return;
01503 }
01504 mwNML = level;
01505 }
01506
01507
01508
01509
01510
01511 static void mwAutoInit( void )
01512 {
01513 if( mwInited ) return;
01514 mwUseAtexit = 1;
01515 mwInit();
01516 return;
01517 }
01518
01519 static FILE *mwLogR() {
01520 if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog;
01521 if( mwLog == mwLogB1 ) mwLogB2 = mwLog;
01522 if( mwLog == mwLogB2 ) mwLogB1 = mwLog;
01523 if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1;
01524 if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) {
01525 mwWrite("internal: log file handle damaged and recovered\n");
01526 FLUSH();
01527 return mwLog;
01528 }
01529 fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" );
01530 mwLog = mwLogB1 = mwLogB2 = mwSTDERR;
01531 return mwSTDERR;
01532 }
01533
01534 static void mwLogW( FILE *p ) {
01535 mwLog = mwLogB1 = mwLogB2 = p;
01536 }
01537
01538 static int mwFlushR() {
01539 if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing;
01540 if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing;
01541 if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing;
01542 if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1;
01543 if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) {
01544 mwWrite("internal: flushing flag damaged and recovered\n");
01545 FLUSH();
01546 return mwFlushing;
01547 }
01548 mwWrite("internal: flushing flag destroyed, so set to true\n");
01549 mwFlushing = mwFlushingB1 = mwFlushingB2 = 1;
01550 return 1;
01551 }
01552
01553 static void mwFlushW( int n ) {
01554 mwFlushing = mwFlushingB1 = mwFlushingB2 = n;
01555 }
01556
01557 static void mwIncErr() {
01558 mwErrors++;
01559 mwFlushW( mwFlushR()+1 );
01560 FLUSH();
01561 }
01562
01563 static void mwFlush() {
01564 if( mwLogR() == NULL ) return;
01565 #ifdef MW_FLUSH
01566 fflush( mwLogR() );
01567 #else
01568 if( mwFlushR() ) fflush( mwLogR() );
01569 #endif
01570 return;
01571 }
01572
01573 static void mwUnlink( mwData* mw, const char* file, int line ) {
01574 if( mw->prev == NULL ) {
01575 if( mwHead != mw )
01576 mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n",
01577 mwCounter, file, line, mw );
01578 mwHead = mw->next;
01579 }
01580 else {
01581 if( mw->prev->next != mw )
01582 mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n",
01583 mwCounter, file, line, mw );
01584 else mw->prev->next = mw->next;
01585 }
01586 if( mw->next == NULL ) {
01587 if( mwTail != mw )
01588 mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n",
01589 mwCounter, file, line, mw );
01590 mwTail = mw->prev;
01591 }
01592 else {
01593 if( mw->next->prev != mw )
01594 mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n",
01595 mwCounter, file, line, mw );
01596 else mw->next->prev = mw->prev;
01597 }
01598 }
01599
01600
01601
01602
01603
01604
01605 static int mwRelink( mwData* mw, const char* file, int line ) {
01606 int fails;
01607 mwData *mw1, *mw2;
01608 long count, size;
01609 mwStat *ms;
01610
01611 if( file == NULL ) file = "unknown";
01612
01613 if( mw == NULL ) {
01614 mwWrite("relink: cannot repair MW at NULL\n");
01615 FLUSH();
01616 goto emergency;
01617 }
01618
01619 if( !mwIsSafeAddr(mw, mwDataSize) ) {
01620 mwWrite("relink: MW-%p is a garbage pointer\n", mw);
01621 FLUSH();
01622 goto emergency;
01623 }
01624
01625 mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw );
01626 FLUSH();
01627 fails = 0;
01628
01629
01630 if( mwHead != mw ) {
01631 if( !mwIsSafeAddr( mwHead, mwDataSize ) ) {
01632 mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw );
01633 FLUSH();
01634 goto emergency;
01635 }
01636 for( mw1=mwHead; mw1; mw1=mw1->next ) {
01637 if( mw1->next == mw ) {
01638 mw->prev = mw1;
01639 break;
01640 }
01641 if( mw1->next &&
01642 ( !mwIsSafeAddr(mw1->next, mwDataSize ) || mw1->next->prev != mw1) ) {
01643 mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next );
01644 FLUSH();
01645 goto emergency;
01646 }
01647 }
01648 if( mw1 == NULL ) {
01649 mwWrite("relink: MW-%p not found in forward chain search\n", mw );
01650 FLUSH();
01651 fails ++;
01652 }
01653 }
01654 else
01655 {
01656 mwWrite( "relink: MW-%p is the head (first) allocation\n", mw );
01657 if( mw->prev != NULL )
01658 {
01659 mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw );
01660 mw->prev = NULL;
01661 }
01662 }
01663
01664
01665 if( mwTail != mw ) {
01666 if( !mwIsSafeAddr( mwTail, mwDataSize ) ) {
01667 mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw );
01668 FLUSH();
01669 goto emergency;
01670 }
01671 for( mw1=mwTail; mw1; mw1=mw1->prev ) {
01672 if( mw1->prev == mw ) {
01673 mw->next = mw1;
01674 break;
01675 }
01676 if( mw1->prev && (!mwIsSafeAddr(mw1->prev, mwDataSize ) || mw1->prev->next != mw1) ) {
01677 mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev );
01678 FLUSH();
01679 goto emergency;
01680 }
01681 }
01682 if( mw1 == NULL ) {
01683 mwWrite("relink: MW-%p not found in reverse chain search\n", mw );
01684 FLUSH();
01685 fails ++;
01686 }
01687 }
01688 else
01689 {
01690 mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw );
01691 if( mw->next != NULL )
01692 {
01693 mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw );
01694 mw->next = NULL;
01695 }
01696 }
01697
01698 if( fails > 1 ) {
01699 mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw );
01700 FLUSH();
01701 goto verifyok;
01702 }
01703
01704
01705 if( mwIsReadAddr( mw->file, 1 ) ) {
01706 ms = mwStatGet( mw->file, -1, 0 );
01707 if( ms == NULL ) mw->file = "<relinked>";
01708 }
01709 mw->check = CHKVAL(mw);
01710 goto verifyok;
01711
01712
01713 emergency:
01714
01715 if( mwHead == NULL && mwTail == NULL )
01716 {
01717 if( mwStatCurAlloc == 0 )
01718 mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line );
01719 else
01720 mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line );
01721 FLUSH();
01722 return 0;
01723 }
01724
01725 mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line );
01726 FLUSH();
01727
01728 if( mwHead == NULL || mwTail == NULL )
01729 {
01730 if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail );
01731 else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead );
01732 }
01733
01734 mw1=NULL;
01735 if( mwHead != NULL )
01736 {
01737 if( !mwIsReadAddr( mwHead, mwDataSize ) || mwHead->check != CHKVAL(mwHead) )
01738 {
01739 mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead );
01740 mwHead = NULL;
01741 goto scan_reverse;
01742 }
01743 if( mwHead->prev != NULL )
01744 {
01745 mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev );
01746 }
01747 for( mw1=mwHead; mw1; mw1=mw1->next )
01748 {
01749 if( mw1->next )
01750 {
01751 if( !mwIsReadAddr(mw1->next,mwDataSize) ||
01752 !mw1->next->check != CHKVAL(mw1) ||
01753 mw1->next->prev != mw1 )
01754 {
01755 mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
01756 mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line );
01757 if( mwIsReadAddr(mw1->next,mwDataSize ) )
01758 {
01759 mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
01760 mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"",
01761 mwIsReadAddr(mw1->file,16)?mw1->file:"<garbage-pointer>", mw1->line );
01762 }
01763 else
01764 {
01765 mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n",
01766 mw1->next );
01767 }
01768 break;
01769 }
01770 }
01771 }
01772 }
01773
01774
01775 scan_reverse:
01776 mw2=NULL;
01777 if( mwTail != NULL )
01778 {
01779 if( !mwIsReadAddr(mwTail,mwDataSize) || mwTail->check != CHKVAL(mwTail) )
01780 {
01781 mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail );
01782 mwTail = NULL;
01783 goto analyze;
01784 }
01785 if( mwTail->next != NULL )
01786 {
01787 mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next );
01788 }
01789 for( mw2=mwTail; mw2; mw2=mw2->prev )
01790 {
01791 if( mw2->prev )
01792 {
01793 if( !mwIsReadAddr(mw2->prev,mwDataSize) ||
01794 !mw2->prev->check != CHKVAL(mw2) ||
01795 mw2->prev->next != mw2 )
01796 {
01797 mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
01798 mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line );
01799 if( mwIsReadAddr(mw2->prev,mwDataSize ) )
01800 {
01801 mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
01802 mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"",
01803 mwIsReadAddr(mw2->file,16)?mw2->file:"<garbage-pointer>", mw2->line );
01804 }
01805 else
01806 {
01807 mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n",
01808 mw2->prev );
01809 }
01810 break;
01811 }
01812 }
01813 }
01814 }
01815
01816 analyze:
01817 if( mwHead == NULL && mwTail == NULL )
01818 {
01819 mwWrite("relink: both head and tail pointers damaged, aborting program\n");
01820 mwFlushW(1);
01821 FLUSH();
01822 abort();
01823 }
01824 if( mwHead == NULL )
01825 {
01826 mwHead = mw2;
01827 mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 );
01828 mw2->prev = NULL;
01829 mw1 = mw2 = NULL;
01830 }
01831 if( mwTail == NULL )
01832 {
01833 mwTail = mw1;
01834 mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 );
01835 mw1->next = NULL;
01836 mw1 = mw2 = NULL;
01837 }
01838 if( mw1 == NULL && mw2 == NULL &&
01839 mwHead->prev == NULL && mwTail->next == NULL ) {
01840 mwWrite("relink: verifying heap integrity...\n" );
01841 FLUSH();
01842 goto verifyok;
01843 }
01844 if( mw1 && mw2 && mw1 != mw2 ) {
01845 mw1->next = mw2;
01846 mw2->prev = mw1;
01847 mwWrite("relink: emergency repairs successful, assessing damage...\n");
01848 FLUSH();
01849 }
01850 else {
01851 mwWrite("relink: heap totally destroyed, aborting program\n");
01852 mwFlushW(1);
01853 FLUSH();
01854 abort();
01855 }
01856
01857
01858
01859 verifyok:
01860 if( !mwIsHeapOK( NULL ) ) {
01861 mwWrite("relink: heap verification FAILS - aborting program\n");
01862 mwFlushW(1);
01863 FLUSH();
01864 abort();
01865 }
01866 for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) {
01867 count ++;
01868 size += (long) mw1->size;
01869 }
01870 if( count == mwNumCurAlloc ) {
01871 mwWrite("relink: successful, ");
01872 if( size == mwStatCurAlloc ) {
01873 mwWrite("no allocations lost\n");
01874 }
01875 else {
01876 if( mw != NULL ) {
01877 mwWrite("size information lost for MW-%p\n", mw);
01878 mw->size = 0;
01879 }
01880 }
01881 }
01882 else {
01883 mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n",
01884 mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size );
01885 return 0;
01886 }
01887
01888 return 1;
01889 }
01890
01891
01892
01893
01894
01895
01896
01897
01898
01899 static int mwIsHeapOK( mwData *includes_mw ) {
01900 int found = 0;
01901 mwData *mw;
01902
01903 for( mw = mwHead; mw; mw=mw->next ) {
01904 if( includes_mw == mw ) found++;
01905 if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
01906 if( mw->prev ) {
01907 if( !mwIsSafeAddr( mw->prev, mwDataSize ) ) return 0;
01908 if( mw==mwHead || mw->prev->next != mw ) return 0;
01909 }
01910 if( mw->next ) {
01911 if( !mwIsSafeAddr( mw->next, mwDataSize ) ) return 0;
01912 if( mw==mwTail || mw->next->prev != mw ) return 0;
01913 }
01914 else if( mw!=mwTail ) return 0;
01915 }
01916
01917 if( includes_mw != NULL && !found ) return 0;
01918
01919 return 1;
01920 }
01921
01922 static int mwIsOwned( mwData* mw, const char *file, int line ) {
01923 int retv;
01924 mwStat *ms;
01925
01926
01927 if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
01928
01929
01930 if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 )
01931 return 0;
01932
01933
01934 if( mw->check != CHKVAL(mw) ) {
01935
01936 if( mwIsHeapOK( mw ) ) {
01937
01938 mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n",
01939 mwCounter, file, line, mw );
01940 mwIncErr();
01941 if( mwIsReadAddr( mw->file, 1 ) ) {
01942 ms = mwStatGet( mw->file, -1, 0 );
01943 if( ms == NULL ) mw->file = "<relinked>";
01944 }
01945 else mw->file = "<unknown>";
01946 mw->size = 0;
01947 mw->check = CHKVAL(mw);
01948 return 1;
01949 }
01950
01951 return 0;
01952 }
01953
01954
01955 if( mw->prev && !mwIsSafeAddr( mw->prev, mwDataSize ) ) mwRelink( mw, file, line );
01956 if( mw->next && !mwIsSafeAddr( mw->next, mwDataSize ) ) mwRelink( mw, file, line );
01957
01958
01959
01960
01961 retv = 0;
01962 if( mw->prev ) { if( mw->prev->next == mw ) retv ++; }
01963 else { if( mwHead == mw ) retv++; }
01964 if( mw->next ) { if( mw->next->prev == mw ) retv ++; }
01965 else { if( mwTail == mw ) retv++; }
01966 if( mw->check == CHKVAL(mw) ) retv ++;
01967 if( retv > 2 ) return 1;
01968
01969
01970
01971 if( !mwIsHeapOK( mw ) ) {
01972 if( mwRelink( mw, file, line ) )
01973 return 1;
01974 }
01975
01976
01977 mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n",
01978 mwCounter, file, line, mw );
01979 mwIncErr();
01980
01981 return 0;
01982 }
01983
01984
01985
01986
01987
01988
01989
01990 static int mwTestBuf( mwData* mw, const char* file, int line ) {
01991 int retv = 0;
01992 char *p;
01993
01994 if( file == NULL ) file = "unknown";
01995
01996 if( !mwIsSafeAddr( mw, mwDataSize + mwOverflowZoneSize ) ) {
01997 mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n",
01998 mwCounter, file, line, mw );
01999 mwIncErr();
02000 return 2;
02001 }
02002
02003 if( mw->check != CHKVAL(mw) ) {
02004 mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n",
02005 mwCounter, file, line );
02006 mwIncErr();
02007 if( !mwRelink( mw, file, line ) ) return 2;
02008 }
02009
02010 if( mw->prev && mw->prev->next != mw ) {
02011 mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n",
02012 mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
02013 mwIncErr();
02014 if( !mwRelink( mw, file, line ) ) retv = 2;
02015 }
02016 if( mw->next && mw->next->prev != mw ) {
02017 mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n",
02018 mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
02019 mwIncErr();
02020 if( !mwRelink( mw, file, line ) ) retv = 2;
02021 }
02022
02023 p = ((char*)mw) + mwDataSize;
02024 if( mwCheckOF( p ) ) {
02025 mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
02026 mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
02027 mwIncErr();
02028 retv = 1;
02029 }
02030 p += mwOverflowZoneSize + mw->size;
02031 if( mwIsReadAddr( p, mwOverflowZoneSize ) && mwCheckOF( p ) ) {
02032 mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
02033 mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
02034 mwIncErr();
02035 retv = 1;
02036 }
02037
02038 return retv;
02039 }
02040
02041 static void mwDefaultOutFunc( int c ) {
02042 if( mwLogR() ) fputc( c, mwLogR() );
02043 }
02044
02045 static void mwWrite( const char *format, ... ) {
02046 int tot, oflow = 0;
02047 va_list mark;
02048 mwAutoInit();
02049 if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
02050 va_start( mark, format );
02051 tot = vsprintf( mwPrintBuf, format, mark );
02052 va_end( mark );
02053 if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; }
02054 for(tot=0;mwPrintBuf[tot];tot++)
02055 (*mwOutFunction)( mwPrintBuf[tot] );
02056 if( oflow ) {
02057 mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 );
02058 FLUSH();
02059 }
02060 return;
02061 }
02062
02063 static void mwLogFile( const char *name ) {
02064 time_t tid;
02065 (void) time( &tid );
02066 if( mwLogR() != NULL ) {
02067 fclose( mwLogR() );
02068 mwLogW( NULL );
02069 }
02070 if( name == NULL ) return;
02071 mwLogW( fopen( name, "a" COMMIT ) );
02072 if( mwLogR() == NULL )
02073 mwWrite( "logfile: failed to open/create file '%s'\n", name );
02074 }
02075
02076
02077
02078
02079
02080
02081
02082 static size_t mwFreeUp( size_t needed, int urgent ) {
02083 void *p;
02084 mwData *mw, *mw2;
02085 char *data;
02086
02087
02088 for(;;) {
02089 if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break;
02090 p = malloc( needed );
02091 if( p == NULL ) continue;
02092 free( p );
02093 return needed;
02094 }
02095
02096
02097 mw = mwHead;
02098 while( mw != NULL ) {
02099 if( !(mw->flag & MW_NML) ) mw = mw->next;
02100 else {
02101 data = ((char*)mw)+mwDataSize+mwOverflowZoneSize;
02102 if( mwTestMem( data, mw->size, MW_VAL_NML ) ) {
02103 mwIncErr();
02104 mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
02105 mw->count, data + mwOverflowZoneSize, mw->file, mw->line );
02106 }
02107 mw2 = mw->next;
02108 mwUnlink( mw, "mwFreeUp", 0 );
02109 free( mw );
02110 mw = mw2;
02111 p = malloc( needed );
02112 if( p == NULL ) continue;
02113 free( p );
02114 return needed;
02115 }
02116 }
02117
02118
02119 if( !urgent ) return 0;
02120
02121
02122 for(;;) {
02123 if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break;
02124 p = malloc( needed );
02125 if( p == NULL ) continue;
02126 free( p );
02127 return needed;
02128 }
02129
02130 return 0;
02131 }
02132
02133 static const void * mwTestMem( const void *p, unsigned len, int c ) {
02134 const unsigned char *ptr;
02135 ptr = (const unsigned char *) p;
02136 while( len-- ) {
02137 if( *ptr != (unsigned char)c ) return (const void*)ptr;
02138 ptr ++;
02139 }
02140 return NULL;
02141 }
02142
02143 static int mwStrCmpI( const char *s1, const char *s2 ) {
02144 if( s1 == NULL || s2 == NULL ) return 0;
02145 while( *s1 ) {
02146 if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; }
02147 return 1;
02148 }
02149 return 0;
02150 }
02151
02152 #define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; }
02153
02154 static int mwTestNow( const char *file, int line, int always_invoked ) {
02155 int retv = 0;
02156 mwData *mw;
02157 char *data;
02158
02159 if( file && !always_invoked )
02160 mwWrite("check: <%ld> %s(%d), checking %s%s%s\n",
02161 mwCounter, file, line,
02162 (mwTestFlags & MW_TEST_CHAIN) ? "chain ": "",
02163 (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "",
02164 (mwTestFlags & MW_TEST_NML) ? "nomansland ": ""
02165 );
02166
02167 if( mwTestFlags & MW_TEST_CHAIN ) {
02168 for( mw = mwHead; mw; mw=mw->next ) {
02169 if( !mwIsSafeAddr(mw, mwDataSize) ) {
02170 AIPH();
02171 mwWrite("check: heap corruption detected\n");
02172 mwIncErr();
02173 return retv + 1;
02174 }
02175 if( mw->prev ) {
02176 if( !mwIsSafeAddr(mw->prev, mwDataSize) ) {
02177 AIPH();
02178 mwWrite("check: heap corruption detected\n");
02179 mwIncErr();
02180 return retv + 1;
02181 }
02182 if( mw==mwHead || mw->prev->next != mw ) {
02183 AIPH();
02184 mwWrite("check: heap chain broken, prev link incorrect\n");
02185 mwIncErr();
02186 retv ++;
02187 }
02188 }
02189 if( mw->next ) {
02190 if( !mwIsSafeAddr(mw->next, mwDataSize) ) {
02191 AIPH();
02192 mwWrite("check: heap corruption detected\n");
02193 mwIncErr();
02194 return retv + 1;
02195 }
02196 if( mw==mwTail || mw->next->prev != mw ) {
02197 AIPH();
02198 mwWrite("check: heap chain broken, next link incorrect\n");
02199 mwIncErr();
02200 retv ++;
02201 }
02202 }
02203 else if( mw!=mwTail ) {
02204 AIPH();
02205 mwWrite("check: heap chain broken, tail incorrect\n");
02206 mwIncErr();
02207 retv ++;
02208 }
02209 }
02210 }
02211 if( mwTestFlags & MW_TEST_ALLOC ) {
02212 for( mw = mwHead; mw; mw=mw->next ) {
02213 if( mwTestBuf( mw, file, line ) ) retv ++;
02214 }
02215 }
02216 if( mwTestFlags & MW_TEST_NML ) {
02217 for( mw = mwHead; mw; mw=mw->next ) {
02218 if( (mw->flag & MW_NML) ) {
02219 data = ((char*)mw)+mwDataSize+mwOverflowZoneSize;
02220 if( mwTestMem( data, mw->size, MW_VAL_NML ) ) {
02221 mwIncErr();
02222 mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
02223 mw->count, data + mwOverflowZoneSize, mw->file, mw->line );
02224 }
02225 }
02226 }
02227 }
02228
02229
02230 if( file && !always_invoked && !retv )
02231 mwWrite("check: <%ld> %s(%d), complete; no errors\n",
02232 mwCounter, file, line );
02233 return retv;
02234 }
02235
02236
02237
02238
02239
02240 static void mwStatReport()
02241 {
02242 mwStat* ms, *ms2;
02243 const char *modname;
02244 int modnamelen;
02245
02246
02247 mwWrite( "\nMemory usage statistics (global):\n" );
02248 mwWrite( " N)umber of allocations made: %ld\n", mwStatNumAlloc );
02249 mwWrite( " L)argest memory usage : %ld\n", mwStatMaxAlloc );
02250 mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc );
02251 mwWrite( " U)nfreed bytes totals : %ld\n", mwStatCurAlloc );
02252 FLUSH();
02253
02254 if( mwStatLevel < 1 ) return;
02255
02256
02257 mwWrite( "\nMemory usage statistics (detailed):\n");
02258 mwWrite( " Module/Line Number Largest Total Unfreed \n");
02259 for( ms=mwStatList; ms; ms=ms->next )
02260 {
02261 if( ms->line == -1 )
02262 {
02263 if( ms->file == NULL || !mwIsReadAddr(ms->file,22) ) modname = "<unknown>";
02264 else modname = ms->file;
02265 modnamelen = strlen(modname);
02266 if( modnamelen > 42 )
02267 {
02268 modname = modname + modnamelen - 42;
02269 }
02270
02271 mwWrite(" %-42s %-8ld %-8ld %-8ld %-8ld\n",
02272 modname, ms->num, ms->max, ms->total, ms->curr );
02273 if( ms->file && mwStatLevel > 1 )
02274 {
02275 for( ms2=mwStatList; ms2; ms2=ms2->next )
02276 {
02277 if( ms2->line!=-1 && ms2->file!=NULL && !mwStrCmpI( ms2->file, ms->file ) )
02278 {
02279 mwWrite( " %-8d %-8ld %-8ld %-8ld %-8ld\n",
02280 ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr );
02281 }
02282 }
02283 }
02284 }
02285 }
02286 }
02287
02288 static mwStat* mwStatGet( const char *file, int line, int makenew ) {
02289 mwStat* ms;
02290
02291 if( mwStatLevel < 2 ) line = -1;
02292
02293 for( ms=mwStatList; ms!=NULL; ms=ms->next ) {
02294 if( line != ms->line ) continue;
02295 if( file==NULL ) {
02296 if( ms->file == NULL ) break;
02297 continue;
02298 }
02299 if( ms->file == NULL ) continue;
02300 if( !strcmp( ms->file, file ) ) break;
02301 }
02302
02303 if( ms != NULL ) return ms;
02304
02305 if( !makenew ) return NULL;
02306
02307 ms = (mwStat*) malloc( sizeof(mwStat) );
02308 if( ms == NULL ) {
02309 if( mwFreeUp( sizeof(mwStat), 0 ) < sizeof(mwStat) ||
02310 (ms=(mwStat*)malloc(sizeof(mwStat))) == NULL ) {
02311 mwWrite("internal: memory low, statistics incomplete for '%s'\n", file );
02312 return NULL;
02313 }
02314 }
02315 ms->file = file;
02316 ms->line = line;
02317 ms->total = 0L;
02318 ms->max = 0L;
02319 ms->num = 0L;
02320 ms->curr = 0L;
02321 ms->next = mwStatList;
02322 mwStatList = ms;
02323 return ms;
02324 }
02325
02326 static void mwStatAlloc( size_t size, const char* file, int line ) {
02327 mwStat* ms;
02328
02329
02330 ms = mwStatGet( file, -1, 1 );
02331 if( ms != NULL ) {
02332 ms->total += (long) size;
02333 ms->curr += (long) size;
02334 ms->num ++;
02335 if( ms->curr > ms->max ) ms->max = ms->curr;
02336 }
02337
02338
02339 if( mwStatLevel > 1 && line != -1 && file ) {
02340 ms = mwStatGet( file, line, 1 );
02341 if( ms != NULL ) {
02342 ms->total += (long) size;
02343 ms->curr += (long) size;
02344 ms->num ++;
02345 if( ms->curr > ms->max ) ms->max = ms->curr;
02346 }
02347 }
02348
02349 }
02350
02351 static void mwStatFree( size_t size, const char* file, int line ) {
02352 mwStat* ms;
02353
02354
02355 ms = mwStatGet( file, -1, 1 );
02356 if( ms != NULL ) ms->curr -= (long) size;
02357
02358
02359 if( mwStatLevel > 1 && line != -1 && file ) {
02360 ms = mwStatGet( file, line, 1 );
02361 if( ms != NULL ) ms->curr -= (long) size;
02362 }
02363 }
02364
02365
02366
02367
02368
02369
02370
02371
02372
02373 static char mwDummy( char c )
02374 {
02375 return c;
02376 }
02377
02378 #ifndef MW_SAFEADDR
02379 #ifdef WIN32
02380 #define MW_SAFEADDR
02381 #define WIN32_LEAN_AND_MEAN
02382 #include <windows.h>
02383 int mwIsReadAddr( const void *p, unsigned len )
02384 {
02385 if( p == NULL ) return 0;
02386 if( IsBadReadPtr(p,len) ) return 0;
02387 return 1;
02388 }
02389 int mwIsSafeAddr( void *p, unsigned len )
02390 {
02391
02392
02393 if( p == NULL ) return 0;
02394 if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) ) return 0;
02395 return 1;
02396 }
02397 #endif
02398 #endif
02399
02400 #ifndef MW_SAFEADDR
02401 #ifdef SIGSEGV
02402 #define MW_SAFEADDR
02403
02404 typedef void (*mwSignalHandlerPtr)( int );
02405 mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0;
02406 jmp_buf mwSIGSEGVjump;
02407 static void mwSIGSEGV( int n );
02408
02409 static void mwSIGSEGV( int n )
02410 {
02411 n = n;
02412 longjmp( mwSIGSEGVjump, 1 );
02413 }
02414
02415 int mwIsReadAddr( const void *p, unsigned len )
02416 {
02417 const char *ptr;
02418
02419 if( p == NULL ) return 0;
02420 if( !len ) return 1;
02421
02422
02423 mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
02424
02425 if( setjmp( mwSIGSEGVjump ) )
02426 {
02427 signal( SIGSEGV, mwOldSIGSEGV );
02428 return 0;
02429 }
02430
02431
02432 ptr = (const char *)p;
02433 ptr += len;
02434
02435
02436
02437
02438
02439
02440 do
02441 {
02442 ptr --;
02443 if( *ptr == 0x7C ) (void) mwDummy( (char)0 );
02444 } while( (const void*) ptr != p );
02445
02446
02447 signal( SIGSEGV, mwOldSIGSEGV );
02448
02449 return 1;
02450 }
02451 int mwIsSafeAddr( void *p, unsigned len )
02452 {
02453 char *ptr;
02454
02455 if( p == NULL ) return 0;
02456 if( !len ) return 1;
02457
02458
02459 mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
02460
02461 if( setjmp( mwSIGSEGVjump ) )
02462 {
02463 signal( SIGSEGV, mwOldSIGSEGV );
02464 return 0;
02465 }
02466
02467
02468 ptr = (char *)p;
02469 ptr += len;
02470
02471
02472
02473
02474
02475
02476 do
02477 {
02478 ptr --;
02479 *ptr = mwDummy( *ptr );
02480 } while( (void*) ptr != p );
02481
02482
02483 signal( SIGSEGV, mwOldSIGSEGV );
02484
02485 return 1;
02486 }
02487 #endif
02488 #endif
02489
02490 #ifndef MW_SAFEADDR
02491 int mwIsReadAddr( const void *p, unsigned len )
02492 {
02493 if( p == NULL ) return 0;
02494 if( len == 0 ) return 1;
02495 return 1;
02496 }
02497 int mwIsSafeAddr( void *p, unsigned len )
02498 {
02499 if( p == NULL ) return 0;
02500 if( len == 0 ) return 1;
02501 return 1;
02502 }
02503 #endif
02504
02505
02506
02507
02508
02509 #if defined(WIN32) || defined(__WIN32__)
02510
02511 static void mwMutexInit( void )
02512 {
02513 mwGlobalMutex = CreateMutex( NULL, FALSE, NULL);
02514 return;
02515 }
02516
02517 static void mwMutexTerm( void )
02518 {
02519 CloseHandle( mwGlobalMutex );
02520 return;
02521 }
02522
02523 static void mwMutexLock( void )
02524 {
02525 if( WaitForSingleObject(mwGlobalMutex, 1000 ) == WAIT_TIMEOUT )
02526 {
02527 mwWrite( "mwMutexLock: timed out, possible deadlock\n" );
02528 }
02529 return;
02530 }
02531
02532 static void mwMutexUnlock( void )
02533 {
02534 ReleaseMutex( mwGlobalMutex );
02535 return;
02536 }
02537
02538 #endif
02539
02540 #if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
02541
02542 static void mwMutexInit( void )
02543 {
02544 pthread_mutex_init( &mwGlobalMutex, NULL );
02545 return;
02546 }
02547
02548 static void mwMutexTerm( void )
02549 {
02550 pthread_mutex_destroy( &mwGlobalMutex );
02551 return;
02552 }
02553
02554 static void mwMutexLock( void )
02555 {
02556 pthread_mutex_lock(&mwGlobalMutex);
02557 return;
02558 }
02559
02560 static void mwMutexUnlock( void )
02561 {
02562 pthread_mutex_unlock(&mwGlobalMutex);
02563 return;
02564 }
02565
02566 #endif
02567
02568
02569
02570
02571
02572 #if 0
02573
02574 #ifdef __cplusplus
02575 #ifndef MEMWATCH_NOCPP
02576
02577 int mwNCur = 0;
02578 const char *mwNFile = NULL;
02579 int mwNLine = 0;
02580
02581 class MemWatch {
02582 public:
02583 MemWatch();
02584 ~MemWatch();
02585 };
02586
02587 MemWatch::MemWatch() {
02588 if( mwInited ) return;
02589 mwUseAtexit = 0;
02590 mwInit();
02591 }
02592
02593 MemWatch::~MemWatch() {
02594 if( mwUseAtexit ) return;
02595 mwTerm();
02596 }
02597
02598
02599
02600
02601
02602 void* operator new( unsigned size ) {
02603 mwNCur = 0;
02604 return mwMalloc( size, "<unknown>", 0 );
02605 }
02606
02607
02608
02609
02610 void* operator new( unsigned size, const char *file, int line ) {
02611 mwNCur = 0;
02612 return mwMalloc( size, file, line );
02613 }
02614
02615
02616
02617
02618
02619 void* operator new[] ( unsigned size, const char *file, int line ) {
02620 mwNCur = 0;
02621 return mwMalloc( size, file, line );
02622 }
02623
02624
02625
02626
02627
02628
02629
02630
02631 void operator delete( void *p ) {
02632 if( p == NULL ) return;
02633 if( !mwInited ) {
02634 free( p );
02635 return;
02636 }
02637 if( mwNCur ) {
02638 mwFree( p, mwNFile, mwNLine );
02639 mwNCur = 0;
02640 return;
02641 }
02642 mwFree_( p );
02643 }
02644
02645 void operator delete[]( void *p ) {
02646 if( p == NULL ) return;
02647 if( !mwInited ) {
02648 free( p );
02649 return;
02650 }
02651 if( mwNCur ) {
02652 mwFree( p, mwNFile, mwNLine );
02653 mwNCur = 0;
02654 return;
02655 }
02656 mwFree_( p );
02657 }
02658
02659 #endif
02660 #endif
02661
02662 #endif
02663
02664