memwatch 修改记录

本文介绍了如何利用memwatch工具检查代码中非法使用的内存问题,特别是解决了原先锁导致的代码阻塞问题,通过将锁改为递归锁。使用memwatch需要在编译时添加特定的编译选项,并在代码中包含<memwatch.h>头文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值