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