BOSS 8.0.0
BESIII Offline Software System
Loading...
Searching...
No Matches
KalFitMemLeak.c
Go to the documentation of this file.
1/*
2** MEMWATCH.C
3** Nonintrusive ANSI C memory leak / overwrite detection
4** Copyright (C) 1992-2003 Johan Lindh
5** All rights reserved.
6** Version 2.71
7
8 This file is part of MEMWATCH.
9
10 MEMWATCH is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 MEMWATCH is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with MEMWATCH; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
24**
25** 920810 JLI [1.00]
26** 920830 JLI [1.10 double-free detection]
27** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit]
28** 921022 JLI [1.20 ASSERT and VERIFY]
29** 921105 JLI [1.30 C++ support and TRACE]
30** 921116 JLI [1.40 mwSetOutFunc]
31** 930215 JLI [1.50 modified ASSERT/VERIFY]
32** 930327 JLI [1.51 better auto-init & PC-lint support]
33** 930506 JLI [1.55 MemWatch class, improved C++ support]
34** 930507 JLI [1.60 mwTest & CHECK()]
35** 930809 JLI [1.65 Abort/Retry/Ignore]
36** 930820 JLI [1.70 data dump when unfreed]
37** 931016 JLI [1.72 modified C++ new/delete handling]
38** 931108 JLI [1.77 mwSetAssertAction() & some small changes]
39** 940110 JLI [1.80 no-mans-land alloc/checking]
40** 940328 JLI [2.00 version 2.0 rewrite]
41** Improved NML (no-mans-land) support.
42** Improved performance (especially for free()ing!).
43** Support for 'read-only' buffers (checksums)
44** ^^ NOTE: I never did this... maybe I should?
45** FBI (free'd block info) tagged before freed blocks
46** Exporting of the mwCounter variable
47** mwBreakOut() localizes debugger support
48** Allocation statistics (global, per-module, per-line)
49** Self-repair ability with relinking
50** 950913 JLI [2.10 improved garbage handling]
51** 951201 JLI [2.11 improved auto-free in emergencies]
52** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()]
53** 960514 JLI [2.12 undefining of existing macros]
54** 960515 JLI [2.13 possibility to use default new() & delete()]
55** 960516 JLI [2.20 suppression of file flushing on unfreed msgs]
56** 960516 JLI [2.21 better support for using MEMWATCH with DLL's]
57** 960710 JLI [X.02 multiple logs and mwFlushNow()]
58** 960801 JLI [2.22 merged X.01 version with current]
59** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's]
60** 960805 JLI [2.31 merged X.02 version with current]
61** 961002 JLI [2.32 support for realloc() + fixed STDERR bug]
62** 961222 JLI [2.40 added mwMark() & mwUnmark()]
63** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY]
64** 970113 JLI [2.42 added support for PC-Lint 7.00g]
65** 970207 JLI [2.43 added support for strdup()]
66** 970209 JLI [2.44 changed default filename to lowercase]
67** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers]
68** 970723 JLI [2.46 added MW_ARI_NULLREAD flag]
69** 970813 JLI [2.47 stabilized marker handling]
70** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway]
71** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support]
72** 980417 JLI [2.51 more checks for invalid addresses]
73** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting]
74** 990112 JLI [2.53 added check for empty heap to mwIsOwned]
75** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML]
76** 990224 JLI [2.56 changed ordering of members in structures]
77** 990303 JLI [2.57 first maybe-fixit-for-hpux test]
78** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit]
79** 990517 JLI [2.59 fixed some high-sensitivity warnings]
80** 990610 JLI [2.60 fixed some more high-sensitivity warnings]
81** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names]
82** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()]
83** 991007 JLI [2.63 first shot at a 64-bit compatible version]
84** 991009 JLI [2.64 undef's strdup() if defined, mwStrdup made const]
85** 000704 JLI [2.65 added some more detection for 64-bits]
86** 010502 JLI [2.66 incorporated some user fixes]
87** [mwRelink() could print out garbage pointer (thanks mac@phobos.ca)]
88** [added array destructor for C++ (thanks
89rdasilva@connecttel.com)]
90** [added mutex support (thanks rdasilva@connecttel.com)]
91** 010531 JLI [2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined]
92** 010619 JLI [2.68 fix: mwRealloc() could leave the mutex locked]
93** 020918 JLI [2.69 changed to GPL, added C++ array allocation by Howard Cohen]
94** 030212 JLI [2.70 mwMalloc() bug for very large allocations (4GB on 32bits)]
95** 030520 JLI [2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)]
96*/
97
98#define __MEMWATCH_C 1
99
100#ifdef MW_NOCPP
101# define MEMWATCH_NOCPP
102#endif
103#ifdef MW_STDIO
104# define MEMWATCH_STDIO
105#endif
106
107/***********************************************************************
108** Include files
109***********************************************************************/
110
111#include "memwatch.h"
112#include <limits.h>
113#include <setjmp.h>
114#include <signal.h>
115#include <stdarg.h>
116#include <stdio.h>
117#include <stdlib.h>
118#include <string.h>
119#include <time.h>
120
121#ifndef toupper
122# include <ctype.h>
123#endif
124
125#if defined( WIN32 ) || defined( __WIN32__ )
126# define MW_HAVE_MUTEX 1
127# include <windows.h>
128#endif
129
130#if defined( MW_PTHREADS ) || defined( HAVE_PTHREAD_H )
131# define MW_HAVE_MUTEX 1
132# include <pthread.h>
133#endif
134
135/***********************************************************************
136** Defines & other weird stuff
137***********************************************************************/
138
139/*lint -save -e767 */
140#define VERSION "2.71" /* the current version number */
141#define CHKVAL( mw ) ( 0xFE0180L ^ (long)mw->count ^ (long)mw->size ^ (long)mw->line )
142#define FLUSH() mwFlush()
143#define TESTS( f, l ) \
144 if ( mwTestAlways ) (void)mwTestNow( f, l, 1 )
145#define PRECHK 0x01234567L
146#define POSTCHK 0x76543210L
147#define mwBUFFER_TO_MW( p ) \
148 ( (mwData*)(void*)( ( (char*)p ) - mwDataSize - mwOverflowZoneSize ) )
149/*lint -restore */
150
151#define MW_NML 0x0001
152
153#ifdef _MSC_VER
154# define COMMIT "c" /* Microsoft C requires the 'c' to perform as desired */
155#else
156# define COMMIT "" /* Normal ANSI */
157#endif /* _MSC_VER */
158
159#ifdef __cplusplus
160# define CPPTEXT "++"
161#else
162# define CPPTEXT ""
163#endif /* __cplusplus */
164
165#ifdef MEMWATCH_STDIO
166# define mwSTDERR stderr
167#else
168# define mwSTDERR mwLog
169#endif
170
171#ifdef MW_HAVE_MUTEX
172# define MW_MUTEX_INIT() mwMutexInit()
173# define MW_MUTEX_TERM() mwMutexTerm()
174# define MW_MUTEX_LOCK() mwMutexLock()
175# define MW_MUTEX_UNLOCK() mwMutexUnlock()
176#else
177# define MW_MUTEX_INIT()
178# define MW_MUTEX_TERM()
179# define MW_MUTEX_LOCK()
180# define MW_MUTEX_UNLOCK()
181#endif
182
183/***********************************************************************
184** If you really, really know what you're doing,
185** you can predefine these things yourself.
186***********************************************************************/
187
188#ifndef mwBYTE_DEFINED
189# if CHAR_BIT != 8
190# error need CHAR_BIT to be 8!
191# else
192typedef unsigned char mwBYTE;
193# define mwBYTE_DEFINED 1
194# endif
195#endif
196
197#if defined( ULONGLONG_MAX ) || defined( ULLONG_MAX ) || defined( _UI64_MAX ) || \
198 defined( ULONG_LONG_MAX )
199# define mw64BIT 1
200# define mwROUNDALLOC_DEFAULT 8
201#else
202# if UINT_MAX <= 0xFFFFUL
203# define mw16BIT 1
204# define mwROUNDALLOC_DEFAULT 2
205# else
206# if ULONG_MAX > 0xFFFFFFFFUL
207# define mw64BIT 1
208# define mwROUNDALLOC_DEFAULT 8
209# else
210# define mw32BIT 1
211# define mwROUNDALLOC_DEFAULT 4
212# endif
213# endif
214#endif
215
216/* mwROUNDALLOC is the number of bytes to */
217/* round up to, to ensure that the end of */
218/* the buffer is suitable for storage of */
219/* any kind of object */
220#ifndef mwROUNDALLOC
221# define mwROUNDALLOC mwROUNDALLOC_DEFAULT
222#endif
223
224#ifndef mwDWORD_DEFINED
225# if ULONG_MAX == 0xFFFFFFFFUL
226typedef unsigned long mwDWORD;
227# define mwDWORD_DEFINED "unsigned long"
228# endif
229#endif
230
231#ifndef mwDWORD_DEFINED
232# if UINT_MAX == 0xFFFFFFFFUL
233typedef unsigned int mwDWORD;
234# define mwDWORD_DEFINED "unsigned int"
235# endif
236#endif
237
238#ifndef mwDWORD_DEFINED
239# if USHRT_MAX == 0xFFFFFFFFUL
240typedef unsigned short mwDWORD;
241# define mwDWORD_DEFINED "unsigned short"
242# endif
243#endif
244
245#ifndef mwBYTE_DEFINED
246# error "can't find out the correct type for a 8 bit scalar"
247#endif
248
249#ifndef mwDWORD_DEFINED
250# error "can't find out the correct type for a 32 bit scalar"
251#endif
252
253/***********************************************************************
254** Typedefs & structures
255***********************************************************************/
256
257/* main data holding area, precedes actual allocation */
258typedef struct mwData_ mwData;
259struct mwData_ {
260 mwData* prev; /* previous allocation in chain */
261 mwData* next; /* next allocation in chain */
262 const char* file; /* file name where allocated */
263 long count; /* action count */
264 long check; /* integrity check value */
265#if 0
266 long crc; /* data crc value */
267#endif
268 size_t size; /* size of allocation */
269 int line; /* line number where allocated */
270 unsigned flag; /* flag word */
271};
272
273/* statistics structure */
274typedef struct mwStat_ mwStat;
275struct mwStat_ {
276 mwStat* next; /* next statistic buffer */
277 const char* file;
278 long total; /* total bytes allocated */
279 long num; /* total number of allocations */
280 long max; /* max allocated at one time */
281 long curr; /* current allocations */
282 int line;
283};
284
285/* grabbing structure, 1K in size */
286typedef struct mwGrabData_ mwGrabData;
289 int type;
290 char blob[1024 - sizeof( mwGrabData* ) - sizeof( int )];
291};
292
293typedef struct mwMarker_ mwMarker;
294struct mwMarker_ {
295 void* host;
296 char* text;
298 int level;
299};
300
301#if defined( WIN32 ) || defined( __WIN32__ )
302typedef HANDLE mwMutex;
303#endif
304
305#if defined( MW_PTHREADS ) || defined( HAVE_PTHREAD_H )
306typedef pthread_mutex_t mwMutex;
307#endif
308
309/***********************************************************************
310** Static variables
311***********************************************************************/
312
313static int mwInited = 0;
314static int mwInfoWritten = 0;
315static int mwUseAtexit = 0;
316static FILE* mwLog = NULL;
317static int mwFlushing = 0;
318static int mwStatLevel = MW_STAT_DEFAULT;
319static int mwNML = MW_NML_DEFAULT;
320static int mwFBI = 0;
321static long mwAllocLimit = 0L;
322static int mwUseLimit = 0;
323
324static long mwNumCurAlloc = 0L;
325static mwData* mwHead = NULL;
326static mwData* mwTail = NULL;
327static int mwDataSize = 0;
328static unsigned char mwOverflowZoneTemplate[] = "mEmwAtch";
329static int mwOverflowZoneSize = mwROUNDALLOC;
330
331static void ( *mwOutFunction )( int ) = NULL;
332static int ( *mwAriFunction )( const char* ) = NULL;
333static int mwAriAction = MW_ARI_ABORT;
334
335static char mwPrintBuf[MW_TRACE_BUFFER + 8];
336
337static unsigned long mwCounter = 0L;
338static long mwErrors = 0L;
339
340static int mwTestFlags = 0;
341static int mwTestAlways = 0;
342
343static FILE* mwLogB1 = NULL;
344static int mwFlushingB1 = 0;
345
346static mwStat* mwStatList = NULL;
347static long mwStatTotAlloc = 0L;
348static long mwStatMaxAlloc = 0L;
349static long mwStatNumAlloc = 0L;
350static long mwStatCurAlloc = 0L;
351static long mwNmlNumAlloc = 0L;
352static long mwNmlCurAlloc = 0L;
353
354static mwGrabData* mwGrabList = NULL;
355static long mwGrabSize = 0L;
356
357static void* mwLastFree[MW_FREE_LIST];
358static const char* mwLFfile[MW_FREE_LIST];
359static int mwLFline[MW_FREE_LIST];
360static int mwLFcur = 0;
361
362static mwMarker* mwFirstMark = NULL;
363
364static FILE* mwLogB2 = NULL;
365static int mwFlushingB2 = 0;
366
367#ifdef MW_HAVE_MUTEX
368static mwMutex mwGlobalMutex;
369#endif
370
371/***********************************************************************
372** Static function declarations
373***********************************************************************/
374
375static void mwAutoInit( void );
376static FILE* mwLogR( void );
377static void mwLogW( FILE* );
378static int mwFlushR( void );
379static void mwFlushW( int );
380static void mwFlush( void );
381static void mwIncErr( void );
382static void mwUnlink( mwData*, const char* file, int line );
383static int mwRelink( mwData*, const char* file, int line );
384static int mwIsHeapOK( mwData* mw );
385static int mwIsOwned( mwData* mw, const char* file, int line );
386static int mwTestBuf( mwData* mw, const char* file, int line );
387static void mwDefaultOutFunc( int );
388static void mwWrite( const char* format, ... );
389static void mwLogFile( const char* name );
390static size_t mwFreeUp( size_t, int );
391static const void* mwTestMem( const void*, unsigned, int );
392static int mwStrCmpI( const char* s1, const char* s2 );
393static int mwTestNow( const char* file, int line, int always_invoked );
394static void mwDropAll( void );
395static const char* mwGrabType( int type );
396static unsigned mwGrab_( unsigned kb, int type, int silent );
397static unsigned mwDrop_( unsigned kb, int type, int silent );
398static int mwARI( const char* text );
399static void mwStatReport( void );
400static mwStat* mwStatGet( const char*, int, int );
401static void mwStatAlloc( size_t, const char*, int );
402static void mwStatFree( size_t, const char*, int );
403static int mwCheckOF( const void* p );
404static void mwWriteOF( void* p );
405static char mwDummy( char c );
406#ifdef MW_HAVE_MUTEX
407static void mwMutexInit( void );
408static void mwMutexTerm( void );
409static void mwMutexLock( void );
410static void mwMutexUnlock( void );
411#endif
412
413/***********************************************************************
414** System functions
415***********************************************************************/
416
417void mwInit( void ) {
418 time_t tid;
419
420 if ( mwInited++ > 0 ) return;
421
423
424 /* start a log if none is running */
425 if ( mwLogR() == NULL ) mwLogFile( "memwatch.log" );
426 if ( mwLogR() == NULL )
427 {
428 int i;
429 char buf[32];
430 /* oops, could not open it! */
431 /* probably because it's already open */
432 /* so we try some other names */
433 for ( i = 1; i < 100; i++ )
434 {
435 sprintf( buf, "memwat%02d.log", i );
436 mwLogFile( buf );
437 if ( mwLogR() != NULL ) break;
438 }
439 }
440
441 /* initialize the statistics */
442 mwStatList = NULL;
443 mwStatTotAlloc = 0L;
444 mwStatCurAlloc = 0L;
445 mwStatMaxAlloc = 0L;
446 mwStatNumAlloc = 0L;
447 mwNmlCurAlloc = 0L;
448 mwNmlNumAlloc = 0L;
449
450 /* calculate the buffer size to use for a mwData */
451 mwDataSize = sizeof( mwData );
452 while ( mwDataSize % mwROUNDALLOC ) mwDataSize++;
453
454 /* write informational header if needed */
455 if ( !mwInfoWritten )
456 {
457 mwInfoWritten = 1;
458 (void)time( &tid );
459 mwWrite( "\n============="
460 " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh "
461 "=============\n" );
462 mwWrite( "\nStarted at %s\n", ctime( &tid ) );
463
464 /**************************************************************** Generic */
465 mwWrite( "Modes: " );
466#ifdef mwNew
467 mwWrite( "C++ " );
468#endif /* mwNew */
469#ifdef __STDC__
470 mwWrite( "__STDC__ " );
471#endif /* __STDC__ */
472#ifdef mw16BIT
473 mwWrite( "16-bit " );
474#endif
475#ifdef mw32BIT
476 mwWrite( "32-bit " );
477#endif
478#ifdef mw64BIT
479 mwWrite( "64-bit " );
480#endif
481 mwWrite( "mwDWORD==(" mwDWORD_DEFINED ")\n" );
482 mwWrite( "mwROUNDALLOC==%d sizeof(mwData)==%d mwDataSize==%d\n", mwROUNDALLOC,
483 sizeof( mwData ), mwDataSize );
484/**************************************************************** Generic */
485
486/************************************************************ Microsoft C */
487#ifdef _MSC_VER
488 mwWrite( "Compiled using Microsoft C" CPPTEXT " %d.%02d\n", _MSC_VER / 100,
489 _MSC_VER % 100 );
490#endif /* _MSC_VER */
491/************************************************************ Microsoft C */
492
493/************************************************************** Borland C */
494#ifdef __BORLANDC__
495 mwWrite( "Compiled using Borland C"
496# ifdef __cplusplus
497 "++ %d.%01d\n",
498 __BCPLUSPLUS__ / 0x100, ( __BCPLUSPLUS__ % 0x100 ) / 0x10 );
499# else
500 " %d.%01d\n",
501 __BORLANDC__ / 0x100, ( __BORLANDC__ % 0x100 ) / 0x10 );
502# endif /* __cplusplus */
503#endif /* __BORLANDC__ */
504/************************************************************** Borland C */
505
506/************************************************************** Watcom C */
507#ifdef __WATCOMC__
508 mwWrite( "Compiled using Watcom C %d.%02d ", __WATCOMC__ / 100, __WATCOMC__ % 100 );
509# ifdef __FLAT__
510 mwWrite( "(32-bit flat model)" );
511# endif /* __FLAT__ */
512 mwWrite( "\n" );
513#endif /* __WATCOMC__ */
514 /************************************************************** Watcom C */
515
516 mwWrite( "\n" );
517 FLUSH();
518 }
519
520 if ( mwUseAtexit ) (void)atexit( mwAbort );
521 return;
522}
523
524void mwAbort( void ) {
525 mwData* mw;
526 mwMarker* mrk;
527 char* data;
528 time_t tid;
529 int c, i, j;
530 int errors;
531
532 tid = time( NULL );
533 mwWrite( "\nStopped at %s\n", ctime( &tid ) );
534
535 if ( !mwInited ) mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" );
536
537 /* release the grab list */
538 mwDropAll();
539
540 /* report mwMarked items */
541 while ( mwFirstMark )
542 {
543 mrk = mwFirstMark->next;
544 mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text );
545 free( mwFirstMark->text );
546 free( mwFirstMark );
547 mwFirstMark = mrk;
548 mwErrors++;
549 }
550
551 /* release all still allocated memory */
552 errors = 0;
553 while ( mwHead != NULL && errors < 3 )
554 {
555 if ( !mwIsOwned( mwHead, __FILE__, __LINE__ ) )
556 {
557 if ( errors < 3 )
558 {
559 errors++;
560 mwWrite( "internal: NML/unfreed scan restarting\n" );
561 FLUSH();
562 mwHead = mwHead;
563 continue;
564 }
565 mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" );
566 FLUSH();
567 break;
568 }
569 mwFlushW( 0 );
570 if ( !( mwHead->flag & MW_NML ) )
571 {
572 mwErrors++;
573 data = ( (char*)mwHead ) + mwDataSize;
574 mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ", mwHead->count, mwHead->file,
575 mwHead->line, (long)mwHead->size, data + mwOverflowZoneSize );
576 if ( mwCheckOF( data ) )
577 {
578 mwWrite( "[underflowed] " );
579 FLUSH();
580 }
581 if ( mwCheckOF( ( data + mwOverflowZoneSize + mwHead->size ) ) )
582 {
583 mwWrite( "[overflowed] " );
584 FLUSH();
585 }
586 mwWrite( " \t{" );
587 j = 16;
588 if ( mwHead->size < 16 ) j = (int)mwHead->size;
589 for ( i = 0; i < 16; i++ )
590 {
591 if ( i < j ) mwWrite( "%02X ", (unsigned char)*( data + mwOverflowZoneSize + i ) );
592 else mwWrite( ".. " );
593 }
594 for ( i = 0; i < j; i++ )
595 {
596 c = *( data + mwOverflowZoneSize + i );
597 if ( c < 32 || c > 126 ) c = '.';
598 mwWrite( "%c", c );
599 }
600 mwWrite( "}\n" );
601 mw = mwHead;
602 mwUnlink( mw, __FILE__, __LINE__ );
603 free( mw );
604 }
605 else
606 {
607 data = ( (char*)mwHead ) + mwDataSize + mwOverflowZoneSize;
608 if ( mwTestMem( data, mwHead->size, MW_VAL_NML ) )
609 {
610 mwErrors++;
611 mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", mwHead->count,
612 data + mwOverflowZoneSize, mwHead->file, mwHead->line );
613 FLUSH();
614 }
615 mwNmlNumAlloc--;
616 mwNmlCurAlloc -= mwHead->size;
617 mw = mwHead;
618 mwUnlink( mw, __FILE__, __LINE__ );
619 free( mw );
620 }
621 }
622
623 if ( mwNmlNumAlloc )
624 mwWrite( "internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc );
625 if ( mwNmlCurAlloc )
626 mwWrite( "internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc );
627
628 /* report statistics */
629 mwStatReport();
630 FLUSH();
631
632 mwInited = 0;
633 mwHead = mwTail = NULL;
634 if ( mwErrors ) fprintf( mwSTDERR, "MEMWATCH detected %ld anomalies\n", mwErrors );
635 mwLogFile( NULL );
636 mwErrors = 0;
637
639}
640
641void mwTerm( void ) {
642 if ( mwInited == 1 )
643 {
644 mwAbort();
645 return;
646 }
647 if ( !mwInited ) mwWrite( "internal: mwTerm(): MEMWATCH has not been started!\n" );
648 else mwInited--;
649}
650
651void mwStatistics( int level ) {
652 mwAutoInit();
653 if ( level < 0 ) level = 0;
654 if ( mwStatLevel != level )
655 {
656 mwWrite( "statistics: now collecting on a %s basis\n",
657 level < 1 ? "global" : ( level < 2 ? "module" : "line" ) );
658 mwStatLevel = level;
659 }
660}
661
662void mwAutoCheck( int onoff ) {
663 mwAutoInit();
664 mwTestAlways = onoff;
665 if ( onoff ) mwTestFlags = MW_TEST_ALL;
666}
667
668void mwSetOutFunc( void ( *func )( int ) ) {
669 mwAutoInit();
670 mwOutFunction = func;
671}
672
673static void mwWriteOF( void* p ) {
674 int i;
675 unsigned char* ptr;
676 ptr = (unsigned char*)p;
677 for ( i = 0; i < mwOverflowZoneSize; i++ ) { *( ptr + i ) = mwOverflowZoneTemplate[i % 8]; }
678 return;
679}
680
681static int mwCheckOF( const void* p ) {
682 int i;
683 const unsigned char* ptr;
684 ptr = (const unsigned char*)p;
685 for ( i = 0; i < mwOverflowZoneSize; i++ )
686 {
687 if ( *( ptr + i ) != mwOverflowZoneTemplate[i % 8] ) return 1; /* errors found */
688 }
689 return 0; /* no errors */
690}
691
692int mwTest( const char* file, int line, int items ) {
693 mwAutoInit();
694 mwTestFlags = items;
695 return mwTestNow( file, line, 0 );
696}
697
698/*
699** Returns zero if there are no errors.
700** Returns nonzero if there are errors.
701*/
702int mwTestBuffer( const char* file, int line, void* p ) {
703 mwData* mw;
704
705 mwAutoInit();
706
707 /* do the quick ownership test */
708 mw = (mwData*)mwBUFFER_TO_MW( p );
709
710 if ( mwIsOwned( mw, file, line ) ) { return mwTestBuf( mw, file, line ); }
711 return 1;
712}
713
714void mwBreakOut( const char* cause ) {
715 fprintf( mwSTDERR, "breakout: %s\n", cause );
716 mwWrite( "breakout: %s\n", cause );
717 return;
718}
719
720/*
721** 981217 JLI: is it possible that ->next is not always set?
722*/
723void* mwMark( void* p, const char* desc, const char* file, unsigned line ) {
724 mwMarker* mrk;
725 unsigned n, isnew;
726 char* buf;
727 int tot, oflow = 0;
728 char wherebuf[128];
729
730 mwAutoInit();
731 TESTS( NULL, 0 );
732
733 if ( desc == NULL ) desc = "unknown";
734 if ( file == NULL ) file = "unknown";
735
736 tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line );
737 if ( tot >= (int)sizeof( wherebuf ) )
738 {
739 wherebuf[sizeof( wherebuf ) - 1] = 0;
740 oflow = 1;
741 }
742
743 if ( p == NULL )
744 {
745 mwWrite( "mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc );
746 return p;
747 }
748
749 if ( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) )
750 {
751 mwWrite( "mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n", file, line,
752 mwFirstMark, desc );
753 return p;
754 }
755
756 for ( mrk = mwFirstMark; mrk; mrk = mrk->next )
757 {
758 if ( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) )
759 {
760 mwWrite( "mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n", file, line,
761 mrk, mrk->next, desc );
762 return p;
763 }
764 if ( mrk->host == p ) break;
765 }
766
767 if ( mrk == NULL )
768 {
769 isnew = 1;
770 mrk = (mwMarker*)malloc( sizeof( mwMarker ) );
771 if ( mrk == NULL )
772 {
773 mwWrite( "mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
774 return p;
775 }
776 mrk->next = NULL;
777 n = 0;
778 }
779 else
780 {
781 isnew = 0;
782 n = strlen( mrk->text );
783 }
784
785 n += strlen( wherebuf );
786 buf = (char*)malloc( n + 3 );
787 if ( buf == NULL )
788 {
789 if ( isnew ) free( mrk );
790 mwWrite( "mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
791 return p;
792 }
793
794 if ( isnew )
795 {
796 memcpy( buf, wherebuf, n + 1 );
797 mrk->next = mwFirstMark;
798 mrk->host = p;
799 mrk->text = buf;
800 mrk->level = 1;
801 mwFirstMark = mrk;
802 }
803 else
804 {
805 strcpy( buf, mrk->text );
806 strcat( buf, ", " );
807 strcat( buf, wherebuf );
808 free( mrk->text );
809 mrk->text = buf;
810 mrk->level++;
811 }
812
813 if ( oflow )
814 {
815 mwIncErr();
816 mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
817 }
818 return p;
819}
820
821void* mwUnmark( void* p, const char* file, unsigned line ) {
822 mwMarker *mrk, *prv;
823 mrk = mwFirstMark;
824 prv = NULL;
825 while ( mrk )
826 {
827 if ( mrk->host == p )
828 {
829 if ( mrk->level < 2 )
830 {
831 if ( prv ) prv->next = mrk->next;
832 else mwFirstMark = mrk->next;
833 free( mrk->text );
834 free( mrk );
835 return p;
836 }
837 mrk->level--;
838 return p;
839 }
840 prv = mrk;
841 mrk = mrk->next;
842 }
843 mwWrite( "mark: %s(%d), no mark found for %p\n", file, line, p );
844 return p;
845}
846
847/***********************************************************************
848** Abort/Retry/Ignore handlers
849***********************************************************************/
850
851static int mwARI( const char* estr ) {
852 char inbuf[81];
853 int c;
854 fprintf( mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr );
855 (void)fgets( inbuf, sizeof( inbuf ), stdin );
856 for ( c = 0; inbuf[c] && inbuf[c] <= ' '; c++ )
857 ;
858 c = inbuf[c];
859 if ( c == 'R' || c == 'r' )
860 {
861 mwBreakOut( estr );
862 return MW_ARI_RETRY;
863 }
864 if ( c == 'I' || c == 'i' ) return MW_ARI_IGNORE;
865 return MW_ARI_ABORT;
866}
867
868/* standard ARI handler (exported) */
869int mwAriHandler( const char* estr ) {
870 mwAutoInit();
871 return mwARI( estr );
872}
873
874/* used to set the ARI function */
875void mwSetAriFunc( int ( *func )( const char* ) ) {
876 mwAutoInit();
877 mwAriFunction = func;
878}
879
880/***********************************************************************
881** Allocation handlers
882***********************************************************************/
883
884void* mwMalloc( size_t size, const char* file, int line ) {
885 size_t needed;
886 mwData* mw;
887 char* ptr;
888 void* p;
889
890 mwAutoInit();
891
893
894 TESTS( file, line );
895
896 mwCounter++;
897 needed = mwDataSize + mwOverflowZoneSize * 2 + size;
898 if ( needed < size )
899 {
900 /* theoretical case: req size + mw overhead exceeded size_t limits */
901 return NULL;
902 }
903
904 /* if this allocation would violate the limit, fail it */
905 if ( mwUseLimit && ( (long)size + mwStatCurAlloc > mwAllocLimit ) )
906 {
907 mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", mwCounter, file, line,
908 (long)size, mwAllocLimit - mwStatCurAlloc );
909 mwIncErr();
910 FLUSH();
912 return NULL;
913 }
914
915 mw = (mwData*)malloc( needed );
916 if ( mw == NULL )
917 {
918 if ( mwFreeUp( needed, 0 ) >= needed )
919 {
920 mw = (mwData*)malloc( needed );
921 if ( mw == NULL )
922 {
923 mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed );
924 mwIncErr();
925 FLUSH();
926 }
927 }
928 if ( mw == NULL )
929 {
930 mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n", mwCounter, file, line,
931 (long)size, mwStatCurAlloc );
932 mwIncErr();
933 FLUSH();
935 return NULL;
936 }
937 }
938
939 mw->count = mwCounter;
940 mw->prev = NULL;
941 mw->next = mwHead;
942 mw->file = file;
943 mw->size = size;
944 mw->line = line;
945 mw->flag = 0;
946 mw->check = CHKVAL( mw );
947
948 if ( mwHead ) mwHead->prev = mw;
949 mwHead = mw;
950 if ( mwTail == NULL ) mwTail = mw;
951
952 ptr = ( (char*)mw ) + mwDataSize;
953 mwWriteOF( ptr ); /* '*(long*)ptr = PRECHK;' */
954 ptr += mwOverflowZoneSize;
955 p = ptr;
956 memset( ptr, MW_VAL_NEW, size );
957 ptr += size;
958 mwWriteOF( ptr ); /* '*(long*)ptr = POSTCHK;' */
959
960 mwNumCurAlloc++;
961 mwStatCurAlloc += (long)size;
962 mwStatTotAlloc += (long)size;
963 if ( mwStatCurAlloc > mwStatMaxAlloc ) mwStatMaxAlloc = mwStatCurAlloc;
964 mwStatNumAlloc++;
965
966 if ( mwStatLevel ) mwStatAlloc( size, file, line );
967
969 return p;
970}
971
972void* mwRealloc( void* p, size_t size, const char* file, int line ) {
973 int oldUseLimit, i;
974 mwData* mw;
975 char* ptr;
976
977 mwAutoInit();
978
979 if ( p == NULL ) return mwMalloc( size, file, line );
980 if ( size == 0 )
981 {
982 mwFree( p, file, line );
983 return NULL;
984 }
985
987
988 /* do the quick ownership test */
989 mw = (mwData*)mwBUFFER_TO_MW( p );
990 if ( mwIsOwned( mw, file, line ) )
991 {
992
993 /* if the buffer is an NML, treat this as a double-free */
994 if ( mw->flag & MW_NML )
995 {
996 mwIncErr();
997 if ( *( (unsigned char*)( mw ) + mwDataSize + mwOverflowZoneSize ) != MW_VAL_NML )
998 {
999 mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", mwCounter, file,
1000 line, mw );
1001 }
1002 goto check_dbl_free;
1003 }
1004
1005 /* if this allocation would violate the limit, fail it */
1006 if ( mwUseLimit && ( (long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit ) )
1007 {
1008 TESTS( file, line );
1009 mwCounter++;
1010 mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", mwCounter, file, line,
1011 (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc );
1012 mwIncErr();
1013 FLUSH();
1015 return NULL;
1016 }
1017
1018 /* fake realloc operation */
1019 oldUseLimit = mwUseLimit;
1020 mwUseLimit = 0;
1021 ptr = (char*)mwMalloc( size, file, line );
1022 if ( ptr != NULL )
1023 {
1024 if ( size < mw->size ) memcpy( ptr, p, size );
1025 else memcpy( ptr, p, mw->size );
1026 mwFree( p, file, line );
1027 }
1028 mwUseLimit = oldUseLimit;
1030 return (void*)ptr;
1031 }
1032
1033 /* Unknown pointer! */
1034
1035 /* using free'd pointer? */
1036check_dbl_free:
1037 for ( i = 0; i < MW_FREE_LIST; i++ )
1038 {
1039 if ( mwLastFree[i] == p )
1040 {
1041 mwIncErr();
1042 mwWrite( "realloc: <%ld> %s(%d), %p was"
1043 " freed from %s(%d)\n",
1044 mwCounter, file, line, p, mwLFfile[i], mwLFline[i] );
1045 FLUSH();
1047 return NULL;
1048 }
1049 }
1050
1051 /* some weird pointer */
1052 mwIncErr();
1053 mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n", mwCounter, file, line, p );
1054 FLUSH();
1056 return NULL;
1057}
1058
1059char* mwStrdup( const char* str, const char* file, int line ) {
1060 size_t len;
1061 char* newstring;
1062
1063 MW_MUTEX_LOCK();
1064
1065 if ( str == NULL )
1066 {
1067 mwIncErr();
1068 mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n", mwCounter, file, line );
1069 FLUSH();
1071 return NULL;
1072 }
1073
1074 len = strlen( str ) + 1;
1075 newstring = (char*)mwMalloc( len, file, line );
1076 if ( newstring != NULL ) memcpy( newstring, str, len );
1078 return newstring;
1079}
1080
1081void mwFree( void* p, const char* file, int line ) {
1082 int i;
1083 mwData* mw;
1084 char buffer[sizeof( mwData ) + ( mwROUNDALLOC * 3 ) + 64];
1085
1086 /* this code is in support of C++ delete */
1087 if ( file == NULL )
1088 {
1089 mwFree_( p );
1091 return;
1092 }
1093
1094 mwAutoInit();
1095
1096 MW_MUTEX_LOCK();
1097 TESTS( file, line );
1098 mwCounter++;
1099
1100 /* on NULL free, write a warning and return */
1101 if ( p == NULL )
1102 {
1103 mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n", mwCounter, file, line );
1104 FLUSH();
1106 return;
1107 }
1108
1109 /* do the quick ownership test */
1110 mw = (mwData*)mwBUFFER_TO_MW( p );
1111
1112 if ( mwIsOwned( mw, file, line ) )
1113 {
1114 (void)mwTestBuf( mw, file, line );
1115
1116 /* if the buffer is an NML, treat this as a double-free */
1117 if ( mw->flag & MW_NML )
1118 {
1119 if ( *( ( (unsigned char*)mw ) + mwDataSize + mwOverflowZoneSize ) != MW_VAL_NML )
1120 {
1121 mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", mwCounter, file,
1122 line, mw );
1123 }
1124 goto check_dbl_free;
1125 }
1126
1127 /* update the statistics */
1128 mwNumCurAlloc--;
1129 mwStatCurAlloc -= (long)mw->size;
1130 if ( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line );
1131
1132 /* we should either free the allocation or keep it as NML */
1133 if ( mwNML )
1134 {
1135 mw->flag |= MW_NML;
1136 mwNmlNumAlloc++;
1137 mwNmlCurAlloc += (long)mw->size;
1138 memset( ( (char*)mw ) + mwDataSize + mwOverflowZoneSize, MW_VAL_NML, mw->size );
1139 }
1140 else
1141 {
1142 /* unlink the allocation, and enter the post-free data */
1143 mwUnlink( mw, file, line );
1144 memset( mw, MW_VAL_DEL,
1145 mw->size + mwDataSize + mwOverflowZoneSize + mwOverflowZoneSize );
1146 if ( mwFBI )
1147 {
1148 memset( mw, '.', mwDataSize + mwOverflowZoneSize );
1149 sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line );
1150 strncpy( (char*)(void*)mw, buffer, mwDataSize + mwOverflowZoneSize );
1151 }
1152 free( mw );
1153 }
1154
1155 /* add the pointer to the last-free track */
1156 mwLFfile[mwLFcur] = file;
1157 mwLFline[mwLFcur] = line;
1158 mwLastFree[mwLFcur++] = p;
1159 if ( mwLFcur == MW_FREE_LIST ) mwLFcur = 0;
1160
1162 return;
1163 }
1164
1165 /* check for double-freeing */
1166check_dbl_free:
1167 for ( i = 0; i < MW_FREE_LIST; i++ )
1168 {
1169 if ( mwLastFree[i] == p )
1170 {
1171 mwIncErr();
1172 mwWrite( "double-free: <%ld> %s(%d), %p was"
1173 " freed from %s(%d)\n",
1174 mwCounter, file, line, p, mwLFfile[i], mwLFline[i] );
1175 FLUSH();
1177 return;
1178 }
1179 }
1180
1181 /* some weird pointer... block the free */
1182 mwIncErr();
1183 mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n", mwCounter, file, line, p );
1184 FLUSH();
1186 return;
1187}
1188
1189void* mwCalloc( size_t a, size_t b, const char* file, int line ) {
1190 void* p;
1191 size_t size = a * b;
1192 p = mwMalloc( size, file, line );
1193 if ( p == NULL ) return NULL;
1194 memset( p, 0, size );
1195 return p;
1196}
1197
1198void mwFree_( void* p ) {
1199 MW_MUTEX_LOCK();
1200 TESTS( NULL, 0 );
1202 free( p );
1203}
1204
1205void* mwMalloc_( size_t size ) {
1206 MW_MUTEX_LOCK();
1207 TESTS( NULL, 0 );
1209 return malloc( size );
1210}
1211
1212void* mwRealloc_( void* p, size_t size ) {
1213 MW_MUTEX_LOCK();
1214 TESTS( NULL, 0 );
1216 return realloc( p, size );
1217}
1218
1219void* mwCalloc_( size_t a, size_t b ) {
1220 MW_MUTEX_LOCK();
1221 TESTS( NULL, 0 );
1223 return calloc( a, b );
1224}
1225
1226void mwFlushNow( void ) {
1227 if ( mwLogR() ) fflush( mwLogR() );
1228 return;
1229}
1230
1231void mwDoFlush( int onoff ) {
1232 mwFlushW( onoff < 1 ? 0 : onoff );
1233 if ( onoff )
1234 if ( mwLogR() ) fflush( mwLogR() );
1235 return;
1236}
1237
1238void mwLimit( long lim ) {
1239 TESTS( NULL, 0 );
1240 mwWrite( "limit: old limit = " );
1241 if ( !mwAllocLimit ) mwWrite( "none" );
1242 else mwWrite( "%ld bytes", mwAllocLimit );
1243 mwWrite( ", new limit = " );
1244 if ( !lim )
1245 {
1246 mwWrite( "none\n" );
1247 mwUseLimit = 0;
1248 }
1249 else
1250 {
1251 mwWrite( "%ld bytes\n", lim );
1252 mwUseLimit = 1;
1253 }
1254 mwAllocLimit = lim;
1255 FLUSH();
1256}
1257
1258void mwSetAriAction( int action ) {
1259 MW_MUTEX_LOCK();
1260 TESTS( NULL, 0 );
1261 mwAriAction = action;
1263 return;
1264}
1265
1266int mwAssert( int exp, const char* exps, const char* fn, int ln ) {
1267 int i;
1268 char buffer[MW_TRACE_BUFFER + 8];
1269 if ( exp ) { return 0; }
1270 mwAutoInit();
1271 MW_MUTEX_LOCK();
1272 TESTS( fn, ln );
1273 mwIncErr();
1274 mwCounter++;
1275 mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
1276 if ( mwAriFunction != NULL )
1277 {
1278 sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps );
1279 i = ( *mwAriFunction )( buffer );
1280 switch ( i )
1281 {
1282 case MW_ARI_IGNORE:
1283 mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter );
1285 return 0;
1286 case MW_ARI_RETRY:
1287 mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter );
1289 return 1;
1290 }
1291 }
1292 else
1293 {
1294 if ( mwAriAction & MW_ARI_IGNORE )
1295 {
1296 mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
1298 return 0;
1299 }
1300 fprintf( mwSTDERR, "\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps );
1301 }
1302
1303 FLUSH();
1304 (void)mwTestNow( fn, ln, 1 );
1305 FLUSH();
1306
1307 if ( mwAriAction & MW_ARI_NULLREAD )
1308 {
1309 /* This is made in an attempt to kick in */
1310 /* any debuggers or OS stack traces */
1311 FLUSH();
1312 /*lint -save -e413 */
1313 i = *( (int*)NULL );
1314 mwDummy( (char)i );
1315 /*lint -restore */
1316 }
1317
1319 exit( 255 );
1320 /* NOT REACHED - the return statement is in to keep */
1321 /* stupid compilers from squeaking about differing return modes. */
1322 /* Smart compilers instead say 'code unreachable...' */
1323 /*lint -save -e527 */
1324 return 0;
1325 /*lint -restore */
1326}
1327
1328int mwVerify( int exp, const char* exps, const char* fn, int ln ) {
1329 int i;
1330 char buffer[MW_TRACE_BUFFER + 8];
1331 if ( exp ) { return 0; }
1332 mwAutoInit();
1333 MW_MUTEX_LOCK();
1334 TESTS( fn, ln );
1335 mwIncErr();
1336 mwCounter++;
1337 mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
1338 if ( mwAriFunction != NULL )
1339 {
1340 sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps );
1341 i = ( *mwAriFunction )( buffer );
1342 if ( i == 0 )
1343 {
1344 mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter );
1346 return 0;
1347 }
1348 if ( i == 1 )
1349 {
1350 mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter );
1352 return 1;
1353 }
1354 }
1355 else
1356 {
1357 if ( mwAriAction & MW_ARI_NULLREAD )
1358 {
1359 /* This is made in an attempt to kick in */
1360 /* any debuggers or OS stack traces */
1361 FLUSH();
1362 /*lint -save -e413 */
1363 i = *( (int*)NULL );
1364 mwDummy( (char)i );
1365 /*lint -restore */
1366 }
1367 if ( mwAriAction & MW_ARI_IGNORE )
1368 {
1369 mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
1371 return 0;
1372 }
1373 fprintf( mwSTDERR, "\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps );
1374 }
1375 FLUSH();
1376 (void)mwTestNow( fn, ln, 1 );
1377 FLUSH();
1379 exit( 255 );
1380 /* NOT REACHED - the return statement is in to keep */
1381 /* stupid compilers from squeaking about differing return modes. */
1382 /* Smart compilers instead say 'code unreachable...' */
1383 /*lint -save -e527 */
1384 return 0;
1385 /*lint -restore */
1386}
1387
1388void mwTrace( const char* format, ... ) {
1389 int tot, oflow = 0;
1390 va_list mark;
1391
1392 mwAutoInit();
1393 MW_MUTEX_LOCK();
1394 TESTS( NULL, 0 );
1395 if ( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
1396
1397 va_start( mark, format );
1398 tot = vsprintf( mwPrintBuf, format, mark );
1399 va_end( mark );
1400 if ( tot >= MW_TRACE_BUFFER )
1401 {
1402 mwPrintBuf[MW_TRACE_BUFFER] = 0;
1403 oflow = 1;
1404 }
1405 for ( tot = 0; mwPrintBuf[tot]; tot++ ) ( *mwOutFunction )( mwPrintBuf[tot] );
1406 if ( oflow )
1407 {
1408 mwIncErr();
1409 mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
1410 }
1411
1412 FLUSH();
1414}
1415
1416/***********************************************************************
1417** Grab & Drop
1418***********************************************************************/
1419
1420unsigned mwGrab( unsigned kb ) {
1421 TESTS( NULL, 0 );
1422 return mwGrab_( kb, MW_VAL_GRB, 0 );
1423}
1424
1425unsigned mwDrop( unsigned kb ) {
1426 TESTS( NULL, 0 );
1427 return mwDrop_( kb, MW_VAL_GRB, 0 );
1428}
1429
1430static void mwDropAll() {
1431 TESTS( NULL, 0 );
1432 (void)mwDrop_( 0, MW_VAL_GRB, 0 );
1433 (void)mwDrop_( 0, MW_VAL_NML, 0 );
1434 if ( mwGrabList != NULL )
1435 mwWrite( "internal: the grab list is not empty after mwDropAll()\n" );
1436}
1437
1438static const char* mwGrabType( int type ) {
1439 switch ( type )
1440 {
1441 case MW_VAL_GRB: return "grabbed";
1442 case MW_VAL_NML: return "no-mans-land";
1443 default:
1444 /* do nothing */
1445 ;
1446 }
1447 return "<unknown type>";
1448}
1449
1450static unsigned mwGrab_( unsigned kb, int type, int silent ) {
1451 unsigned i = kb;
1452 mwGrabData* gd;
1453 if ( !kb ) i = kb = 65000U;
1454
1455 for ( ; kb; kb-- )
1456 {
1457 if ( mwUseLimit &&
1458 ( mwStatCurAlloc + mwGrabSize + (long)sizeof( mwGrabData ) > mwAllocLimit ) )
1459 {
1460 if ( !silent )
1461 {
1462 mwWrite( "grabbed: all allowed memory to %s (%u kb)\n", mwGrabType( type ), i - kb );
1463 FLUSH();
1464 }
1465 return i - kb;
1466 }
1467 gd = (mwGrabData*)malloc( sizeof( mwGrabData ) );
1468 if ( gd == NULL )
1469 {
1470 if ( !silent )
1471 {
1472 mwWrite( "grabbed: all available memory to %s (%u kb)\n", mwGrabType( type ), i - kb );
1473 FLUSH();
1474 }
1475 return i - kb;
1476 }
1477 mwGrabSize += (long)sizeof( mwGrabData );
1478 gd->next = mwGrabList;
1479 memset( gd->blob, type, sizeof( gd->blob ) );
1480 gd->type = type;
1481 mwGrabList = gd;
1482 }
1483 if ( !silent )
1484 {
1485 mwWrite( "grabbed: %u kilobytes of %s memory\n", i, mwGrabType( type ) );
1486 FLUSH();
1487 }
1488 return i;
1489}
1490
1491static unsigned mwDrop_( unsigned kb, int type, int silent ) {
1492 unsigned i = kb;
1493 mwGrabData *gd, *tmp, *pr;
1494 const void* p;
1495
1496 if ( mwGrabList == NULL && kb == 0 ) return 0;
1497 if ( !kb ) i = kb = 60000U;
1498
1499 pr = NULL;
1500 gd = mwGrabList;
1501 for ( ; kb; )
1502 {
1503 if ( gd == NULL )
1504 {
1505 if ( i - kb > 0 && !silent )
1506 {
1507 mwWrite( "dropped: all %s memory (%u kb)\n", mwGrabType( type ), i - kb );
1508 FLUSH();
1509 }
1510 return i - kb;
1511 }
1512 if ( gd->type == type )
1513 {
1514 if ( pr ) pr->next = gd->next;
1515 kb--;
1516 tmp = gd;
1517 if ( mwGrabList == gd ) mwGrabList = gd->next;
1518 gd = gd->next;
1519 p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type );
1520 if ( p != NULL )
1521 {
1522 mwWrite( "wild pointer: <%ld> %s memory hit at %p\n", mwCounter, mwGrabType( type ),
1523 p );
1524 FLUSH();
1525 }
1526 mwGrabSize -= (long)sizeof( mwGrabData );
1527 free( tmp );
1528 }
1529 else
1530 {
1531 pr = gd;
1532 gd = gd->next;
1533 }
1534 }
1535 if ( !silent )
1536 {
1537 mwWrite( "dropped: %u kilobytes of %s memory\n", i, mwGrabType( type ) );
1538 FLUSH();
1539 }
1540 return i;
1541}
1542
1543/***********************************************************************
1544** No-Mans-Land
1545***********************************************************************/
1546
1547void mwNoMansLand( int level ) {
1548 mwAutoInit();
1549 TESTS( NULL, 0 );
1550 switch ( level )
1551 {
1552 case MW_NML_NONE: (void)mwDrop_( 0, MW_VAL_NML, 0 ); break;
1553 case MW_NML_FREE: break;
1554 case MW_NML_ALL: (void)mwGrab_( 0, MW_VAL_NML, 0 ); break;
1555 default: return;
1556 }
1557 mwNML = level;
1558}
1559
1560/***********************************************************************
1561** Static functions
1562***********************************************************************/
1563
1564static void mwAutoInit( void ) {
1565 if ( mwInited ) return;
1566 mwUseAtexit = 1;
1567 mwInit();
1568 return;
1569}
1570
1571static FILE* mwLogR() {
1572 if ( ( mwLog == mwLogB1 ) && ( mwLog == mwLogB2 ) ) return mwLog;
1573 if ( mwLog == mwLogB1 ) mwLogB2 = mwLog;
1574 if ( mwLog == mwLogB2 ) mwLogB1 = mwLog;
1575 if ( mwLogB1 == mwLogB2 ) mwLog = mwLogB1;
1576 if ( ( mwLog == mwLogB1 ) && ( mwLog == mwLogB2 ) )
1577 {
1578 mwWrite( "internal: log file handle damaged and recovered\n" );
1579 FLUSH();
1580 return mwLog;
1581 }
1582 fprintf( mwSTDERR, "\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" );
1583 mwLog = mwLogB1 = mwLogB2 = mwSTDERR;
1584 return mwSTDERR;
1585}
1586
1587static void mwLogW( FILE* p ) { mwLog = mwLogB1 = mwLogB2 = p; }
1588
1589static int mwFlushR() {
1590 if ( ( mwFlushing == mwFlushingB1 ) && ( mwFlushing == mwFlushingB2 ) ) return mwFlushing;
1591 if ( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing;
1592 if ( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing;
1593 if ( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1;
1594 if ( ( mwFlushing == mwFlushingB1 ) && ( mwFlushing == mwFlushingB2 ) )
1595 {
1596 mwWrite( "internal: flushing flag damaged and recovered\n" );
1597 FLUSH();
1598 return mwFlushing;
1599 }
1600 mwWrite( "internal: flushing flag destroyed, so set to true\n" );
1601 mwFlushing = mwFlushingB1 = mwFlushingB2 = 1;
1602 return 1;
1603}
1604
1605static void mwFlushW( int n ) { mwFlushing = mwFlushingB1 = mwFlushingB2 = n; }
1606
1607static void mwIncErr() {
1608 mwErrors++;
1609 mwFlushW( mwFlushR() + 1 );
1610 FLUSH();
1611}
1612
1613static void mwFlush() {
1614 if ( mwLogR() == NULL ) return;
1615#ifdef MW_FLUSH
1616 fflush( mwLogR() );
1617#else
1618 if ( mwFlushR() ) fflush( mwLogR() );
1619#endif
1620 return;
1621}
1622
1623static void mwUnlink( mwData* mw, const char* file, int line ) {
1624 if ( mw->prev == NULL )
1625 {
1626 if ( mwHead != mw )
1627 mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n", mwCounter, file,
1628 line, mw );
1629 mwHead = mw->next;
1630 }
1631 else
1632 {
1633 if ( mw->prev->next != mw )
1634 mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n", mwCounter, file, line, mw );
1635 else mw->prev->next = mw->next;
1636 }
1637 if ( mw->next == NULL )
1638 {
1639 if ( mwTail != mw )
1640 mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n", mwCounter, file,
1641 line, mw );
1642 mwTail = mw->prev;
1643 }
1644 else
1645 {
1646 if ( mw->next->prev != mw )
1647 mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n", mwCounter, file, line, mw );
1648 else mw->next->prev = mw->prev;
1649 }
1650}
1651
1652/*
1653** Relinking tries to repair a damaged mw block.
1654** Returns nonzero if it thinks it successfully
1655** repaired the heap chain.
1656*/
1657static int mwRelink( mwData* mw, const char* file, int line ) {
1658 int fails;
1659 mwData *mw1, *mw2;
1660 long count, size;
1661 mwStat* ms;
1662
1663 if ( file == NULL ) file = "unknown";
1664
1665 if ( mw == NULL )
1666 {
1667 mwWrite( "relink: cannot repair MW at NULL\n" );
1668 FLUSH();
1669 goto emergency;
1670 }
1671
1672 if ( !mwIsSafeAddr( mw, mwDataSize ) )
1673 {
1674 mwWrite( "relink: MW-%p is a garbage pointer\n", mw );
1675 FLUSH();
1676 goto emergency;
1677 }
1678
1679 mwWrite( "relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw );
1680 FLUSH();
1681 fails = 0;
1682
1683 /* Repair from head */
1684 if ( mwHead != mw )
1685 {
1686 if ( !mwIsSafeAddr( mwHead, mwDataSize ) )
1687 {
1688 mwWrite( "relink: failed for MW-%p; head pointer destroyed\n", mw );
1689 FLUSH();
1690 goto emergency;
1691 }
1692 for ( mw1 = mwHead; mw1; mw1 = mw1->next )
1693 {
1694 if ( mw1->next == mw )
1695 {
1696 mw->prev = mw1;
1697 break;
1698 }
1699 if ( mw1->next && ( !mwIsSafeAddr( mw1->next, mwDataSize ) || mw1->next->prev != mw1 ) )
1700 {
1701 mwWrite( "relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n",
1702 mw, mw1, mw1->next );
1703 FLUSH();
1704 goto emergency;
1705 }
1706 }
1707 if ( mw1 == NULL )
1708 {
1709 mwWrite( "relink: MW-%p not found in forward chain search\n", mw );
1710 FLUSH();
1711 fails++;
1712 }
1713 }
1714 else
1715 {
1716 mwWrite( "relink: MW-%p is the head (first) allocation\n", mw );
1717 if ( mw->prev != NULL )
1718 {
1719 mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw );
1720 mw->prev = NULL;
1721 }
1722 }
1723
1724 /* Repair from tail */
1725 if ( mwTail != mw )
1726 {
1727 if ( !mwIsSafeAddr( mwTail, mwDataSize ) )
1728 {
1729 mwWrite( "relink: failed for MW-%p; tail pointer destroyed\n", mw );
1730 FLUSH();
1731 goto emergency;
1732 }
1733 for ( mw1 = mwTail; mw1; mw1 = mw1->prev )
1734 {
1735 if ( mw1->prev == mw )
1736 {
1737 mw->next = mw1;
1738 break;
1739 }
1740 if ( mw1->prev && ( !mwIsSafeAddr( mw1->prev, mwDataSize ) || mw1->prev->next != mw1 ) )
1741 {
1742 mwWrite( "relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n",
1743 mw, mw1, mw1->prev );
1744 FLUSH();
1745 goto emergency;
1746 }
1747 }
1748 if ( mw1 == NULL )
1749 {
1750 mwWrite( "relink: MW-%p not found in reverse chain search\n", mw );
1751 FLUSH();
1752 fails++;
1753 }
1754 }
1755 else
1756 {
1757 mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw );
1758 if ( mw->next != NULL )
1759 {
1760 mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw );
1761 mw->next = NULL;
1762 }
1763 }
1764
1765 if ( fails > 1 )
1766 {
1767 mwWrite( "relink: heap appears intact, MW-%p probably garbage pointer\n", mw );
1768 FLUSH();
1769 goto verifyok;
1770 }
1771
1772 /* restore MW info where possible */
1773 if ( mwIsReadAddr( mw->file, 1 ) )
1774 {
1775 ms = mwStatGet( mw->file, -1, 0 );
1776 if ( ms == NULL ) mw->file = "<relinked>";
1777 }
1778 mw->check = CHKVAL( mw );
1779 goto verifyok;
1780
1781/* Emergency repair */
1782emergency:
1783
1784 if ( mwHead == NULL && mwTail == NULL )
1785 {
1786 if ( mwStatCurAlloc == 0 )
1787 mwWrite( "relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file,
1788 line );
1789 else mwWrite( "relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line );
1790 FLUSH();
1791 return 0;
1792 }
1793
1794 mwWrite( "relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line );
1795 FLUSH();
1796
1797 if ( mwHead == NULL || mwTail == NULL )
1798 {
1799 if ( mwHead == NULL ) mwWrite( "relink: mwHead is NULL, but mwTail is %p\n", mwTail );
1800 else mwWrite( "relink: mwTail is NULL, but mwHead is %p\n", mwHead );
1801 }
1802
1803 mw1 = NULL;
1804 if ( mwHead != NULL )
1805 {
1806 if ( !mwIsReadAddr( mwHead, mwDataSize ) || mwHead->check != CHKVAL( mwHead ) )
1807 {
1808 mwWrite( "relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead );
1809 mwHead = NULL;
1810 goto scan_reverse;
1811 }
1812 if ( mwHead->prev != NULL )
1813 {
1814 mwWrite( "relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev );
1815 }
1816 for ( mw1 = mwHead; mw1; mw1 = mw1->next )
1817 {
1818 if ( mw1->next )
1819 {
1820 if ( !mwIsReadAddr( mw1->next, mwDataSize ) || !mw1->next->check != CHKVAL( mw1 ) ||
1821 mw1->next->prev != mw1 )
1822 {
1823 mwWrite( "relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
1824 mw1, mw1->size, ( mw->flag & MW_NML ) ? "NoMansLand " : "", mw1->file,
1825 mw1->line );
1826 if ( mwIsReadAddr( mw1->next, mwDataSize ) )
1827 {
1828 mwWrite(
1829 "relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
1830 mw1->next, mw1->size, ( mw->flag & MW_NML ) ? "NoMansLand " : "",
1831 mwIsReadAddr( mw1->file, 16 ) ? mw1->file : "<garbage-pointer>", mw1->line );
1832 }
1833 else
1834 {
1835 mwWrite( "relink: the 'next' pointer of this MW points to %p, which is "
1836 "out-of-legal-access\n",
1837 mw1->next );
1838 }
1839 break;
1840 }
1841 }
1842 }
1843 }
1844
1845scan_reverse:
1846 mw2 = NULL;
1847 if ( mwTail != NULL )
1848 {
1849 if ( !mwIsReadAddr( mwTail, mwDataSize ) || mwTail->check != CHKVAL( mwTail ) )
1850 {
1851 mwWrite( "relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail );
1852 mwTail = NULL;
1853 goto analyze;
1854 }
1855 if ( mwTail->next != NULL )
1856 {
1857 mwWrite( "relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next );
1858 }
1859 for ( mw2 = mwTail; mw2; mw2 = mw2->prev )
1860 {
1861 if ( mw2->prev )
1862 {
1863 if ( !mwIsReadAddr( mw2->prev, mwDataSize ) || !mw2->prev->check != CHKVAL( mw2 ) ||
1864 mw2->prev->next != mw2 )
1865 {
1866 mwWrite( "relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
1867 mw2, mw2->size, ( mw->flag & MW_NML ) ? "NoMansLand " : "", mw2->file,
1868 mw2->line );
1869 if ( mwIsReadAddr( mw2->prev, mwDataSize ) )
1870 {
1871 mwWrite(
1872 "relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
1873 mw2->prev, mw2->size, ( mw->flag & MW_NML ) ? "NoMansLand " : "",
1874 mwIsReadAddr( mw2->file, 16 ) ? mw2->file : "<garbage-pointer>", mw2->line );
1875 }
1876 else
1877 {
1878 mwWrite( "relink: the 'prev' pointer of this MW points to %p, which is "
1879 "out-of-legal-access\n",
1880 mw2->prev );
1881 }
1882 break;
1883 }
1884 }
1885 }
1886 }
1887
1888analyze:
1889 if ( mwHead == NULL && mwTail == NULL )
1890 {
1891 mwWrite( "relink: both head and tail pointers damaged, aborting program\n" );
1892 mwFlushW( 1 );
1893 FLUSH();
1894 abort();
1895 }
1896 if ( mwHead == NULL )
1897 {
1898 mwHead = mw2;
1899 mwWrite( "relink: heap truncated, MW-%p designated as new mwHead\n", mw2 );
1900 mw2->prev = NULL;
1901 mw1 = mw2 = NULL;
1902 }
1903 if ( mwTail == NULL )
1904 {
1905 mwTail = mw1;
1906 mwWrite( "relink: heap truncated, MW-%p designated as new mwTail\n", mw1 );
1907 mw1->next = NULL;
1908 mw1 = mw2 = NULL;
1909 }
1910 if ( mw1 == NULL && mw2 == NULL && mwHead->prev == NULL && mwTail->next == NULL )
1911 {
1912 mwWrite( "relink: verifying heap integrity...\n" );
1913 FLUSH();
1914 goto verifyok;
1915 }
1916 if ( mw1 && mw2 && mw1 != mw2 )
1917 {
1918 mw1->next = mw2;
1919 mw2->prev = mw1;
1920 mwWrite( "relink: emergency repairs successful, assessing damage...\n" );
1921 FLUSH();
1922 }
1923 else
1924 {
1925 mwWrite( "relink: heap totally destroyed, aborting program\n" );
1926 mwFlushW( 1 );
1927 FLUSH();
1928 abort();
1929 }
1930
1931 /* Verify by checking that the number of active allocations */
1932 /* match the number of entries in the chain */
1933verifyok:
1934 if ( !mwIsHeapOK( NULL ) )
1935 {
1936 mwWrite( "relink: heap verification FAILS - aborting program\n" );
1937 mwFlushW( 1 );
1938 FLUSH();
1939 abort();
1940 }
1941 for ( size = count = 0, mw1 = mwHead; mw1; mw1 = mw1->next )
1942 {
1943 count++;
1944 size += (long)mw1->size;
1945 }
1946 if ( count == mwNumCurAlloc )
1947 {
1948 mwWrite( "relink: successful, " );
1949 if ( size == mwStatCurAlloc ) { mwWrite( "no allocations lost\n" ); }
1950 else
1951 {
1952 if ( mw != NULL )
1953 {
1954 mwWrite( "size information lost for MW-%p\n", mw );
1955 mw->size = 0;
1956 }
1957 }
1958 }
1959 else
1960 {
1961 mwWrite( "relink: partial, %ld MW-blocks of %ld bytes lost\n",
1962 mwNmlNumAlloc + mwNumCurAlloc - count, mwNmlCurAlloc + mwStatCurAlloc - size );
1963 return 0;
1964 }
1965
1966 return 1;
1967}
1968
1969/*
1970** If mwData* is NULL:
1971** Returns 0 if heap chain is broken.
1972** Returns 1 if heap chain is intact.
1973** If mwData* is not NULL:
1974** Returns 0 if mwData* is missing or if chain is broken.
1975** Returns 1 if chain is intact and mwData* is found.
1976*/
1977static int mwIsHeapOK( mwData* includes_mw ) {
1978 int found = 0;
1979 mwData* mw;
1980
1981 for ( mw = mwHead; mw; mw = mw->next )
1982 {
1983 if ( includes_mw == mw ) found++;
1984 if ( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
1985 if ( mw->prev )
1986 {
1987 if ( !mwIsSafeAddr( mw->prev, mwDataSize ) ) return 0;
1988 if ( mw == mwHead || mw->prev->next != mw ) return 0;
1989 }
1990 if ( mw->next )
1991 {
1992 if ( !mwIsSafeAddr( mw->next, mwDataSize ) ) return 0;
1993 if ( mw == mwTail || mw->next->prev != mw ) return 0;
1994 }
1995 else if ( mw != mwTail ) return 0;
1996 }
1997
1998 if ( includes_mw != NULL && !found ) return 0;
1999
2000 return 1;
2001}
2002
2003static int mwIsOwned( mwData* mw, const char* file, int line ) {
2004 int retv;
2005 mwStat* ms;
2006
2007 /* see if the address is legal according to OS */
2008 if ( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
2009
2010 /* make sure we have _anything_ allocated */
2011 if ( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 ) return 0;
2012
2013 /* calculate checksum */
2014 if ( mw->check != CHKVAL( mw ) )
2015 {
2016 /* may be damaged checksum, see if block is in heap */
2017 if ( mwIsHeapOK( mw ) )
2018 {
2019 /* damaged checksum, repair it */
2020 mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n", mwCounter, file,
2021 line, mw );
2022 mwIncErr();
2023 if ( mwIsReadAddr( mw->file, 1 ) )
2024 {
2025 ms = mwStatGet( mw->file, -1, 0 );
2026 if ( ms == NULL ) mw->file = "<relinked>";
2027 }
2028 else mw->file = "<unknown>";
2029 mw->size = 0;
2030 mw->check = CHKVAL( mw );
2031 return 1;
2032 }
2033 /* no, it's just some garbage data */
2034 return 0;
2035 }
2036
2037 /* check that the non-NULL pointers are safe */
2038 if ( mw->prev && !mwIsSafeAddr( mw->prev, mwDataSize ) ) mwRelink( mw, file, line );
2039 if ( mw->next && !mwIsSafeAddr( mw->next, mwDataSize ) ) mwRelink( mw, file, line );
2040
2041 /* safe address, checksum OK, proceed with heap checks */
2042
2043 /* see if the block is in the heap */
2044 retv = 0;
2045 if ( mw->prev )
2046 {
2047 if ( mw->prev->next == mw ) retv++;
2048 }
2049 else
2050 {
2051 if ( mwHead == mw ) retv++;
2052 }
2053 if ( mw->next )
2054 {
2055 if ( mw->next->prev == mw ) retv++;
2056 }
2057 else
2058 {
2059 if ( mwTail == mw ) retv++;
2060 }
2061 if ( mw->check == CHKVAL( mw ) ) retv++;
2062 if ( retv > 2 ) return 1;
2063
2064 /* block not in heap, check heap for corruption */
2065
2066 if ( !mwIsHeapOK( mw ) )
2067 {
2068 if ( mwRelink( mw, file, line ) ) return 1;
2069 }
2070
2071 /* unable to repair */
2072 mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n", mwCounter, file, line, mw );
2073 mwIncErr();
2074
2075 return 0;
2076}
2077
2078/*
2079** mwTestBuf:
2080** Checks a buffers links and pre/postfixes.
2081** Writes errors found to the log.
2082** Returns zero if no errors found.
2083*/
2084static int mwTestBuf( mwData* mw, const char* file, int line ) {
2085 int retv = 0;
2086 char* p;
2087
2088 if ( file == NULL ) file = "unknown";
2089
2090 if ( !mwIsSafeAddr( mw, mwDataSize + mwOverflowZoneSize ) )
2091 {
2092 mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n", mwCounter, file, line, mw );
2093 mwIncErr();
2094 return 2;
2095 }
2096
2097 if ( mw->check != CHKVAL( mw ) )
2098 {
2099 mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n", mwCounter, file, line );
2100 mwIncErr();
2101 if ( !mwRelink( mw, file, line ) ) return 2;
2102 }
2103
2104 if ( mw->prev && mw->prev->next != mw )
2105 {
2106 mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n", mwCounter, file,
2107 line, (long)mw->size, mw->count, mw->file, mw->line );
2108 mwIncErr();
2109 if ( !mwRelink( mw, file, line ) ) retv = 2;
2110 }
2111 if ( mw->next && mw->next->prev != mw )
2112 {
2113 mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n", mwCounter, file,
2114 line, (long)mw->size, mw->count, mw->file, mw->line );
2115 mwIncErr();
2116 if ( !mwRelink( mw, file, line ) ) retv = 2;
2117 }
2118
2119 p = ( (char*)mw ) + mwDataSize;
2120 if ( mwCheckOF( p ) )
2121 {
2122 mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", mwCounter, file,
2123 line, (long)mw->size, mw->count, mw->file, mw->line );
2124 mwIncErr();
2125 retv = 1;
2126 }
2127 p += mwOverflowZoneSize + mw->size;
2128 if ( mwIsReadAddr( p, mwOverflowZoneSize ) && mwCheckOF( p ) )
2129 {
2130 mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", mwCounter, file,
2131 line, (long)mw->size, mw->count, mw->file, mw->line );
2132 mwIncErr();
2133 retv = 1;
2134 }
2135
2136 return retv;
2137}
2138
2139static void mwDefaultOutFunc( int c ) {
2140 if ( mwLogR() ) fputc( c, mwLogR() );
2141}
2142
2143static void mwWrite( const char* format, ... ) {
2144 int tot, oflow = 0;
2145 va_list mark;
2146 mwAutoInit();
2147 if ( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
2148 va_start( mark, format );
2149 tot = vsprintf( mwPrintBuf, format, mark );
2150 va_end( mark );
2151 if ( tot >= MW_TRACE_BUFFER )
2152 {
2153 mwPrintBuf[MW_TRACE_BUFFER] = 0;
2154 oflow = 1;
2155 }
2156 for ( tot = 0; mwPrintBuf[tot]; tot++ ) ( *mwOutFunction )( mwPrintBuf[tot] );
2157 if ( oflow )
2158 {
2159 mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n",
2160 MW_TRACE_BUFFER - 1 );
2161 FLUSH();
2162 }
2163 return;
2164}
2165
2166static void mwLogFile( const char* name ) {
2167 time_t tid;
2168 (void)time( &tid );
2169 if ( mwLogR() != NULL )
2170 {
2171 fclose( mwLogR() );
2172 mwLogW( NULL );
2173 }
2174 if ( name == NULL ) return;
2175 mwLogW( fopen( name, "a" COMMIT ) );
2176 if ( mwLogR() == NULL ) mwWrite( "logfile: failed to open/create file '%s'\n", name );
2177}
2178
2179/*
2180** Try to free NML memory until a contiguous allocation of
2181** 'needed' bytes can be satisfied. If this is not enough
2182** and the 'urgent' parameter is nonzero, grabbed memory is
2183** also freed.
2184*/
2185static size_t mwFreeUp( size_t needed, int urgent ) {
2186 void* p;
2187 mwData *mw, *mw2;
2188 char* data;
2189
2190 /* free grabbed NML memory */
2191 for ( ;; )
2192 {
2193 if ( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break;
2194 p = malloc( needed );
2195 if ( p == NULL ) continue;
2196 free( p );
2197 return needed;
2198 }
2199
2200 /* free normal NML memory */
2201 mw = mwHead;
2202 while ( mw != NULL )
2203 {
2204 if ( !( mw->flag & MW_NML ) ) mw = mw->next;
2205 else
2206 {
2207 data = ( (char*)mw ) + mwDataSize + mwOverflowZoneSize;
2208 if ( mwTestMem( data, mw->size, MW_VAL_NML ) )
2209 {
2210 mwIncErr();
2211 mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", mw->count,
2212 data + mwOverflowZoneSize, mw->file, mw->line );
2213 }
2214 mw2 = mw->next;
2215 mwUnlink( mw, "mwFreeUp", 0 );
2216 free( mw );
2217 mw = mw2;
2218 p = malloc( needed );
2219 if ( p == NULL ) continue;
2220 free( p );
2221 return needed;
2222 }
2223 }
2224
2225 /* if not urgent (for internal purposes), fail */
2226 if ( !urgent ) return 0;
2227
2228 /* free grabbed memory */
2229 for ( ;; )
2230 {
2231 if ( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break;
2232 p = malloc( needed );
2233 if ( p == NULL ) continue;
2234 free( p );
2235 return needed;
2236 }
2237
2238 return 0;
2239}
2240
2241static const void* mwTestMem( const void* p, unsigned len, int c ) {
2242 const unsigned char* ptr;
2243 ptr = (const unsigned char*)p;
2244 while ( len-- )
2245 {
2246 if ( *ptr != (unsigned char)c ) return (const void*)ptr;
2247 ptr++;
2248 }
2249 return NULL;
2250}
2251
2252static int mwStrCmpI( const char* s1, const char* s2 ) {
2253 if ( s1 == NULL || s2 == NULL ) return 0;
2254 while ( *s1 )
2255 {
2256 if ( toupper( *s2 ) == toupper( *s1 ) )
2257 {
2258 s1++;
2259 s2++;
2260 continue;
2261 }
2262 return 1;
2263 }
2264 return 0;
2265}
2266
2267#define AIPH() \
2268 if ( always_invoked ) \
2269 { \
2270 mwWrite( "autocheck: <%ld> %s(%d) ", mwCounter, file, line ); \
2271 always_invoked = 0; \
2272 }
2273
2274static int mwTestNow( const char* file, int line, int always_invoked ) {
2275 int retv = 0;
2276 mwData* mw;
2277 char* data;
2278
2279 if ( file && !always_invoked )
2280 mwWrite( "check: <%ld> %s(%d), checking %s%s%s\n", mwCounter, file, line,
2281 ( mwTestFlags & MW_TEST_CHAIN ) ? "chain " : "",
2282 ( mwTestFlags & MW_TEST_ALLOC ) ? "alloc " : "",
2283 ( mwTestFlags & MW_TEST_NML ) ? "nomansland " : "" );
2284
2285 if ( mwTestFlags & MW_TEST_CHAIN )
2286 {
2287 for ( mw = mwHead; mw; mw = mw->next )
2288 {
2289 if ( !mwIsSafeAddr( mw, mwDataSize ) )
2290 {
2291 AIPH();
2292 mwWrite( "check: heap corruption detected\n" );
2293 mwIncErr();
2294 return retv + 1;
2295 }
2296 if ( mw->prev )
2297 {
2298 if ( !mwIsSafeAddr( mw->prev, mwDataSize ) )
2299 {
2300 AIPH();
2301 mwWrite( "check: heap corruption detected\n" );
2302 mwIncErr();
2303 return retv + 1;
2304 }
2305 if ( mw == mwHead || mw->prev->next != mw )
2306 {
2307 AIPH();
2308 mwWrite( "check: heap chain broken, prev link incorrect\n" );
2309 mwIncErr();
2310 retv++;
2311 }
2312 }
2313 if ( mw->next )
2314 {
2315 if ( !mwIsSafeAddr( mw->next, mwDataSize ) )
2316 {
2317 AIPH();
2318 mwWrite( "check: heap corruption detected\n" );
2319 mwIncErr();
2320 return retv + 1;
2321 }
2322 if ( mw == mwTail || mw->next->prev != mw )
2323 {
2324 AIPH();
2325 mwWrite( "check: heap chain broken, next link incorrect\n" );
2326 mwIncErr();
2327 retv++;
2328 }
2329 }
2330 else if ( mw != mwTail )
2331 {
2332 AIPH();
2333 mwWrite( "check: heap chain broken, tail incorrect\n" );
2334 mwIncErr();
2335 retv++;
2336 }
2337 }
2338 }
2339 if ( mwTestFlags & MW_TEST_ALLOC )
2340 {
2341 for ( mw = mwHead; mw; mw = mw->next )
2342 {
2343 if ( mwTestBuf( mw, file, line ) ) retv++;
2344 }
2345 }
2346 if ( mwTestFlags & MW_TEST_NML )
2347 {
2348 for ( mw = mwHead; mw; mw = mw->next )
2349 {
2350 if ( ( mw->flag & MW_NML ) )
2351 {
2352 data = ( (char*)mw ) + mwDataSize + mwOverflowZoneSize;
2353 if ( mwTestMem( data, mw->size, MW_VAL_NML ) )
2354 {
2355 mwIncErr();
2356 mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", mw->count,
2357 data + mwOverflowZoneSize, mw->file, mw->line );
2358 }
2359 }
2360 }
2361 }
2362
2363 if ( file && !always_invoked && !retv )
2364 mwWrite( "check: <%ld> %s(%d), complete; no errors\n", mwCounter, file, line );
2365 return retv;
2366}
2367
2368/**********************************************************************
2369** Statistics
2370**********************************************************************/
2371
2372static void mwStatReport() {
2373 mwStat * ms, *ms2;
2374 const char* modname;
2375 int modnamelen;
2376
2377 /* global statistics report */
2378 mwWrite( "\nMemory usage statistics (global):\n" );
2379 mwWrite( " N)umber of allocations made: %ld\n", mwStatNumAlloc );
2380 mwWrite( " L)argest memory usage : %ld\n", mwStatMaxAlloc );
2381 mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc );
2382 mwWrite( " U)nfreed bytes totals : %ld\n", mwStatCurAlloc );
2383 FLUSH();
2384
2385 if ( mwStatLevel < 1 ) return;
2386
2387 /* on a per-module basis */
2388 mwWrite( "\nMemory usage statistics (detailed):\n" );
2389 mwWrite(
2390 " Module/Line Number Largest Total Unfreed \n" );
2391 for ( ms = mwStatList; ms; ms = ms->next )
2392 {
2393 if ( ms->line == -1 )
2394 {
2395 if ( ms->file == NULL || !mwIsReadAddr( ms->file, 22 ) ) modname = "<unknown>";
2396 else modname = ms->file;
2397 modnamelen = strlen( modname );
2398 if ( modnamelen > 42 ) { modname = modname + modnamelen - 42; }
2399
2400 mwWrite( " %-42s %-8ld %-8ld %-8ld %-8ld\n", modname, ms->num, ms->max, ms->total,
2401 ms->curr );
2402 if ( ms->file && mwStatLevel > 1 )
2403 {
2404 for ( ms2 = mwStatList; ms2; ms2 = ms2->next )
2405 {
2406 if ( ms2->line != -1 && ms2->file != NULL && !mwStrCmpI( ms2->file, ms->file ) )
2407 {
2408 mwWrite( " %-8d %-8ld %-8ld %-8ld %-8ld\n",
2409 ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr );
2410 }
2411 }
2412 }
2413 }
2414 }
2415}
2416
2417static mwStat* mwStatGet( const char* file, int line, int makenew ) {
2418 mwStat* ms;
2419
2420 if ( mwStatLevel < 2 ) line = -1;
2421
2422 for ( ms = mwStatList; ms != NULL; ms = ms->next )
2423 {
2424 if ( line != ms->line ) continue;
2425 if ( file == NULL )
2426 {
2427 if ( ms->file == NULL ) break;
2428 continue;
2429 }
2430 if ( ms->file == NULL ) continue;
2431 if ( !strcmp( ms->file, file ) ) break;
2432 }
2433
2434 if ( ms != NULL ) return ms;
2435
2436 if ( !makenew ) return NULL;
2437
2438 ms = (mwStat*)malloc( sizeof( mwStat ) );
2439 if ( ms == NULL )
2440 {
2441 if ( mwFreeUp( sizeof( mwStat ), 0 ) < sizeof( mwStat ) ||
2442 ( ms = (mwStat*)malloc( sizeof( mwStat ) ) ) == NULL )
2443 {
2444 mwWrite( "internal: memory low, statistics incomplete for '%s'\n", file );
2445 return NULL;
2446 }
2447 }
2448 ms->file = file;
2449 ms->line = line;
2450 ms->total = 0L;
2451 ms->max = 0L;
2452 ms->num = 0L;
2453 ms->curr = 0L;
2454 ms->next = mwStatList;
2455 mwStatList = ms;
2456 return ms;
2457}
2458
2459static void mwStatAlloc( size_t size, const char* file, int line ) {
2460 mwStat* ms;
2461
2462 /* update the module statistics */
2463 ms = mwStatGet( file, -1, 1 );
2464 if ( ms != NULL )
2465 {
2466 ms->total += (long)size;
2467 ms->curr += (long)size;
2468 ms->num++;
2469 if ( ms->curr > ms->max ) ms->max = ms->curr;
2470 }
2471
2472 /* update the line statistics */
2473 if ( mwStatLevel > 1 && line != -1 && file )
2474 {
2475 ms = mwStatGet( file, line, 1 );
2476 if ( ms != NULL )
2477 {
2478 ms->total += (long)size;
2479 ms->curr += (long)size;
2480 ms->num++;
2481 if ( ms->curr > ms->max ) ms->max = ms->curr;
2482 }
2483 }
2484}
2485
2486static void mwStatFree( size_t size, const char* file, int line ) {
2487 mwStat* ms;
2488
2489 /* update the module statistics */
2490 ms = mwStatGet( file, -1, 1 );
2491 if ( ms != NULL ) ms->curr -= (long)size;
2492
2493 /* update the line statistics */
2494 if ( mwStatLevel > 1 && line != -1 && file )
2495 {
2496 ms = mwStatGet( file, line, 1 );
2497 if ( ms != NULL ) ms->curr -= (long)size;
2498 }
2499}
2500
2501/***********************************************************************
2502** Safe memory checkers
2503**
2504** Using ifdefs, implement the operating-system specific mechanism
2505** of identifying a piece of memory as legal to access with read
2506** and write priviliges. Default: return nonzero for non-NULL pointers.
2507***********************************************************************/
2508
2509static char mwDummy( char c ) { return c; }
2510
2511#ifndef MW_SAFEADDR
2512# ifdef WIN32
2513# define MW_SAFEADDR
2514# define WIN32_LEAN_AND_MEAN
2515# include <windows.h>
2516int mwIsReadAddr( const void* p, unsigned len ) {
2517 if ( p == NULL ) return 0;
2518 if ( IsBadReadPtr( p, len ) ) return 0;
2519 return 1;
2520}
2521int mwIsSafeAddr( void* p, unsigned len ) {
2522 /* NOTE: For some reason, under Win95 the IsBad... */
2523 /* can return false for invalid pointers. */
2524 if ( p == NULL ) return 0;
2525 if ( IsBadReadPtr( p, len ) || IsBadWritePtr( p, len ) ) return 0;
2526 return 1;
2527}
2528# endif /* WIN32 */
2529#endif /* MW_SAFEADDR */
2530
2531#ifndef MW_SAFEADDR
2532# ifdef SIGSEGV
2533# define MW_SAFEADDR
2534
2535typedef void ( *mwSignalHandlerPtr )( int );
2536mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr)0;
2537jmp_buf mwSIGSEGVjump;
2538static void mwSIGSEGV( int n );
2539
2540static void mwSIGSEGV( int n ) {
2541 n = n;
2542 longjmp( mwSIGSEGVjump, 1 );
2543}
2544
2545int mwIsReadAddr( const void* p, unsigned len ) {
2546 const char* ptr;
2547
2548 if ( p == NULL ) return 0;
2549 if ( !len ) return 1;
2550
2551 /* set up to catch the SIGSEGV signal */
2552 mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
2553
2554 if ( setjmp( mwSIGSEGVjump ) )
2555 {
2556 signal( SIGSEGV, mwOldSIGSEGV );
2557 return 0;
2558 }
2559
2560 /* read all the bytes in the range */
2561 ptr = (const char*)p;
2562 ptr += len;
2563
2564 /* the reason for this rather strange construct is that */
2565 /* we want to keep the number of used parameters and locals */
2566 /* to a minimum. if we use len for a counter gcc will complain */
2567 /* it may get clobbered by longjmp() at high warning levels. */
2568 /* it's a harmless warning, but this way we don't have to see it. */
2569 do {
2570 ptr--;
2571 if ( *ptr == 0x7C ) (void)mwDummy( (char)0 );
2572 } while ( (const void*)ptr != p );
2573
2574 /* remove the handler */
2575 signal( SIGSEGV, mwOldSIGSEGV );
2576
2577 return 1;
2578}
2579int mwIsSafeAddr( void* p, unsigned len ) {
2580 char* ptr;
2581
2582 if ( p == NULL ) return 0;
2583 if ( !len ) return 1;
2584
2585 /* set up to catch the SIGSEGV signal */
2586 mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
2587
2588 if ( setjmp( mwSIGSEGVjump ) )
2589 {
2590 signal( SIGSEGV, mwOldSIGSEGV );
2591 return 0;
2592 }
2593
2594 /* read and write-back all the bytes in the range */
2595 ptr = (char*)p;
2596 ptr += len;
2597
2598 /* the reason for this rather strange construct is that */
2599 /* we want to keep the number of used parameters and locals */
2600 /* to a minimum. if we use len for a counter gcc will complain */
2601 /* it may get clobbered by longjmp() at high warning levels. */
2602 /* it's a harmless warning, but this way we don't have to see it. */
2603 do {
2604 ptr--;
2605 *ptr = mwDummy( *ptr );
2606 } while ( (void*)ptr != p );
2607
2608 /* remove the handler */
2609 signal( SIGSEGV, mwOldSIGSEGV );
2610
2611 return 1;
2612}
2613# endif /* SIGSEGV */
2614#endif /* MW_SAFEADDR */
2615
2616#ifndef MW_SAFEADDR
2617int mwIsReadAddr( const void* p, unsigned len ) {
2618 if ( p == NULL ) return 0;
2619 if ( len == 0 ) return 1;
2620 return 1;
2621}
2622int mwIsSafeAddr( void* p, unsigned len ) {
2623 if ( p == NULL ) return 0;
2624 if ( len == 0 ) return 1;
2625 return 1;
2626}
2627#endif
2628
2629/**********************************************************************
2630** Mutex handling
2631**********************************************************************/
2632
2633#if defined( WIN32 ) || defined( __WIN32__ )
2634
2635static void mwMutexInit( void ) {
2636 mwGlobalMutex = CreateMutex( NULL, FALSE, NULL );
2637 return;
2638}
2639
2640static void mwMutexTerm( void ) {
2641 CloseHandle( mwGlobalMutex );
2642 return;
2643}
2644
2645static void mwMutexLock( void ) {
2646 if ( WaitForSingleObject( mwGlobalMutex, 1000 ) == WAIT_TIMEOUT )
2647 { mwWrite( "mwMutexLock: timed out, possible deadlock\n" ); }
2648 return;
2649}
2650
2651static void mwMutexUnlock( void ) {
2652 ReleaseMutex( mwGlobalMutex );
2653 return;
2654}
2655
2656#endif
2657
2658#if defined( MW_PTHREADS ) || defined( HAVE_PTHREAD_H )
2659
2660static void mwMutexInit( void ) {
2661 pthread_mutex_init( &mwGlobalMutex, NULL );
2662 return;
2663}
2664
2665static void mwMutexTerm( void ) {
2666 pthread_mutex_destroy( &mwGlobalMutex );
2667 return;
2668}
2669
2670static void mwMutexLock( void ) {
2671 pthread_mutex_lock( &mwGlobalMutex );
2672 return;
2673}
2674
2675static void mwMutexUnlock( void ) {
2676 pthread_mutex_unlock( &mwGlobalMutex );
2677 return;
2678}
2679
2680#endif
2681
2682/**********************************************************************
2683** C++ new & delete
2684**********************************************************************/
2685
2686#if 0 /* 980317: disabled C++ */
2687
2688# ifdef __cplusplus
2689# ifndef MEMWATCH_NOCPP
2690
2691int mwNCur = 0;
2692const char *mwNFile = NULL;
2693int mwNLine = 0;
2694
2695class MemWatch {
2696public:
2697 MemWatch();
2698 ~MemWatch();
2699 };
2700
2701MemWatch::MemWatch() {
2702 if( mwInited ) return;
2703 mwUseAtexit = 0;
2704 mwInit();
2705 }
2706
2707MemWatch::~MemWatch() {
2708 if( mwUseAtexit ) return;
2709 mwTerm();
2710 }
2711
2712/*
2713** This global new will catch all 'new' calls where MEMWATCH is
2714** not active.
2715*/
2716void* operator new( unsigned size ) {
2717 mwNCur = 0;
2718 return mwMalloc( size, "<unknown>", 0 );
2719 }
2720
2721/*
2722** This is the new operator that's called when a module uses mwNew.
2723*/
2724void* operator new( unsigned size, const char *file, int line ) {
2725 mwNCur = 0;
2726 return mwMalloc( size, file, line );
2727 }
2728
2729/*
2730** This is the new operator that's called when a module uses mwNew[].
2731** -- hjc 07/16/02
2732*/
2733void* operator new[] ( unsigned size, const char *file, int line ) {
2734 mwNCur = 0;
2735 return mwMalloc( size, file, line );
2736 }
2737
2738/*
2739** Since this delete operator will recieve ALL delete's
2740** even those from within libraries, we must accept
2741** delete's before we've been initialized. Nor can we
2742** reliably check for wild free's if the mwNCur variable
2743** is not set.
2744*/
2745void operator delete( void *p ) {
2746 if( p == NULL ) return;
2747 if( !mwInited ) {
2748 free( p );
2749 return;
2750 }
2751 if( mwNCur ) {
2752 mwFree( p, mwNFile, mwNLine );
2753 mwNCur = 0;
2754 return;
2755 }
2756 mwFree_( p );
2757 }
2758
2759void operator delete[]( void *p ) {
2760 if( p == NULL ) return;
2761 if( !mwInited ) {
2762 free( p );
2763 return;
2764 }
2765 if( mwNCur ) {
2766 mwFree( p, mwNFile, mwNLine );
2767 mwNCur = 0;
2768 return;
2769 }
2770 mwFree_( p );
2771 }
2772
2773# endif /* MEMWATCH_NOCPP */
2774# endif /* __cplusplus */
2775
2776#endif /* 980317: disabled C++ */
2777
2778/* MEMWATCH.C */
sprintf(cut, "kal_costheta0_em>-0.93&&kal_costheta0_em<0.93&&kal_pxy0_em>=0.05+%d*0.1&&kal_" "pxy0_em<0.15+%d*0.1&&NGch>=2", j, j)
char * file
Definition DQA_TO_DB.cxx:16
const Int_t n
TTree * data
Double_t time
EvtComplex exp(const EvtComplex &c)
DOUBLE_PRECISION count[3]
void mwAbort(void)
int mwIsReadAddr(const void *p, unsigned len)
const unsigned long mwCounter
int mwIsSafeAddr(void *p, unsigned len)
void mwFlushNow(void)
void mwNoMansLand(int level)
#define VERSION
struct mwMarker_ mwMarker
#define COMMIT
#define MW_MUTEX_UNLOCK()
#define MW_MUTEX_INIT()
struct mwStat_ mwStat
void mwAbort(void)
#define TESTS(f, l)
void mwAutoCheck(int onoff)
void mwInit(void)
#define mwBUFFER_TO_MW(p)
void mwBreakOut(const char *cause)
int mwIsReadAddr(const void *p, unsigned len)
void mwTerm(void)
#define MW_NML
#define mwROUNDALLOC
#define MW_MUTEX_TERM()
#define CPPTEXT
#define CHKVAL(mw)
#define AIPH()
int mwIsSafeAddr(void *p, unsigned len)
void mwSetAriAction(int action)
#define mwSTDERR
struct mwGrabData_ mwGrabData
int mwAriHandler(const char *estr)
#define FLUSH()
struct mwData_ mwData
#define MW_MUTEX_LOCK()
mwData * prev
size_t size
const char * file
unsigned flag
mwData * next
char blob[1024 - sizeof(mwGrabData *) - sizeof(int)]
mwGrabData * next
mwMarker * next
const char * file
mwStat * next