Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

memwatch.c

00001 /*
00002 ** MEMWATCH.C
00003 ** Nonintrusive ANSI C memory leak / overwrite detection
00004 ** Copyright (C) 1992-2003 Johan Lindh
00005 ** All rights reserved.
00006 ** Version 2.71
00007 
00008    This file is part of MEMWATCH.
00009 
00010     MEMWATCH is free software; you can redistribute it and/or modify
00011     it under the terms of the GNU General Public License as published by
00012     the Free Software Foundation; either version 2 of the License, or
00013     (at your option) any later version.
00014 
00015     MEMWATCH is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018     GNU General Public License for more details.
00019 
00020     You should have received a copy of the GNU General Public License
00021     along with MEMWATCH; if not, write to the Free Software
00022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 
00024 **
00025 ** 920810 JLI   [1.00]
00026 ** 920830 JLI   [1.10 double-free detection]
00027 ** 920912 JLI   [1.15 mwPuts, mwGrab/Drop, mwLimit]
00028 ** 921022 JLI   [1.20 ASSERT and VERIFY]
00029 ** 921105 JLI   [1.30 C++ support and TRACE]
00030 ** 921116 JLI   [1.40 mwSetOutFunc]
00031 ** 930215 JLI   [1.50 modified ASSERT/VERIFY]
00032 ** 930327 JLI   [1.51 better auto-init & PC-lint support]
00033 ** 930506 JLI   [1.55 MemWatch class, improved C++ support]
00034 ** 930507 JLI   [1.60 mwTest & CHECK()]
00035 ** 930809 JLI   [1.65 Abort/Retry/Ignore]
00036 ** 930820 JLI   [1.70 data dump when unfreed]
00037 ** 931016 JLI   [1.72 modified C++ new/delete handling]
00038 ** 931108 JLI   [1.77 mwSetAssertAction() & some small changes]
00039 ** 940110 JLI   [1.80 no-mans-land alloc/checking]
00040 ** 940328 JLI   [2.00 version 2.0 rewrite]
00041 **              Improved NML (no-mans-land) support.
00042 **              Improved performance (especially for free()ing!).
00043 **              Support for 'read-only' buffers (checksums)
00044 **              ^^ NOTE: I never did this... maybe I should?
00045 **              FBI (free'd block info) tagged before freed blocks
00046 **              Exporting of the mwCounter variable
00047 **              mwBreakOut() localizes debugger support
00048 **              Allocation statistics (global, per-module, per-line)
00049 **              Self-repair ability with relinking
00050 ** 950913 JLI   [2.10 improved garbage handling]
00051 ** 951201 JLI   [2.11 improved auto-free in emergencies]
00052 ** 960125 JLI   [X.01 implemented auto-checking using mwAutoCheck()]
00053 ** 960514 JLI   [2.12 undefining of existing macros]
00054 ** 960515 JLI   [2.13 possibility to use default new() & delete()]
00055 ** 960516 JLI   [2.20 suppression of file flushing on unfreed msgs]
00056 ** 960516 JLI   [2.21 better support for using MEMWATCH with DLL's]
00057 ** 960710 JLI   [X.02 multiple logs and mwFlushNow()]
00058 ** 960801 JLI   [2.22 merged X.01 version with current]
00059 ** 960805 JLI   [2.30 mwIsXXXXAddr() to avoid unneeded GP's]
00060 ** 960805 JLI   [2.31 merged X.02 version with current]
00061 ** 961002 JLI   [2.32 support for realloc() + fixed STDERR bug]
00062 ** 961222 JLI   [2.40 added mwMark() & mwUnmark()]
00063 ** 970101 JLI   [2.41 added over/underflow checking after failed ASSERT/VERIFY]
00064 ** 970113 JLI   [2.42 added support for PC-Lint 7.00g]
00065 ** 970207 JLI   [2.43 added support for strdup()]
00066 ** 970209 JLI   [2.44 changed default filename to lowercase]
00067 ** 970405 JLI   [2.45 fixed bug related with atexit() and some C++ compilers]
00068 ** 970723 JLI   [2.46 added MW_ARI_NULLREAD flag]
00069 ** 970813 JLI   [2.47 stabilized marker handling]
00070 ** 980317 JLI   [2.48 ripped out C++ support; wasn't working good anyway]
00071 ** 980318 JLI   [2.50 improved self-repair facilities & SIGSEGV support]
00072 ** 980417 JLI  [2.51 more checks for invalid addresses]
00073 ** 980512 JLI  [2.52 moved MW_ARI_NULLREAD to occur before aborting]
00074 ** 990112 JLI  [2.53 added check for empty heap to mwIsOwned]
00075 ** 990217 JLI  [2.55 improved the emergency repairs diagnostics and NML]
00076 ** 990224 JLI  [2.56 changed ordering of members in structures]
00077 ** 990303 JLI  [2.57 first maybe-fixit-for-hpux test]
00078 ** 990516 JLI  [2.58 added 'static' to the definition of mwAutoInit]
00079 ** 990517 JLI  [2.59 fixed some high-sensitivity warnings]
00080 ** 990610 JLI  [2.60 fixed some more high-sensitivity warnings]
00081 ** 990715 JLI  [2.61 changed TRACE/ASSERT/VERIFY macro names]
00082 ** 991001 JLI  [2.62 added CHECK_BUFFER() and mwTestBuffer()]
00083 ** 991007 JLI  [2.63 first shot at a 64-bit compatible version]
00084 ** 991009 JLI  [2.64 undef's strdup() if defined, mwStrdup made const]
00085 ** 000704 JLI  [2.65 added some more detection for 64-bits]
00086 ** 010502 JLI   [2.66 incorporated some user fixes]
00087 **              [mwRelink() could print out garbage pointer (thanks mac@phobos.ca)]
00088 **          [added array destructor for C++ (thanks rdasilva@connecttel.com)]
00089 **          [added mutex support (thanks rdasilva@connecttel.com)]
00090 ** 010531 JLI  [2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined]
00091 ** 010619 JLI  [2.68 fix: mwRealloc() could leave the mutex locked]
00092 ** 020918 JLI  [2.69 changed to GPL, added C++ array allocation by Howard Cohen]
00093 ** 030212 JLI  [2.70 mwMalloc() bug for very large allocations (4GB on 32bits)]
00094 ** 030520 JLI  [2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)]
00095 */
00096 
00097 #ifdef MEMWATCH
00098 
00099 #define __MEMWATCH_C 1
00100 
00101 #ifdef MW_NOCPP
00102 #define MEMWATCH_NOCPP
00103 #endif
00104 #ifdef MW_STDIO
00105 #define MEMWATCH_STDIO
00106 #endif
00107 
00108 /***********************************************************************
00109 ** Include files
00110 ***********************************************************************/
00111 
00112 #include <stdio.h>
00113 #include <stdlib.h>
00114 #include <stdarg.h>
00115 #include <string.h>
00116 #include <signal.h>
00117 #include <setjmp.h>
00118 #include <time.h>
00119 #include <limits.h>
00120 #include "memwatch.h"
00121 
00122 #ifndef toupper
00123 #include <ctype.h>
00124 #endif
00125 
00126 #if defined(WIN32) || defined(__WIN32__)
00127 #define MW_HAVE_MUTEX 1
00128 #include <windows.h>
00129 #endif
00130 
00131 #if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
00132 #define MW_HAVE_MUTEX 1
00133 #include <pthread.h>
00134 #endif
00135 
00136 /***********************************************************************
00137 ** Defines & other weird stuff
00138 ***********************************************************************/
00139 
00140 /*lint -save -e767 */
00141 #define VERSION     "2.71"         /* the current version number */
00142 #define CHKVAL(mw)  (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line)
00143 #define FLUSH()     mwFlush()
00144 #define TESTS(f,l)  if(mwTestAlways) (void)mwTestNow(f,l,1)
00145 #define PRECHK      0x01234567L
00146 #define POSTCHK     0x76543210L
00147 #define mwBUFFER_TO_MW(p) ( (mwData*) (void*) ( ((char*)p)-mwDataSize-mwOverflowZoneSize ) )
00148 /*lint -restore */
00149 
00150 #define MW_NML      0x0001
00151 
00152 #ifdef _MSC_VER
00153 #define COMMIT "c"  /* Microsoft C requires the 'c' to perform as desired */
00154 #else
00155 #define COMMIT ""   /* Normal ANSI */
00156 #endif /* _MSC_VER */
00157 
00158 #ifdef __cplusplus
00159 #define CPPTEXT "++"
00160 #else
00161 #define CPPTEXT ""
00162 #endif /* __cplusplus */
00163 
00164 #ifdef MEMWATCH_STDIO
00165 #define mwSTDERR stderr
00166 #else
00167 #define mwSTDERR mwLog
00168 #endif
00169 
00170 #ifdef MW_HAVE_MUTEX
00171 #define MW_MUTEX_INIT()    mwMutexInit()
00172 #define MW_MUTEX_TERM()    mwMutexTerm()
00173 #define MW_MUTEX_LOCK()    mwMutexLock()
00174 #define MW_MUTEX_UNLOCK()  mwMutexUnlock()
00175 #else
00176 #define MW_MUTEX_INIT()
00177 #define MW_MUTEX_TERM()
00178 #define MW_MUTEX_LOCK()
00179 #define MW_MUTEX_UNLOCK()
00180 #endif
00181 
00182 /***********************************************************************
00183 ** If you really, really know what you're doing,
00184 ** you can predefine these things yourself.
00185 ***********************************************************************/
00186 
00187 #ifndef mwBYTE_DEFINED
00188 # if CHAR_BIT != 8
00189 #  error need CHAR_BIT to be 8!
00190 # else
00191 typedef unsigned char mwBYTE;
00192 #  define mwBYTE_DEFINED 1
00193 # endif
00194 #endif
00195 
00196 #if defined(ULONGLONG_MAX) || defined(ULLONG_MAX) || defined(_UI64_MAX) || defined(ULONG_LONG_MAX)
00197 # define mw64BIT 1
00198 # define mwROUNDALLOC_DEFAULT 8
00199 #else
00200 # if UINT_MAX <= 0xFFFFUL
00201 #  define mw16BIT 1
00202 #  define mwROUNDALLOC_DEFAULT   2
00203 # else
00204 #  if ULONG_MAX > 0xFFFFFFFFUL
00205 #   define mw64BIT 1
00206 #   define mwROUNDALLOC_DEFAULT  8
00207 #  else
00208 #   define mw32BIT 1
00209 #   define mwROUNDALLOC_DEFAULT  4
00210 #  endif
00211 # endif
00212 #endif
00213 
00214 /* mwROUNDALLOC is the number of bytes to */
00215 /* round up to, to ensure that the end of */
00216 /* the buffer is suitable for storage of */
00217 /* any kind of object */
00218 #ifndef mwROUNDALLOC
00219 # define mwROUNDALLOC mwROUNDALLOC_DEFAULT
00220 #endif
00221 
00222 #ifndef mwDWORD_DEFINED
00223 #if ULONG_MAX == 0xFFFFFFFFUL
00224 typedef unsigned long mwDWORD;
00225 #define mwDWORD_DEFINED "unsigned long"
00226 #endif
00227 #endif
00228 
00229 #ifndef mwDWORD_DEFINED
00230 #if UINT_MAX == 0xFFFFFFFFUL
00231 typedef unsigned int mwDWORD;
00232 #define mwDWORD_DEFINED "unsigned int"
00233 #endif
00234 #endif
00235 
00236 #ifndef mwDWORD_DEFINED
00237 #if USHRT_MAX == 0xFFFFFFFFUL
00238 typedef unsigned short mwDWORD;
00239 #define mwDWORD_DEFINED "unsigned short"
00240 #endif
00241 #endif
00242 
00243 #ifndef mwBYTE_DEFINED
00244 #error "can't find out the correct type for a 8 bit scalar"
00245 #endif
00246 
00247 #ifndef mwDWORD_DEFINED
00248 #error "can't find out the correct type for a 32 bit scalar"
00249 #endif
00250 
00251 /***********************************************************************
00252 ** Typedefs & structures
00253 ***********************************************************************/
00254 
00255 /* main data holding area, precedes actual allocation */
00256 typedef struct mwData_ mwData;
00257 struct mwData_ {
00258     mwData*     prev;   /* previous allocation in chain */
00259     mwData*     next;   /* next allocation in chain */
00260     const char* file;   /* file name where allocated */
00261     long        count;  /* action count */
00262     long        check;  /* integrity check value */
00263 #if 0
00264     long        crc;    /* data crc value */
00265 #endif
00266     size_t      size;   /* size of allocation */
00267     int         line;   /* line number where allocated */
00268     unsigned    flag;   /* flag word */
00269     };
00270 
00271 /* statistics structure */
00272 typedef struct mwStat_ mwStat;
00273 struct mwStat_ {
00274     mwStat*     next;   /* next statistic buffer */
00275     const char* file;
00276     long        total;  /* total bytes allocated */
00277     long        num;    /* total number of allocations */
00278     long        max;    /* max allocated at one time */
00279     long        curr;   /* current allocations */
00280     int         line;
00281     };
00282 
00283 /* grabbing structure, 1K in size */
00284 typedef struct mwGrabData_ mwGrabData;
00285 struct mwGrabData_ {
00286     mwGrabData* next;
00287     int         type;
00288     char        blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ];
00289     };
00290 
00291 typedef struct mwMarker_ mwMarker;
00292 struct mwMarker_ {
00293     void *host;
00294     char *text;
00295     mwMarker *next;
00296     int level;
00297     };
00298 
00299 #if defined(WIN32) || defined(__WIN32__)
00300 typedef HANDLE          mwMutex;
00301 #endif
00302 
00303 #if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
00304 typedef pthread_mutex_t mwMutex;
00305 #endif
00306 
00307 /***********************************************************************
00308 ** Static variables
00309 ***********************************************************************/
00310 
00311 static int      mwInited =      0;
00312 static int      mwInfoWritten = 0;
00313 static int      mwUseAtexit =   0;
00314 static FILE*    mwLog =         NULL;
00315 static int      mwFlushing =    0;
00316 static int      mwStatLevel =   MW_STAT_DEFAULT;
00317 static int      mwNML =         MW_NML_DEFAULT;
00318 static int      mwFBI =         0;
00319 static long     mwAllocLimit =  0L;
00320 static int      mwUseLimit =    0;
00321 
00322 static long     mwNumCurAlloc = 0L;
00323 static mwData*  mwHead =      NULL;
00324 static mwData*  mwTail =      NULL;
00325 static int     mwDataSize =   0;
00326 static unsigned char mwOverflowZoneTemplate[] = "mEmwAtch";
00327 static int     mwOverflowZoneSize = mwROUNDALLOC;
00328 
00329 static void     (*mwOutFunction)(int) = NULL;
00330 static int      (*mwAriFunction)(const char*) = NULL;
00331 static int      mwAriAction = MW_ARI_ABORT;
00332 
00333 static char     mwPrintBuf[MW_TRACE_BUFFER+8];
00334 
00335 static unsigned long mwCounter = 0L;
00336 static long     mwErrors =      0L;
00337 
00338 static int      mwTestFlags =   0;
00339 static int      mwTestAlways =  0;
00340 
00341 static FILE*    mwLogB1 =       NULL;
00342 static int      mwFlushingB1 =  0;
00343 
00344 static mwStat*  mwStatList = NULL;
00345 static long     mwStatTotAlloc = 0L;
00346 static long     mwStatMaxAlloc = 0L;
00347 static long     mwStatNumAlloc = 0L;
00348 static long     mwStatCurAlloc = 0L;
00349 static long     mwNmlNumAlloc = 0L;
00350 static long     mwNmlCurAlloc = 0L;
00351 
00352 static mwGrabData* mwGrabList = NULL;
00353 static long     mwGrabSize = 0L;
00354 
00355 static void *   mwLastFree[MW_FREE_LIST];
00356 static const char *mwLFfile[MW_FREE_LIST];
00357 static int      mwLFline[MW_FREE_LIST];
00358 static int      mwLFcur = 0;
00359 
00360 static mwMarker* mwFirstMark = NULL;
00361 
00362 static FILE*    mwLogB2 =       NULL;
00363 static int      mwFlushingB2 =  0;
00364 
00365 #ifdef MW_HAVE_MUTEX
00366 static mwMutex mwGlobalMutex;
00367 #endif
00368 
00369 /***********************************************************************
00370 ** Static function declarations
00371 ***********************************************************************/
00372 
00373 static void     mwAutoInit( void );
00374 static FILE*    mwLogR( void );
00375 static void     mwLogW( FILE* );
00376 static int      mwFlushR( void );
00377 static void     mwFlushW( int );
00378 static void     mwFlush( void );
00379 static void     mwIncErr( void );
00380 static void     mwUnlink( mwData*, const char* file, int line );
00381 static int      mwRelink( mwData*, const char* file, int line );
00382 static int      mwIsHeapOK( mwData *mw );
00383 static int      mwIsOwned( mwData* mw, const char* file, int line );
00384 static int      mwTestBuf( mwData* mw, const char* file, int line );
00385 static void     mwDefaultOutFunc( int );
00386 static void     mwWrite( const char* format, ... );
00387 static void     mwLogFile( const char* name );
00388 static size_t   mwFreeUp( size_t, int );
00389 static const void *mwTestMem( const void *, unsigned, int );
00390 static int      mwStrCmpI( const char *s1, const char *s2 );
00391 static int      mwTestNow( const char *file, int line, int always_invoked );
00392 static void     mwDropAll( void );
00393 static const char *mwGrabType( int type );
00394 static unsigned mwGrab_( unsigned kb, int type, int silent );
00395 static unsigned mwDrop_( unsigned kb, int type, int silent );
00396 static int      mwARI( const char* text );
00397 static void     mwStatReport( void );
00398 static mwStat*  mwStatGet( const char*, int, int );
00399 static void     mwStatAlloc( size_t, const char*, int );
00400 static void     mwStatFree( size_t, const char*, int );
00401 static int     mwCheckOF( const void * p );
00402 static void    mwWriteOF( void * p );
00403 static char    mwDummy( char c );
00404 #ifdef MW_HAVE_MUTEX
00405 static void    mwMutexInit( void );
00406 static void    mwMutexTerm( void );
00407 static void    mwMutexLock( void );
00408 static void    mwMutexUnlock( void );
00409 #endif
00410 
00411 /***********************************************************************
00412 ** System functions
00413 ***********************************************************************/
00414 
00415 void mwInit( void ) {
00416     time_t tid;
00417 
00418     if( mwInited++ > 0 ) return;
00419 
00420    MW_MUTEX_INIT();
00421 
00422     /* start a log if none is running */
00423     if( mwLogR() == NULL ) mwLogFile( "memwatch.log" );
00424     if( mwLogR() == NULL ) {
00425         int i;
00426         char buf[32];
00427         /* oops, could not open it! */
00428         /* probably because it's already open */
00429         /* so we try some other names */
00430         for( i=1; i<100; i++ ) {
00431             sprintf( buf, "memwat%02d.log", i );
00432             mwLogFile( buf );
00433             if( mwLogR() != NULL ) break;
00434             }
00435         }
00436 
00437     /* initialize the statistics */
00438     mwStatList = NULL;
00439     mwStatTotAlloc = 0L;
00440     mwStatCurAlloc = 0L;
00441     mwStatMaxAlloc = 0L;
00442     mwStatNumAlloc = 0L;
00443    mwNmlCurAlloc = 0L;
00444    mwNmlNumAlloc = 0L;
00445 
00446    /* calculate the buffer size to use for a mwData */
00447    mwDataSize = sizeof(mwData);
00448    while( mwDataSize % mwROUNDALLOC ) mwDataSize ++;
00449 
00450     /* write informational header if needed */
00451     if( !mwInfoWritten ) {
00452         mwInfoWritten = 1;
00453         (void) time( &tid );
00454         mwWrite(
00455             "\n============="
00456             " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh "
00457             "=============\n");
00458         mwWrite( "\nStarted at %s\n", ctime( &tid ) );
00459 
00460 /**************************************************************** Generic */
00461       mwWrite( "Modes: " );
00462 #ifdef mwNew
00463         mwWrite( "C++ " );
00464 #endif /* mwNew */
00465 #ifdef __STDC__
00466         mwWrite( "__STDC__ " );
00467 #endif /* __STDC__ */
00468 #ifdef mw16BIT
00469       mwWrite( "16-bit " );
00470 #endif
00471 #ifdef mw32BIT
00472       mwWrite( "32-bit " );
00473 #endif
00474 #ifdef mw64BIT
00475       mwWrite( "64-bit " );
00476 #endif
00477       mwWrite( "mwDWORD==(" mwDWORD_DEFINED ")\n" );
00478       mwWrite( "mwROUNDALLOC==%d sizeof(mwData)==%d mwDataSize==%d\n",
00479          mwROUNDALLOC, sizeof(mwData), mwDataSize );
00480 /**************************************************************** Generic */
00481 
00482 /************************************************************ Microsoft C */
00483 #ifdef _MSC_VER
00484         mwWrite( "Compiled using Microsoft C" CPPTEXT
00485             " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 );
00486 #endif /* _MSC_VER */
00487 /************************************************************ Microsoft C */
00488 
00489 /************************************************************** Borland C */
00490 #ifdef __BORLANDC__
00491         mwWrite( "Compiled using Borland C"
00492 #ifdef __cplusplus
00493             "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 );
00494 #else
00495             " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 );
00496 #endif /* __cplusplus */
00497 #endif /* __BORLANDC__ */
00498 /************************************************************** Borland C */
00499 
00500 /************************************************************** Watcom C */
00501 #ifdef __WATCOMC__
00502         mwWrite( "Compiled using Watcom C %d.%02d ",
00503             __WATCOMC__/100, __WATCOMC__%100 );
00504 #ifdef __FLAT__
00505         mwWrite( "(32-bit flat model)" );
00506 #endif /* __FLAT__ */
00507         mwWrite( "\n" );
00508 #endif /* __WATCOMC__ */
00509 /************************************************************** Watcom C */
00510 
00511         mwWrite( "\n" );
00512         FLUSH();
00513         }
00514 
00515     if( mwUseAtexit ) (void) atexit( mwAbort );
00516     return;
00517     }
00518 
00519 void mwAbort( void ) {
00520     mwData *mw;
00521     mwMarker *mrk;
00522     char *data;
00523     time_t tid;
00524     int c, i, j;
00525    int errors;
00526 
00527     tid = time( NULL );
00528     mwWrite( "\nStopped at %s\n", ctime( &tid) );
00529 
00530     if( !mwInited )
00531         mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" );
00532 
00533     /* release the grab list */
00534     mwDropAll();
00535 
00536     /* report mwMarked items */
00537     while( mwFirstMark ) {
00538         mrk = mwFirstMark->next;
00539         mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text );
00540         free( mwFirstMark->text );
00541         free( mwFirstMark );
00542         mwFirstMark = mrk;
00543         mwErrors ++;
00544         }
00545 
00546     /* release all still allocated memory */
00547    errors = 0;
00548     while( mwHead != NULL && errors < 3 ) {
00549       if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) {
00550          if( errors < 3 )
00551          {
00552             errors ++;
00553             mwWrite( "internal: NML/unfreed scan restarting\n" );
00554             FLUSH();
00555             mwHead = mwHead;
00556             continue;
00557          }
00558          mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" );
00559          FLUSH();
00560          break;
00561          }
00562         mwFlushW(0);
00563         if( !(mwHead->flag & MW_NML) ) {
00564             mwErrors++;
00565             data = ((char*)mwHead)+mwDataSize;
00566             mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ",
00567                 mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+mwOverflowZoneSize );
00568             if( mwCheckOF( data ) ) {
00569                 mwWrite( "[underflowed] ");
00570                 FLUSH();
00571                 }
00572             if( mwCheckOF( (data+mwOverflowZoneSize+mwHead->size) ) ) {
00573                 mwWrite( "[overflowed] ");
00574                 FLUSH();
00575                 }
00576             mwWrite( " \t{" );
00577             j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size;
00578             for( i=0;i<16;i++ ) {
00579                 if( i<j ) mwWrite( "%02X ",
00580                     (unsigned char) *(data+mwOverflowZoneSize+i) );
00581                 else mwWrite( ".. " );
00582                 }
00583             for( i=0;i<j;i++ ) {
00584                 c = *(data+mwOverflowZoneSize+i);
00585                 if( c < 32 || c > 126 ) c = '.';
00586                 mwWrite( "%c", c );
00587                 }
00588             mwWrite( "}\n" );
00589          mw = mwHead;
00590          mwUnlink( mw, __FILE__, __LINE__ );
00591             free( mw );
00592             }
00593         else {
00594             data = ((char*)mwHead) + mwDataSize + mwOverflowZoneSize;
00595             if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) {
00596                 mwErrors++;
00597                 mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
00598                     mwHead->count, data + mwOverflowZoneSize, mwHead->file, mwHead->line );
00599                 FLUSH();
00600                 }
00601          mwNmlNumAlloc --;
00602          mwNmlCurAlloc -= mwHead->size;
00603          mw = mwHead;
00604          mwUnlink( mw, __FILE__, __LINE__ );
00605             free( mw );
00606             }
00607         }
00608 
00609    if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc );
00610    if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc );
00611 
00612     /* report statistics */
00613     mwStatReport();
00614     FLUSH();
00615 
00616     mwInited = 0;
00617     mwHead = mwTail = NULL;
00618     if( mwErrors )
00619         fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors);
00620     mwLogFile( NULL );
00621     mwErrors = 0;
00622 
00623     MW_MUTEX_TERM();
00624 
00625     }
00626 
00627 void mwTerm( void ) {
00628     if( mwInited == 1 )
00629     {
00630         mwAbort();
00631         return;
00632     }
00633     if( !mwInited )
00634         mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n");
00635     else
00636         mwInited --;
00637     }
00638 
00639 void mwStatistics( int level )
00640 {
00641     mwAutoInit();
00642     if( level<0 ) level=0;
00643     if( mwStatLevel != level )
00644     {
00645       mwWrite( "statistics: now collecting on a %s basis\n",
00646          level<1?"global":(level<2?"module":"line") );
00647        mwStatLevel = level;
00648    }
00649 }
00650 
00651 void mwAutoCheck( int onoff ) {
00652     mwAutoInit();
00653     mwTestAlways = onoff;
00654     if( onoff ) mwTestFlags = MW_TEST_ALL;
00655     }
00656 
00657 void mwSetOutFunc( void (*func)(int) ) {
00658     mwAutoInit();
00659     mwOutFunction = func;
00660     }
00661 
00662 static void mwWriteOF( void *p )
00663 {
00664    int i;
00665    unsigned char *ptr;
00666    ptr = (unsigned char*) p;
00667    for( i=0; i<mwOverflowZoneSize; i++ )
00668    {
00669       *(ptr+i) = mwOverflowZoneTemplate[i%8];
00670    }
00671    return;
00672 }
00673 
00674 static int mwCheckOF( const void *p )
00675 {
00676    int i;
00677    const unsigned char *ptr;
00678    ptr = (const unsigned char *) p;
00679    for( i=0; i<mwOverflowZoneSize; i++ )
00680    {
00681       if( *(ptr+i) != mwOverflowZoneTemplate[i%8] )
00682          return 1; /* errors found */
00683    }
00684    return 0; /* no errors */
00685 }
00686 
00687 int mwTest( const char *file, int line, int items ) {
00688     mwAutoInit();
00689     mwTestFlags = items;
00690     return mwTestNow( file, line, 0 );
00691     }
00692 
00693 /*
00694 ** Returns zero if there are no errors.
00695 ** Returns nonzero if there are errors.
00696 */
00697 int mwTestBuffer( const char *file, int line, void *p ) {
00698     mwData* mw;
00699 
00700     mwAutoInit();
00701 
00702     /* do the quick ownership test */
00703     mw = (mwData*) mwBUFFER_TO_MW( p );
00704 
00705     if( mwIsOwned( mw, file, line ) ) {
00706         return mwTestBuf( mw, file, line );
00707       }
00708    return 1;
00709    }
00710 
00711 void mwBreakOut( const char* cause ) {
00712     fprintf(mwSTDERR, "breakout: %s\n", cause);
00713     mwWrite("breakout: %s\n", cause );
00714     return;
00715     }
00716 
00717 /*
00718 ** 981217 JLI: is it possible that ->next is not always set?
00719 */
00720 void * mwMark( void *p, const char *desc, const char *file, unsigned line ) {
00721     mwMarker *mrk;
00722     unsigned n, isnew;
00723     char *buf;
00724     int tot, oflow = 0;
00725     char wherebuf[128];
00726 
00727     mwAutoInit();
00728     TESTS(NULL,0);
00729 
00730     if( desc == NULL ) desc = "unknown";
00731     if( file == NULL ) file = "unknown";
00732 
00733     tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line );
00734     if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; }
00735 
00736     if( p == NULL ) {
00737         mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc );
00738         return p;
00739         }
00740 
00741    if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) )
00742    {
00743       mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n",
00744          file, line, mwFirstMark, desc );
00745       return p;
00746    }
00747 
00748     for( mrk=mwFirstMark; mrk; mrk=mrk->next )
00749    {
00750       if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) )
00751       {
00752          mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n",
00753             file, line, mrk, mrk->next, desc );
00754          return p;
00755       }
00756       if( mrk->host == p ) break;
00757    }
00758 
00759     if( mrk == NULL ) {
00760         isnew = 1;
00761         mrk = (mwMarker*) malloc( sizeof( mwMarker ) );
00762         if( mrk == NULL ) {
00763             mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
00764             return p;
00765             }
00766       mrk->next = NULL;
00767         n = 0;
00768         }
00769     else {
00770         isnew = 0;
00771         n = strlen( mrk->text );
00772         }
00773 
00774     n += strlen( wherebuf );
00775     buf = (char*) malloc( n+3 );
00776     if( buf == NULL ) {
00777         if( isnew ) free( mrk );
00778         mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
00779         return p;
00780         }
00781 
00782     if( isnew ) {
00783         memcpy( buf, wherebuf, n+1 );
00784         mrk->next = mwFirstMark;
00785         mrk->host = p;
00786         mrk->text = buf;
00787         mrk->level = 1;
00788         mwFirstMark = mrk;
00789         }
00790     else {
00791         strcpy( buf, mrk->text );
00792         strcat( buf, ", " );
00793         strcat( buf, wherebuf );
00794         free( mrk->text );
00795         mrk->text = buf;
00796         mrk->level ++;
00797         }
00798 
00799     if( oflow ) {
00800         mwIncErr();
00801         mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
00802         }
00803     return p;
00804     }
00805 
00806 void* mwUnmark( void *p, const char *file, unsigned line ) {
00807     mwMarker *mrk, *prv;
00808     mrk = mwFirstMark;
00809     prv = NULL;
00810     while( mrk ) {
00811         if( mrk->host == p ) {
00812             if( mrk->level < 2 ) {
00813                 if( prv ) prv->next = mrk->next;
00814                 else mwFirstMark = mrk->next;
00815                 free( mrk->text );
00816                 free( mrk );
00817                 return p;
00818                 }
00819             mrk->level --;
00820             return p;
00821             }
00822         prv = mrk;
00823         mrk = mrk->next;
00824         }
00825     mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p );
00826     return p;
00827     }
00828 
00829 
00830 /***********************************************************************
00831 ** Abort/Retry/Ignore handlers
00832 ***********************************************************************/
00833 
00834 static int mwARI( const char *estr ) {
00835     char inbuf[81];
00836     int c;
00837     fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr);
00838     (void) fgets(inbuf,sizeof(inbuf),stdin);
00839    for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ;
00840     c = inbuf[c];
00841     if( c == 'R' || c == 'r' ) {
00842         mwBreakOut( estr );
00843         return MW_ARI_RETRY;
00844         }
00845     if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE;
00846     return MW_ARI_ABORT;
00847     }
00848 
00849 /* standard ARI handler (exported) */
00850 int mwAriHandler( const char *estr ) {
00851     mwAutoInit();
00852     return mwARI( estr );
00853     }
00854 
00855 /* used to set the ARI function */
00856 void mwSetAriFunc( int (*func)(const char *) ) {
00857     mwAutoInit();
00858     mwAriFunction = func;
00859     }
00860 
00861 /***********************************************************************
00862 ** Allocation handlers
00863 ***********************************************************************/
00864 
00865 void* mwMalloc( size_t size, const char* file, int line) {
00866     size_t needed;
00867     mwData *mw;
00868     char *ptr;
00869     void *p;
00870 
00871     mwAutoInit();
00872 
00873    MW_MUTEX_LOCK();
00874 
00875     TESTS(file,line);
00876 
00877     mwCounter ++;
00878     needed = mwDataSize + mwOverflowZoneSize*2 + size;
00879     if( needed < size )
00880     {
00881       /* theoretical case: req size + mw overhead exceeded size_t limits */
00882       return NULL;
00883     }
00884 
00885     /* if this allocation would violate the limit, fail it */
00886     if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) {
00887         mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
00888             mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc );
00889         mwIncErr();
00890         FLUSH();
00891       MW_MUTEX_UNLOCK();
00892         return NULL;
00893         }
00894 
00895     mw = (mwData*) malloc( needed );
00896     if( mw == NULL ) {
00897         if( mwFreeUp(needed,0) >= needed ) {
00898             mw = (mwData*) malloc(needed);
00899             if( mw == NULL ) {
00900                 mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed );
00901                 mwIncErr();
00902                 FLUSH();
00903                 }
00904             }
00905         if( mw == NULL ) {
00906             mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n",
00907                 mwCounter, file, line, (long)size, mwStatCurAlloc );
00908             mwIncErr();
00909             FLUSH();
00910          MW_MUTEX_UNLOCK();
00911             return NULL;
00912             }
00913         }
00914 
00915     mw->count = mwCounter;
00916     mw->prev = NULL;
00917     mw->next = mwHead;
00918     mw->file = file;
00919     mw->size = size;
00920     mw->line = line;
00921     mw->flag = 0;
00922     mw->check = CHKVAL(mw);
00923 
00924     if( mwHead ) mwHead->prev = mw;
00925     mwHead = mw;
00926     if( mwTail == NULL ) mwTail = mw;
00927 
00928     ptr = ((char*)mw) + mwDataSize;
00929    mwWriteOF( ptr ); /* '*(long*)ptr = PRECHK;' */
00930     ptr += mwOverflowZoneSize;
00931     p = ptr;
00932     memset( ptr, MW_VAL_NEW, size );
00933     ptr += size;
00934     mwWriteOF( ptr ); /* '*(long*)ptr = POSTCHK;' */
00935 
00936     mwNumCurAlloc ++;
00937     mwStatCurAlloc += (long) size;
00938     mwStatTotAlloc += (long) size;
00939     if( mwStatCurAlloc > mwStatMaxAlloc )
00940         mwStatMaxAlloc = mwStatCurAlloc;
00941     mwStatNumAlloc ++;
00942 
00943     if( mwStatLevel ) mwStatAlloc( size, file, line );
00944 
00945    MW_MUTEX_UNLOCK();
00946     return p;
00947     }
00948 
00949 void* mwRealloc( void *p, size_t size, const char* file, int line) {
00950     int oldUseLimit, i;
00951     mwData *mw;
00952     char *ptr;
00953 
00954     mwAutoInit();
00955 
00956     if( p == NULL ) return mwMalloc( size, file, line );
00957     if( size == 0 ) { mwFree( p, file, line ); return NULL; }
00958 
00959    MW_MUTEX_LOCK();
00960 
00961     /* do the quick ownership test */
00962     mw = (mwData*) mwBUFFER_TO_MW( p );
00963     if( mwIsOwned( mw, file, line ) ) {
00964 
00965       /* if the buffer is an NML, treat this as a double-free */
00966       if( mw->flag & MW_NML )
00967       {
00968             mwIncErr();
00969          if( *((unsigned char*)(mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML )
00970          {
00971             mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
00972                mwCounter, file, line, mw );
00973          }
00974          goto check_dbl_free;
00975       }
00976 
00977         /* if this allocation would violate the limit, fail it */
00978         if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) {
00979             TESTS(file,line);
00980             mwCounter ++;
00981             mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
00982                 mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc );
00983             mwIncErr();
00984             FLUSH();
00985          MW_MUTEX_UNLOCK();
00986             return NULL;
00987             }
00988 
00989         /* fake realloc operation */
00990         oldUseLimit = mwUseLimit;
00991         mwUseLimit = 0;
00992         ptr = (char*) mwMalloc( size, file, line );
00993         if( ptr != NULL ) {
00994             if( size < mw->size )
00995                 memcpy( ptr, p, size );
00996             else
00997                 memcpy( ptr, p, mw->size );
00998             mwFree( p, file, line );
00999             }
01000         mwUseLimit = oldUseLimit;
01001       MW_MUTEX_UNLOCK();
01002         return (void*) ptr;
01003         }
01004 
01005     /* Unknown pointer! */
01006 
01007     /* using free'd pointer? */
01008 check_dbl_free:
01009     for(i=0;i<MW_FREE_LIST;i++) {
01010         if( mwLastFree[i] == p ) {
01011             mwIncErr();
01012             mwWrite( "realloc: <%ld> %s(%d), %p was"
01013                 " freed from %s(%d)\n",
01014                 mwCounter, file, line, p,
01015                 mwLFfile[i], mwLFline[i] );
01016             FLUSH();
01017          MW_MUTEX_UNLOCK();
01018             return NULL;
01019             }
01020         }
01021 
01022     /* some weird pointer */
01023     mwIncErr();
01024     mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n",
01025         mwCounter, file, line, p );
01026     FLUSH();
01027    MW_MUTEX_UNLOCK();
01028     return NULL;
01029     }
01030 
01031 char *mwStrdup( const char* str, const char* file, int line ) {
01032     size_t len;
01033     char *newstring;
01034 
01035    MW_MUTEX_LOCK();
01036 
01037     if( str == NULL ) {
01038         mwIncErr();
01039         mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n",
01040             mwCounter, file, line );
01041         FLUSH();
01042       MW_MUTEX_UNLOCK();
01043         return NULL;
01044         }
01045 
01046     len = strlen( str ) + 1;
01047     newstring = (char*) mwMalloc( len, file, line );
01048     if( newstring != NULL ) memcpy( newstring, str, len );
01049    MW_MUTEX_UNLOCK();
01050     return newstring;
01051     }
01052 
01053 void mwFree( void* p, const char* file, int line ) {
01054     int i;
01055     mwData* mw;
01056     char buffer[ sizeof(mwData) + (mwROUNDALLOC*3) + 64 ];
01057 
01058     /* this code is in support of C++ delete */
01059     if( file == NULL ) {
01060         mwFree_( p );
01061       MW_MUTEX_UNLOCK();
01062         return;
01063         }
01064 
01065     mwAutoInit();
01066 
01067    MW_MUTEX_LOCK();
01068     TESTS(file,line);
01069     mwCounter ++;
01070 
01071     /* on NULL free, write a warning and return */
01072     if( p == NULL ) {
01073         mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n",
01074             mwCounter, file, line );
01075         FLUSH();
01076       MW_MUTEX_UNLOCK();
01077         return;
01078         }
01079 
01080     /* do the quick ownership test */
01081     mw = (mwData*) mwBUFFER_TO_MW( p );
01082 
01083     if( mwIsOwned( mw, file, line ) ) {
01084         (void) mwTestBuf( mw, file, line );
01085 
01086       /* if the buffer is an NML, treat this as a double-free */
01087       if( mw->flag & MW_NML )
01088       {
01089          if( *(((unsigned char*)mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML )
01090          {
01091             mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
01092                mwCounter, file, line, mw );
01093          }
01094          goto check_dbl_free;
01095       }
01096 
01097         /* update the statistics */
01098         mwNumCurAlloc --;
01099         mwStatCurAlloc -= (long) mw->size;
01100         if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line );
01101 
01102         /* we should either free the allocation or keep it as NML */
01103         if( mwNML ) {
01104             mw->flag |= MW_NML;
01105          mwNmlNumAlloc ++;
01106          mwNmlCurAlloc += (long) mw->size;
01107             memset( ((char*)mw)+mwDataSize+mwOverflowZoneSize, MW_VAL_NML, mw->size );
01108             }
01109         else {
01110             /* unlink the allocation, and enter the post-free data */
01111             mwUnlink( mw, file, line );
01112             memset( mw, MW_VAL_DEL,
01113                 mw->size + mwDataSize+mwOverflowZoneSize+mwOverflowZoneSize );
01114             if( mwFBI ) {
01115                 memset( mw, '.', mwDataSize + mwOverflowZoneSize );
01116                 sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line );
01117                 strncpy( (char*)(void*)mw, buffer, mwDataSize + mwOverflowZoneSize );
01118                 }
01119             free( mw );
01120             }
01121 
01122         /* add the pointer to the last-free track */
01123         mwLFfile[ mwLFcur ] = file;
01124         mwLFline[ mwLFcur ] = line;
01125         mwLastFree[ mwLFcur++ ] = p;
01126         if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0;
01127 
01128       MW_MUTEX_UNLOCK();
01129         return;
01130         }
01131 
01132     /* check for double-freeing */
01133 check_dbl_free:
01134     for(i=0;i<MW_FREE_LIST;i++) {
01135         if( mwLastFree[i] == p ) {
01136             mwIncErr();
01137             mwWrite( "double-free: <%ld> %s(%d), %p was"
01138                 " freed from %s(%d)\n",
01139                 mwCounter, file, line, p,
01140                 mwLFfile[i], mwLFline[i] );
01141             FLUSH();
01142          MW_MUTEX_UNLOCK();
01143             return;
01144             }
01145         }
01146 
01147     /* some weird pointer... block the free */
01148     mwIncErr();
01149     mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n",
01150         mwCounter, file, line, p );
01151     FLUSH();
01152    MW_MUTEX_UNLOCK();
01153     return;
01154     }
01155 
01156 void* mwCalloc( size_t a, size_t b, const char *file, int line ) {
01157     void *p;
01158     size_t size = a * b;
01159     p = mwMalloc( size, file, line );
01160     if( p == NULL ) return NULL;
01161     memset( p, 0, size );
01162     return p;
01163     }
01164 
01165 void mwFree_( void *p ) {
01166    MW_MUTEX_LOCK();
01167     TESTS(NULL,0);
01168    MW_MUTEX_UNLOCK();
01169     free(p);
01170     }
01171 
01172 void* mwMalloc_( size_t size ) {
01173    MW_MUTEX_LOCK();
01174     TESTS(NULL,0);
01175    MW_MUTEX_UNLOCK();
01176     return malloc( size );
01177     }
01178 
01179 void* mwRealloc_( void *p, size_t size ) {
01180    MW_MUTEX_LOCK();
01181     TESTS(NULL,0);
01182    MW_MUTEX_UNLOCK();
01183     return realloc( p, size );
01184     }
01185 
01186 void* mwCalloc_( size_t a, size_t b ) {
01187    MW_MUTEX_LOCK();
01188     TESTS(NULL,0);
01189    MW_MUTEX_UNLOCK();
01190     return calloc( a, b );
01191     }
01192 
01193 void mwFlushNow( void ) {
01194     if( mwLogR() ) fflush( mwLogR() );
01195     return;
01196     }
01197 
01198 void mwDoFlush( int onoff ) {
01199     mwFlushW( onoff<1?0:onoff );
01200     if( onoff ) if( mwLogR() ) fflush( mwLogR() );
01201     return;
01202     }
01203 
01204 void mwLimit( long lim ) {
01205     TESTS(NULL,0);
01206     mwWrite("limit: old limit = ");
01207     if( !mwAllocLimit ) mwWrite( "none" );
01208     else mwWrite( "%ld bytes", mwAllocLimit );
01209     mwWrite( ", new limit = ");
01210     if( !lim ) {
01211         mwWrite( "none\n" );
01212         mwUseLimit = 0;
01213         }
01214     else {
01215         mwWrite( "%ld bytes\n", lim );
01216         mwUseLimit = 1;
01217         }
01218     mwAllocLimit = lim;
01219     FLUSH();
01220     }
01221 
01222 void mwSetAriAction( int action ) {
01223    MW_MUTEX_LOCK();
01224     TESTS(NULL,0);
01225     mwAriAction = action;
01226    MW_MUTEX_UNLOCK();
01227     return;
01228     }
01229 
01230 int mwAssert( int exp, const char *exps, const char *fn, int ln ) {
01231     int i;
01232     char buffer[MW_TRACE_BUFFER+8];
01233     if( exp ) {
01234       return 0;
01235       }
01236     mwAutoInit();
01237    MW_MUTEX_LOCK();
01238     TESTS(fn,ln);
01239     mwIncErr();
01240     mwCounter++;
01241     mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
01242     if( mwAriFunction != NULL ) {
01243         sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps );
01244         i = (*mwAriFunction)(buffer);
01245       switch( i ) {
01246          case MW_ARI_IGNORE:
01247                mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter );
01248             MW_MUTEX_UNLOCK();
01249               return 0;
01250          case MW_ARI_RETRY:
01251                mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter );
01252             MW_MUTEX_UNLOCK();
01253                return 1;
01254          }
01255         }
01256     else {
01257         if( mwAriAction & MW_ARI_IGNORE ) {
01258             mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
01259          MW_MUTEX_UNLOCK();
01260             return 0;
01261             }
01262         fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps );
01263         }
01264 
01265     FLUSH();
01266     (void) mwTestNow( fn, ln, 1 );
01267     FLUSH();
01268 
01269    if( mwAriAction & MW_ARI_NULLREAD ) {
01270       /* This is made in an attempt to kick in */
01271       /* any debuggers or OS stack traces */
01272        FLUSH();
01273       /*lint -save -e413 */
01274       i = *((int*)NULL);
01275       mwDummy( (char)i );
01276       /*lint -restore */
01277       }
01278 
01279    MW_MUTEX_UNLOCK();
01280     exit(255);
01281     /* NOT REACHED - the return statement is in to keep */
01282     /* stupid compilers from squeaking about differing return modes. */
01283     /* Smart compilers instead say 'code unreachable...' */
01284     /*lint -save -e527 */
01285     return 0;
01286     /*lint -restore */
01287     }
01288 
01289 int mwVerify( int exp, const char *exps, const char *fn, int ln ) {
01290     int i;
01291     char buffer[MW_TRACE_BUFFER+8];
01292     if( exp ) {
01293       return 0;
01294       }
01295     mwAutoInit();
01296    MW_MUTEX_LOCK();
01297     TESTS(fn,ln);
01298     mwIncErr();
01299     mwCounter++;
01300     mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
01301     if( mwAriFunction != NULL ) {
01302         sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps );
01303         i = (*mwAriFunction)(buffer);
01304         if( i == 0 ) {
01305             mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter );
01306          MW_MUTEX_UNLOCK();
01307             return 0;
01308             }
01309         if( i == 1 ) {
01310             mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter );
01311          MW_MUTEX_UNLOCK();
01312             return 1;
01313             }
01314         }
01315     else {
01316         if( mwAriAction & MW_ARI_NULLREAD ) {
01317             /* This is made in an attempt to kick in */
01318             /* any debuggers or OS stack traces */
01319           FLUSH();
01320             /*lint -save -e413 */
01321             i = *((int*)NULL);
01322          mwDummy( (char)i );
01323             /*lint -restore */
01324             }
01325         if( mwAriAction & MW_ARI_IGNORE ) {
01326             mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
01327          MW_MUTEX_UNLOCK();
01328             return 0;
01329             }
01330         fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps );
01331         }
01332     FLUSH();
01333     (void) mwTestNow( fn, ln, 1 );
01334     FLUSH();
01335    MW_MUTEX_UNLOCK();
01336    exit(255);
01337     /* NOT REACHED - the return statement is in to keep */
01338     /* stupid compilers from squeaking about differing return modes. */
01339     /* Smart compilers instead say 'code unreachable...' */
01340     /*lint -save -e527 */
01341     return 0;
01342     /*lint -restore */
01343     }
01344 
01345 void mwTrace( const char *format, ... ) {
01346     int tot, oflow = 0;
01347     va_list mark;
01348 
01349     mwAutoInit();
01350    MW_MUTEX_LOCK();
01351     TESTS(NULL,0);
01352     if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
01353 
01354     va_start( mark, format );
01355     tot = vsprintf( mwPrintBuf, format, mark );
01356     va_end( mark );
01357     if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; }
01358     for(tot=0;mwPrintBuf[tot];tot++)
01359         (*mwOutFunction)( mwPrintBuf[tot] );
01360     if( oflow ) {
01361         mwIncErr();
01362         mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
01363         }
01364 
01365     FLUSH();
01366    MW_MUTEX_UNLOCK();
01367     }
01368 
01369 
01370 /***********************************************************************
01371 ** Grab & Drop
01372 ***********************************************************************/
01373 
01374 unsigned mwGrab( unsigned kb ) {
01375     TESTS(NULL,0);
01376     return mwGrab_( kb, MW_VAL_GRB, 0 );
01377     }
01378 
01379 unsigned mwDrop( unsigned kb ) {
01380     TESTS(NULL,0);
01381     return mwDrop_( kb, MW_VAL_GRB, 0 );
01382     }
01383 
01384 static void mwDropAll() {
01385     TESTS(NULL,0);
01386     (void) mwDrop_( 0, MW_VAL_GRB, 0 );
01387     (void) mwDrop_( 0, MW_VAL_NML, 0 );
01388     if( mwGrabList != NULL )
01389         mwWrite( "internal: the grab list is not empty after mwDropAll()\n");
01390     }
01391 
01392 static const char *mwGrabType( int type ) {
01393     switch( type ) {
01394         case MW_VAL_GRB:
01395             return "grabbed";
01396         case MW_VAL_NML:
01397             return "no-mans-land";
01398         default:
01399             /* do nothing */
01400             ;
01401         }
01402     return "<unknown type>";
01403     }
01404 
01405 static unsigned mwGrab_( unsigned kb, int type, int silent ) {
01406     unsigned i = kb;
01407     mwGrabData *gd;
01408     if( !kb ) i = kb = 65000U;
01409 
01410     for(;kb;kb--) {
01411         if( mwUseLimit &&
01412             (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) {
01413             if( !silent ) {
01414                 mwWrite("grabbed: all allowed memory to %s (%u kb)\n",
01415                     mwGrabType(type), i-kb);
01416                 FLUSH();
01417                 }
01418             return i-kb;
01419             }
01420         gd = (mwGrabData*) malloc( sizeof(mwGrabData) );
01421         if( gd == NULL ) {
01422             if( !silent ) {
01423                 mwWrite("grabbed: all available memory to %s (%u kb)\n",
01424                     mwGrabType(type), i-kb);
01425                 FLUSH();
01426                 }
01427             return i-kb;
01428             }
01429         mwGrabSize += (long) sizeof(mwGrabData);
01430         gd->next = mwGrabList;
01431         memset( gd->blob, type, sizeof(gd->blob) );
01432         gd->type = type;
01433         mwGrabList = gd;
01434         }
01435     if( !silent ) {
01436         mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) );
01437         FLUSH();
01438         }
01439     return i;
01440     }
01441 
01442 static unsigned mwDrop_( unsigned kb, int type, int silent ) {
01443     unsigned i = kb;
01444     mwGrabData *gd,*tmp,*pr;
01445     const void *p;
01446 
01447     if( mwGrabList == NULL && kb == 0 ) return 0;
01448     if( !kb ) i = kb = 60000U;
01449 
01450     pr = NULL;
01451     gd = mwGrabList;
01452     for(;kb;) {
01453         if( gd == NULL ) {
01454             if( i-kb > 0 && !silent ) {
01455                 mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb);
01456                 FLUSH();
01457                 }
01458             return i-kb;
01459             }
01460         if( gd->type == type ) {
01461             if( pr ) pr->next = gd->next;
01462             kb --;
01463             tmp = gd;
01464             if( mwGrabList == gd ) mwGrabList = gd->next;
01465             gd = gd->next;
01466             p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type );
01467             if( p != NULL ) {
01468                 mwWrite( "wild pointer: <%ld> %s memory hit at %p\n",
01469                     mwCounter, mwGrabType(type), p );
01470                 FLUSH();
01471                 }
01472             mwGrabSize -= (long) sizeof(mwGrabData);
01473             free( tmp );
01474             }
01475         else {
01476             pr = gd;
01477             gd = gd->next;
01478             }
01479         }
01480     if( !silent ) {
01481         mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) );
01482         FLUSH();
01483         }
01484     return i;
01485     }
01486 
01487 /***********************************************************************
01488 ** No-Mans-Land
01489 ***********************************************************************/
01490 
01491 void mwNoMansLand( int level ) {
01492     mwAutoInit();
01493     TESTS(NULL,0);
01494     switch( level ) {
01495         case MW_NML_NONE:
01496             (void) mwDrop_( 0, MW_VAL_NML, 0 );
01497             break;
01498         case MW_NML_FREE:
01499             break;
01500         case MW_NML_ALL:
01501             (void) mwGrab_( 0, MW_VAL_NML, 0 );
01502             break;
01503         default:
01504             return;
01505         }
01506     mwNML = level;
01507     }
01508 
01509 /***********************************************************************
01510 ** Static functions
01511 ***********************************************************************/
01512 
01513 static void mwAutoInit( void )
01514 {
01515     if( mwInited ) return;
01516     mwUseAtexit = 1;
01517     mwInit();
01518     return;
01519 }
01520 
01521 static FILE *mwLogR() {
01522     if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog;
01523     if( mwLog == mwLogB1 ) mwLogB2 = mwLog;
01524     if( mwLog == mwLogB2 ) mwLogB1 = mwLog;
01525     if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1;
01526     if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) {
01527         mwWrite("internal: log file handle damaged and recovered\n");
01528         FLUSH();
01529         return mwLog;
01530         }
01531     fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" );
01532     mwLog = mwLogB1 = mwLogB2 = mwSTDERR;
01533     return mwSTDERR;
01534     }
01535 
01536 static void mwLogW( FILE *p ) {
01537     mwLog = mwLogB1 = mwLogB2 = p;
01538     }
01539 
01540 static int mwFlushR() {
01541     if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing;
01542     if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing;
01543     if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing;
01544     if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1;
01545     if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) {
01546         mwWrite("internal: flushing flag damaged and recovered\n");
01547         FLUSH();
01548         return mwFlushing;
01549         }
01550     mwWrite("internal: flushing flag destroyed, so set to true\n");
01551     mwFlushing = mwFlushingB1 = mwFlushingB2 = 1;
01552     return 1;
01553     }
01554 
01555 static void mwFlushW( int n ) {
01556     mwFlushing = mwFlushingB1 = mwFlushingB2 = n;
01557     }
01558 
01559 static void mwIncErr() {
01560     mwErrors++;
01561     mwFlushW( mwFlushR()+1 );
01562     FLUSH();
01563     }
01564 
01565 static void mwFlush() {
01566     if( mwLogR() == NULL ) return;
01567 #ifdef MW_FLUSH
01568     fflush( mwLogR() );
01569 #else
01570     if( mwFlushR() ) fflush( mwLogR() );
01571 #endif
01572     return;
01573     }
01574 
01575 static void mwUnlink( mwData* mw, const char* file, int line ) {
01576     if( mw->prev == NULL ) {
01577         if( mwHead != mw )
01578             mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n",
01579                 mwCounter, file, line, mw );
01580         mwHead = mw->next;
01581         }
01582     else {
01583         if( mw->prev->next != mw )
01584             mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n",
01585                 mwCounter, file, line, mw );
01586         else mw->prev->next = mw->next;
01587         }
01588     if( mw->next == NULL ) {
01589         if( mwTail != mw )
01590             mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n",
01591                 mwCounter, file, line, mw );
01592         mwTail = mw->prev;
01593         }
01594     else {
01595         if( mw->next->prev != mw )
01596             mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n",
01597                 mwCounter, file, line, mw );
01598         else mw->next->prev = mw->prev;
01599         }
01600     }
01601 
01602 /*
01603 ** Relinking tries to repair a damaged mw block.
01604 ** Returns nonzero if it thinks it successfully
01605 ** repaired the heap chain.
01606 */
01607 static int mwRelink( mwData* mw, const char* file, int line ) {
01608     int fails;
01609     mwData *mw1, *mw2;
01610     long count, size;
01611     mwStat *ms;
01612 
01613    if( file == NULL ) file = "unknown";
01614 
01615     if( mw == NULL ) {
01616         mwWrite("relink: cannot repair MW at NULL\n");
01617         FLUSH();
01618         goto emergency;
01619         }
01620 
01621     if( !mwIsSafeAddr(mw, mwDataSize) ) {
01622         mwWrite("relink: MW-%p is a garbage pointer\n", mw);
01623         FLUSH();
01624         goto emergency;
01625         }
01626 
01627     mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw );
01628     FLUSH();
01629     fails = 0;
01630 
01631     /* Repair from head */
01632     if( mwHead != mw ) {
01633         if( !mwIsSafeAddr( mwHead, mwDataSize ) ) {
01634             mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw );
01635             FLUSH();
01636             goto emergency;
01637             }
01638         for( mw1=mwHead; mw1; mw1=mw1->next ) {
01639             if( mw1->next == mw ) {
01640                 mw->prev = mw1;
01641                 break;
01642                 }
01643             if( mw1->next &&
01644                 ( !mwIsSafeAddr(mw1->next, mwDataSize ) || mw1->next->prev != mw1) ) {
01645                 mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next );
01646                 FLUSH();
01647                 goto emergency;
01648                 }
01649             }
01650         if( mw1 == NULL ) {
01651             mwWrite("relink: MW-%p not found in forward chain search\n", mw );
01652             FLUSH();
01653             fails ++;
01654             }
01655         }
01656    else
01657    {
01658       mwWrite( "relink: MW-%p is the head (first) allocation\n", mw );
01659       if( mw->prev != NULL )
01660       {
01661          mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw );
01662          mw->prev = NULL;
01663       }
01664    }
01665 
01666     /* Repair from tail */
01667     if( mwTail != mw ) {
01668         if( !mwIsSafeAddr( mwTail, mwDataSize ) ) {
01669             mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw );
01670             FLUSH();
01671             goto emergency;
01672             }
01673         for( mw1=mwTail; mw1; mw1=mw1->prev ) {
01674             if( mw1->prev == mw ) {
01675                 mw->next = mw1;
01676                 break;
01677                 }
01678             if( mw1->prev && (!mwIsSafeAddr(mw1->prev, mwDataSize ) || mw1->prev->next != mw1) ) {
01679                 mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev );
01680                 FLUSH();
01681                 goto emergency;
01682                 }
01683             }
01684         if( mw1 == NULL ) {
01685             mwWrite("relink: MW-%p not found in reverse chain search\n", mw );
01686             FLUSH();
01687             fails ++;
01688             }
01689         }
01690    else
01691    {
01692       mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw );
01693       if( mw->next != NULL )
01694       {
01695          mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw );
01696          mw->next = NULL;
01697       }
01698    }
01699 
01700     if( fails > 1 ) {
01701         mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw );
01702         FLUSH();
01703         goto verifyok;
01704         }
01705 
01706     /* restore MW info where possible */
01707     if( mwIsReadAddr( mw->file, 1 ) ) {
01708         ms = mwStatGet( mw->file, -1, 0 );
01709         if( ms == NULL ) mw->file = "<relinked>";
01710         }
01711     mw->check = CHKVAL(mw);
01712     goto verifyok;
01713 
01714     /* Emergency repair */
01715     emergency:
01716 
01717     if( mwHead == NULL && mwTail == NULL )
01718     {
01719         if( mwStatCurAlloc == 0 )
01720             mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line );
01721         else
01722             mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line );
01723         FLUSH();
01724         return 0;
01725     }
01726 
01727     mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line );
01728     FLUSH();
01729 
01730    if( mwHead == NULL || mwTail == NULL )
01731    {
01732       if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail );
01733       else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead );
01734    }
01735 
01736     mw1=NULL;
01737     if( mwHead != NULL )
01738    {
01739       if( !mwIsReadAddr( mwHead, mwDataSize ) || mwHead->check != CHKVAL(mwHead) )
01740       {
01741          mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead );
01742          mwHead = NULL;
01743          goto scan_reverse;
01744       }
01745       if( mwHead->prev != NULL )
01746       {
01747          mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev );
01748       }
01749         for( mw1=mwHead; mw1; mw1=mw1->next )
01750       {
01751          if( mw1->next )
01752          {
01753             if( !mwIsReadAddr(mw1->next,mwDataSize) ||
01754                !mw1->next->check != CHKVAL(mw1) ||
01755                mw1->next->prev != mw1 )
01756             {
01757                mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
01758                   mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line );
01759                if( mwIsReadAddr(mw1->next,mwDataSize ) )
01760                {
01761                   mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
01762                      mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"",
01763                      mwIsReadAddr(mw1->file,16)?mw1->file:"<garbage-pointer>", mw1->line );
01764                }
01765                else
01766                {
01767                   mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n",
01768                      mw1->next );
01769                }
01770                break;
01771             }
01772          }
01773         }
01774    }
01775 
01776 
01777 scan_reverse:
01778     mw2=NULL;
01779     if( mwTail != NULL )
01780    {
01781       if( !mwIsReadAddr(mwTail,mwDataSize) || mwTail->check != CHKVAL(mwTail) )
01782       {
01783          mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail );
01784          mwTail = NULL;
01785          goto analyze;
01786       }
01787       if( mwTail->next != NULL )
01788       {
01789          mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next );
01790       }
01791         for( mw2=mwTail; mw2; mw2=mw2->prev )
01792       {
01793             if( mw2->prev )
01794          {
01795             if( !mwIsReadAddr(mw2->prev,mwDataSize) ||
01796                !mw2->prev->check != CHKVAL(mw2) ||
01797                mw2->prev->next != mw2 )
01798             {
01799                mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
01800                   mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line );
01801                if( mwIsReadAddr(mw2->prev,mwDataSize ) )
01802                {
01803                   mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
01804                      mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"",
01805                      mwIsReadAddr(mw2->file,16)?mw2->file:"<garbage-pointer>", mw2->line );
01806                }
01807                else
01808                {
01809                   mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n",
01810                      mw2->prev );
01811                }
01812                break;
01813             }
01814          }
01815         }
01816    }
01817 
01818 analyze:
01819    if( mwHead == NULL && mwTail == NULL )
01820    {
01821         mwWrite("relink: both head and tail pointers damaged, aborting program\n");
01822         mwFlushW(1);
01823         FLUSH();
01824         abort();
01825    }
01826    if( mwHead == NULL )
01827    {
01828       mwHead = mw2;
01829       mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 );
01830       mw2->prev = NULL;
01831       mw1 = mw2 = NULL;
01832    }
01833    if( mwTail == NULL )
01834    {
01835       mwTail = mw1;
01836       mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 );
01837       mw1->next = NULL;
01838       mw1 = mw2 = NULL;
01839    }
01840     if( mw1 == NULL && mw2 == NULL &&
01841         mwHead->prev == NULL && mwTail->next == NULL ) {
01842         mwWrite("relink: verifying heap integrity...\n" );
01843         FLUSH();
01844         goto verifyok;
01845         }
01846     if( mw1 && mw2 && mw1 != mw2 ) {
01847         mw1->next = mw2;
01848         mw2->prev = mw1;
01849         mwWrite("relink: emergency repairs successful, assessing damage...\n");
01850         FLUSH();
01851         }
01852     else {
01853         mwWrite("relink: heap totally destroyed, aborting program\n");
01854         mwFlushW(1);
01855         FLUSH();
01856         abort();
01857         }
01858 
01859     /* Verify by checking that the number of active allocations */
01860     /* match the number of entries in the chain */
01861 verifyok:
01862     if( !mwIsHeapOK( NULL ) ) {
01863         mwWrite("relink: heap verification FAILS - aborting program\n");
01864         mwFlushW(1);
01865         FLUSH();
01866         abort();
01867         }
01868     for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) {
01869         count ++;
01870         size += (long) mw1->size;
01871         }
01872     if( count == mwNumCurAlloc ) {
01873         mwWrite("relink: successful, ");
01874         if( size == mwStatCurAlloc ) {
01875             mwWrite("no allocations lost\n");
01876             }
01877         else {
01878             if( mw != NULL ) {
01879                 mwWrite("size information lost for MW-%p\n", mw);
01880                 mw->size = 0;
01881                 }
01882             }
01883         }
01884     else {
01885         mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n",
01886          mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size );
01887         return 0;
01888         }
01889 
01890     return 1;
01891     }
01892 
01893 /*
01894 **  If mwData* is NULL:
01895 **      Returns 0 if heap chain is broken.
01896 **      Returns 1 if heap chain is intact.
01897 **  If mwData* is not NULL:
01898 **      Returns 0 if mwData* is missing or if chain is broken.
01899 **      Returns 1 if chain is intact and mwData* is found.
01900 */
01901 static int mwIsHeapOK( mwData *includes_mw ) {
01902     int found = 0;
01903     mwData *mw;
01904 
01905     for( mw = mwHead; mw; mw=mw->next ) {
01906         if( includes_mw == mw ) found++;
01907         if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
01908         if( mw->prev ) {
01909             if( !mwIsSafeAddr( mw->prev, mwDataSize ) ) return 0;
01910             if( mw==mwHead || mw->prev->next != mw ) return 0;
01911             }
01912         if( mw->next ) {
01913             if( !mwIsSafeAddr( mw->next, mwDataSize ) ) return 0;
01914             if( mw==mwTail || mw->next->prev != mw ) return 0;
01915             }
01916         else if( mw!=mwTail ) return 0;
01917         }
01918 
01919     if( includes_mw != NULL && !found ) return 0;
01920 
01921     return 1;
01922     }
01923 
01924 static int mwIsOwned( mwData* mw, const char *file, int line ) {
01925     int retv;
01926     mwStat *ms;
01927 
01928     /* see if the address is legal according to OS */
01929     if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
01930 
01931     /* make sure we have _anything_ allocated */
01932     if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 )
01933         return 0;
01934 
01935     /* calculate checksum */
01936     if( mw->check != CHKVAL(mw) ) {
01937         /* may be damaged checksum, see if block is in heap */
01938         if( mwIsHeapOK( mw ) ) {
01939             /* damaged checksum, repair it */
01940             mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n",
01941                 mwCounter, file, line, mw );
01942             mwIncErr();
01943             if( mwIsReadAddr( mw->file, 1 ) ) {
01944                 ms = mwStatGet( mw->file, -1, 0 );
01945                 if( ms == NULL ) mw->file = "<relinked>";
01946                 }
01947             else mw->file = "<unknown>";
01948             mw->size = 0;
01949             mw->check = CHKVAL(mw);
01950             return 1;
01951             }
01952         /* no, it's just some garbage data */
01953         return 0;
01954         }
01955 
01956    /* check that the non-NULL pointers are safe */
01957    if( mw->prev && !mwIsSafeAddr( mw->prev, mwDataSize ) ) mwRelink( mw, file, line );
01958    if( mw->next && !mwIsSafeAddr( mw->next, mwDataSize ) ) mwRelink( mw, file, line );
01959 
01960     /* safe address, checksum OK, proceed with heap checks */
01961 
01962     /* see if the block is in the heap */
01963     retv = 0;
01964     if( mw->prev ) { if( mw->prev->next == mw ) retv ++; }
01965     else { if( mwHead == mw ) retv++; }
01966     if( mw->next ) { if( mw->next->prev == mw ) retv ++; }
01967     else { if( mwTail == mw ) retv++; }
01968     if( mw->check == CHKVAL(mw) ) retv ++;
01969     if( retv > 2 ) return 1;
01970 
01971     /* block not in heap, check heap for corruption */
01972 
01973     if( !mwIsHeapOK( mw ) ) {
01974         if( mwRelink( mw, file, line ) )
01975             return 1;
01976         }
01977 
01978     /* unable to repair */
01979     mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n",
01980        mwCounter, file, line, mw );
01981     mwIncErr();
01982 
01983     return 0;
01984     }
01985 
01986 /*
01987 ** mwTestBuf:
01988 **  Checks a buffers links and pre/postfixes.
01989 **  Writes errors found to the log.
01990 **  Returns zero if no errors found.
01991 */
01992 static int mwTestBuf( mwData* mw, const char* file, int line ) {
01993     int retv = 0;
01994     char *p;
01995 
01996     if( file == NULL ) file = "unknown";
01997 
01998     if( !mwIsSafeAddr( mw, mwDataSize + mwOverflowZoneSize ) ) {
01999         mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n",
02000             mwCounter, file, line, mw );
02001         mwIncErr();
02002         return 2;
02003         }
02004 
02005     if( mw->check != CHKVAL(mw) ) {
02006         mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n",
02007             mwCounter, file, line );
02008         mwIncErr();
02009         if( !mwRelink( mw, file, line ) ) return 2;
02010         }
02011 
02012     if( mw->prev && mw->prev->next != mw ) {
02013         mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n",
02014             mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
02015         mwIncErr();
02016         if( !mwRelink( mw, file, line ) ) retv = 2;
02017         }
02018     if( mw->next && mw->next->prev != mw ) {
02019         mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n",
02020             mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
02021         mwIncErr();
02022         if( !mwRelink( mw, file, line ) ) retv = 2;
02023         }
02024 
02025     p = ((char*)mw) + mwDataSize;
02026     if( mwCheckOF( p ) ) {
02027         mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
02028             mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
02029         mwIncErr();
02030         retv = 1;
02031         }
02032     p += mwOverflowZoneSize + mw->size;
02033     if( mwIsReadAddr( p, mwOverflowZoneSize ) && mwCheckOF( p ) ) {
02034         mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
02035             mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
02036         mwIncErr();
02037         retv = 1;
02038         }
02039 
02040     return retv;
02041     }
02042 
02043 static void mwDefaultOutFunc( int c ) {
02044     if( mwLogR() ) fputc( c, mwLogR() );
02045     }
02046 
02047 static void mwWrite( const char *format, ... ) {
02048     int tot, oflow = 0;
02049     va_list mark;
02050     mwAutoInit();
02051     if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
02052     va_start( mark, format );
02053     tot = vsprintf( mwPrintBuf, format, mark );
02054     va_end( mark );
02055     if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; }
02056     for(tot=0;mwPrintBuf[tot];tot++)
02057         (*mwOutFunction)( mwPrintBuf[tot] );
02058     if( oflow ) {
02059         mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 );
02060         FLUSH();
02061         }
02062     return;
02063     }
02064 
02065 static void mwLogFile( const char *name ) {
02066    time_t tid;
02067    (void) time( &tid );
02068    if( mwLogR() != NULL ) {
02069       fclose( mwLogR() );
02070       mwLogW( NULL );
02071    }
02072    if( name == NULL ) {
02073       return;
02074    }   
02075     mwLogW( fopen( name, "a" COMMIT ) );
02076     if( mwLogR() == NULL ){
02077         mwWrite( "logfile: failed to open/create file '%s'\n", name );
02078     }   
02079 }
02080 
02081 /*
02082 ** Try to free NML memory until a contiguous allocation of
02083 ** 'needed' bytes can be satisfied. If this is not enough
02084 ** and the 'urgent' parameter is nonzero, grabbed memory is
02085 ** also freed.
02086 */
02087 static size_t mwFreeUp( size_t needed, int urgent ) {
02088     void *p;
02089     mwData *mw, *mw2;
02090     char *data;
02091 
02092     /* free grabbed NML memory */
02093     for(;;) {
02094         if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break;
02095         p = malloc( needed );
02096         if( p == NULL ) continue;
02097         free( p );
02098         return needed;
02099         }
02100 
02101     /* free normal NML memory */
02102     mw = mwHead;
02103     while( mw != NULL ) {
02104         if( !(mw->flag & MW_NML) ) mw = mw->next;
02105         else {
02106             data = ((char*)mw)+mwDataSize+mwOverflowZoneSize;
02107             if( mwTestMem( data, mw->size, MW_VAL_NML ) ) {
02108                 mwIncErr();
02109                 mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
02110                     mw->count, data + mwOverflowZoneSize, mw->file, mw->line );
02111                 }
02112             mw2 = mw->next;
02113             mwUnlink( mw, "mwFreeUp", 0 );
02114             free( mw );
02115             mw = mw2;
02116             p = malloc( needed );
02117             if( p == NULL ) continue;
02118             free( p );
02119             return needed;
02120             }
02121         }
02122 
02123     /* if not urgent (for internal purposes), fail */
02124     if( !urgent ) return 0;
02125 
02126     /* free grabbed memory */
02127     for(;;) {
02128         if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break;
02129         p = malloc( needed );
02130         if( p == NULL ) continue;
02131         free( p );
02132         return needed;
02133         }
02134 
02135     return 0;
02136     }
02137 
02138 static const void * mwTestMem( const void *p, unsigned len, int c ) {
02139     const unsigned char *ptr;
02140     ptr = (const unsigned char *) p;
02141     while( len-- ) {
02142         if( *ptr != (unsigned char)c ) return (const void*)ptr;
02143         ptr ++;
02144         }
02145     return NULL;
02146     }
02147 
02148 static int mwStrCmpI( const char *s1, const char *s2 ) {
02149     if( s1 == NULL || s2 == NULL ) return 0;
02150     while( *s1 ) {
02151         if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; }
02152         return 1;
02153         }
02154     return 0;
02155     }
02156 
02157 #define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; }
02158 
02159 static int mwTestNow( const char *file, int line, int always_invoked ) {
02160     int retv = 0;
02161     mwData *mw;
02162     char *data;
02163 
02164     if( file && !always_invoked )
02165         mwWrite("check: <%ld> %s(%d), checking %s%s%s\n",
02166             mwCounter, file, line,
02167          (mwTestFlags & MW_TEST_CHAIN) ? "chain ": "",
02168           (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "",
02169           (mwTestFlags & MW_TEST_NML) ? "nomansland ": ""
02170          );
02171 
02172     if( mwTestFlags & MW_TEST_CHAIN ) {
02173         for( mw = mwHead; mw; mw=mw->next ) {
02174          if( !mwIsSafeAddr(mw, mwDataSize) ) {
02175             AIPH();
02176             mwWrite("check: heap corruption detected\n");
02177             mwIncErr();
02178             return retv + 1;
02179             }
02180          if( mw->prev ) {
02181             if( !mwIsSafeAddr(mw->prev, mwDataSize) ) {
02182                AIPH();
02183                mwWrite("check: heap corruption detected\n");
02184                mwIncErr();
02185                return retv + 1;
02186                }
02187             if( mw==mwHead || mw->prev->next != mw ) {
02188                AIPH();
02189                mwWrite("check: heap chain broken, prev link incorrect\n");
02190                mwIncErr();
02191                retv ++;
02192                }
02193             }
02194          if( mw->next ) {
02195             if( !mwIsSafeAddr(mw->next, mwDataSize) ) {
02196                AIPH();
02197                mwWrite("check: heap corruption detected\n");
02198                mwIncErr();
02199                return retv + 1;
02200                }
02201             if( mw==mwTail || mw->next->prev != mw ) {
02202                AIPH();
02203                mwWrite("check: heap chain broken, next link incorrect\n");
02204                mwIncErr();
02205                retv ++;
02206                }
02207             }
02208          else if( mw!=mwTail ) {
02209             AIPH();
02210             mwWrite("check: heap chain broken, tail incorrect\n");
02211             mwIncErr();
02212             retv ++;
02213             }
02214             }
02215         }
02216     if( mwTestFlags & MW_TEST_ALLOC ) {
02217         for( mw = mwHead; mw; mw=mw->next ) {
02218             if( mwTestBuf( mw, file, line ) ) retv ++;
02219             }
02220         }
02221     if( mwTestFlags & MW_TEST_NML ) {
02222         for( mw = mwHead; mw; mw=mw->next ) {
02223             if( (mw->flag & MW_NML) ) {
02224                 data = ((char*)mw)+mwDataSize+mwOverflowZoneSize;
02225                 if( mwTestMem( data, mw->size, MW_VAL_NML ) ) {
02226                     mwIncErr();
02227                     mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
02228                         mw->count, data + mwOverflowZoneSize, mw->file, mw->line );
02229                     }
02230                 }
02231             }
02232         }
02233 
02234 
02235    if( file && !always_invoked && !retv )
02236         mwWrite("check: <%ld> %s(%d), complete; no errors\n",
02237             mwCounter, file, line );
02238     return retv;
02239     }
02240 
02241 /**********************************************************************
02242 ** Statistics
02243 **********************************************************************/
02244 
02245 static void mwStatReport()
02246 {
02247     mwStat* ms, *ms2;
02248     const char *modname;
02249     int modnamelen;
02250 
02251     /* global statistics report */
02252     mwWrite( "\nMemory usage statistics (global):\n" );
02253     mwWrite( " N)umber of allocations made: %ld\n", mwStatNumAlloc );
02254     mwWrite( " L)argest memory usage      : %ld\n", mwStatMaxAlloc );
02255     mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc );
02256     mwWrite( " U)nfreed bytes totals      : %ld\n", mwStatCurAlloc );
02257     FLUSH();
02258 
02259     if( mwStatLevel < 1 ) return;
02260 
02261     /* on a per-module basis */
02262     mwWrite( "\nMemory usage statistics (detailed):\n");
02263     mwWrite( " Module/Line                                Number   Largest  Total    Unfreed \n");
02264     for( ms=mwStatList; ms; ms=ms->next )
02265     {
02266         if( ms->line == -1 )
02267         {
02268          if( ms->file == NULL || !mwIsReadAddr(ms->file,22) ) modname = "<unknown>";
02269          else modname = ms->file;
02270          modnamelen = strlen(modname);
02271          if( modnamelen > 42 )
02272          {
02273             modname = modname + modnamelen - 42;
02274          }
02275 
02276             mwWrite(" %-42s %-8ld %-8ld %-8ld %-8ld\n",
02277                modname, ms->num, ms->max, ms->total, ms->curr );
02278             if( ms->file && mwStatLevel > 1 )
02279             {
02280                 for( ms2=mwStatList; ms2; ms2=ms2->next )
02281                 {
02282                     if( ms2->line!=-1 && ms2->file!=NULL && !mwStrCmpI( ms2->file, ms->file ) )
02283                {
02284                mwWrite( "  %-8d                                  %-8ld %-8ld %-8ld %-8ld\n",
02285                   ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr );
02286                }
02287             }
02288          }
02289       }
02290    }
02291 }
02292 
02293 static mwStat* mwStatGet( const char *file, int line, int makenew ) {
02294     mwStat* ms;
02295 
02296     if( mwStatLevel < 2 ) line = -1;
02297 
02298     for( ms=mwStatList; ms!=NULL; ms=ms->next ) {
02299         if( line != ms->line ) continue;
02300         if( file==NULL ) {
02301             if( ms->file == NULL ) break;
02302             continue;
02303             }
02304         if( ms->file == NULL ) continue;
02305         if( !strcmp( ms->file, file ) ) break;
02306         }
02307 
02308     if( ms != NULL ) return ms;
02309 
02310     if( !makenew ) return NULL;
02311 
02312     ms = (mwStat*) malloc( sizeof(mwStat) );
02313     if( ms == NULL ) {
02314         if( mwFreeUp( sizeof(mwStat), 0 ) < sizeof(mwStat) ||
02315             (ms=(mwStat*)malloc(sizeof(mwStat))) == NULL ) {
02316             mwWrite("internal: memory low, statistics incomplete for '%s'\n", file );
02317             return NULL;
02318             }
02319         }
02320     ms->file = file;
02321     ms->line = line;
02322     ms->total = 0L;
02323     ms->max = 0L;
02324     ms->num = 0L;
02325     ms->curr = 0L;
02326     ms->next = mwStatList;
02327     mwStatList = ms;
02328     return ms;
02329     }
02330 
02331 static void mwStatAlloc( size_t size, const char* file, int line ) {
02332     mwStat* ms;
02333 
02334     /* update the module statistics */
02335     ms = mwStatGet( file, -1, 1 );
02336     if( ms != NULL ) {
02337         ms->total += (long) size;
02338         ms->curr += (long) size;
02339         ms->num ++;
02340         if( ms->curr > ms->max ) ms->max = ms->curr;
02341         }
02342 
02343     /* update the line statistics */
02344     if( mwStatLevel > 1 && line != -1 && file ) {
02345         ms = mwStatGet( file, line, 1 );
02346         if( ms != NULL ) {
02347             ms->total += (long) size;
02348             ms->curr += (long) size;
02349             ms->num ++;
02350             if( ms->curr > ms->max ) ms->max = ms->curr;
02351             }
02352         }
02353 
02354     }
02355 
02356 static void mwStatFree( size_t size, const char* file, int line ) {
02357     mwStat* ms;
02358 
02359     /* update the module statistics */
02360     ms = mwStatGet( file, -1, 1 );
02361     if( ms != NULL ) ms->curr -= (long) size;
02362 
02363     /* update the line statistics */
02364     if( mwStatLevel > 1 && line != -1 && file ) {
02365         ms = mwStatGet( file, line, 1 );
02366         if( ms != NULL ) ms->curr -= (long) size;
02367         }
02368     }
02369 
02370 /***********************************************************************
02371 ** Safe memory checkers
02372 **
02373 ** Using ifdefs, implement the operating-system specific mechanism
02374 ** of identifying a piece of memory as legal to access with read
02375 ** and write priviliges. Default: return nonzero for non-NULL pointers.
02376 ***********************************************************************/
02377 
02378 static char mwDummy( char c )
02379 {
02380    return c;
02381 }
02382 
02383 #ifndef MW_SAFEADDR
02384 #ifdef WIN32
02385 #define MW_SAFEADDR
02386 #define WIN32_LEAN_AND_MEAN
02387 #include <windows.h>
02388 int mwIsReadAddr( const void *p, unsigned len )
02389 {
02390     if( p == NULL ) return 0;
02391     if( IsBadReadPtr(p,len) ) return 0;
02392     return 1;
02393 }
02394 int mwIsSafeAddr( void *p, unsigned len )
02395 {
02396     /* NOTE: For some reason, under Win95 the IsBad... */
02397     /* can return false for invalid pointers. */
02398     if( p == NULL ) return 0;
02399     if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) ) return 0;
02400     return 1;
02401 }
02402 #endif /* WIN32 */
02403 #endif /* MW_SAFEADDR */
02404 
02405 #ifndef MW_SAFEADDR
02406 #ifdef SIGSEGV
02407 #define MW_SAFEADDR
02408 
02409 typedef void (*mwSignalHandlerPtr)( int );
02410 mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0;
02411 jmp_buf mwSIGSEGVjump;
02412 static void mwSIGSEGV( int n );
02413 
02414 static void mwSIGSEGV( int n )
02415 {
02416    n = n;
02417    longjmp( mwSIGSEGVjump, 1 );
02418 }
02419 
02420 int mwIsReadAddr( const void *p, unsigned len )
02421 {
02422    const char *ptr;
02423 
02424     if( p == NULL ) return 0;
02425    if( !len ) return 1;
02426 
02427    /* set up to catch the SIGSEGV signal */
02428    mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
02429 
02430    if( setjmp( mwSIGSEGVjump ) )
02431    {
02432       signal( SIGSEGV, mwOldSIGSEGV );
02433       return 0;
02434    }
02435 
02436    /* read all the bytes in the range */
02437    ptr = (const char *)p;
02438    ptr += len;
02439 
02440    /* the reason for this rather strange construct is that */
02441    /* we want to keep the number of used parameters and locals */
02442    /* to a minimum. if we use len for a counter gcc will complain */
02443    /* it may get clobbered by longjmp() at high warning levels. */
02444    /* it's a harmless warning, but this way we don't have to see it. */
02445    do
02446    {
02447       ptr --;
02448       if( *ptr == 0x7C ) (void) mwDummy( (char)0 );
02449    } while( (const void*) ptr != p );
02450 
02451    /* remove the handler */
02452    signal( SIGSEGV, mwOldSIGSEGV );
02453 
02454     return 1;
02455 }
02456 int mwIsSafeAddr( void *p, unsigned len )
02457 {
02458    char *ptr;
02459 
02460    if( p == NULL ) return 0;
02461    if( !len ) return 1;
02462 
02463    /* set up to catch the SIGSEGV signal */
02464    mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
02465 
02466    if( setjmp( mwSIGSEGVjump ) )
02467    {
02468       signal( SIGSEGV, mwOldSIGSEGV );
02469       return 0;
02470    }
02471 
02472    /* read and write-back all the bytes in the range */
02473    ptr = (char *)p;
02474    ptr += len;
02475 
02476    /* the reason for this rather strange construct is that */
02477    /* we want to keep the number of used parameters and locals */
02478    /* to a minimum. if we use len for a counter gcc will complain */
02479    /* it may get clobbered by longjmp() at high warning levels. */
02480    /* it's a harmless warning, but this way we don't have to see it. */
02481    do
02482    {
02483       ptr --;
02484       *ptr = mwDummy( *ptr );
02485    } while( (void*) ptr != p );
02486 
02487    /* remove the handler */
02488    signal( SIGSEGV, mwOldSIGSEGV );
02489 
02490     return 1;
02491 }
02492 #endif /* SIGSEGV */
02493 #endif /* MW_SAFEADDR */
02494 
02495 #ifndef MW_SAFEADDR
02496 int mwIsReadAddr( const void *p, unsigned len )
02497 {
02498     if( p == NULL ) return 0;
02499     if( len == 0 ) return 1;
02500     return 1;
02501 }
02502 int mwIsSafeAddr( void *p, unsigned len )
02503 {
02504     if( p == NULL ) return 0;
02505     if( len == 0 ) return 1;
02506     return 1;
02507 }
02508 #endif
02509 
02510 /**********************************************************************
02511 ** Mutex handling
02512 **********************************************************************/
02513 
02514 #if defined(WIN32) || defined(__WIN32__)
02515 
02516 static void mwMutexInit( void )
02517 {
02518    mwGlobalMutex = CreateMutex( NULL, FALSE, NULL);
02519    return;
02520 }
02521 
02522 static void mwMutexTerm( void )
02523 {
02524    CloseHandle( mwGlobalMutex );
02525    return;
02526 }
02527 
02528 static void mwMutexLock( void )
02529 {
02530    if( WaitForSingleObject(mwGlobalMutex, 1000 ) == WAIT_TIMEOUT )
02531    {
02532       mwWrite( "mwMutexLock: timed out, possible deadlock\n" );
02533    }
02534    return;
02535 }
02536 
02537 static void mwMutexUnlock( void )
02538 {
02539    ReleaseMutex( mwGlobalMutex );
02540    return;
02541 }
02542 
02543 #endif
02544 
02545 #if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
02546 
02547 static void mwMutexInit( void )
02548 {
02549    pthread_mutex_init( &mwGlobalMutex, NULL );
02550    return;
02551 }
02552 
02553 static void mwMutexTerm( void )
02554 {
02555    pthread_mutex_destroy( &mwGlobalMutex );
02556    return;
02557 }
02558 
02559 static void mwMutexLock( void )
02560 {
02561    pthread_mutex_lock(&mwGlobalMutex);
02562    return;
02563 }
02564 
02565 static void mwMutexUnlock( void )
02566 {
02567    pthread_mutex_unlock(&mwGlobalMutex);
02568    return;
02569 }
02570 
02571 #endif
02572 
02573 /**********************************************************************
02574 ** C++ new & delete
02575 **********************************************************************/
02576 
02577 #if 0 /* 980317: disabled C++ */
02578 
02579 #ifdef __cplusplus
02580 #ifndef MEMWATCH_NOCPP
02581 
02582 int mwNCur = 0;
02583 const char *mwNFile = NULL;
02584 int mwNLine = 0;
02585 
02586 class MemWatch {
02587 public:
02588     MemWatch();
02589     ~MemWatch();
02590     };
02591 
02592 MemWatch::MemWatch() {
02593     if( mwInited ) return;
02594     mwUseAtexit = 0;
02595     mwInit();
02596     }
02597 
02598 MemWatch::~MemWatch() {
02599     if( mwUseAtexit ) return;
02600     mwTerm();
02601     }
02602 
02603 /*
02604 ** This global new will catch all 'new' calls where MEMWATCH is
02605 ** not active.
02606 */
02607 void* operator new( unsigned size ) {
02608     mwNCur = 0;
02609     return mwMalloc( size, "<unknown>", 0 );
02610     }
02611 
02612 /*
02613 ** This is the new operator that's called when a module uses mwNew.
02614 */
02615 void* operator new( unsigned size, const char *file, int line ) {
02616     mwNCur = 0;
02617     return mwMalloc( size, file, line );
02618     }
02619 
02620 /*
02621 ** This is the new operator that's called when a module uses mwNew[].
02622 ** -- hjc 07/16/02
02623 */
02624 void* operator new[] ( unsigned size, const char *file, int line ) {
02625     mwNCur = 0;
02626     return mwMalloc( size, file, line );
02627     }
02628 
02629 /*
02630 ** Since this delete operator will recieve ALL delete's
02631 ** even those from within libraries, we must accept
02632 ** delete's before we've been initialized. Nor can we
02633 ** reliably check for wild free's if the mwNCur variable
02634 ** is not set.
02635 */
02636 void operator delete( void *p ) {
02637     if( p == NULL ) return;
02638     if( !mwInited ) {
02639         free( p );
02640         return;
02641         }
02642     if( mwNCur ) {
02643         mwFree( p, mwNFile, mwNLine );
02644         mwNCur = 0;
02645         return;
02646         }
02647     mwFree_( p );
02648     }
02649 
02650 void operator delete[]( void *p ) {
02651     if( p == NULL ) return;
02652     if( !mwInited ) {
02653         free( p );
02654         return;
02655         }
02656     if( mwNCur ) {
02657         mwFree( p, mwNFile, mwNLine );
02658         mwNCur = 0;
02659         return;
02660         }
02661     mwFree_( p );
02662     }
02663 
02664 #endif /* MEMWATCH_NOCPP */
02665 #endif /* __cplusplus */
02666 
02667 #endif /* 980317: disabled C++ */
02668 
02669 #endif /* MEMWATCH */
02670     
02671 /* MEMWATCH.C */

Generated on Wed Mar 30 13:43:26 2005 for Mntd by  doxygen 1.3.9.1