📄 dmalloc.c
字号:
/* * mpatrol * A library for controlling and tracing dynamic memory allocations. * Copyright (C) 1997-2002 Graeme S. Roy <graeme.roy@analog.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307, USA. *//* * Dmalloc-compatible interface. Implements Dmalloc functions using * mpatrol. Dmalloc is copyright (C) 1992-2001 Gray Watson. */#include "config.h"#include "dmalloc.h"#include <stdio.h>#include <ctype.h>#include <time.h>#if MP_IDENT_SUPPORT#ident "$Id: dmalloc.c,v 1.16 2002/01/08 20:05:10 graeme Exp $"#else /* MP_IDENT_SUPPORT */static MP_CONST MP_VOLATILE char *dmalloc_id = "$Id: dmalloc.c,v 1.16 2002/01/08 20:05:10 graeme Exp $";#endif /* MP_IDENT_SUPPORT *//* Specify whether to prefix every log message produced by * __mpt_dmallocmessage() and __mpt_dmallocvmessage() with the current * time in numerical form and/or string form. The current event number * can also be logged as well. */#define LOG_TIME_NUMBER 1#define LOG_CTIME_STRING 0#define LOG_ITERATION_COUNT 1/* The escape characters that should be given special consideration in * bytestring(). */#define ESCAPE_CHARS "\\\a\b\f\n\r\t\v"#define ESCAPE_REPLACE "\\abfnrtv"/* The structure used to store information about each debugging token * recognised by the Dmalloc library. */typedef struct tokeninfo{ char *longname; /* long token name */ char *shortname; /* short token name */ unsigned long flag; /* associated flag */}tokeninfo;/* The structure used to pass information to the callback function from * __mp_iterate() when __mpt_dmalloclogchanged() is called. */typedef struct listinfo{ unsigned long kcount; /* known count */ unsigned long ktotal; /* known total */ unsigned long ucount; /* unknown count */ unsigned long utotal; /* unknown total */ int unfreed : 1; /* log unfreed allocations */ int freed : 1; /* log freed allocations */ int details : 1; /* log pointer details */}listinfo;#ifdef __cplusplusextern "C"{#endif /* __cplusplus *//* The table containing all of the recognised debugging tokens with their * associated flags. */static tokeninfo tokens[] ={ {"none", "nil", 0}, {"log-stats", "lst", DMALLOC_LOG_STATS}, {"log-non-free", "lnf", DMALLOC_LOG_NONFREE}, {"log-known", "lkn", DMALLOC_LOG_KNOWN}, {"log-trans", "ltr", DMALLOC_LOG_TRANS}, {"log-admin", "lad", DMALLOC_LOG_ADMIN}, {"log-blocks", "lbl", DMALLOC_LOG_BLOCKS}, {"log-bad-space", "lbs", DMALLOC_LOG_BAD_SPACE}, {"log-nonfree-space", "lns", DMALLOC_LOG_NONFREE_SPACE}, {"check-fence", "cfe", DMALLOC_CHECK_FENCE}, {"check-heap", "che", DMALLOC_CHECK_HEAP}, {"check-lists", "cli", DMALLOC_CHECK_LISTS}, {"check-blank", "cbl", DMALLOC_CHECK_BLANK}, {"check-funcs", "cfu", DMALLOC_CHECK_FUNCS}, {"force-linear", "fli", DMALLOC_FORCE_LINEAR}, {"catch-signals", "csi", DMALLOC_CATCH_SIGNALS}, {"log-elapsed-time", "let", DMALLOC_LOG_ELAPSED_TIME}, {"log-current-time", "lct", DMALLOC_LOG_CURRENT_TIME}, {"realloc-copy", "rco", DMALLOC_REALLOC_COPY}, {"free-blank", "fbl", DMALLOC_FREE_BLANK}, {"error-abort", "eab", DMALLOC_ERROR_ABORT}, {"alloc-blank", "abl", DMALLOC_ALLOC_BLANK}, {"heap-check-map", "hcm", DMALLOC_HEAP_CHECK_MAP}, {"print-messages", "pme", DMALLOC_PRINT_MESSAGES}, {"catch-null", "cnu", DMALLOC_CATCH_NULL}, {"never-reuse", "nre", DMALLOC_NEVER_REUSE}, {"allow-free-null", "afn", DMALLOC_ALLOW_FREE_NULL}, {"error-dump", "edu", DMALLOC_ERROR_DUMP}, {NULL, NULL, 0}};/* Indicates if this module has been initialised. */static int malloc_initialised;/* The time at which this module was initialised. */static time_t malloc_time;/* The library debug flags. */static unsigned long malloc_flags;/* The point at which to start checking the heap and the frequency at which * to check it. */static unsigned long malloc_start, malloc_interval;/* The pointer to the callback function registered with __mpt_dmalloctrack(). */static dmalloc_track_t malloc_tracker;/* The previous mpatrol prologue and epilogue handlers. */static __mp_prologuehandler old_prologue;static __mp_epiloguehandler old_epilogue;/* The pointer, size and alignment obtained each time our prologue function is * called. This is then used by our epilogue function, but we don't need to * worry about nested calls to the prologue function since the mpatrol library * guarantees that it will never occur, even when there are multiple threads. */static void *malloc_pointer;static size_t malloc_size;static size_t malloc_align;/* The global variables which control the behaviour of the library and are * part of the Dmalloc library interface. The last two are intended for use * within a debugger. */char *dmalloc_logpath;void *dmalloc_address;unsigned long dmalloc_address_count;/* Read any library options from the DMALLOC_OPTIONS environment variable. */staticvoidreadoptions(void){ static char b[1024]; tokeninfo *i; char *p, *s, *t; if (((s = getenv("DMALLOC_OPTIONS")) == NULL) || (*s == '\0')) return; strncpy(b, s, sizeof(b) - 1); b[sizeof(b) - 1] = '\0'; for (s = t = b; t != NULL; s = t + 1) { if (t = strchr(s, ',')) *t = '\0'; if (*s == '\0') continue; if ((strncmp(s, "addr", 4) == 0) && (s[4] == '=')) { if (p = strchr(s + 5, ':')) *p = '\0'; dmalloc_address = (void *) strtoul(s + 5, NULL, 16); if (p != NULL) dmalloc_address_count = strtoul(p + 1, NULL, 10); } else if ((strncmp(s, "debug", 5) == 0) && (s[5] == '=')) malloc_flags = strtoul(s + 6, NULL, 16); else if ((strncmp(s, "inter", 5) == 0) && (s[5] == '=')) { if ((malloc_interval = strtoul(s + 6, NULL, 10)) == 0) malloc_interval = 1; } else if ((strncmp(s, "log", 3) == 0) && (s[3] == '=')) dmalloc_logpath = s + 4; else if ((strncmp(s, "start", 5) == 0) && (s[5] == '=')) if (strchr(s + 6, ':') == NULL) malloc_start = strtoul(s + 6, NULL, 10); else malloc_start = 0; else for (i = tokens; i->longname != NULL; i++) if ((strcmp(s, i->longname) == 0) || (strcmp(s, i->shortname) == 0)) { malloc_flags |= i->flag; break; } }}/* Map the Dmalloc options to mpatrol options. */staticvoidsetoptions(void){ unsigned long v; if (dmalloc_logpath != NULL) { __mp_setoption(MP_OPT_LOGFILE, (unsigned long) dmalloc_logpath); dmalloc_logpath = NULL; } v = MP_FLG_SHOWFREE; if (malloc_flags & DMALLOC_LOG_STATS) __mp_setoption(MP_OPT_SETFLAGS, v); else __mp_setoption(MP_OPT_UNSETFLAGS, v); v = MP_FLG_SHOWUNFREED; if (malloc_flags & DMALLOC_LOG_NONFREE) __mp_setoption(MP_OPT_SETFLAGS, v); else __mp_setoption(MP_OPT_UNSETFLAGS, v); v = MP_FLG_LOGALLOCS | MP_FLG_LOGREALLOCS | MP_FLG_LOGFREES; if (malloc_flags & DMALLOC_LOG_TRANS) __mp_setoption(MP_OPT_SETFLAGS, v); else __mp_setoption(MP_OPT_UNSETFLAGS, v); if (malloc_flags & DMALLOC_CHECK_FENCE) { if (!__mp_getoption(MP_OPT_OFLOWSIZE, &v) || (v == 0)) v = sizeof(void *); } else v = 0; __mp_setoption(MP_OPT_OFLOWSIZE, v); if (malloc_flags & DMALLOC_CHECK_HEAP) { v = (unsigned long) -1; __mp_setoption(MP_OPT_CHECKLOWER, malloc_start); } else { v = 0; __mp_setoption(MP_OPT_CHECKLOWER, 0); } __mp_setoption(MP_OPT_CHECKUPPER, v); __mp_setoption(MP_OPT_CHECKFREQ, malloc_interval); v = MP_FLG_SAFESIGNALS; if (malloc_flags & DMALLOC_CATCH_SIGNALS) __mp_setoption(MP_OPT_SETFLAGS, v); else __mp_setoption(MP_OPT_UNSETFLAGS, v); v = MP_FLG_PRESERVE; if (malloc_flags & DMALLOC_FREE_BLANK) __mp_setoption(MP_OPT_UNSETFLAGS, v); else __mp_setoption(MP_OPT_SETFLAGS, v); v = MP_FLG_SHOWMAP; if (malloc_flags & DMALLOC_HEAP_CHECK_MAP) __mp_setoption(MP_OPT_SETFLAGS, v); else __mp_setoption(MP_OPT_UNSETFLAGS, v); if (malloc_flags & DMALLOC_NEVER_REUSE) v = ~0L; else v = 0; __mp_setoption(MP_OPT_NOFREE, v); v = MP_FLG_CHECKFREES; if (malloc_flags & DMALLOC_ALLOW_FREE_NULL) __mp_setoption(MP_OPT_UNSETFLAGS, v); else __mp_setoption(MP_OPT_SETFLAGS, v);}/* Record the pointer, size and alignment for later processing by the epilogue * function and possibly also call the old prologue function if one was * installed. */staticvoidprologue(MP_CONST void *p, size_t l, size_t m, MP_CONST char *s, MP_CONST char *t, unsigned long u, MP_CONST void *a){ if (old_prologue != NULL) old_prologue(p, l, m, s, t, u, a); malloc_pointer = (void *) p; malloc_size = l; malloc_align = m;}/* Call the tracker function with any relevant details if one has been * registered and possibly also call the old epilogue function if one was * installed. */staticvoidepilogue(MP_CONST void *p, MP_CONST char *s, MP_CONST char *t, unsigned long u, MP_CONST void *a){ size_t l; if (dmalloc_logpath != NULL) { __mp_setoption(MP_OPT_LOGFILE, (unsigned long) dmalloc_logpath); dmalloc_logpath = NULL; } if (malloc_tracker != NULL) { if (malloc_pointer == (void *) -1) malloc_tracker(t, u, DMALLOC_FUNC_MALLOC, malloc_size, malloc_align, NULL, p); else if (malloc_size == (size_t) -1) malloc_tracker(t, u, DMALLOC_FUNC_FREE, 0, 0, malloc_pointer, NULL); else if (malloc_size == (size_t) -2) { if (malloc_pointer == NULL) l = 0; else l = strlen((char *) malloc_pointer) + 1; malloc_tracker(t, u, DMALLOC_FUNC_STRDUP, l, malloc_align, NULL, p); } else if (malloc_pointer == NULL) malloc_tracker(t, u, DMALLOC_FUNC_MALLOC, malloc_size, malloc_align, NULL, p); else if (malloc_size == 0) malloc_tracker(t, u, DMALLOC_FUNC_FREE, 0, 0, malloc_pointer, NULL); else malloc_tracker(t, u, DMALLOC_FUNC_REALLOC, malloc_size, malloc_align, malloc_pointer, p); } if (old_epilogue != NULL) old_epilogue(p, s, t, u, a);}/* Convert the bytes in a memory allocation to human-readable form. */staticchar *bytestring(char *b, size_t s, char *p, size_t l){ char *t; size_t i, n; for (i = n = 0; (i < s) && (i < l); i++) if (p[i] == '\0') { b[n++] = '\\'; b[n++] = '0'; if ((i < s - 1) && (i < l - 1)) { b[n++] = '0'; b[n++] = '0'; } } else if (t = strchr(ESCAPE_CHARS, p[i])) { b[n++] = '\\'; b[n++] = ESCAPE_REPLACE[t - ESCAPE_CHARS]; } else if (!isprint(p[i])) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -