📄 memwatch.c
字号:
/*** MEMWATCH.C** Nonintrusive ANSI C memory leak / overwrite detection** Copyright (C) 1992-2003 Johan Lindh** All rights reserved.** Version 2.71 This file is part of MEMWATCH. MEMWATCH is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. MEMWATCH is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with MEMWATCH; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA**** 920810 JLI [1.00]** 920830 JLI [1.10 double-free detection]** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit]** 921022 JLI [1.20 ASSERT and VERIFY]** 921105 JLI [1.30 C++ support and TRACE]** 921116 JLI [1.40 mwSetOutFunc]** 930215 JLI [1.50 modified ASSERT/VERIFY]** 930327 JLI [1.51 better auto-init & PC-lint support]** 930506 JLI [1.55 MemWatch class, improved C++ support]** 930507 JLI [1.60 mwTest & CHECK()]** 930809 JLI [1.65 Abort/Retry/Ignore]** 930820 JLI [1.70 data dump when unfreed]** 931016 JLI [1.72 modified C++ new/delete handling]** 931108 JLI [1.77 mwSetAssertAction() & some small changes]** 940110 JLI [1.80 no-mans-land alloc/checking]** 940328 JLI [2.00 version 2.0 rewrite]** Improved NML (no-mans-land) support.** Improved performance (especially for free()ing!).** Support for 'read-only' buffers (checksums)** ^^ NOTE: I never did this... maybe I should?** FBI (free'd block info) tagged before freed blocks** Exporting of the mwCounter variable** mwBreakOut() localizes debugger support** Allocation statistics (global, per-module, per-line)** Self-repair ability with relinking** 950913 JLI [2.10 improved garbage handling]** 951201 JLI [2.11 improved auto-free in emergencies]** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()]** 960514 JLI [2.12 undefining of existing macros]** 960515 JLI [2.13 possibility to use default new() & delete()]** 960516 JLI [2.20 suppression of file flushing on unfreed msgs]** 960516 JLI [2.21 better support for using MEMWATCH with DLL's]** 960710 JLI [X.02 multiple logs and mwFlushNow()]** 960801 JLI [2.22 merged X.01 version with current]** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's]** 960805 JLI [2.31 merged X.02 version with current]** 961002 JLI [2.32 support for realloc() + fixed STDERR bug]** 961222 JLI [2.40 added mwMark() & mwUnmark()]** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY]** 970113 JLI [2.42 added support for PC-Lint 7.00g]** 970207 JLI [2.43 added support for strdup()]** 970209 JLI [2.44 changed default filename to lowercase]** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers]** 970723 JLI [2.46 added MW_ARI_NULLREAD flag]** 970813 JLI [2.47 stabilized marker handling]** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway]** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support]** 980417 JLI [2.51 more checks for invalid addresses]** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting]** 990112 JLI [2.53 added check for empty heap to mwIsOwned]** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML]** 990224 JLI [2.56 changed ordering of members in structures]** 990303 JLI [2.57 first maybe-fixit-for-hpux test]** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit]** 990517 JLI [2.59 fixed some high-sensitivity warnings]** 990610 JLI [2.60 fixed some more high-sensitivity warnings]** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names]** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()]** 991007 JLI [2.63 first shot at a 64-bit compatible version]** 991009 JLI [2.64 undef's strdup() if defined, mwStrdup made const]** 000704 JLI [2.65 added some more detection for 64-bits]** 010502 JLI [2.66 incorporated some user fixes]** [mwRelink() could print out garbage pointer (thanks mac@phobos.ca)]** [added array destructor for C++ (thanks rdasilva@connecttel.com)]** [added mutex support (thanks rdasilva@connecttel.com)]** 010531 JLI [2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined]** 010619 JLI [2.68 fix: mwRealloc() could leave the mutex locked]** 020918 JLI [2.69 changed to GPL, added C++ array allocation by Howard Cohen]** 030212 JLI [2.70 mwMalloc() bug for very large allocations (4GB on 32bits)]** 030520 JLI [2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)]*/#define __MEMWATCH_C 1#ifdef MW_NOCPP#define MEMWATCH_NOCPP#endif#ifdef MW_STDIO#define MEMWATCH_STDIO#endif/************************************************************************* Include files***********************************************************************/#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <string.h>#include <signal.h>#include <setjmp.h>#include <time.h>#include <limits.h>#include "memwatch.h"#ifndef toupper#include <ctype.h>#endif#if defined(WIN32) || defined(__WIN32__)#define MW_HAVE_MUTEX 1#include <windows.h>#endif#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)#define MW_HAVE_MUTEX 1#include <pthread.h>#endif/************************************************************************* Defines & other weird stuff***********************************************************************//*lint -save -e767 */#define VERSION "2.71" /* the current version number */#define CHKVAL(mw) (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line)#define FLUSH() mwFlush()#define TESTS(f,l) if(mwTestAlways) (void)mwTestNow(f,l,1)#define PRECHK 0x01234567L#define POSTCHK 0x76543210L#define mwBUFFER_TO_MW(p) ( (mwData*) (void*) ( ((char*)p)-mwDataSize-mwOverflowZoneSize ) )/*lint -restore */#define MW_NML 0x0001#ifdef _MSC_VER#define COMMIT "c" /* Microsoft C requires the 'c' to perform as desired */#else#define COMMIT "" /* Normal ANSI */#endif /* _MSC_VER */#ifdef __cplusplus#define CPPTEXT "++"#else#define CPPTEXT ""#endif /* __cplusplus */#ifdef MEMWATCH_STDIO#define mwSTDERR stderr#else#define mwSTDERR mwLog#endif#ifdef MW_HAVE_MUTEX#define MW_MUTEX_INIT() mwMutexInit()#define MW_MUTEX_TERM() mwMutexTerm()#define MW_MUTEX_LOCK() mwMutexLock()#define MW_MUTEX_UNLOCK() mwMutexUnlock()#else#define MW_MUTEX_INIT()#define MW_MUTEX_TERM()#define MW_MUTEX_LOCK()#define MW_MUTEX_UNLOCK()#endif/************************************************************************* If you really, really know what you're doing,** you can predefine these things yourself.***********************************************************************/#ifndef mwBYTE_DEFINED# if CHAR_BIT != 8# error need CHAR_BIT to be 8!# elsetypedef unsigned char mwBYTE;# define mwBYTE_DEFINED 1# endif#endif#if defined(ULONGLONG_MAX) || defined(ULLONG_MAX) || defined(_UI64_MAX) || defined(ULONG_LONG_MAX)# define mw64BIT 1# define mwROUNDALLOC_DEFAULT 8#else# if UINT_MAX <= 0xFFFFUL# define mw16BIT 1# define mwROUNDALLOC_DEFAULT 2# else# if ULONG_MAX > 0xFFFFFFFFUL# define mw64BIT 1# define mwROUNDALLOC_DEFAULT 8# else# define mw32BIT 1# define mwROUNDALLOC_DEFAULT 4# endif# endif#endif/* mwROUNDALLOC is the number of bytes to *//* round up to, to ensure that the end of *//* the buffer is suitable for storage of *//* any kind of object */#ifndef mwROUNDALLOC# define mwROUNDALLOC mwROUNDALLOC_DEFAULT#endif#ifndef mwDWORD_DEFINED#if ULONG_MAX == 0xFFFFFFFFULtypedef unsigned long mwDWORD;#define mwDWORD_DEFINED "unsigned long"#endif#endif#ifndef mwDWORD_DEFINED#if UINT_MAX == 0xFFFFFFFFULtypedef unsigned int mwDWORD;#define mwDWORD_DEFINED "unsigned int"#endif#endif#ifndef mwDWORD_DEFINED#if USHRT_MAX == 0xFFFFFFFFULtypedef unsigned short mwDWORD;#define mwDWORD_DEFINED "unsigned short"#endif#endif#ifndef mwBYTE_DEFINED#error "can't find out the correct type for a 8 bit scalar"#endif#ifndef mwDWORD_DEFINED#error "can't find out the correct type for a 32 bit scalar"#endif/************************************************************************* Typedefs & structures***********************************************************************//* main data holding area, precedes actual allocation */typedef struct mwData_ mwData;struct mwData_ { mwData* prev; /* previous allocation in chain */ mwData* next; /* next allocation in chain */ const char* file; /* file name where allocated */ long count; /* action count */ long check; /* integrity check value */#if 0 long crc; /* data crc value */#endif size_t size; /* size of allocation */ int line; /* line number where allocated */ unsigned flag; /* flag word */ };/* statistics structure */typedef struct mwStat_ mwStat;struct mwStat_ { mwStat* next; /* next statistic buffer */ const char* file; long total; /* total bytes allocated */ long num; /* total number of allocations */ long max; /* max allocated at one time */ long curr; /* current allocations */ int line; };/* grabbing structure, 1K in size */typedef struct mwGrabData_ mwGrabData;struct mwGrabData_ { mwGrabData* next; int type; char blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ]; };typedef struct mwMarker_ mwMarker;struct mwMarker_ { void *host; char *text; mwMarker *next; int level; };#if defined(WIN32) || defined(__WIN32__)typedef HANDLE mwMutex;#endif#if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)typedef pthread_mutex_t mwMutex;#endif/************************************************************************* Static variables***********************************************************************/static int mwInited = 0;static int mwInfoWritten = 0;static int mwUseAtexit = 0;static FILE* mwLog = NULL;static int mwFlushing = 0;static int mwStatLevel = MW_STAT_DEFAULT;static int mwNML = MW_NML_DEFAULT;static int mwFBI = 0;static long mwAllocLimit = 0L;static int mwUseLimit = 0;static long mwNumCurAlloc = 0L;static mwData* mwHead = NULL;static mwData* mwTail = NULL;static int mwDataSize = 0;static unsigned char mwOverflowZoneTemplate[] = "mEmwAtch";static int mwOverflowZoneSize = mwROUNDALLOC;static void (*mwOutFunction)(int) = NULL;static int (*mwAriFunction)(const char*) = NULL;static int mwAriAction = MW_ARI_ABORT;static char mwPrintBuf[MW_TRACE_BUFFER+8];static unsigned long mwCounter = 0L;static long mwErrors = 0L;static int mwTestFlags = 0;static int mwTestAlways = 0;static FILE* mwLogB1 = NULL;static int mwFlushingB1 = 0;static mwStat* mwStatList = NULL;static long mwStatTotAlloc = 0L;static long mwStatMaxAlloc = 0L;static long mwStatNumAlloc = 0L;static long mwStatCurAlloc = 0L;static long mwNmlNumAlloc = 0L;static long mwNmlCurAlloc = 0L;static mwGrabData* mwGrabList = NULL;static long mwGrabSize = 0L;static void * mwLastFree[MW_FREE_LIST];static const char *mwLFfile[MW_FREE_LIST];static int mwLFline[MW_FREE_LIST];static int mwLFcur = 0;static mwMarker* mwFirstMark = NULL;static FILE* mwLogB2 = NULL;static int mwFlushingB2 = 0;#ifdef MW_HAVE_MUTEXstatic mwMutex mwGlobalMutex;#endif/************************************************************************* Static function declarations***********************************************************************/static void mwAutoInit( void );static FILE* mwLogR( void );static void mwLogW( FILE* );static int mwFlushR( void );static void mwFlushW( int );static void mwFlush( void );static void mwIncErr( void );static void mwUnlink( mwData*, const char* file, int line );static int mwRelink( mwData*, const char* file, int line );static int mwIsHeapOK( mwData *mw );static int mwIsOwned( mwData* mw, const char* file, int line );static int mwTestBuf( mwData* mw, const char* file, int line );static void mwDefaultOutFunc( int );static void mwWrite( const char* format, ... );static void mwLogFile( const char* name );static size_t mwFreeUp( size_t, int );static const void *mwTestMem( const void *, unsigned, int );static int mwStrCmpI( const char *s1, const char *s2 );static int mwTestNow( const char *file, int line, int always_invoked );static void mwDropAll( void );static const char *mwGrabType( int type );static unsigned mwGrab_( unsigned kb, int type, int silent );static unsigned mwDrop_( unsigned kb, int type, int silent );static int mwARI( const char* text );static void mwStatReport( void );static mwStat* mwStatGet( const char*, int, int );static void mwStatAlloc( size_t, const char*, int );static void mwStatFree( size_t, const char*, int );static int mwCheckOF( const void * p );static void mwWriteOF( void * p );static char mwDummy( char c );#ifdef MW_HAVE_MUTEXstatic void mwMutexInit( void );static void mwMutexTerm( void );static void mwMutexLock( void );static void mwMutexUnlock( void );#endif/************************************************************************* System functions***********************************************************************/void mwInit( void ) { time_t tid; if( mwInited++ > 0 ) return; MW_MUTEX_INIT(); /* start a log if none is running */ if( mwLogR() == NULL ) mwLogFile( "memwatch.log" ); if( mwLogR() == NULL ) { int i; char buf[32]; /* oops, could not open it! */ /* probably because it's already open */ /* so we try some other names */ for( i=1; i<100; i++ ) { sprintf( buf, "memwat%02d.log", i ); mwLogFile( buf ); if( mwLogR() != NULL ) break; } } /* initialize the statistics */ mwStatList = NULL; mwStatTotAlloc = 0L; mwStatCurAlloc = 0L; mwStatMaxAlloc = 0L; mwStatNumAlloc = 0L; mwNmlCurAlloc = 0L; mwNmlNumAlloc = 0L; /* calculate the buffer size to use for a mwData */ mwDataSize = sizeof(mwData);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -