📄 mleak.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. *//* * A tool designed to read a log file produced by the mpatrol library * and report any unfreed memory allocations. This should be used if * the mpatrol library could not finish writing the log file due to * abnormal program termination, but note that some of the unfreed * allocations might have been freed if the program had terminated * successfully. Also note that no attempt is made to account for * resizing of memory allocations and so the total amount of memory * used by the resulting unfreed allocations may not be entirely accurate. */#include "tree.h"#include "getopt.h"#include "version.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#if MP_IDENT_SUPPORT#ident "$Id: mleak.c,v 1.16 2002/01/08 20:13:59 graeme Exp $"#else /* MP_IDENT_SUPPORT */static MP_CONST MP_VOLATILE char *mleak_id = "$Id: mleak.c,v 1.16 2002/01/08 20:13:59 graeme Exp $";#endif /* MP_IDENT_SUPPORT */#define PROGVERSION "1.3" /* the current version of this program *//* The flags used to parse the command line options. */typedef enum options_flags{ OF_HELP = 'h', OF_IGNORE = 'i', OF_MAXSTACK = 'n', OF_VERSION = 'V'}options_flags;/* Structure containing the allocation details and log file offset for a * single memory allocation. */typedef struct allocation{ treenode node; /* tree node */ unsigned long addr; /* allocation address */ unsigned long size; /* allocation size */ unsigned long offset; /* log file offset */}allocation;/* The tree containing information about each memory allocation. */static treeroot alloctree;/* The total number of bytes currently allocated. */static unsigned long alloctotal;/* The log file produced by mpatrol. */static FILE *logfile;/* The current offset in the log file. */static long fileoffset;/* The filename used to invoke this tool. */static char *progname;/* Indicates that the unfreed memory allocation list in the log file, if it * exists, should be ignored. */static int ignorelist;/* Indicates the maximum stack depth to display. */static unsigned long maxstack;/* The table describing all recognised options. */static option options_table[] ={ {"help", OF_HELP, NULL, "\tDisplays this quick-reference option summary.\n"}, {"ignore", OF_IGNORE, NULL, "\tSpecifies that the list of unfreed allocations in the log file\n" "\tshould be ignored.\n"}, {"max-stack", OF_MAXSTACK, "depth", "\tSpecifies the maximum stack depth to display.\n"}, {"version", OF_VERSION, NULL, "\tDisplays the version number of this program.\n"}, NULL};/* Create a new memory allocation and record its log file offset. */staticvoidnewalloc(unsigned long i, unsigned long a, unsigned long l, unsigned long o){ allocation *n; if ((n = (allocation *) malloc(sizeof(allocation))) == NULL) { fprintf(stderr, "%s: Out of memory\n", progname); exit(EXIT_FAILURE); } __mp_treeinsert(&alloctree, &n->node, i); n->addr = a; n->size = l; n->offset = o; alloctotal += l;}/* Free an existing memory allocation. */staticvoidfreealloc(unsigned long i){ allocation *n; if (n = (allocation *) __mp_search(alloctree.root, i)) { __mp_treeremove(&alloctree, &n->node); alloctotal -= n->size; free(n); }}/* Read an input line from the log file. */staticchar *getnextline(void){ static char s[MP_BUFFER_SIZE + 1]; unsigned long i; int c; i = 0; /* Record the file offset so that we can go back to this position during * the second pass of the log file. */ if ((fileoffset = ftell(logfile)) == -1) { fprintf(stderr, "%s: Cannot determine file position\n", progname); exit(EXIT_FAILURE); } while (((c = fgetc(logfile)) != EOF) && (c != '\n')) { if (i == MP_BUFFER_SIZE) { fprintf(stderr, "%s: Buffer overflow\n", progname); exit(EXIT_FAILURE); } s[i++] = c; } if (c == EOF) return NULL; s[i] = '\0'; return s;}/* Log the allocations and deallocations from the log file. */staticvoidreadfile(void){ char *s, *t; unsigned long a, l, n, o; while (s = getnextline()) if (strncmp(s, "ALLOC: ", 7) == 0) { /* Parse relevant details from the memory allocation and * add the allocation to the allocation tree. */ o = fileoffset; if ((s = strchr(s + 7, '(')) && (t = strchr(s + 1, ','))) { /* Get the allocation index. */ *t = '\0'; n = strtoul(s + 1, NULL, 0); if ((*(s = t + 1) == ' ') && (t = strchr(s + 1, ' '))) { /* Get the allocation size. */ *t = '\0'; l = strtoul(s + 1, NULL, 0); /* Don't record the allocation if the pointer returned is * NULL. */ while ((s = getnextline()) && (strncmp(s, "returns ", 8) != 0)); if ((n != 0) && (s != NULL) && (a = strtoul(s + 8, NULL, 0))) newalloc(n, a, l, o); } } } else if (strncmp(s, "FREE: ", 6) == 0) { /* Parse relevant details from the memory deallocation and * remove the allocation from the allocation tree. */ if ((s = strchr(s + 6, '(')) && (t = strchr(s + 1, ')'))) { /* Get the allocation address. */ *t = '\0'; if (a = strtoul(s + 1, NULL, 0)) { while ((s = getnextline()) && (*s != '\0')); /* Don't record the deallocation if a warning or error * occurred. */ if ((s = getnextline()) && (strncmp(s, " ", 4) == 0) && (s = strchr(s + 4, ':')) && (t = strchr(s + 1, ':'))) { /* Get the allocation index. */ *t = '\0'; n = strtoul(s + 1, NULL, 0); freealloc(n); } } } } else if (!ignorelist && (strncmp(s, "unfreed allocations: ", 21) == 0)) /* If we get here then there is already a list of unfreed memory * allocations in the log file. In this case we just parse them * anyway, adding any new entries to the allocation tree. */ while (s = getnextline()) { /* Parse relevant details from the unfreed allocation and * add the allocation to the allocation tree. */ o = fileoffset; if ((strncmp(s, " ", 4) == 0) && (t = strchr(s + 4, ' '))) { /* Get the allocation address. */ *t = '\0'; if ((a = strtoul(s + 4, NULL, 0)) && (*(s = t + 1) == '(') && (t = strchr(s + 1, ' '))) { /* Get the allocation size. */ *t = '\0'; l = strtoul(s + 1, NULL, 0); if ((s = strchr(t + 1, ':')) && (t = strchr(s + 1, ':'))) { /* Get the allocation index. */ *t = '\0'; n = strtoul(s + 1, NULL, 0); if (!__mp_search(alloctree.root, n)) newalloc(n, a, l, o); } } } while ((s = getnextline()) && (*s != '\0')); }}/* Display all remaining memory allocations. */staticvoidprintallocs(void){ allocation *n, *p; char *r, *s, *t; size_t i; printf("unfreed allocations: %lu (%lu byte%s)\n", alloctree.size, alloctotal, (alloctotal == 1) ? "" : "s"); for (n = (allocation *) __mp_minimum(alloctree.root); n != NULL; n = p) { p = (allocation *) __mp_successor(&n->node); /* Move to the position in the log file that records the original * allocation. */ if (fseek(logfile, n->offset, SEEK_SET) == -1) { fprintf(stderr, "%s: Cannot set file position\n", progname); exit(EXIT_FAILURE); } /* Extract the relevant information from the allocation log so that * we can format it in the same way as that displayed for the * SHOWUNFREED option. */ if (s = getnextline()) if ((strncmp(s, "ALLOC: ", 7) == 0) && (t = strchr(s + 7, '(')) && (t > s) && (*(t = t - 1) == ' ')) { *t = '\0'; r = s + 7; if (s = strchr(t + 2, '[')) { i = 0; printf(" " MP_POINTER " (%lu byte%s) {%s:%lu:0} %s\n", n->addr, n->size, (n->size == 1) ? "" : "s", r, n->node.key, s); while ((s = getnextline()) && (*s != '\0')) if (i++ < maxstack) puts(s); if ((alloctree.size > 1) && (maxstack != 0)) putchar('\n'); } } else { i = 0; puts(s); while ((s = getnextline()) && (*s != '\0')) if (i++ < maxstack) puts(s); if ((alloctree.size > 1) && (maxstack != 0)) putchar('\n'); } __mp_treeremove(&alloctree, &n->node); free(n); }}/* Read the log file and display all unfreed memory allocations. */intmain(int argc, char **argv){ char b[256]; char *f; int c, e, h, v; e = h = v = 0; maxstack = ~0; progname = __mp_basename(argv[0]); while ((c = __mp_getopt(argc, argv, __mp_shortopts(b, options_table), options_table)) != EOF) switch (c) { case OF_HELP: h = 1; break; case OF_IGNORE: ignorelist = 1; break; case OF_MAXSTACK: if (!__mp_getnum(progname, __mp_optarg, (long *) &maxstack, 1)) e = 1; break; case OF_VERSION: v = 1; break; default: e = 1; break; } argc -= __mp_optindex; argv += __mp_optindex; if (v == 1) { fprintf(stdout, "%s %s\n%s %s\n\n", progname, PROGVERSION, __mp_copyright, __mp_author); fputs("This is free software, and you are welcome to redistribute it " "under certain\n", stdout); fputs("conditions; see the GNU Library General Public License for " "details.\n\n", stdout); fputs("For the latest mpatrol release and documentation,\n", stdout); fprintf(stdout, "visit %s.\n\n", __mp_homepage); } if (argc > 1) e = 1; if ((e == 1) || (h == 1)) { fprintf(stdout, "Usage: %s [options] [file]\n\n", progname); if (h == 0) fprintf(stdout, "Type `%s --help' for a complete list of " "options.\n", progname); else __mp_showopts(options_table); if (e == 1) exit(EXIT_FAILURE); exit(EXIT_SUCCESS); } if (argc == 1) f = argv[0]; else f = MP_LOGFILE; __mp_newtree(&alloctree); alloctotal = 0; if (strcmp(f, "-") == 0) logfile = stdin; else if ((logfile = fopen(f, "r")) == NULL) { fprintf(stderr, "%s: Cannot open file `%s'\n", progname, f); exit(EXIT_FAILURE); } fileoffset = 0; readfile(); printallocs(); fclose(logfile); return EXIT_SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -