debug_malloc.c

来自「一个小公司要求给写的很简单的任务管理系统。」· C语言 代码 · 共 767 行 · 第 1/2 页

C
767
字号
/* * @(#)debug_malloc.c	1.13 05/11/17 *  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. *  * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: *  * -Redistribution of source code must retain the above copyright notice, this *  list of conditions and the following disclaimer. *  * -Redistribution in binary form must reproduce the above copyright notice,  *  this list of conditions and the following disclaimer in the documentation *  and/or other materials provided with the distribution. *  * Neither the name of Sun Microsystems, Inc. or the names of contributors may  * be used to endorse or promote products derived from this software without  * specific prior written permission. *  * This software is provided "AS IS," without a warranty of any kind. ALL  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. *  * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. *//* ************************************************************************** * * Set of malloc/realloc/calloc/strdup/free replacement macros that  *    insert some extra words around each allocation for debugging purposes *    and also attempt to detect invalid uses of the malloc heap through *    various tricks like inserting clobber words at the head and tail of *    the user's area, delayed free() calls, and setting the memory to *    a fixed pattern on allocation and when freed.  The allocations also *    can include warrants so that when an area is clobbered, this *    package can report where the allocation took place. *    The macros included are: *		malloc(size) *		realloc(ptr,size) *		calloc(nelem,elsize) *		strdup(s1) *		free(ptr) *		malloc_police()   <--- Not a system function *    The above macros match the standard behavior of the system functions. * *    They should be used through the include file "debug_malloc.h". * *       IMPORTANT: All source files that call any of these macros *                  should include debug_malloc.h. This package will *                  not work if the memory isn't allocated and freed *                  by the macros in debug_malloc.h. The important issue *                  is that any malloc() from debug_malloc.h must be *                  freed by the free() in debug_malloc.h. * *    The macros in debug_malloc.h will override the normal use of *       malloc, realloc, calloc, strdup, and free with the functions below. * *    These functions include: *         void *debug_malloc(size_t, void*, int); *         void *debug_realloc(void*, size_t, void*, int); *         void *debug_calloc(size_t, size_t, void*, int); *         void  debug_free(void *, void*, int); * *   In addition the function debug_malloc_police() can be called to *      tell you what memory has not been freed. *	   void debug_malloc_police(void*, int); *      The function debug_malloc_police() is available through the macro *      malloc_police(). Normally you would want to call this at exit() *      time to find out what memory is still allocated. * *   The variable malloc_watch determines if the warrants are generated. *      warrants are structures that include the filename and line number *      of the caller who allocated the memory. This structure is stored *      at the tail of the malloc space, which is allocated large enough *      to hold some clobber words at the head and tail, the user's request *      and the warrant record (if malloc_watch is non-zero). * *   The macro LEFT_OVER_CHAR is what the trailing bytes of an allocation *     are set to (when the allocation is not a multiple of 8) on allocation. *     At free(0 time, these bytes are double checked to make sure they were *     not clobbered. To remove this feature #undef LEFT_OVER_CHAR. * *   The memory freed will have the FREED_CHAR put into it. To remove this *     feature #undef FREED_CHAR. * *   The memory allocated (not calloc'd) will have the ALLOC_CHAR put into it *     at the time of allocation. To remove this feature #undef ALLOC_CHAR. * *   The macro MAX_FREE_DELAY_COUNT controls how many free blocks will *     be kept around before being freed. This creates a delayed affect *     so that free space that gets clobbered just might get detected. *     The free() call will immediately set the user space to the FREED_CHAR, *     leaving the clobber words and warrant in place (making sure they *     haven't been clobbered). Then the free() pointer is added to a *     queue of MAX_FREE_DELAY_COUNT long, and if the queue was full, the *     oldest free()'d memory is actually freed, getting it's entire *     memory length set to the FREED_CHAR. * *  WARNING: This can significantly slow down an application, depending *           on how many allocations are made. Also the additional memory *           needed for the clobber words and the warrants can be significant *           again, depending on how many allocations are made. *           In addition, the delayed free calls can create situations *           where you might run out of memory prematurely. * * ************************************************************************** */#ifdef DEBUG#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <stdarg.h>#include "hprof.h"/* *************************************************************************** * Space normally looks like (clobber Word is 64 bits and aligned to 8 bytes): * *		    ----------------- * malloc/free get->| clobber Word  |   ---> contains -size requested by user *		    ----------------- *    User gets --->| user space    | *		    | 		    | *		    |  | left_over  |  ---> left_over bytes will be <= 7 *		    ----------------- *		    | clobber Word  |   ---> contains -size requested by user *		    ----------------- *		    |   Warrant     |   ---> Optional (malloc_watch!=0) *		    |		    |        Contains filename and line number *		    |		    |          where allocation happened *		    |		    | *		    ----------------- ***************************************************************************//* *  Flag that tells debug_malloc/debug_free/debug_realloc to police *   heap space usage. (This is a dynamic flag that can be turned on/off) */static int      malloc_watch = 1;/* Character to stuff into freed space */#define FREED_CHAR  'F'/* Character to stuff into allocated space */#define ALLOC_CHAR  'A'/* Character to stuff into left over trailing bytes */#define LEFT_OVER_CHAR  'Z'/* Number of 'free' calls that will be delayed until the end */#define MAX_FREE_DELAY_COUNT	1#undef MAX_FREE_DELAY_COUNT/* Maximum name of __FILE_ stored in each malloc'd area */#define WARRANT_NAME_MAX (32-1)	/* 1 less than multiple of 8 is best *//* Macro to convert a user pointer to the malloc pointer */#define user2malloc_(uptr)   (((char*)(void*)uptr)-sizeof(Word))/* Macro to convert a macro pointer to the user pointer */#define malloc2user_(mptr)   (((char*)(void*)(mptr))+sizeof(Word))/* Size of the warrant record (this is dynamic) */#define warrant_space  ( malloc_watch?sizeof(Warrant_Record):0 )/* Macro to round up a number of bytes to a multiple of sizeof(Word) bytes */#define round_up_(n) \	((n)==0?0:(sizeof(Word)+(((n)-1)/sizeof(Word))*sizeof(Word)))/* Macro to calculate the needed malloc bytes from the user's request. */#define rbytes_(nbytes) \    (size_t)( sizeof(Word) + round_up_(nbytes) + sizeof(Word) + warrant_space )/* Macro to get the -size stored in space through the malloc pointer */#define nsize1_(mptr) 		(((Word*)(void*)(mptr))->nsize1)#define nsize2_(mptr) 		(((Word*)(void*)(mptr))->nsize2)/* Macro to get the -size stored in the tail of the space through *//*     the malloc pointer */#define tail_nsize1_(mptr)     \	nsize1_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word))#define tail_nsize2_(mptr)     \	nsize2_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word))/* Macro to get the -size stored in space through the user pointer */#define user_nsize1_(uptr)    	nsize1_(user2malloc_(uptr))#define user_nsize2_(uptr)    	nsize2_(user2malloc_(uptr))/* Macro to get the -size stored in the tail of the space through *//*     the user pointer */#define user_tail_nsize1_(uptr)	tail_nsize1_(user2malloc_(uptr))#define user_tail_nsize2_(uptr)	tail_nsize2_(user2malloc_(uptr))/* Macro to get the int* of the last 32bit word of user space */#define last_user_word_(mptr)	\	((int*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))))/* Macros to get at the warrant contents from the malloc pointer */#define warrant_(mptr) \  (*((Warrant_Record*)(void*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word)*2)))/* This struct is allocated after the tail clobber word if malloc_watch *//*    is true. */typedef struct {    void           *link;	/* Next mptr in list */    char            name[WARRANT_NAME_MAX + 1];	/* Name of allocator */    int             line;	/* Line number where allocated */    int             id;	        /* Nth allocation */}               Warrant_Record;#define warrant_link_(mptr) warrant_(mptr).link#define warrant_name_(mptr) warrant_(mptr).name#define warrant_line_(mptr) warrant_(mptr).line#define warrant_id_(mptr)   warrant_(mptr).id#define MFILE(mptr) (malloc_watch?warrant_name_(mptr):"?")#define MLINE(mptr) (malloc_watch?warrant_line_(mptr):0)#define MID(mptr)   (malloc_watch?warrant_id_(mptr):0)/* This should be one machine word and is also the clobber word struct */typedef struct {    int             nsize1;    int             nsize2;}               Word;		/* Largest basic type , sizeof(double)? *//* The first malloc pointer for the warrants */static void    *first_warrant_mptr = NULL;/* Counter of allocations */static int id_counter = 0;static int largest_size = 0;static void * largest_addr = NULL;static void * smallest_addr = NULL;/* Used to isolate what the error is */static char *debug_check;static void *clobbered_ptr;/* Minumum macro */#define minimum(a,b) ((a)<(b)?(a):(b))/* Message routine */static voiderror_message(const char * format, ...){    FILE *error_fp = stderr; /* All debug_malloc.c messages */    va_list ap;    va_start(ap, format);    (void)fprintf(error_fp, "debug_malloc: ");    (void)vfprintf(error_fp, format, ap);    (void)fprintf(error_fp, "\n");    (void)fflush(error_fp);    va_end(ap);}/* This function prints out a memory error for the memory function *   'name' which was called in file 'file' at line number 'line'.  The malloc *   pointer with the error is in 'mptr'. */static voidmemory_error(void *mptr, const char *name, int mid, const char *mfile, int mline, const char *file, int line){    char  nice_words[512];    char  temp[256];    int   len;    void *mptr_walk;    if (name == NULL)	name = "UNKNOWN_NAME";    if (file == NULL)	file = "UNKNOWN_FILE";    md_system_error(temp, (int)sizeof(temp));    (void)strcpy(nice_words, temp);    if ( debug_check!=NULL ) {       (void)md_snprintf(nice_words, sizeof(nice_words),		    "%s The %s at %p appears to have been hit.",		    temp, debug_check, clobbered_ptr);    }    len = -nsize1_(mptr);    error_message("Error: "		   "%s The malloc space #%d is at %p [user size=%d(0x%x)],"		   " and was allocated from file \"%s\" at line %d."		   " [The debug function %s() detected this error "		   "in file \"%s\" at line %d.]",		   nice_words, mid, mptr, len, len, mfile, mline, 		   name, file, line);        /* Print out contents of this allocation */    {	int i;        void *uptr = malloc2user_(mptr);	char *pmess;	pmess = temp;	for(i=0;i<(int)sizeof(temp);i++) {	    int ch = ((unsigned char*)uptr)[i];	    if ( isprint(ch) ) {		*pmess++ = ch;	    } else {		*pmess++ = '\\';		*pmess++ = 'x';		(void)sprintf(pmess,"%02x",ch);		pmess+=2;	    }	}	*pmess = 0;        error_message("Error: %p contains user data: %s", uptr, temp);    }    /* Try and print out table */    if (!malloc_watch) {	return;    }    mptr_walk = first_warrant_mptr;    if (mptr_walk != NULL) {	error_message("Active allocations: "	   "count=%d, largest_size=%d, address range (%p,%p)", 			id_counter, largest_size, smallest_addr, largest_addr);	do {	    int size1;	    int size2;	    char *mfile_walk;	    if ( mptr_walk > largest_addr || mptr_walk < smallest_addr ) {		error_message("Terminating list due to pointer corruption");		break;	    }	    size1 = -nsize1_(mptr_walk);	    size2 = -nsize2_(mptr_walk);	    mfile_walk = MFILE(mptr_walk);	    error_message("#%d: addr=%p size1=%d size2=%d file=\"%.*s\" line=%d",		MID(mptr_walk), mptr_walk, size1, size2, 		WARRANT_NAME_MAX, mfile_walk, MLINE(mptr_walk));	    if ( size1 != size2 || size1 > largest_size || size1 < 0 ) {		error_message("Terminating list due to size corruption");		break;	    }	    mptr_walk = warrant_link_(mptr_walk);	} while (mptr_walk != NULL);    }    abort();}/* This function sets the clobber word and sets up the warrant for the input *   malloc pointer "mptr". */static voidsetup_space_and_issue_warrant(void *mptr, size_t size, const char *file, int line){    register int    nbytes;    /*LINTED*/    nbytes = (int)size;    if ( nbytes > largest_size || largest_addr == NULL ) largest_size = nbytes;    /*LINTED*/    if ( mptr > largest_addr ) largest_addr = mptr;    /*LINTED*/    if ( mptr < smallest_addr || smallest_addr == NULL ) smallest_addr = mptr;    /* Must be done first: */    nsize1_(mptr) = -nbytes;    nsize2_(mptr) = -nbytes;    tail_nsize1_(mptr) = -nbytes;    tail_nsize2_(mptr) = -nbytes;#ifdef LEFT_OVER_CHAR    /* Fill in those few extra bytes just before the tail Word structure */    {        register int    trailing_extra_bytes;        /* LINTED */        trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes);        if (  trailing_extra_bytes > 0 ) {            register char  *p;            register int    i;            p = ((char *) mptr) + sizeof(Word) + nbytes;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?