?? rmalloc.c
字號:
/* ===================================================================== File: rmalloc.c Author: Rammi Date: 11/16/1995 (started) Reminder: Use at your own risk. Content: Debug wrapper functions for the malloc library. For more information see rmalloc.h Last Change: $Date: 2006/01/29 18:56:12 $ History: $Log: rmalloc.c,v $ History: Revision 1.9 2006/01/29 18:56:12 rammi History: Streamlined various things due to a proposal by Brant L Gurganus. Thanks Brant! History: History: Revision 1.8 2003/01/31 15:47:52 rammi History: Changed signature of Rmalloc_set_flags() and Rmalloc_retag to return pointer. History: History: Revision 1.7 2003/01/31 15:04:20 rammi History: Fixed unclosed comment. History: History: Revision 1.6 2003/01/31 14:51:48 rammi History: Updated version to 1.16 History: History: Revision 1.5 2003/01/31 14:49:00 rammi History: Unset RM_STATIC flag in realloc to avoid warning on free History: History: Revision 1.4 2002/04/22 17:39:34 rammi History: Added output of BREAK_GENERATION environment variable when used History: History: Revision 1.3 2002/04/22 16:28:06 rammi History: Finetuning of generations feature History: History: Revision 1.2 2002/04/22 15:26:16 rammi History: Added Karl Brace's generations feature. History: Pre-CVS history: 04/11/1996 (Rammi) Changed to hashed table for faster access 04/15/1996 (Rammi) Included statistics 08/16/1997 (Rammi) Automatic output of used memory on exit 08/25/1997 (Rammi) Catching signals in critical situations (partly) 02/18/1998 (Rammi) Testing memory before outputting statistic Overworked signal handling in IsPossibleFilePos() Made it unnecessary of changing all mallocs etc to upper case 02/19/1998 (Rammi) Little changes to compile on Alpha (64bit) without warnings 03/10/1998 (Rammi) Added comments. 03/24/1998 (Rammi) Allowed compilation without WITH_FLAGS 04/07/1998 (Rammi) All output goes to stderr.. 1.11beta is released as 1.11! 05/28/1998 (Rammi) Changed comments to english for public release Added some more signal handling. 06/01/1998 (Rammi) Added output of (flagged) strings in ELOQUENT mode. Changed all names from my_... to R... This is version 1.12! 11/13/1998 (Rammi) Multiple defined label when using ELOQUENT mode now fixed. Added getcwd wrapper as a prototype how to handle library functions returning heap memory. This is version 1.13! 06/10/99 (Rammi) The getcwd wrapper had a bug as Greg Silverman pointed out (I should better have tested it!). Also fixed a missing prototype and improved the signal handling in rtest to allow receiving more signals while handling one. ===================================================================== *//* ========= INCLUDEs: ========= */#define ALLOW_OS_CODE 1#include <stdio.h>#include <unistd.h>#include <string.h>#include <strings.h>#include <assert.h>#include <setjmp.h>#include <signal.h>#undef MALLOC_DEBUG /* here we need the correct malloc functions */#define RM_NEED_PROTOTYPES /* but we want to compare prototypes */#include "rmalloc.h"/* ======== DEFINEs: ======== *//* Actual version */#define VERSION "1.17"/* ================================================================== *//* ============ Switch settings for different behaviours ============ *//* ============ Please set as needed ============ *//* ================================================================== *//* This switch sets, how and when the allocated blocks are tested * on correctness. Each block is tested at least when * reallocating/freeing it. * Possible values: * 0: Minimum testing. Uses less memory, but * does not allow statistics. * 1: Extra testing possible by using RM_TEST * macro. Statistics possible. * 2: Testing ALL blocks on every malloc/free. * Statistics possible. */#ifndef RM_TEST_DEPTH#define RM_TEST_DEPTH 1#endif/* This switch sets whether Karl's generations feature should be used * See the HTML doc for a indepth explanation of generations. * If set generations are used, otherwise no generations are included. */#define GENERATIONS#ifdef GENERATIONS/* BREAK_GENERATION_COND is the condition to find the generation you are * interested in. * Set your debugger to the function rmalloc_generation() to find out which * function stack creates that generation. * You can either set it as a comparision directly to the number of a * generation (known from a previous run), a comparision to the function * GetBreakGenerationEnv() which reads the break generation from the environment * variable BREAK_GENERATION or don't set it so the break feature is not used. * The macro form allows for more complicated conditions, see example below. */#define BREAK_GENERATION_COND(nr) ((nr) == GetBreakGenerationEnv())/* #define BREAK_GENERATION_COND(nr) ((nr) == 125) *//* #define BREAK_GENERATION_COND(nr) ((nr) == 42 || (nr) == 4711) *//* The maximum number of generations you'd like to see in the statistics */#define MAX_STAT_GENERATIONS 3#endif /* GENERATIONS *//* Switch on EXTENTED alloc information. (Makes sense if an actual * error is observed such as a multiple free) *///#define ELOQUENT/* Allows setting of special flags with the RM_SET_FLAGS macro. * Needs more memory. */#define WITH_FLAGS/* Allows realloc(NULL, ...) * Posix allows this but there are some old malloc libraries * which crash on this. Switch on if you want to be compatible. *//* #define ALLOW_REALLOC_NULL *//* Allows free(NULL) * I still consider this an error in my progs because I use * NULL always as a very special value. *//* #define ALLOW_FREE_NULL *//* ================================================================== *//* ======================== Other Defines ========================= *//* ================================================================== *//* Alignment (8 bytes are ok for virtually all machines) */#define ALIGNMENT 8/* Output message header: */#define HEAD "<MALLOC_DEBUG>\t"/* Alignment padding: */#define ALIGN(s) (((s+ALIGNMENT-1)/ALIGNMENT)*ALIGNMENT)/* Magic marker for block start: */#define PREV_STOP 0x55555555/* Additional space for block begin to keep alignment: */#define START_SPACE ALIGN(sizeof(begin))/* Additional space at end of block */#define END_SPACE (sizeof(End))/* Overall additional space per block: */#define EXTRA_SPACE (START_SPACE+END_SPACE)/* Hashtable size: */#define HASHSIZE 513/* Hash function: */#define HASH(p) ((((unsigned long)(p))/ALIGNMENT)%HASHSIZE)/* ========================== STRUCTs, TYPEDEFs & ENUMs: ========================== *//* This Information is added to the beginning of every * allocated block. */typedef struct _begin { unsigned StpA; /* Magic bytes */#if RM_TEST_DEPTH > 0 struct _begin *Next, /* for linking in forward */ *Prev; /* and backward direction */#endif const char *File; /* Filepos of allocation command */ size_t Size; /* Size demanded */#ifdef GENERATIONS unsigned Generation; /* All mallocs are numbered */#endif#ifdef WITH_FLAGS unsigned Flags; /* Special flags */#endif unsigned StpB; /* Magic bytes */} begin;/* * Global data. */typedef struct _global { unsigned isInitialized; /* Flag: already initialized? */ unsigned BlockCount; /* Number of allocated blocks */} global;/* ======= CONSTs: ======= *//* Magic block end: */static unsigned char End[] = { 0xA5, 0xA5, 0xA5, 0xA5, /* odd */ 0x5B, 0x5B, 0x5B, 0x5B, /* odd */ 0xAB, 0xAB, 0xAB, 0xAB, /* odd */ 0xAA, 0x55, 0xAA, 0x55 /* odd */};/* ======== GLOBALs: ======== */#ifdef GENERATIONS/* The current generation. This is simply incremented which each call. */static unsigned cur_generation = 0;#endif/* ======= LOCALs: ======= */#if RM_TEST_DEPTH > 0/* Stop marker for linked list of allocated blocks: */static begin ChainTempl = { PREV_STOP, &ChainTempl, &ChainTempl, "<Special>", 0,#ifdef GENERATIONS 0,#endif#ifdef WITH_FLAGS 0,#endif PREV_STOP};/* Hashed linked lists: */static begin Chain[HASHSIZE];/* Global data used: */static global Global = { 0, /* is initialized? */ 0 /* number of blocks */};#endif /* RM_TEST_DEPTH *//* Internally used longjmp target used if errors occure. */static jmp_buf errorbuf;/* ======== FORWARD: ======== */static int FindBlk(const unsigned char *P);/* =============================================================== IMPLEMENTATION =============================================================== *//* ============================================================================= Function: FatalSignal // local // Author: Rammi Date: 08/25/1997 Return: --- Parameter: signum signal number Purpose: Signal handler f?r fatal signals (SIGBUS, SIGSEGV) ============================================================================= *///static void FatalSignal(int signum)//{// /* --- jump to a save place --- */// longjmp(errorbuf, signum);//}/* ============================================================================= Function: IsPossibleFilePos // local // Author: Rammi Date: 11/30/1996 Return: != 0 possibly ok 0 seems not so Parameter: file possible filename size possible size Purpose: Decide whether file could be a filename and size a block size. ============================================================================= */static int IsPossibleFilePos(const char *file, int size){ void (*old_sigsegv_handler)(int) = SIG_DFL; void (*old_sigbus_handler)(int) = SIG_DFL;// char *dp;// int ret; if (setjmp(errorbuf)) { /* uh oh, we got a kick in the ass */ signal(SIGSEGV, old_sigsegv_handler); signal(SIGBUS, old_sigbus_handler); printf ("hola\n"); return 0; } printf ("nohola\n");// /* --- the following is dangerous! So catch signals --- */// old_sigsegv_handler = signal(SIGSEGV, FatalSignal);// old_sigbus_handler = signal(SIGBUS, FatalSignal);//// dp = strchr(file, ':'); /* file pos needs : *///// ret = (dp && dp-file > 3 && !strncmp(dp-2, ".c", 2) &&// atoi(dp+1) > 0 && size >= 0);//// /* --- danger is over! --- */// signal(SIGSEGV, old_sigsegv_handler);// signal(SIGBUS, old_sigbus_handler);//// return ret; return 0;}#ifdef GENERATIONS/* ============================================================================= Function: GetBreakGenerationEnv // lokal // Author: Rammi Date: 04/22/2002 Return: the content of the BREAK_GENERATION environment variable or 0 Parameter: --- Purpose: Return the content of the environment variable BREAK_GENERATION (a number indicating which is the generation you want to break with the debugger). ============================================================================= */static unsigned GetBreakGenerationEnv(void){ /* The environment variable is buffered here for faster access. */ static char *breakGenerationEnv = (char *)-1; /** The result of the conversion to unsigned is buffered here. */ static unsigned result = 0; if (breakGenerationEnv == (char *)-1) { /* 1st call: get the environment variable */ breakGenerationEnv = getenv("BREAK_GENERATION"); if (breakGenerationEnv != NULL) { /* try conversion */ result = atoi(breakGenerationEnv); fprintf(stderr, HEAD "Using environment variable BREAK_GENERATION=%d\n", result); } } return result;}#endif /* GENERATIONS *//* ============================================================================= Function: ControlBlock // lokal // Author: Rammi Date: 11/16/1995 Return: --- Parameter: Bkl Pos of allocated block (original) file file pos from where initial lib function was called Purpose: Control integrity of block ============================================================================= */static void ControlBlock(begin *B, const char *file){ unsigned char *p = (((unsigned char *)B)+START_SPACE);#if RM_TEST_DEPTH > 0 int DoAbort = 0;#endif /* === the very beginning === */ if (B->StpA != PREV_STOP) {#if RM_TEST_DEPTH > 0 DoAbort = 1;#endif fprintf(stderr, HEAD "Corrupted block begin (overwritten from elsewhere)\n" "\tshould be: %08x\n" "\tis: %08x\n"#ifdef GENERATIONS "\tblock was allocated in %s [%u Bytes, generation %u]\n"#else "\tblock was allocated in %s [%u Bytes]\n"#endif "\terror was detected in %s\n", PREV_STOP, B->StpA, B->File, (unsigned) B->Size,#ifdef GENERATIONS B->Generation,#endif file); } /* === begin of user data === */ if (B->StpB != PREV_STOP) {#if RM_TEST_DEPTH > 0 DoAbort = 1;#endif fprintf(stderr, HEAD "Corrupted block begin (possibly written back)\n" "\tshould be: %08x\n" "\tis: %08x\n"#ifdef GENERATIONS "\tblock was allocated in %s [%u Bytes, generation %u]\n"#else "\tblock was allocated in %s [%u Bytes]\n"#endif "\terror was detected in %s\n", PREV_STOP, B->StpB, B->File, (unsigned) B->Size,#ifdef GENERATIONS B->Generation,#endif file); } /* === end of user data === */ if (memcmp(p+B->Size, &End, END_SPACE) != 0) { unsigned char *E = (unsigned char *)(p+B->Size); unsigned i; int found = 0;#if RM_TEST_DEPTH > 0 DoAbort = 1;#endif fprintf(stderr, HEAD "Corrupted block end (possibly written past the end)\n" "\tshould be:"); for (i = 0; i < END_SPACE; i++) { fprintf(stderr, i%4 ? "%02x" : " %02x", End[i]); } fprintf(stderr, "\n\tis: "); for (i = 0; i < END_SPACE; i++) { fprintf(stderr, i%sizeof(int) ? "%02x" : " %02x", E[i]); } fprintf(stderr, "\n"#ifdef GENERATIONS "\tblock was allocated in %s [%u Bytes, generation %u]\n"#else "\tblock was allocated in %s [%u Bytes]\n"#endif "\terror was detected in %s\n", B->File, (unsigned) B->Size,#ifdef GENERATIONS B->Generation,#endif file );#if RM_TEST_DEPTH > 0 if (!((unsigned long)E % sizeof(void *)) && !(*(unsigned long *)E % sizeof(void *))) { /* because of alignment */ /* Special service: look if memory was overwritten with pointer */ if (FindBlk(*(unsigned char **)E)) { begin *b = (begin *)((*(unsigned char **)E)-START_SPACE); if (IsPossibleFilePos(b->File, b->Size)) { fprintf(stderr, "\tFirst %d bytes of overwritten memory can be interpreted\n" "\t\tas a pointer to a block " " allocated in:\n"#ifdef GENERATIONS "\t\t%s [%u Bytes, generation %u]\n",#else "\t\t%s [%u Bytes]\n",#endif (short)sizeof(void *), b->File, (unsigned short) b->Size#ifdef GENERATIONS , (unsigned short)b->Generation#endif ); found = 1; } } } if (!found)#endif { /* Look, what we can find... */ int j; for (j = END_SPACE-1; j >= 0; j--) { if (E[j] != End[j]) { break; } } if (j >= 0 && !E[j]) { /* Ends with '\0', so it's possibly a string */ if (j > 0) { while (--j >= 0) { if (!E[j]) { break; } } if (j < 0) { fprintf(stderr, "\tLooks somewhat like a too long string,\n" "\t\tending with \"%s\"\n", E); } } else { /* Off by one? */ fprintf(stderr, "\tLooks like string allocated one byte too short\n" "\t\t(forgetting the nul byte)\n"); }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -