/home/bes3soft/bes3soft/Boss/7.0.2/dist/7.0.2/Reconstruction/KalFitAlg/KalFitAlg-00-07-55-p03/src/KalFitMemLeak.c

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

Generated on Tue Nov 29 23:13:24 2016 for BOSS_7.0.2 by  doxygen 1.4.7