📄 memwatch.c
字号:
} mw = (mwData*) malloc( needed ); if( mw == NULL ) { if( mwFreeUp(needed,0) >= needed ) { mw = (mwData*) malloc(needed); if( mw == NULL ) { mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed ); mwIncErr(); FLUSH(); } } if( mw == NULL ) { mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n", mwCounter, file, line, (long)size, mwStatCurAlloc ); mwIncErr(); FLUSH(); MW_MUTEX_UNLOCK(); return NULL; } } mw->count = mwCounter; mw->prev = NULL; mw->next = mwHead; mw->file = file; mw->size = size; mw->line = line; mw->flag = 0; mw->check = CHKVAL(mw); if( mwHead ) mwHead->prev = mw; mwHead = mw; if( mwTail == NULL ) mwTail = mw; ptr = ((char*)mw) + mwDataSize; mwWriteOF( ptr ); /* '*(long*)ptr = PRECHK;' */ ptr += mwOverflowZoneSize; p = ptr; memset( ptr, MW_VAL_NEW, size ); ptr += size; mwWriteOF( ptr ); /* '*(long*)ptr = POSTCHK;' */ mwNumCurAlloc ++; mwStatCurAlloc += (long) size; mwStatTotAlloc += (long) size; if( mwStatCurAlloc > mwStatMaxAlloc ) mwStatMaxAlloc = mwStatCurAlloc; mwStatNumAlloc ++; if( mwStatLevel ) mwStatAlloc( size, file, line ); MW_MUTEX_UNLOCK(); return p; }void* mwRealloc( void *p, size_t size, const char* file, int line) { int oldUseLimit, i; mwData *mw; char *ptr; mwAutoInit(); if( p == NULL ) return mwMalloc( size, file, line ); if( size == 0 ) { mwFree( p, file, line ); return NULL; } MW_MUTEX_LOCK(); /* do the quick ownership test */ mw = (mwData*) mwBUFFER_TO_MW( p ); if( mwIsOwned( mw, file, line ) ) { /* if the buffer is an NML, treat this as a double-free */ if( mw->flag & MW_NML ) { mwIncErr(); if( *((unsigned char*)(mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML ) { mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", mwCounter, file, line, mw ); } goto check_dbl_free; } /* if this allocation would violate the limit, fail it */ if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) { TESTS(file,line); mwCounter ++; mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc ); mwIncErr(); FLUSH(); MW_MUTEX_UNLOCK(); return NULL; } /* fake realloc operation */ oldUseLimit = mwUseLimit; mwUseLimit = 0; ptr = (char*) mwMalloc( size, file, line ); if( ptr != NULL ) { if( size < mw->size ) memcpy( ptr, p, size ); else memcpy( ptr, p, mw->size ); mwFree( p, file, line ); } mwUseLimit = oldUseLimit; MW_MUTEX_UNLOCK(); return (void*) ptr; } /* Unknown pointer! */ /* using free'd pointer? */check_dbl_free: for(i=0;i<MW_FREE_LIST;i++) { if( mwLastFree[i] == p ) { mwIncErr(); mwWrite( "realloc: <%ld> %s(%d), %p was" " freed from %s(%d)\n", mwCounter, file, line, p, mwLFfile[i], mwLFline[i] ); FLUSH(); MW_MUTEX_UNLOCK(); return NULL; } } /* some weird pointer */ mwIncErr(); mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n", mwCounter, file, line, p ); FLUSH(); MW_MUTEX_UNLOCK(); return NULL; }char *mwStrdup( const char* str, const char* file, int line ) { size_t len; char *newstring; MW_MUTEX_LOCK(); if( str == NULL ) { mwIncErr(); mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n", mwCounter, file, line ); FLUSH(); MW_MUTEX_UNLOCK(); return NULL; } len = strlen( str ) + 1; newstring = (char*) mwMalloc( len, file, line ); if( newstring != NULL ) memcpy( newstring, str, len ); MW_MUTEX_UNLOCK(); return newstring; }void mwFree( void* p, const char* file, int line ) { int i; mwData* mw; char buffer[ sizeof(mwData) + (mwROUNDALLOC*3) + 64 ]; /* this code is in support of C++ delete */ if( file == NULL ) { mwFree_( p ); MW_MUTEX_UNLOCK(); return; } mwAutoInit(); MW_MUTEX_LOCK(); TESTS(file,line); mwCounter ++; /* on NULL free, write a warning and return */ if( p == NULL ) { mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n", mwCounter, file, line ); FLUSH(); MW_MUTEX_UNLOCK(); return; } /* do the quick ownership test */ mw = (mwData*) mwBUFFER_TO_MW( p ); if( mwIsOwned( mw, file, line ) ) { (void) mwTestBuf( mw, file, line ); /* if the buffer is an NML, treat this as a double-free */ if( mw->flag & MW_NML ) { if( *(((unsigned char*)mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML ) { mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", mwCounter, file, line, mw ); } goto check_dbl_free; } /* update the statistics */ mwNumCurAlloc --; mwStatCurAlloc -= (long) mw->size; if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line ); /* we should either free the allocation or keep it as NML */ if( mwNML ) { mw->flag |= MW_NML; mwNmlNumAlloc ++; mwNmlCurAlloc += (long) mw->size; memset( ((char*)mw)+mwDataSize+mwOverflowZoneSize, MW_VAL_NML, mw->size ); } else { /* unlink the allocation, and enter the post-free data */ mwUnlink( mw, file, line ); memset( mw, MW_VAL_DEL, mw->size + mwDataSize+mwOverflowZoneSize+mwOverflowZoneSize ); if( mwFBI ) { memset( mw, '.', mwDataSize + mwOverflowZoneSize ); sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line ); strncpy( (char*)(void*)mw, buffer, mwDataSize + mwOverflowZoneSize ); } free( mw ); } /* add the pointer to the last-free track */ mwLFfile[ mwLFcur ] = file; mwLFline[ mwLFcur ] = line; mwLastFree[ mwLFcur++ ] = p; if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0; MW_MUTEX_UNLOCK(); return; } /* check for double-freeing */check_dbl_free: for(i=0;i<MW_FREE_LIST;i++) { if( mwLastFree[i] == p ) { mwIncErr(); mwWrite( "double-free: <%ld> %s(%d), %p was" " freed from %s(%d)\n", mwCounter, file, line, p, mwLFfile[i], mwLFline[i] ); FLUSH(); MW_MUTEX_UNLOCK(); return; } } /* some weird pointer... block the free */ mwIncErr(); mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n", mwCounter, file, line, p ); FLUSH(); MW_MUTEX_UNLOCK(); return; }void* mwCalloc( size_t a, size_t b, const char *file, int line ) { void *p; size_t size = a * b; p = mwMalloc( size, file, line ); if( p == NULL ) return NULL; memset( p, 0, size ); return p; }void mwFree_( void *p ) { MW_MUTEX_LOCK(); TESTS(NULL,0); MW_MUTEX_UNLOCK(); free(p); }void* mwMalloc_( size_t size ) { MW_MUTEX_LOCK(); TESTS(NULL,0); MW_MUTEX_UNLOCK(); return malloc( size ); }void* mwRealloc_( void *p, size_t size ) { MW_MUTEX_LOCK(); TESTS(NULL,0); MW_MUTEX_UNLOCK(); return realloc( p, size ); }void* mwCalloc_( size_t a, size_t b ) { MW_MUTEX_LOCK(); TESTS(NULL,0); MW_MUTEX_UNLOCK(); return calloc( a, b ); }void mwFlushNow( void ) { if( mwLogR() ) fflush( mwLogR() ); return; }void mwDoFlush( int onoff ) { mwFlushW( onoff<1?0:onoff ); if( onoff ) if( mwLogR() ) fflush( mwLogR() ); return; }void mwLimit( long lim ) { TESTS(NULL,0); mwWrite("limit: old limit = "); if( !mwAllocLimit ) mwWrite( "none" ); else mwWrite( "%ld bytes", mwAllocLimit ); mwWrite( ", new limit = "); if( !lim ) { mwWrite( "none\n" ); mwUseLimit = 0; } else { mwWrite( "%ld bytes\n", lim ); mwUseLimit = 1; } mwAllocLimit = lim; FLUSH(); }void mwSetAriAction( int action ) { MW_MUTEX_LOCK(); TESTS(NULL,0); mwAriAction = action; MW_MUTEX_UNLOCK(); return; }int mwAssert( int exp, const char *exps, const char *fn, int ln ) { int i; char buffer[MW_TRACE_BUFFER+8]; if( exp ) { return 0; } mwAutoInit(); MW_MUTEX_LOCK(); TESTS(fn,ln); mwIncErr(); mwCounter++; mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); if( mwAriFunction != NULL ) { sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps ); i = (*mwAriFunction)(buffer); switch( i ) { case MW_ARI_IGNORE: mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter ); MW_MUTEX_UNLOCK(); return 0; case MW_ARI_RETRY: mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter ); MW_MUTEX_UNLOCK(); return 1; } } else { if( mwAriAction & MW_ARI_IGNORE ) { mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); MW_MUTEX_UNLOCK(); return 0; } fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps ); } FLUSH(); (void) mwTestNow( fn, ln, 1 ); FLUSH(); if( mwAriAction & MW_ARI_NULLREAD ) { /* This is made in an attempt to kick in */ /* any debuggers or OS stack traces */ FLUSH(); /*lint -save -e413 */ i = *((int*)NULL); mwDummy( (char)i ); /*lint -restore */ } MW_MUTEX_UNLOCK(); exit(255); /* NOT REACHED - the return statement is in to keep */ /* stupid compilers from squeaking about differing return modes. */ /* Smart compilers instead say 'code unreachable...' */ /*lint -save -e527 */ return 0; /*lint -restore */ }int mwVerify( int exp, const char *exps, const char *fn, int ln ) { int i; char buffer[MW_TRACE_BUFFER+8]; if( exp ) { return 0; } mwAutoInit(); MW_MUTEX_LOCK(); TESTS(fn,ln); mwIncErr(); mwCounter++; mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); if( mwAriFunction != NULL ) { sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps ); i = (*mwAriFunction)(buffer); if( i == 0 ) { mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter ); MW_MUTEX_UNLOCK(); return 0; } if( i == 1 ) { mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter ); MW_MUTEX_UNLOCK(); return 1; } } else { if( mwAriAction & MW_ARI_NULLREAD ) { /* This is made in an attempt to kick in */ /* any debuggers or OS stack traces */ FLUSH(); /*lint -save -e413 */ i = *((int*)NULL); mwDummy( (char)i ); /*lint -restore */ } if( mwAriAction & MW_ARI_IGNORE ) { mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); MW_MUTEX_UNLOCK(); return 0; } fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps ); } FLUSH(); (void) mwTestNow( fn, ln, 1 ); FLUSH(); MW_MUTEX_UNLOCK(); exit(255); /* NOT REACHED - the return statement is in to keep */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -