ruby-xslt 0.9.2

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