ruby-xslt 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 */