📄 memwatch.c
字号:
mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail ); mwTail = NULL; goto analyze; } if( mwTail->next != NULL ) { mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next ); } for( mw2=mwTail; mw2; mw2=mw2->prev ) { if( mw2->prev ) { if( !mwIsReadAddr(mw2->prev,mwDataSize) || !mw2->prev->check != CHKVAL(mw2) || mw2->prev->next != mw2 ) { mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line ); if( mwIsReadAddr(mw2->prev,mwDataSize ) ) { mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mwIsReadAddr(mw2->file,16)?mw2->file:"<garbage-pointer>", mw2->line ); } else { mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n", mw2->prev ); } break; } } } }analyze: if( mwHead == NULL && mwTail == NULL ) { mwWrite("relink: both head and tail pointers damaged, aborting program\n"); mwFlushW(1); FLUSH(); abort(); } if( mwHead == NULL ) { mwHead = mw2; mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 ); mw2->prev = NULL; mw1 = mw2 = NULL; } if( mwTail == NULL ) { mwTail = mw1; mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 ); mw1->next = NULL; mw1 = mw2 = NULL; } if( mw1 == NULL && mw2 == NULL && mwHead->prev == NULL && mwTail->next == NULL ) { mwWrite("relink: verifying heap integrity...\n" ); FLUSH(); goto verifyok; } if( mw1 && mw2 && mw1 != mw2 ) { mw1->next = mw2; mw2->prev = mw1; mwWrite("relink: emergency repairs successful, assessing damage...\n"); FLUSH(); } else { mwWrite("relink: heap totally destroyed, aborting program\n"); mwFlushW(1); FLUSH(); abort(); } /* Verify by checking that the number of active allocations */ /* match the number of entries in the chain */verifyok: if( !mwIsHeapOK( NULL ) ) { mwWrite("relink: heap verification FAILS - aborting program\n"); mwFlushW(1); FLUSH(); abort(); } for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) { count ++; size += (long) mw1->size; } if( count == mwNumCurAlloc ) { mwWrite("relink: successful, "); if( size == mwStatCurAlloc ) { mwWrite("no allocations lost\n"); } else { if( mw != NULL ) { mwWrite("size information lost for MW-%p\n", mw); mw->size = 0; } } } else { mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n", mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size ); return 0; } return 1; }/*** If mwData* is NULL:** Returns 0 if heap chain is broken.** Returns 1 if heap chain is intact.** If mwData* is not NULL:** Returns 0 if mwData* is missing or if chain is broken.** Returns 1 if chain is intact and mwData* is found.*/static int mwIsHeapOK( mwData *includes_mw ) { int found = 0; mwData *mw; for( mw = mwHead; mw; mw=mw->next ) { if( includes_mw == mw ) found++; if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0; if( mw->prev ) { if( !mwIsSafeAddr( mw->prev, mwDataSize ) ) return 0; if( mw==mwHead || mw->prev->next != mw ) return 0; } if( mw->next ) { if( !mwIsSafeAddr( mw->next, mwDataSize ) ) return 0; if( mw==mwTail || mw->next->prev != mw ) return 0; } else if( mw!=mwTail ) return 0; } if( includes_mw != NULL && !found ) return 0; return 1; }static int mwIsOwned( mwData* mw, const char *file, int line ) { int retv; mwStat *ms; /* see if the address is legal according to OS */ if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0; /* make sure we have _anything_ allocated */ if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 ) return 0; /* calculate checksum */ if( mw->check != CHKVAL(mw) ) { /* may be damaged checksum, see if block is in heap */ if( mwIsHeapOK( mw ) ) { /* damaged checksum, repair it */ mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n", mwCounter, file, line, mw ); mwIncErr(); if( mwIsReadAddr( mw->file, 1 ) ) { ms = mwStatGet( mw->file, -1, 0 ); if( ms == NULL ) mw->file = "<relinked>"; } else mw->file = "<unknown>"; mw->size = 0; mw->check = CHKVAL(mw); return 1; } /* no, it's just some garbage data */ return 0; } /* check that the non-NULL pointers are safe */ if( mw->prev && !mwIsSafeAddr( mw->prev, mwDataSize ) ) mwRelink( mw, file, line ); if( mw->next && !mwIsSafeAddr( mw->next, mwDataSize ) ) mwRelink( mw, file, line ); /* safe address, checksum OK, proceed with heap checks */ /* see if the block is in the heap */ retv = 0; if( mw->prev ) { if( mw->prev->next == mw ) retv ++; } else { if( mwHead == mw ) retv++; } if( mw->next ) { if( mw->next->prev == mw ) retv ++; } else { if( mwTail == mw ) retv++; } if( mw->check == CHKVAL(mw) ) retv ++; if( retv > 2 ) return 1; /* block not in heap, check heap for corruption */ if( !mwIsHeapOK( mw ) ) { if( mwRelink( mw, file, line ) ) return 1; } /* unable to repair */ mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n", mwCounter, file, line, mw ); mwIncErr(); return 0; }/*** mwTestBuf:** Checks a buffers links and pre/postfixes.** Writes errors found to the log.** Returns zero if no errors found.*/static int mwTestBuf( mwData* mw, const char* file, int line ) { int retv = 0; char *p; if( file == NULL ) file = "unknown"; if( !mwIsSafeAddr( mw, mwDataSize + mwOverflowZoneSize ) ) { mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n", mwCounter, file, line, mw ); mwIncErr(); return 2; } if( mw->check != CHKVAL(mw) ) { mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n", mwCounter, file, line ); mwIncErr(); if( !mwRelink( mw, file, line ) ) return 2; } if( mw->prev && mw->prev->next != mw ) { mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n", mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); mwIncErr(); if( !mwRelink( mw, file, line ) ) retv = 2; } if( mw->next && mw->next->prev != mw ) { mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n", mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); mwIncErr(); if( !mwRelink( mw, file, line ) ) retv = 2; } p = ((char*)mw) + mwDataSize; if( mwCheckOF( p ) ) { mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); mwIncErr(); retv = 1; } p += mwOverflowZoneSize + mw->size; if( mwIsReadAddr( p, mwOverflowZoneSize ) && mwCheckOF( p ) ) { mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); mwIncErr(); retv = 1; } return retv; }static void mwDefaultOutFunc( int c ) { if( mwLogR() ) fputc( c, mwLogR() ); }static void mwWrite( const char *format, ... ) { int tot, oflow = 0; va_list mark; mwAutoInit(); 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 ) { mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 ); FLUSH(); } return; }static void mwLogFile( const char *name ) { time_t tid; (void) time( &tid ); if( mwLogR() != NULL ) { fclose( mwLogR() ); mwLogW( NULL ); } if( name == NULL ) return; mwLogW( fopen( name, "a" COMMIT ) ); if( mwLogR() == NULL ) mwWrite( "logfile: failed to open/create file '%s'\n", name ); }/*** Try to free NML memory until a contiguous allocation of** 'needed' bytes can be satisfied. If this is not enough** and the 'urgent' parameter is nonzero, grabbed memory is** also freed.*/static size_t mwFreeUp( size_t needed, int urgent ) { void *p; mwData *mw, *mw2; char *data; /* free grabbed NML memory */ for(;;) { if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break; p = malloc( needed ); if( p == NULL ) continue; free( p ); return needed; } /* free normal NML memory */ mw = mwHead; while( mw != NULL ) { if( !(mw->flag & MW_NML) ) mw = mw->next; else { data = ((char*)mw)+mwDataSize+mwOverflowZoneSize; if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { mwIncErr(); mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", mw->count, data + mwOverflowZoneSize, mw->file, mw->line ); } mw2 = mw->next; mwUnlink( mw, "mwFreeUp", 0 ); free( mw ); mw = mw2; p = malloc( needed ); if( p == NULL ) continue; free( p ); return needed; } } /* if not urgent (for internal purposes), fail */ if( !urgent ) return 0; /* free grabbed memory */ for(;;) { if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break; p = malloc( needed ); if( p == NULL ) continue; free( p ); return needed; } return 0; }static const void * mwTestMem( const void *p, unsigned len, int c ) { const unsigned char *ptr; ptr = (const unsigned char *) p; while( len-- ) { if( *ptr != (unsigned char)c ) return (const void*)ptr; ptr ++; } return NULL; }static int mwStrCmpI( const char *s1, const char *s2 ) { if( s1 == NULL || s2 == NULL ) return 0; while( *s1 ) { if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; } return 1; } return 0; }#define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; }static int mwTestNow( const char *file, int line, int always_invoked ) { int retv = 0; mwData *mw; char *data; if( file && !always_invoked ) mwWrite("check: <%ld> %s(%d), checking %s%s%s\n", mwCounter, file, line, (mwTestFlags & MW_TEST_CHAIN) ? "chain ": "", (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "", (mwTestFlags & MW_TEST_NML) ? "nomansland ": "" ); if( mwTestFlags & MW_TEST_CHAIN ) { for( mw = mwHead; mw; mw=mw->next ) { if( !mwIsSafeAddr(mw, mwDataSize) ) { AIPH(); mwWrite("check: heap corruption detected\n"); mwIncErr(); return retv + 1; } if( mw->prev ) { if( !mwIsSafeAddr(mw->prev, mwDataSize) ) { AIPH(); mwWrite("check: heap corruption detected\n"); mwIncErr(); return retv + 1; } if( mw==mwHead || mw->prev->next != mw ) { AIPH(); mwWrite("check: heap chain broken, prev link incorrect\n"); mwIncErr(); retv ++; } } if( mw->next ) { if( !mwIsSafeAddr(mw->next, mwDataSize) ) { AIPH(); mwWrite("check: heap corruption detected\n"); mwIncErr(); return retv + 1; } if( mw==mwTail || mw->next->prev != mw ) { AIPH(); mwWrite("check: heap chain broken, next link incorrect\n"); mwIncErr(); retv ++; } } else if( mw!=mwTail ) { AIPH(); mwWrite("check: heap chain broken, tail incorrect\n"); mwIncErr(); retv ++; } } } if( mwTestFlags & MW_TEST_ALLOC ) { for( mw = mwHead; mw; mw=mw->next ) { if( mwTestBuf( mw, file, line ) ) retv ++; } } if( mwTestFlags & MW_TEST_NML ) { for( mw = mwHead; mw; mw=mw->next ) { if( (mw->flag & MW_NML) ) { data = ((char*)mw)+mwDataSize+mwOverflowZoneSize; if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { mwIncErr(); mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", mw-
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -