📄 memwatch.c
字号:
while( mwDataSize % mwROUNDALLOC ) mwDataSize ++; /* write informational header if needed */ if( !mwInfoWritten ) { mwInfoWritten = 1; (void) time( &tid ); mwWrite( "\n=============" " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh " "=============\n"); mwWrite( "\nStarted at %s\n", ctime( &tid ) );/**************************************************************** Generic */ mwWrite( "Modes: " );#ifdef mwNew mwWrite( "C++ " );#endif /* mwNew */#ifdef __STDC__ mwWrite( "__STDC__ " );#endif /* __STDC__ */#ifdef mw16BIT mwWrite( "16-bit " );#endif#ifdef mw32BIT mwWrite( "32-bit " );#endif#ifdef mw64BIT mwWrite( "64-bit " );#endif mwWrite( "mwDWORD==(" mwDWORD_DEFINED ")\n" ); mwWrite( "mwROUNDALLOC==%d sizeof(mwData)==%d mwDataSize==%d\n", mwROUNDALLOC, sizeof(mwData), mwDataSize );/**************************************************************** Generic *//************************************************************ Microsoft C */#ifdef _MSC_VER mwWrite( "Compiled using Microsoft C" CPPTEXT " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 );#endif /* _MSC_VER *//************************************************************ Microsoft C *//************************************************************** Borland C */#ifdef __BORLANDC__ mwWrite( "Compiled using Borland C"#ifdef __cplusplus "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 );#else " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 );#endif /* __cplusplus */#endif /* __BORLANDC__ *//************************************************************** Borland C *//************************************************************** Watcom C */#ifdef __WATCOMC__ mwWrite( "Compiled using Watcom C %d.%02d ", __WATCOMC__/100, __WATCOMC__%100 );#ifdef __FLAT__ mwWrite( "(32-bit flat model)" );#endif /* __FLAT__ */ mwWrite( "\n" );#endif /* __WATCOMC__ *//************************************************************** Watcom C */ mwWrite( "\n" ); FLUSH(); } if( mwUseAtexit ) (void) atexit( mwAbort ); return; }void mwAbort( void ) { mwData *mw; mwMarker *mrk; char *data; time_t tid; int c, i, j; int errors; tid = time( NULL ); mwWrite( "\nStopped at %s\n", ctime( &tid) ); if( !mwInited ) mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" ); /* release the grab list */ mwDropAll(); /* report mwMarked items */ while( mwFirstMark ) { mrk = mwFirstMark->next; mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text ); free( mwFirstMark->text ); free( mwFirstMark ); mwFirstMark = mrk; mwErrors ++; } /* release all still allocated memory */ errors = 0; while( mwHead != NULL && errors < 3 ) { if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) { if( errors < 3 ) { errors ++; mwWrite( "internal: NML/unfreed scan restarting\n" ); FLUSH(); mwHead = mwHead; continue; } mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" ); FLUSH(); break; } mwFlushW(0); if( !(mwHead->flag & MW_NML) ) { mwErrors++; data = ((char*)mwHead)+mwDataSize; mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ", mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+mwOverflowZoneSize ); if( mwCheckOF( data ) ) { mwWrite( "[underflowed] "); FLUSH(); } if( mwCheckOF( (data+mwOverflowZoneSize+mwHead->size) ) ) { mwWrite( "[overflowed] "); FLUSH(); } mwWrite( " \t{" ); j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size; for( i=0;i<16;i++ ) { if( i<j ) mwWrite( "%02X ", (unsigned char) *(data+mwOverflowZoneSize+i) ); else mwWrite( ".. " ); } for( i=0;i<j;i++ ) { c = *(data+mwOverflowZoneSize+i); if( c < 32 || c > 126 ) c = '.'; mwWrite( "%c", c ); } mwWrite( "}\n" ); mw = mwHead; mwUnlink( mw, __FILE__, __LINE__ ); free( mw ); } else { data = ((char*)mwHead) + mwDataSize + mwOverflowZoneSize; if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) { mwErrors++; mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", mwHead->count, data + mwOverflowZoneSize, mwHead->file, mwHead->line ); FLUSH(); } mwNmlNumAlloc --; mwNmlCurAlloc -= mwHead->size; mw = mwHead; mwUnlink( mw, __FILE__, __LINE__ ); free( mw ); } } if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc ); if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc ); /* report statistics */ mwStatReport(); FLUSH(); mwInited = 0; mwHead = mwTail = NULL; if( mwErrors ) fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors); mwLogFile( NULL ); mwErrors = 0; MW_MUTEX_TERM(); }void mwTerm( void ) { if( mwInited == 1 ) { mwAbort(); return; } if( !mwInited ) mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n"); else mwInited --; }void mwStatistics( int level ){ mwAutoInit(); if( level<0 ) level=0; if( mwStatLevel != level ) { mwWrite( "statistics: now collecting on a %s basis\n", level<1?"global":(level<2?"module":"line") ); mwStatLevel = level; }}void mwAutoCheck( int onoff ) { mwAutoInit(); mwTestAlways = onoff; if( onoff ) mwTestFlags = MW_TEST_ALL; }void mwSetOutFunc( void (*func)(int) ) { mwAutoInit(); mwOutFunction = func; }static void mwWriteOF( void *p ){ int i; unsigned char *ptr; ptr = (unsigned char*) p; for( i=0; i<mwOverflowZoneSize; i++ ) { *(ptr+i) = mwOverflowZoneTemplate[i%8]; } return;}static int mwCheckOF( const void *p ){ int i; const unsigned char *ptr; ptr = (const unsigned char *) p; for( i=0; i<mwOverflowZoneSize; i++ ) { if( *(ptr+i) != mwOverflowZoneTemplate[i%8] ) return 1; /* errors found */ } return 0; /* no errors */}int mwTest( const char *file, int line, int items ) { mwAutoInit(); mwTestFlags = items; return mwTestNow( file, line, 0 ); }/*** Returns zero if there are no errors.** Returns nonzero if there are errors.*/int mwTestBuffer( const char *file, int line, void *p ) { mwData* mw; mwAutoInit(); /* do the quick ownership test */ mw = (mwData*) mwBUFFER_TO_MW( p ); if( mwIsOwned( mw, file, line ) ) { return mwTestBuf( mw, file, line ); } return 1; }void mwBreakOut( const char* cause ) { fprintf(mwSTDERR, "breakout: %s\n", cause); mwWrite("breakout: %s\n", cause ); return; }/*** 981217 JLI: is it possible that ->next is not always set?*/void * mwMark( void *p, const char *desc, const char *file, unsigned line ) { mwMarker *mrk; unsigned n, isnew; char *buf; int tot, oflow = 0; char wherebuf[128]; mwAutoInit(); TESTS(NULL,0); if( desc == NULL ) desc = "unknown"; if( file == NULL ) file = "unknown"; tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line ); if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; } if( p == NULL ) { mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc ); return p; } if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) ) { mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n", file, line, mwFirstMark, desc ); return p; } for( mrk=mwFirstMark; mrk; mrk=mrk->next ) { if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) ) { mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n", file, line, mrk, mrk->next, desc ); return p; } if( mrk->host == p ) break; } if( mrk == NULL ) { isnew = 1; mrk = (mwMarker*) malloc( sizeof( mwMarker ) ); if( mrk == NULL ) { mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); return p; } mrk->next = NULL; n = 0; } else { isnew = 0; n = strlen( mrk->text ); } n += strlen( wherebuf ); buf = (char*) malloc( n+3 ); if( buf == NULL ) { if( isnew ) free( mrk ); mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); return p; } if( isnew ) { memcpy( buf, wherebuf, n+1 ); mrk->next = mwFirstMark; mrk->host = p; mrk->text = buf; mrk->level = 1; mwFirstMark = mrk; } else { strcpy( buf, mrk->text ); strcat( buf, ", " ); strcat( buf, wherebuf ); free( mrk->text ); mrk->text = buf; mrk->level ++; } if( oflow ) { mwIncErr(); mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); } return p; }void* mwUnmark( void *p, const char *file, unsigned line ) { mwMarker *mrk, *prv; mrk = mwFirstMark; prv = NULL; while( mrk ) { if( mrk->host == p ) { if( mrk->level < 2 ) { if( prv ) prv->next = mrk->next; else mwFirstMark = mrk->next; free( mrk->text ); free( mrk ); return p; } mrk->level --; return p; } prv = mrk; mrk = mrk->next; } mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p ); return p; }/************************************************************************* Abort/Retry/Ignore handlers***********************************************************************/static int mwARI( const char *estr ) { char inbuf[81]; int c; fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr); (void) fgets(inbuf,sizeof(inbuf),stdin); for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ; c = inbuf[c]; if( c == 'R' || c == 'r' ) { mwBreakOut( estr ); return MW_ARI_RETRY; } if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE; return MW_ARI_ABORT; }/* standard ARI handler (exported) */int mwAriHandler( const char *estr ) { mwAutoInit(); return mwARI( estr ); }/* used to set the ARI function */void mwSetAriFunc( int (*func)(const char *) ) { mwAutoInit(); mwAriFunction = func; }/************************************************************************* Allocation handlers***********************************************************************/void* mwMalloc( size_t size, const char* file, int line) { size_t needed; mwData *mw; char *ptr; void *p; mwAutoInit(); MW_MUTEX_LOCK(); TESTS(file,line); mwCounter ++; needed = mwDataSize + mwOverflowZoneSize*2 + size; if( needed < size ) { /* theoretical case: req size + mw overhead exceeded size_t limits */ return NULL; } /* if this allocation would violate the limit, fail it */ if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) { mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc ); mwIncErr(); FLUSH(); MW_MUTEX_UNLOCK(); return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -