利用memwatch来检查代码 什么地方非法使用了内存;
/*
** 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 <base/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!
# else
typedef 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
// # define mw32BIT 1
// # define mwROUNDALLOC_DEFAULT 4
/* 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 == 0xFFFFFFFFUL
typedef unsigned long mwDWORD;
#define mwDWORD_DEFINED "unsigned long"
#endif
#endif
#ifndef mwDWORD_DEFINED
#if UINT_MAX == 0xFFFFFFFFUL
typedef unsigned int mwDWORD;
#define mwDWORD_DEFINED "unsigned int"
#endif
#endif
#ifndef mwDWORD_DEFINED
#if USHRT_MAX == 0xFFFFFFFFUL
typedef 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_MUTEX
static 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_MUTEX
static 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);
while( mwDataSize % mwROUNDALLOC ) mwDataSize ++;
/* write informational header if needed */
if( !mwInfoWritten ) {
mwInfoWritten = 1;
(void) time( &tid );
mwWrite(
"\n============="
" MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh "
"=============\n");
mwWrite( "\nStarted at %s\n", ctime( &tid ) );
/**************************************************************** Generic */
mwWrite( "Modes: " );
#ifdef mwNew
mwWrite( "C++ " );
#endif /* mwNew */
#ifdef __STDC__
mwWrite( "__STDC__ " );
#endif /* __STDC__ */
#ifdef mw16BIT
mwWrite( "16-bit " );
#endif
#ifdef mw32BIT
mwWrite( "32-bit " );
#endif
#ifdef mw64BIT
mwWrite( "64-bit " );
#endif
mwWrite( "mwDWORD==(" mwDWORD_DEFINED ")\n" );
mwWrite( "mwROUNDALLOC==%d sizeof(mwData)==%d mwDataSize==%d\n",
mwROUNDALLOC, sizeof(mwData), mwDataSize );
/**************************************************************** Generic */
/************************************************************ Microsoft C */
#ifdef _MSC_VER
mwWrite( "Compiled using Microsoft C" CPPTEXT
" %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 );
#endif /* _MSC_VER */
/************************************************************ Microsoft C */
/************************************************************** Borland C */
#ifdef __BORLANDC__
mwWrite( "Compiled using Borland C"
#ifdef __cplusplus
"++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 );
#else
" %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 );
#endif /* __cplusplus */
#endif /* __BORLANDC__ */
/************************************************************** Borland C */
/************************************************************** Watcom C */
#ifdef __WATCOMC__
mwWrite( "Compiled using Watcom C %d.%02d ",
__WATCOMC__/100, __WATCOMC__%100 );
#ifdef __FLAT__
mwWrite( "(32-bit flat model)" );
#endif /* __FLAT__ */
mwWrite( "\n" );
#endif /* __WATCOMC__ */
/************************************************************** Watcom C */
mwWrite( "\n" );
FLUSH();
}
if( mwUseAtexit ) (void) atexit( mwAbort );
return;
}
void mwAbort( void ) {
mwData *mw;
mwMarker *mrk;
char *data;
time_t tid;
int c, i, j;
int errors;
tid = time( NULL );
mwWrite( "\nStopped at %s\n", ctime( &tid) );
if( !mwInited )
mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" );
/* release the grab list */
mwDropAll();
/* report mwMarked items */
while( mwFirstMark ) {
mrk = mwFirstMark->next;
mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text );
free( mwFirstMark->text );
free( mwFirstMark );
mwFirstMark = mrk;
mwErrors ++;
}
/* release all still allocated memory */
errors = 0;
while( mwHead != NULL && errors < 3 ) {
if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) {
if( errors < 3 )
{
errors ++;
mwWrite( "internal: NML/unfreed scan restarting\n" );
FLUSH();
mwHead = mwHead;
continue;
}
mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" );
FLUSH();
break;
}
mwFlushW(0);
if( !(mwHead->flag & MW_NML) ) {
mwErrors++;
data = ((char*)mwHead)+mwDataSize;
mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ",
mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+mwOverflowZoneSize );
if( mwCheckOF( data ) ) {
mwWrite( "[underflowed] ");
FLUSH();
}
if( mwCheckOF( (data+mwOverflowZoneSize+mwHead->size) ) ) {
mwWrite( "[overflowed] ");
FLUSH();
}
mwWrite( " \t{" );
j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size;
for( i=0;i<16;i++ ) {
if( i<j ) mwWrite( "%02X ",
(unsigned char) *(data+mwOverflowZoneSize+i) );
else mwWrite( ".. " );
}
for( i=0;i<j;i++ ) {
c = *(data+mwOverflowZoneSize+i);
if( c < 32 || c > 126 ) c = '.';
mwWrite( "%c", c );
}
mwWrite( "}\n" );
mw = mwHead;
mwUnlink( mw, __FILE__, __LINE__ );
free( mw );
}
else {
data = ((char*)mwHead) + mwDataSize + mwOverflowZoneSize;
if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) {
mwErrors++;
mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
mwHead->count, data + mwOverflowZoneSize, mwHead->file, mwHead->line );
FLUSH();
}
mwNmlNumAlloc --;
mwNmlCurAlloc -= mwHead->size;
mw = mwHead;
mwUnlink( mw, __FILE__, __LINE__ );
free( mw );
}
}
if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc );
if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc );
/* report statistics */
mwStatReport();
FLUSH();
mwInited = 0;
mwHead = mwTail = NULL;
if( mwErrors )
fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors);
mwLogFile( NULL );
mwErrors = 0;
MW_MUTEX_TERM();
}
void mwTerm( void ) {
if( mwInited == 1 )
{
mwAbort();
return;
}
if( !mwInited )
mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n");
else
mwInited --;
}
void mwStatistics( int level )
{
mwAutoInit();
if( level<0 ) level=0;
if( mwStatLevel != level )
{
mwWrite( "statistics: now collecting on a %s basis\n",
level<1?"global":(level<2?"module":"line") );
mwStatLevel = level;
}
}
void mwAutoCheck( int onoff ) {
mwAutoInit();
mwTestAlways = onoff;
if( onoff ) mwTestFlags = MW_TEST_ALL;
}
void mwSetOutFunc( void (*func)(int) ) {
mwAutoInit();
mwOutFunction = func;
}
static void mwWriteOF( void *p )
{
int i;
unsigned char *ptr;
ptr = (unsigned char*) p;
for( i=0; i<mwOverflowZoneSize; i++ )
{
*(ptr+i) = mwOverflowZoneTemplate[i%8];
}
return;
}
static int mwCheckOF( const void *p )
{
int i;
const unsigned char *ptr;
ptr = (const unsigned char *) p;
for( i=0; i<mwOverflowZoneSize; i++ )
{
if( *(ptr+i) != mwOverflowZo