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 + -
显示快捷键?