📄 memwatch.c
字号:
/* stupid compilers from squeaking about differing return modes. */ /* Smart compilers instead say 'code unreachable...' */ /*lint -save -e527 */ return 0; /*lint -restore */ }void mwTrace( const char *format, ... ) { int tot, oflow = 0; va_list mark; mwAutoInit(); MW_MUTEX_LOCK(); TESTS(NULL,0); if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; va_start( mark, format ); tot = vsprintf( mwPrintBuf, format, mark ); va_end( mark ); if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } for(tot=0;mwPrintBuf[tot];tot++) (*mwOutFunction)( mwPrintBuf[tot] ); if( oflow ) { mwIncErr(); mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); } FLUSH(); MW_MUTEX_UNLOCK(); }/************************************************************************* Grab & Drop***********************************************************************/unsigned mwGrab( unsigned kb ) { TESTS(NULL,0); return mwGrab_( kb, MW_VAL_GRB, 0 ); }unsigned mwDrop( unsigned kb ) { TESTS(NULL,0); return mwDrop_( kb, MW_VAL_GRB, 0 ); }static void mwDropAll() { TESTS(NULL,0); (void) mwDrop_( 0, MW_VAL_GRB, 0 ); (void) mwDrop_( 0, MW_VAL_NML, 0 ); if( mwGrabList != NULL ) mwWrite( "internal: the grab list is not empty after mwDropAll()\n"); }static const char *mwGrabType( int type ) { switch( type ) { case MW_VAL_GRB: return "grabbed"; case MW_VAL_NML: return "no-mans-land"; default: /* do nothing */ ; } return "<unknown type>"; }static unsigned mwGrab_( unsigned kb, int type, int silent ) { unsigned i = kb; mwGrabData *gd; if( !kb ) i = kb = 65000U; for(;kb;kb--) { if( mwUseLimit && (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) { if( !silent ) { mwWrite("grabbed: all allowed memory to %s (%u kb)\n", mwGrabType(type), i-kb); FLUSH(); } return i-kb; } gd = (mwGrabData*) malloc( sizeof(mwGrabData) ); if( gd == NULL ) { if( !silent ) { mwWrite("grabbed: all available memory to %s (%u kb)\n", mwGrabType(type), i-kb); FLUSH(); } return i-kb; } mwGrabSize += (long) sizeof(mwGrabData); gd->next = mwGrabList; memset( gd->blob, type, sizeof(gd->blob) ); gd->type = type; mwGrabList = gd; } if( !silent ) { mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) ); FLUSH(); } return i; }static unsigned mwDrop_( unsigned kb, int type, int silent ) { unsigned i = kb; mwGrabData *gd,*tmp,*pr; const void *p; if( mwGrabList == NULL && kb == 0 ) return 0; if( !kb ) i = kb = 60000U; pr = NULL; gd = mwGrabList; for(;kb;) { if( gd == NULL ) { if( i-kb > 0 && !silent ) { mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb); FLUSH(); } return i-kb; } if( gd->type == type ) { if( pr ) pr->next = gd->next; kb --; tmp = gd; if( mwGrabList == gd ) mwGrabList = gd->next; gd = gd->next; p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type ); if( p != NULL ) { mwWrite( "wild pointer: <%ld> %s memory hit at %p\n", mwCounter, mwGrabType(type), p ); FLUSH(); } mwGrabSize -= (long) sizeof(mwGrabData); free( tmp ); } else { pr = gd; gd = gd->next; } } if( !silent ) { mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) ); FLUSH(); } return i; }/************************************************************************* No-Mans-Land***********************************************************************/void mwNoMansLand( int level ) { mwAutoInit(); TESTS(NULL,0); switch( level ) { case MW_NML_NONE: (void) mwDrop_( 0, MW_VAL_NML, 0 ); break; case MW_NML_FREE: break; case MW_NML_ALL: (void) mwGrab_( 0, MW_VAL_NML, 0 ); break; default: return; } mwNML = level; }/************************************************************************* Static functions***********************************************************************/static void mwAutoInit( void ){ if( mwInited ) return; mwUseAtexit = 1; mwInit(); return;}static FILE *mwLogR() { if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog; if( mwLog == mwLogB1 ) mwLogB2 = mwLog; if( mwLog == mwLogB2 ) mwLogB1 = mwLog; if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1; if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) { mwWrite("internal: log file handle damaged and recovered\n"); FLUSH(); return mwLog; } fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" ); mwLog = mwLogB1 = mwLogB2 = mwSTDERR; return mwSTDERR; }static void mwLogW( FILE *p ) { mwLog = mwLogB1 = mwLogB2 = p; }static int mwFlushR() { if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing; if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing; if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing; if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1; if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) { mwWrite("internal: flushing flag damaged and recovered\n"); FLUSH(); return mwFlushing; } mwWrite("internal: flushing flag destroyed, so set to true\n"); mwFlushing = mwFlushingB1 = mwFlushingB2 = 1; return 1; }static void mwFlushW( int n ) { mwFlushing = mwFlushingB1 = mwFlushingB2 = n; }static void mwIncErr() { mwErrors++; mwFlushW( mwFlushR()+1 ); FLUSH(); }static void mwFlush() { if( mwLogR() == NULL ) return;#ifdef MW_FLUSH fflush( mwLogR() );#else if( mwFlushR() ) fflush( mwLogR() );#endif return; }static void mwUnlink( mwData* mw, const char* file, int line ) { if( mw->prev == NULL ) { if( mwHead != mw ) mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n", mwCounter, file, line, mw ); mwHead = mw->next; } else { if( mw->prev->next != mw ) mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n", mwCounter, file, line, mw ); else mw->prev->next = mw->next; } if( mw->next == NULL ) { if( mwTail != mw ) mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n", mwCounter, file, line, mw ); mwTail = mw->prev; } else { if( mw->next->prev != mw ) mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n", mwCounter, file, line, mw ); else mw->next->prev = mw->prev; } }/*** Relinking tries to repair a damaged mw block.** Returns nonzero if it thinks it successfully** repaired the heap chain.*/static int mwRelink( mwData* mw, const char* file, int line ) { int fails; mwData *mw1, *mw2; long count, size; mwStat *ms; if( file == NULL ) file = "unknown"; if( mw == NULL ) { mwWrite("relink: cannot repair MW at NULL\n"); FLUSH(); goto emergency; } if( !mwIsSafeAddr(mw, mwDataSize) ) { mwWrite("relink: MW-%p is a garbage pointer\n", mw); FLUSH(); goto emergency; } mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw ); FLUSH(); fails = 0; /* Repair from head */ if( mwHead != mw ) { if( !mwIsSafeAddr( mwHead, mwDataSize ) ) { mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw ); FLUSH(); goto emergency; } for( mw1=mwHead; mw1; mw1=mw1->next ) { if( mw1->next == mw ) { mw->prev = mw1; break; } if( mw1->next && ( !mwIsSafeAddr(mw1->next, mwDataSize ) || mw1->next->prev != mw1) ) { mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next ); FLUSH(); goto emergency; } } if( mw1 == NULL ) { mwWrite("relink: MW-%p not found in forward chain search\n", mw ); FLUSH(); fails ++; } } else { mwWrite( "relink: MW-%p is the head (first) allocation\n", mw ); if( mw->prev != NULL ) { mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw ); mw->prev = NULL; } } /* Repair from tail */ if( mwTail != mw ) { if( !mwIsSafeAddr( mwTail, mwDataSize ) ) { mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw ); FLUSH(); goto emergency; } for( mw1=mwTail; mw1; mw1=mw1->prev ) { if( mw1->prev == mw ) { mw->next = mw1; break; } if( mw1->prev && (!mwIsSafeAddr(mw1->prev, mwDataSize ) || mw1->prev->next != mw1) ) { mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev ); FLUSH(); goto emergency; } } if( mw1 == NULL ) { mwWrite("relink: MW-%p not found in reverse chain search\n", mw ); FLUSH(); fails ++; } } else { mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw ); if( mw->next != NULL ) { mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw ); mw->next = NULL; } } if( fails > 1 ) { mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw ); FLUSH(); goto verifyok; } /* restore MW info where possible */ if( mwIsReadAddr( mw->file, 1 ) ) { ms = mwStatGet( mw->file, -1, 0 ); if( ms == NULL ) mw->file = "<relinked>"; } mw->check = CHKVAL(mw); goto verifyok; /* Emergency repair */ emergency: if( mwHead == NULL && mwTail == NULL ) { if( mwStatCurAlloc == 0 ) mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line ); else mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line ); FLUSH(); return 0; } mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line ); FLUSH(); if( mwHead == NULL || mwTail == NULL ) { if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail ); else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead ); } mw1=NULL; if( mwHead != NULL ) { if( !mwIsReadAddr( mwHead, mwDataSize ) || mwHead->check != CHKVAL(mwHead) ) { mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead ); mwHead = NULL; goto scan_reverse; } if( mwHead->prev != NULL ) { mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev ); } for( mw1=mwHead; mw1; mw1=mw1->next ) { if( mw1->next ) { if( !mwIsReadAddr(mw1->next,mwDataSize) || !mw1->next->check != CHKVAL(mw1) || mw1->next->prev != mw1 ) { mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line ); if( mwIsReadAddr(mw1->next,mwDataSize ) ) { mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mwIsReadAddr(mw1->file,16)?mw1->file:"<garbage-pointer>", mw1->line ); } else { mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n", mw1->next ); } break; } } } }scan_reverse: mw2=NULL; if( mwTail != NULL ) { if( !mwIsReadAddr(mwTail,mwDataSize) || mwTail->check != CHKVAL(mwTail) ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -