100#define MEMWATCH_NOCPP
103#define MEMWATCH_STDIO
124#if defined(WIN32) || defined(__WIN32__)
125#define MW_HAVE_MUTEX 1
129#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
130#define MW_HAVE_MUTEX 1
139#define VERSION "2.71"
140#define CHKVAL(mw) (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line)
141#define FLUSH() mwFlush()
142#define TESTS(f,l) if(mwTestAlways) (void)mwTestNow(f,l,1)
143#define PRECHK 0x01234567L
144#define POSTCHK 0x76543210L
145#define mwBUFFER_TO_MW(p) ( (mwData*) (void*) ( ((char*)p)-mwDataSize-mwOverflowZoneSize ) )
163#define mwSTDERR stderr
165#define mwSTDERR mwLog
169#define MW_MUTEX_INIT() mwMutexInit()
170#define MW_MUTEX_TERM() mwMutexTerm()
171#define MW_MUTEX_LOCK() mwMutexLock()
172#define MW_MUTEX_UNLOCK() mwMutexUnlock()
174#define MW_MUTEX_INIT()
175#define MW_MUTEX_TERM()
176#define MW_MUTEX_LOCK()
177#define MW_MUTEX_UNLOCK()
185#ifndef mwBYTE_DEFINED
187# error need CHAR_BIT to be 8!
189typedef unsigned char mwBYTE;
190# define mwBYTE_DEFINED 1
194#if defined(ULONGLONG_MAX) || defined(ULLONG_MAX) || defined(_UI64_MAX) || defined(ULONG_LONG_MAX)
196# define mwROUNDALLOC_DEFAULT 8
198# if UINT_MAX <= 0xFFFFUL
200# define mwROUNDALLOC_DEFAULT 2
202# if ULONG_MAX > 0xFFFFFFFFUL
204# define mwROUNDALLOC_DEFAULT 8
207# define mwROUNDALLOC_DEFAULT 4
217# define mwROUNDALLOC mwROUNDALLOC_DEFAULT
220#ifndef mwDWORD_DEFINED
221#if ULONG_MAX == 0xFFFFFFFFUL
222typedef unsigned long mwDWORD;
223#define mwDWORD_DEFINED "unsigned long"
227#ifndef mwDWORD_DEFINED
228#if UINT_MAX == 0xFFFFFFFFUL
229typedef unsigned int mwDWORD;
230#define mwDWORD_DEFINED "unsigned int"
234#ifndef mwDWORD_DEFINED
235#if USHRT_MAX == 0xFFFFFFFFUL
236typedef unsigned short mwDWORD;
237#define mwDWORD_DEFINED "unsigned short"
241#ifndef mwBYTE_DEFINED
242#error "can't find out the correct type for a 8 bit scalar"
245#ifndef mwDWORD_DEFINED
246#error "can't find out the correct type for a 32 bit scalar"
297#if defined(WIN32) || defined(__WIN32__)
298typedef HANDLE mwMutex;
301#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
302typedef pthread_mutex_t mwMutex;
309static int mwInited = 0;
310static int mwInfoWritten = 0;
311static int mwUseAtexit = 0;
312static FILE* mwLog = NULL;
313static int mwFlushing = 0;
317static long mwAllocLimit = 0L;
318static int mwUseLimit = 0;
320static long mwNumCurAlloc = 0L;
321static mwData* mwHead = NULL;
322static mwData* mwTail = NULL;
323static int mwDataSize = 0;
324static unsigned char mwOverflowZoneTemplate[] =
"mEmwAtch";
327static void (*mwOutFunction)(int) = NULL;
328static int (*mwAriFunction)(
const char*) = NULL;
334static long mwErrors = 0L;
336static int mwTestFlags = 0;
337static int mwTestAlways = 0;
339static FILE* mwLogB1 = NULL;
340static int mwFlushingB1 = 0;
342static mwStat* mwStatList = NULL;
343static long mwStatTotAlloc = 0L;
344static long mwStatMaxAlloc = 0L;
345static long mwStatNumAlloc = 0L;
346static long mwStatCurAlloc = 0L;
347static long mwNmlNumAlloc = 0L;
348static long mwNmlCurAlloc = 0L;
351static long mwGrabSize = 0L;
356static int mwLFcur = 0;
360static FILE* mwLogB2 = NULL;
361static int mwFlushingB2 = 0;
364static mwMutex mwGlobalMutex;
371static void mwAutoInit(
void );
372static FILE* mwLogR(
void );
373static void mwLogW( FILE* );
374static int mwFlushR(
void );
375static void mwFlushW(
int );
376static void mwFlush(
void );
377static void mwIncErr(
void );
378static void mwUnlink(
mwData*,
const char*
file,
int line );
379static int mwRelink(
mwData*,
const char*
file,
int line );
380static int mwIsHeapOK(
mwData *mw );
381static int mwIsOwned(
mwData* mw,
const char*
file,
int line );
382static int mwTestBuf(
mwData* mw,
const char*
file,
int line );
383static void mwDefaultOutFunc(
int );
384static void mwWrite(
const char* format, ... );
385static void mwLogFile(
const char* name );
386static size_t mwFreeUp(
size_t,
int );
387static const void *mwTestMem(
const void *,
unsigned,
int );
388static int mwStrCmpI(
const char *s1,
const char *s2 );
389static int mwTestNow(
const char *
file,
int line,
int always_invoked );
390static void mwDropAll(
void );
391static const char *mwGrabType(
int type );
392static unsigned mwGrab_(
unsigned kb,
int type,
int silent );
393static unsigned mwDrop_(
unsigned kb,
int type,
int silent );
394static int mwARI(
const char* text );
395static void mwStatReport(
void );
396static mwStat* mwStatGet(
const char*,
int,
int );
397static void mwStatAlloc(
size_t,
const char*,
int );
398static void mwStatFree(
size_t,
const char*,
int );
399static int mwCheckOF(
const void * p );
400static void mwWriteOF(
void * p );
401static char mwDummy(
char c );
403static void mwMutexInit(
void );
404static void mwMutexTerm(
void );
405static void mwMutexLock(
void );
406static void mwMutexUnlock(
void );
416 if( mwInited++ > 0 )
return;
421 if( mwLogR() == NULL ) mwLogFile(
"memwatch.log" );
422 if( mwLogR() == NULL ) {
428 for( i=1; i<100; i++ ) {
429 sprintf( buf,
"memwat%02d.log", i );
431 if( mwLogR() != NULL )
break;
445 mwDataSize =
sizeof(
mwData);
449 if( !mwInfoWritten ) {
454 " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh "
456 mwWrite(
"\nStarted at %s\n", ctime( &tid ) );
459 mwWrite(
"Modes: " );
464 mwWrite(
"__STDC__ " );
467 mwWrite(
"16-bit " );
470 mwWrite(
"32-bit " );
473 mwWrite(
"64-bit " );
475 mwWrite(
"mwDWORD==(" mwDWORD_DEFINED
")\n" );
476 mwWrite(
"mwROUNDALLOC==%d sizeof(mwData)==%d mwDataSize==%d\n",
482 mwWrite(
"Compiled using Microsoft C" CPPTEXT
483 " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 );
489 mwWrite(
"Compiled using Borland C"
491 "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 );
493 " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 );
500 mwWrite(
"Compiled using Watcom C %d.%02d ",
501 __WATCOMC__/100, __WATCOMC__%100 );
503 mwWrite(
"(32-bit flat model)" );
513 if( mwUseAtexit ) (void) atexit(
mwAbort );
526 mwWrite(
"\nStopped at %s\n", ctime( &tid) );
529 mwWrite(
"internal: mwAbort(): MEMWATCH not initialized!\n" );
535 while( mwFirstMark ) {
536 mrk = mwFirstMark->
next;
537 mwWrite(
"mark: %p: %s\n", mwFirstMark->
host, mwFirstMark->
text );
538 free( mwFirstMark->
text );
546 while( mwHead != NULL && errors < 3 ) {
547 if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) {
551 mwWrite(
"internal: NML/unfreed scan restarting\n" );
556 mwWrite(
"internal: NML/unfreed scan aborted, heap too damaged\n" );
563 data = ((
char*)mwHead)+mwDataSize;
564 mwWrite(
"unfreed: <%ld> %s(%d), %ld bytes at %p ",
566 if( mwCheckOF(
data ) ) {
567 mwWrite(
"[underflowed] ");
570 if( mwCheckOF( (
data+mwOverflowZoneSize+mwHead->
size) ) ) {
571 mwWrite(
"[overflowed] ");
575 j = 16;
if( mwHead->
size < 16 ) j = (int) mwHead->
size;
576 for( i=0;i<16;i++ ) {
577 if( i<j ) mwWrite(
"%02X ",
578 (
unsigned char) *(
data+mwOverflowZoneSize+i) );
579 else mwWrite(
".. " );
582 c = *(
data+mwOverflowZoneSize+i);
583 if( c < 32 || c > 126 ) c =
'.';
588 mwUnlink( mw, __FILE__, __LINE__ );
592 data = ((
char*)mwHead) + mwDataSize + mwOverflowZoneSize;
595 mwWrite(
"wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
600 mwNmlCurAlloc -= mwHead->
size;
602 mwUnlink( mw, __FILE__, __LINE__ );
607 if( mwNmlNumAlloc ) mwWrite(
"internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc );
608 if( mwNmlCurAlloc ) mwWrite(
"internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc );
615 mwHead = mwTail = NULL;
617 fprintf(
mwSTDERR,
"MEMWATCH detected %ld anomalies\n",mwErrors);
632 mwWrite(
"internal: mwTerm(): MEMWATCH has not been started!\n");
640 if( level<0 ) level=0;
641 if( mwStatLevel != level )
643 mwWrite(
"statistics: now collecting on a %s basis\n",
644 level<1?
"global":(level<2?
"module":
"line") );
651 mwTestAlways = onoff;
657 mwOutFunction = func;
660static void mwWriteOF(
void *p )
664 ptr = (
unsigned char*) p;
665 for( i=0; i<mwOverflowZoneSize; i++ )
667 *(ptr+i) = mwOverflowZoneTemplate[i%8];
672static int mwCheckOF(
const void *p )
675 const unsigned char *ptr;
676 ptr = (
const unsigned char *) p;
677 for( i=0; i<mwOverflowZoneSize; i++ )
679 if( *(ptr+i) != mwOverflowZoneTemplate[i%8] )
688 return mwTestNow(
file, line, 0 );
703 if( mwIsOwned( mw,
file, line ) ) {
704 return mwTestBuf( mw,
file, line );
710 fprintf(
mwSTDERR,
"breakout: %s\n", cause);
711 mwWrite(
"breakout: %s\n", cause );
718void *
mwMark(
void *p,
const char *desc,
const char *
file,
unsigned line ) {
728 if( desc == NULL ) desc =
"unknown";
729 if(
file == NULL )
file =
"unknown";
731 tot = sprintf( wherebuf,
"%.48s called from %s(%d)", desc,
file, line );
732 if( tot >= (
int)
sizeof(wherebuf) ) { wherebuf[
sizeof(wherebuf)-1] = 0; oflow = 1; }
735 mwWrite(
"mark: %s(%d), no mark for NULL:'%s' may be set\n",
file, line, desc );
741 mwWrite(
"mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n",
742 file, line, mwFirstMark, desc );
746 for( mrk=mwFirstMark; mrk; mrk=mrk->
next )
750 mwWrite(
"mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n",
754 if( mrk->
host == p )
break;
761 mwWrite(
"mark: %s(%d), no mark for %p:'%s', out of memory\n",
file, line, p, desc );
769 n = strlen( mrk->
text );
772 n += strlen( wherebuf );
773 buf = (
char*) malloc(
n+3 );
775 if( isnew ) free( mrk );
776 mwWrite(
"mark: %s(%d), no mark for %p:'%s', out of memory\n",
file, line, p, desc );
781 memcpy( buf, wherebuf,
n+1 );
782 mrk->
next = mwFirstMark;
789 strcpy( buf, mrk->
text );
791 strcat( buf, wherebuf );
799 mwTrace(
" [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
809 if( mrk->
host == p ) {
810 if( mrk->
level < 2 ) {
812 else mwFirstMark = mrk->
next;
823 mwWrite(
"mark: %s(%d), no mark found for %p\n",
file, line, p );
832static int mwARI(
const char *estr ) {
835 fprintf(
mwSTDERR,
"\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr);
836 (void) fgets(inbuf,
sizeof(inbuf),stdin);
837 for( c=0; inbuf[c] && inbuf[c] <=
' '; c++ ) ;
839 if( c ==
'R' || c ==
'r' ) {
850 return mwARI( estr );
856 mwAriFunction = func;
876 needed = mwDataSize + mwOverflowZoneSize*2 + size;
884 if( mwUseLimit && ((
long)size + mwStatCurAlloc > mwAllocLimit) ) {
885 mwWrite(
"limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
886 mwCounter,
file, line, (
long)size, mwAllocLimit - mwStatCurAlloc );
893 mw = (
mwData*) malloc( needed );
895 if( mwFreeUp(needed,0) >= needed ) {
896 mw = (
mwData*) malloc(needed);
898 mwWrite(
"internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed );
904 mwWrite(
"fail: <%ld> %s(%d), %ld wanted %ld allocated\n",
922 if( mwHead ) mwHead->
prev = mw;
924 if( mwTail == NULL ) mwTail = mw;
926 ptr = ((
char*)mw) + mwDataSize;
928 ptr += mwOverflowZoneSize;
935 mwStatCurAlloc += (long) size;
936 mwStatTotAlloc += (long) size;
937 if( mwStatCurAlloc > mwStatMaxAlloc )
938 mwStatMaxAlloc = mwStatCurAlloc;
941 if( mwStatLevel ) mwStatAlloc( size,
file, line );
955 if( size == 0 ) {
mwFree( p,
file, line );
return NULL; }
961 if( mwIsOwned( mw,
file, line ) ) {
967 if( *((
unsigned char*)(mw)+mwDataSize+mwOverflowZoneSize) !=
MW_VAL_NML )
969 mwWrite(
"internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
976 if( mwUseLimit && ((
long)size + mwStatCurAlloc - (
long)mw->
size > mwAllocLimit) ) {
979 mwWrite(
"limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
980 mwCounter,
file, line, (
unsigned long)size - mw->
size, mwAllocLimit - mwStatCurAlloc );
988 oldUseLimit = mwUseLimit;
992 if( size < mw->size )
993 memcpy( ptr, p, size );
995 memcpy( ptr, p, mw->
size );
998 mwUseLimit = oldUseLimit;
1008 if( mwLastFree[i] == p ) {
1010 mwWrite(
"realloc: <%ld> %s(%d), %p was"
1011 " freed from %s(%d)\n",
1013 mwLFfile[i], mwLFline[i] );
1022 mwWrite(
"realloc: <%ld> %s(%d), unknown pointer %p\n",
1037 mwWrite(
"strdup: <%ld> %s(%d), strdup(NULL) called\n",
1044 len = strlen( str ) + 1;
1046 if( newstring != NULL ) memcpy( newstring, str, len );
1057 if(
file == NULL ) {
1071 mwWrite(
"NULL free: <%ld> %s(%d), NULL pointer free'd\n",
1081 if( mwIsOwned( mw,
file, line ) ) {
1082 (void) mwTestBuf( mw,
file, line );
1087 if( *(((
unsigned char*)mw)+mwDataSize+mwOverflowZoneSize) !=
MW_VAL_NML )
1089 mwWrite(
"internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
1092 goto check_dbl_free;
1097 mwStatCurAlloc -= (long) mw->
size;
1098 if( mwStatLevel ) mwStatFree( mw->
size, mw->
file, mw->
line );
1104 mwNmlCurAlloc += (long) mw->
size;
1105 memset( ((
char*)mw)+mwDataSize+mwOverflowZoneSize,
MW_VAL_NML, mw->size );
1109 mwUnlink( mw,
file, line );
1111 mw->
size + mwDataSize+mwOverflowZoneSize+mwOverflowZoneSize );
1113 memset( mw,
'.', mwDataSize + mwOverflowZoneSize );
1115 strncpy( (
char*)(
void*)mw, buffer, mwDataSize + mwOverflowZoneSize );
1121 mwLFfile[ mwLFcur ] =
file;
1122 mwLFline[ mwLFcur ] = line;
1123 mwLastFree[ mwLFcur++ ] = p;
1133 if( mwLastFree[i] == p ) {
1135 mwWrite(
"double-free: <%ld> %s(%d), %p was"
1136 " freed from %s(%d)\n",
1138 mwLFfile[i], mwLFline[i] );
1147 mwWrite(
"WILD free: <%ld> %s(%d), unknown pointer %p\n",
1156 size_t size = a * b;
1158 if( p == NULL )
return NULL;
1159 memset( p, 0, size );
1174 return malloc( size );
1181 return realloc( p, size );
1188 return calloc( a, b );
1192 if( mwLogR() ) fflush( mwLogR() );
1197 mwFlushW( onoff<1?0:onoff );
1198 if( onoff )
if( mwLogR() ) fflush( mwLogR() );
1204 mwWrite(
"limit: old limit = ");
1205 if( !mwAllocLimit ) mwWrite(
"none" );
1206 else mwWrite(
"%ld bytes", mwAllocLimit );
1207 mwWrite(
", new limit = ");
1209 mwWrite(
"none\n" );
1213 mwWrite(
"%ld bytes\n", lim );
1223 mwAriAction = action;
1239 mwWrite(
"assert trap: <%ld> %s(%d), %s\n",
mwCounter, fn, ln, exps );
1240 if( mwAriFunction != NULL ) {
1241 sprintf( buffer,
"MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps );
1242 i = (*mwAriFunction)(buffer);
1245 mwWrite(
"assert trap: <%ld> IGNORED - execution continues\n",
mwCounter );
1249 mwWrite(
"assert trap: <%ld> RETRY - executing again\n",
mwCounter );
1256 mwWrite(
"assert trap: <%ld> AUTO IGNORED - execution continues\n",
mwCounter );
1260 fprintf(
mwSTDERR,
"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps );
1264 (void) mwTestNow( fn, ln, 1 );
1298 mwWrite(
"verify trap: <%ld> %s(%d), %s\n",
mwCounter, fn, ln, exps );
1299 if( mwAriFunction != NULL ) {
1300 sprintf( buffer,
"MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps );
1301 i = (*mwAriFunction)(buffer);
1303 mwWrite(
"verify trap: <%ld> IGNORED - execution continues\n",
mwCounter );
1308 mwWrite(
"verify trap: <%ld> RETRY - executing again\n",
mwCounter );
1324 mwWrite(
"verify trap: <%ld> AUTO IGNORED - execution continues\n",
mwCounter );
1328 fprintf(
mwSTDERR,
"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps );
1331 (void) mwTestNow( fn, ln, 1 );
1350 if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
1352 va_start( mark, format );
1353 tot = vsprintf( mwPrintBuf, format, mark );
1356 for(tot=0;mwPrintBuf[tot];tot++)
1357 (*mwOutFunction)( mwPrintBuf[tot] );
1360 mwTrace(
" [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
1382static void mwDropAll() {
1386 if( mwGrabList != NULL )
1387 mwWrite(
"internal: the grab list is not empty after mwDropAll()\n");
1390static const char *mwGrabType(
int type ) {
1395 return "no-mans-land";
1400 return "<unknown type>";
1403static unsigned mwGrab_(
unsigned kb,
int type,
int silent ) {
1406 if( !kb ) i = kb = 65000U;
1410 (mwStatCurAlloc + mwGrabSize + (
long)
sizeof(
mwGrabData) > mwAllocLimit) ) {
1412 mwWrite(
"grabbed: all allowed memory to %s (%u kb)\n",
1413 mwGrabType(type), i-kb);
1421 mwWrite(
"grabbed: all available memory to %s (%u kb)\n",
1422 mwGrabType(type), i-kb);
1428 gd->
next = mwGrabList;
1429 memset( gd->
blob, type,
sizeof(gd->
blob) );
1434 mwWrite(
"grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) );
1440static unsigned mwDrop_(
unsigned kb,
int type,
int silent ) {
1445 if( mwGrabList == NULL && kb == 0 )
return 0;
1446 if( !kb ) i = kb = 60000U;
1452 if( i-kb > 0 && !silent ) {
1453 mwWrite(
"dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb);
1458 if( gd->
type == type ) {
1462 if( mwGrabList == gd ) mwGrabList = gd->
next;
1464 p = mwTestMem( tmp->
blob,
sizeof( tmp->
blob ), type );
1466 mwWrite(
"wild pointer: <%ld> %s memory hit at %p\n",
1467 mwCounter, mwGrabType(type), p );
1479 mwWrite(
"dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) );
1511static void mwAutoInit(
void )
1513 if( mwInited )
return;
1519static FILE *mwLogR() {
1520 if( (mwLog == mwLogB1) && (mwLog == mwLogB2) )
return mwLog;
1521 if( mwLog == mwLogB1 ) mwLogB2 = mwLog;
1522 if( mwLog == mwLogB2 ) mwLogB1 = mwLog;
1523 if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1;
1524 if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) {
1525 mwWrite(
"internal: log file handle damaged and recovered\n");
1529 fprintf(
mwSTDERR,
"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" );
1530 mwLog = mwLogB1 = mwLogB2 =
mwSTDERR;
1534static void mwLogW( FILE *p ) {
1535 mwLog = mwLogB1 = mwLogB2 = p;
1538static int mwFlushR() {
1539 if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) )
return mwFlushing;
1540 if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing;
1541 if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing;
1542 if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1;
1543 if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) {
1544 mwWrite(
"internal: flushing flag damaged and recovered\n");
1548 mwWrite(
"internal: flushing flag destroyed, so set to true\n");
1549 mwFlushing = mwFlushingB1 = mwFlushingB2 = 1;
1553static void mwFlushW(
int n ) {
1554 mwFlushing = mwFlushingB1 = mwFlushingB2 =
n;
1557static void mwIncErr() {
1559 mwFlushW( mwFlushR()+1 );
1563static void mwFlush() {
1564 if( mwLogR() == NULL )
return;
1568 if( mwFlushR() ) fflush( mwLogR() );
1573static void mwUnlink(
mwData* mw,
const char*
file,
int line ) {
1574 if( mw->
prev == NULL ) {
1576 mwWrite(
"internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n",
1577 mwCounter,
file, line, mw );
1582 mwWrite(
"internal: <%ld> %s(%d), MW-%p: link1 failure\n",
1583 mwCounter,
file, line, mw );
1586 if( mw->
next == NULL ) {
1588 mwWrite(
"internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n",
1589 mwCounter,
file, line, mw );
1594 mwWrite(
"internal: <%ld> %s(%d), MW-%p: link2 failure\n",
1595 mwCounter,
file, line, mw );
1605static int mwRelink(
mwData* mw,
const char*
file,
int line ) {
1611 if(
file == NULL )
file =
"unknown";
1614 mwWrite(
"relink: cannot repair MW at NULL\n");
1620 mwWrite(
"relink: MW-%p is a garbage pointer\n", mw);
1625 mwWrite(
"relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter,
file, line, mw );
1630 if( mwHead != mw ) {
1632 mwWrite(
"relink: failed for MW-%p; head pointer destroyed\n", mw );
1636 for( mw1=mwHead; mw1; mw1=mw1->
next ) {
1637 if( mw1->
next == mw ) {
1643 mwWrite(
"relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->
next );
1649 mwWrite(
"relink: MW-%p not found in forward chain search\n", mw );
1656 mwWrite(
"relink: MW-%p is the head (first) allocation\n", mw );
1657 if( mw->
prev != NULL )
1659 mwWrite(
"relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw );
1665 if( mwTail != mw ) {
1667 mwWrite(
"relink: failed for MW-%p; tail pointer destroyed\n", mw );
1671 for( mw1=mwTail; mw1; mw1=mw1->
prev ) {
1672 if( mw1->
prev == mw ) {
1677 mwWrite(
"relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->
prev );
1683 mwWrite(
"relink: MW-%p not found in reverse chain search\n", mw );
1690 mwWrite(
"relink: MW-%p is the tail (last) allocation\n", mw );
1691 if( mw->
next != NULL )
1693 mwWrite(
"relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw );
1699 mwWrite(
"relink: heap appears intact, MW-%p probably garbage pointer\n", mw );
1706 ms = mwStatGet( mw->
file, -1, 0 );
1707 if( ms == NULL ) mw->
file =
"<relinked>";
1715 if( mwHead == NULL && mwTail == NULL )
1717 if( mwStatCurAlloc == 0 )
1718 mwWrite(
"relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter,
file, line );
1720 mwWrite(
"relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter,
file, line );
1725 mwWrite(
"relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter,
file, line );
1728 if( mwHead == NULL || mwTail == NULL )
1730 if( mwHead == NULL ) mwWrite(
"relink: mwHead is NULL, but mwTail is %p\n", mwTail );
1731 else mwWrite(
"relink: mwTail is NULL, but mwHead is %p\n", mwHead );
1735 if( mwHead != NULL )
1739 mwWrite(
"relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead );
1743 if( mwHead->
prev != NULL )
1745 mwWrite(
"relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->
prev );
1747 for( mw1=mwHead; mw1; mw1=mw1->
next )
1755 mwWrite(
"relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
1759 mwWrite(
"relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
1765 mwWrite(
"relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n",
1777 if( mwTail != NULL )
1781 mwWrite(
"relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail );
1785 if( mwTail->
next != NULL )
1787 mwWrite(
"relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->
next );
1789 for( mw2=mwTail; mw2; mw2=mw2->
prev )
1797 mwWrite(
"relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
1801 mwWrite(
"relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
1807 mwWrite(
"relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n",
1817 if( mwHead == NULL && mwTail == NULL )
1819 mwWrite(
"relink: both head and tail pointers damaged, aborting program\n");
1824 if( mwHead == NULL )
1827 mwWrite(
"relink: heap truncated, MW-%p designated as new mwHead\n", mw2 );
1831 if( mwTail == NULL )
1834 mwWrite(
"relink: heap truncated, MW-%p designated as new mwTail\n", mw1 );
1838 if( mw1 == NULL && mw2 == NULL &&
1839 mwHead->
prev == NULL && mwTail->
next == NULL ) {
1840 mwWrite(
"relink: verifying heap integrity...\n" );
1844 if( mw1 && mw2 && mw1 != mw2 ) {
1847 mwWrite(
"relink: emergency repairs successful, assessing damage...\n");
1851 mwWrite(
"relink: heap totally destroyed, aborting program\n");
1860 if( !mwIsHeapOK( NULL ) ) {
1861 mwWrite(
"relink: heap verification FAILS - aborting program\n");
1866 for( size=
count=0, mw1=mwHead; mw1; mw1=mw1->
next ) {
1868 size += (long) mw1->
size;
1870 if(
count == mwNumCurAlloc ) {
1871 mwWrite(
"relink: successful, ");
1872 if( size == mwStatCurAlloc ) {
1873 mwWrite(
"no allocations lost\n");
1877 mwWrite(
"size information lost for MW-%p\n", mw);
1883 mwWrite(
"relink: partial, %ld MW-blocks of %ld bytes lost\n",
1884 mwNmlNumAlloc+mwNumCurAlloc-
count, mwNmlCurAlloc+mwStatCurAlloc-size );
1899static int mwIsHeapOK(
mwData *includes_mw ) {
1903 for( mw = mwHead; mw; mw=mw->
next ) {
1904 if( includes_mw == mw ) found++;
1908 if( mw==mwHead || mw->
prev->
next != mw )
return 0;
1912 if( mw==mwTail || mw->
next->
prev != mw )
return 0;
1914 else if( mw!=mwTail )
return 0;
1917 if( includes_mw != NULL && !found )
return 0;
1922static int mwIsOwned(
mwData* mw,
const char *
file,
int line ) {
1930 if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 )
1936 if( mwIsHeapOK( mw ) ) {
1938 mwWrite(
"internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n",
1939 mwCounter,
file, line, mw );
1942 ms = mwStatGet( mw->
file, -1, 0 );
1943 if( ms == NULL ) mw->
file =
"<relinked>";
1945 else mw->
file =
"<unknown>";
1963 else {
if( mwHead == mw ) retv++; }
1965 else {
if( mwTail == mw ) retv++; }
1967 if( retv > 2 )
return 1;
1971 if( !mwIsHeapOK( mw ) ) {
1972 if( mwRelink( mw,
file, line ) )
1977 mwWrite(
"internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n",
1978 mwCounter,
file, line, mw );
1990static int mwTestBuf(
mwData* mw,
const char*
file,
int line ) {
1994 if(
file == NULL )
file =
"unknown";
1996 if( !
mwIsSafeAddr( mw, mwDataSize + mwOverflowZoneSize ) ) {
1997 mwWrite(
"internal: <%ld> %s(%d): pointer MW-%p is invalid\n",
1998 mwCounter,
file, line, mw );
2004 mwWrite(
"internal: <%ld> %s(%d), info trashed; relinking\n",
2005 mwCounter,
file, line );
2007 if( !mwRelink( mw,
file, line ) )
return 2;
2011 mwWrite(
"internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n",
2014 if( !mwRelink( mw,
file, line ) ) retv = 2;
2017 mwWrite(
"internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n",
2020 if( !mwRelink( mw,
file, line ) ) retv = 2;
2023 p = ((
char*)mw) + mwDataSize;
2024 if( mwCheckOF( p ) ) {
2025 mwWrite(
"underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
2030 p += mwOverflowZoneSize + mw->
size;
2031 if(
mwIsReadAddr( p, mwOverflowZoneSize ) && mwCheckOF( p ) ) {
2032 mwWrite(
"overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
2041static void mwDefaultOutFunc(
int c ) {
2042 if( mwLogR() ) fputc( c, mwLogR() );
2045static void mwWrite(
const char *format, ... ) {
2049 if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
2050 va_start( mark, format );
2051 tot = vsprintf( mwPrintBuf, format, mark );
2054 for(tot=0;mwPrintBuf[tot];tot++)
2055 (*mwOutFunction)( mwPrintBuf[tot] );
2057 mwWrite(
"\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n",
MW_TRACE_BUFFER-1 );
2063static void mwLogFile(
const char *name ) {
2065 (void)
time( &tid );
2066 if( mwLogR() != NULL ) {
2070 if( name == NULL )
return;
2071 mwLogW( fopen( name,
"a" COMMIT ) );
2072 if( mwLogR() == NULL )
2073 mwWrite(
"logfile: failed to open/create file '%s'\n", name );
2082static size_t mwFreeUp(
size_t needed,
int urgent ) {
2089 if( mwDrop_( 1,
MW_VAL_NML, 1 ) == 0 )
break;
2090 p = malloc( needed );
2091 if( p == NULL )
continue;
2098 while( mw != NULL ) {
2101 data = ((
char*)mw)+mwDataSize+mwOverflowZoneSize;
2104 mwWrite(
"wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
2108 mwUnlink( mw,
"mwFreeUp", 0 );
2111 p = malloc( needed );
2112 if( p == NULL )
continue;
2119 if( !urgent )
return 0;
2123 if( mwDrop_( 1,
MW_VAL_GRB, 1 ) == 0 )
break;
2124 p = malloc( needed );
2125 if( p == NULL )
continue;
2133static const void * mwTestMem(
const void *p,
unsigned len,
int c ) {
2134 const unsigned char *ptr;
2135 ptr = (
const unsigned char *) p;
2137 if( *ptr != (
unsigned char)c )
return (
const void*)ptr;
2143static int mwStrCmpI(
const char *s1,
const char *s2 ) {
2144 if( s1 == NULL || s2 == NULL )
return 0;
2146 if( toupper(*s2) == toupper(*s1) ) { s1++; s2++;
continue; }
2152#define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; }
2154static int mwTestNow(
const char *
file,
int line,
int always_invoked ) {
2159 if(
file && !always_invoked )
2160 mwWrite(
"check: <%ld> %s(%d), checking %s%s%s\n",
2168 for( mw = mwHead; mw; mw=mw->
next ) {
2171 mwWrite(
"check: heap corruption detected\n");
2178 mwWrite(
"check: heap corruption detected\n");
2182 if( mw==mwHead || mw->
prev->
next != mw ) {
2184 mwWrite(
"check: heap chain broken, prev link incorrect\n");
2192 mwWrite(
"check: heap corruption detected\n");
2196 if( mw==mwTail || mw->
next->
prev != mw ) {
2198 mwWrite(
"check: heap chain broken, next link incorrect\n");
2203 else if( mw!=mwTail ) {
2205 mwWrite(
"check: heap chain broken, tail incorrect\n");
2212 for( mw = mwHead; mw; mw=mw->
next ) {
2213 if( mwTestBuf( mw,
file, line ) ) retv ++;
2217 for( mw = mwHead; mw; mw=mw->
next ) {
2219 data = ((
char*)mw)+mwDataSize+mwOverflowZoneSize;
2222 mwWrite(
"wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
2230 if(
file && !always_invoked && !retv )
2231 mwWrite(
"check: <%ld> %s(%d), complete; no errors\n",
2240static void mwStatReport()
2243 const char *modname;
2247 mwWrite(
"\nMemory usage statistics (global):\n" );
2248 mwWrite(
" N)umber of allocations made: %ld\n", mwStatNumAlloc );
2249 mwWrite(
" L)argest memory usage : %ld\n", mwStatMaxAlloc );
2250 mwWrite(
" T)otal of all alloc() calls: %ld\n", mwStatTotAlloc );
2251 mwWrite(
" U)nfreed bytes totals : %ld\n", mwStatCurAlloc );
2254 if( mwStatLevel < 1 )
return;
2257 mwWrite(
"\nMemory usage statistics (detailed):\n");
2258 mwWrite(
" Module/Line Number Largest Total Unfreed \n");
2259 for( ms=mwStatList; ms; ms=ms->
next )
2261 if( ms->
line == -1 )
2264 else modname = ms->
file;
2265 modnamelen = strlen(modname);
2266 if( modnamelen > 42 )
2268 modname = modname + modnamelen - 42;
2271 mwWrite(
" %-42s %-8ld %-8ld %-8ld %-8ld\n",
2273 if( ms->
file && mwStatLevel > 1 )
2275 for( ms2=mwStatList; ms2; ms2=ms2->
next )
2277 if( ms2->
line!=-1 && ms2->
file!=NULL && !mwStrCmpI( ms2->
file, ms->
file ) )
2279 mwWrite(
" %-8d %-8ld %-8ld %-8ld %-8ld\n",
2288static mwStat* mwStatGet(
const char *
file,
int line,
int makenew ) {
2291 if( mwStatLevel < 2 ) line = -1;
2293 for( ms=mwStatList; ms!=NULL; ms=ms->
next ) {
2294 if( line != ms->
line )
continue;
2296 if( ms->
file == NULL )
break;
2299 if( ms->
file == NULL )
continue;
2300 if( !strcmp( ms->
file,
file ) )
break;
2303 if( ms != NULL )
return ms;
2305 if( !makenew )
return NULL;
2311 mwWrite(
"internal: memory low, statistics incomplete for '%s'\n",
file );
2321 ms->
next = mwStatList;
2326static void mwStatAlloc(
size_t size,
const char*
file,
int line ) {
2330 ms = mwStatGet(
file, -1, 1 );
2332 ms->
total += (long) size;
2333 ms->
curr += (long) size;
2339 if( mwStatLevel > 1 && line != -1 &&
file ) {
2340 ms = mwStatGet(
file, line, 1 );
2342 ms->
total += (long) size;
2343 ms->
curr += (long) size;
2351static void mwStatFree(
size_t size,
const char*
file,
int line ) {
2355 ms = mwStatGet(
file, -1, 1 );
2356 if( ms != NULL ) ms->
curr -= (long) size;
2359 if( mwStatLevel > 1 && line != -1 &&
file ) {
2360 ms = mwStatGet(
file, line, 1 );
2361 if( ms != NULL ) ms->
curr -= (long) size;
2373static char mwDummy(
char c )
2381#define WIN32_LEAN_AND_MEAN
2385 if( p == NULL )
return 0;
2386 if( IsBadReadPtr(p,len) )
return 0;
2393 if( p == NULL )
return 0;
2394 if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) )
return 0;
2404typedef void (*mwSignalHandlerPtr)( int );
2405mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0;
2406jmp_buf mwSIGSEGVjump;
2407static void mwSIGSEGV(
int n );
2409static void mwSIGSEGV(
int n )
2412 longjmp( mwSIGSEGVjump, 1 );
2419 if( p == NULL )
return 0;
2420 if( !len )
return 1;
2423 mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
2425 if( setjmp( mwSIGSEGVjump ) )
2427 signal( SIGSEGV, mwOldSIGSEGV );
2432 ptr = (
const char *)p;
2443 if( *ptr == 0x7C ) (void) mwDummy( (
char)0 );
2444 }
while( (
const void*) ptr != p );
2447 signal( SIGSEGV, mwOldSIGSEGV );
2455 if( p == NULL )
return 0;
2456 if( !len )
return 1;
2459 mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
2461 if( setjmp( mwSIGSEGVjump ) )
2463 signal( SIGSEGV, mwOldSIGSEGV );
2479 *ptr = mwDummy( *ptr );
2480 }
while( (
void*) ptr != p );
2483 signal( SIGSEGV, mwOldSIGSEGV );
2493 if( p == NULL )
return 0;
2494 if( len == 0 )
return 1;
2499 if( p == NULL )
return 0;
2500 if( len == 0 )
return 1;
2509#if defined(WIN32) || defined(__WIN32__)
2511static void mwMutexInit(
void )
2513 mwGlobalMutex = CreateMutex( NULL, FALSE, NULL);
2517static void mwMutexTerm(
void )
2519 CloseHandle( mwGlobalMutex );
2523static void mwMutexLock(
void )
2525 if( WaitForSingleObject(mwGlobalMutex, 1000 ) == WAIT_TIMEOUT )
2527 mwWrite(
"mwMutexLock: timed out, possible deadlock\n" );
2532static void mwMutexUnlock(
void )
2534 ReleaseMutex( mwGlobalMutex );
2540#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
2542static void mwMutexInit(
void )
2544 pthread_mutex_init( &mwGlobalMutex, NULL );
2548static void mwMutexTerm(
void )
2550 pthread_mutex_destroy( &mwGlobalMutex );
2554static void mwMutexLock(
void )
2556 pthread_mutex_lock(&mwGlobalMutex);
2560static void mwMutexUnlock(
void )
2562 pthread_mutex_unlock(&mwGlobalMutex);
2575#ifndef MEMWATCH_NOCPP
2578const char *mwNFile = NULL;
2587MemWatch::MemWatch() {
2588 if( mwInited )
return;
2593MemWatch::~MemWatch() {
2594 if( mwUseAtexit )
return;
2602void*
operator new(
unsigned size ) {
2604 return mwMalloc( size,
"<unknown>", 0 );
2610void*
operator new(
unsigned size,
const char *
file,
int line ) {
2619void*
operator new[] (
unsigned size,
const char *
file,
int line ) {
2631void operator delete(
void *p ) {
2632 if( p == NULL )
return;
2638 mwFree( p, mwNFile, mwNLine );
2645void operator delete[](
void *p ) {
2646 if( p == NULL )
return;
2652 mwFree( p, mwNFile, mwNLine );
EvtComplex exp(const EvtComplex &c)
DOUBLE_PRECISION count[2]
#define mwMark(p, t, f, n)
#define mwAssert(e, es, f, l)
#define mwVerify(e, es, f, l)
#define mwUnmark(p, f, n)
#define mwMalloc(n, f, l)
#define mwRealloc(p, n, f, l)
#define mwTestBuffer(f, l, b)
const unsigned long mwCounter
#define mwCalloc(n, m, f, l)
#define mwStrdup(p, f, l)
void mwNoMansLand(int level)
#define MW_MUTEX_UNLOCK()
void mwAutoCheck(int onoff)
#define mwBUFFER_TO_MW(p)
void mwBreakOut(const char *cause)
int mwIsReadAddr(const void *p, unsigned len)
int mwIsSafeAddr(void *p, unsigned len)
void mwSetAriAction(int action)
int mwAriHandler(const char *estr)
char blob[1024 - sizeof(mwGrabData *) - sizeof(int)]