summaryrefslogtreecommitdiff
path: root/lib/libmalloc/leak.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libmalloc/leak.c')
-rw-r--r--lib/libmalloc/leak.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/lib/libmalloc/leak.c b/lib/libmalloc/leak.c
new file mode 100644
index 000000000000..b4014582b32e
--- /dev/null
+++ b/lib/libmalloc/leak.c
@@ -0,0 +1,160 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "sptree.h"
+
+RCSID("$Id: leak.c,v 1.1 1994/03/06 22:59:46 nate Exp $")
+
+/*
+ * These routines provide an interface for tracing memory leaks. The
+ * user can turn on leak tracing at any time by calling
+ * mal_leaktrace(1), after which every block allocated by
+ * _malloc()/_calloc()/_realloc()/_valloc()/_memalign() has a string
+ * (containing the filename and linenumber of the routine invoking it)
+ * stored in a database. When _free()/_cfree() is called on that block,
+ * the record is deleted from the database. The user can call
+ * mal_dumpleaktrace() to show the list of blocks allocated, and
+ * where they were allocated. The location of leaks can usually be
+ * detected from this.
+ */
+/*
+ * The tree implementation used to store the blocks is a splay-tree,
+ * using an implementation in C by Dave Brower (daveb@rtech.uucp),
+ * translated from Douglas Jones' original Pascal. However, any data
+ * structure that permits insert(), delete() and traverse()/apply() of
+ * key, value pairs should be suitable. Only this file needs to be
+ * changed.
+ */
+static SPTREE *sp = NULL;
+
+/*
+ * num is a sequence number, incremented for ever block. min_num gets
+ * set to num after every dumpleaktrace - subsequent dumps do not print
+ * any blocks with sequence numbers less than min_num
+ */
+static unsigned long min_num = 0;
+static unsigned long num = 0;
+
+/*
+ * These are used by mal_contents to count number of allocated blocks and the
+ * number of bytes allocated. Better way to do this is to walk the heap
+ * rather than scan the splay tree.
+ */
+static unsigned long nmallocs;
+static unsigned long nbytes;
+
+static FILE *dumpfd = NULL;
+
+/*
+ * Turns recording of FILE and LINE number of each call to
+ * malloc/free/realloc/calloc/cfree/memalign/valloc on (if value != 0)
+ * or off, (if value == 0)
+ */
+void
+mal_leaktrace(value)
+int value;
+{
+ _malloc_leaktrace = (value != 0);
+ if (sp == NULL)
+ sp = __spinit();
+}
+
+/*
+ * The routine which actually does the printing. I know it is silly to
+ * print address in decimal, but sort doesn't read hex, so sorting the
+ * printed data by address is impossible otherwise. Urr. The format is
+ * FILE:LINE: sequence_number address_in_decimal (address_in_hex)
+ */
+void
+__m_prnode(spblk)
+SPBLK *spblk;
+{
+ if ((unsigned long) spblk->datb < min_num)
+ return;
+ (void) sprintf(_malloc_statsbuf, "%s%8lu %8lu(0x%08lx)\n",
+ (char *) spblk->data, (unsigned long) spblk->datb,
+ (unsigned long) spblk->key, (unsigned long) spblk->key);
+ (void) fputs(_malloc_statsbuf, dumpfd);
+}
+
+/*
+ * Dumps all blocks which have been recorded.
+ */
+void
+mal_dumpleaktrace(fd)
+FILE *fd;
+{
+ dumpfd = fd;
+ __spscan(__m_prnode, (SPBLK *) NULL, sp);
+ (void) fflush(dumpfd);
+ min_num = num;
+}
+
+/*
+ * Inserts a copy of a string keyed by the address addr into the tree
+ * that stores the leak trace information. The string is presumably of
+ * the form "file:linenumber:". It also stores a sequence number that
+ * gets incremented with each call to this routine.
+ */
+void
+__m_install_record(addr, s)
+univptr_t addr;
+const char *s;
+{
+ num++;
+ (void) __spadd(addr, strsave(s), (char *) num, sp);
+}
+
+/* Deletes the record keyed by addr if it exists */
+void
+__m_delete_record(addr)
+univptr_t addr;
+{
+ SPBLK *result;
+
+ if ((result = __splookup(addr, sp)) != NULL) {
+ free(result->data);
+ result->data = 0;
+ __spdelete(result, sp);
+ }
+}
+
+void
+__m_count(spblk)
+SPBLK *spblk;
+{
+ Word *p;
+
+ nmallocs++;
+ p = (Word *) spblk->key;
+ p -= HEADERWORDS;
+
+ /* A little paranoia... */
+ ASSERT(PTR_IN_HEAP(p), "bad pointer seen in __m_count");
+ ASSERT(TAG(p) != FREE, "freed block seen in __m_count");
+ ASSERT(VALID_START_SIZE_FIELD(p), "corrupt block seen in __m_count");
+ ASSERT(VALID_MAGIC(p), "block with end overwritten seen in __m_count");
+
+ nbytes += SIZE(p) * sizeof(Word);
+ return;
+}
+
+void
+mal_contents(fp)
+FILE *fp;
+{
+ void __m_count proto((SPBLK *));
+
+ nmallocs = 0;
+ nbytes = 0;
+ __spscan(__m_count, (SPBLK *) NULL, sp);
+ (void) sprintf(_malloc_statsbuf,
+ "%% %lu bytes %lu mallocs %lu available %lu vm\n",
+ nbytes, nmallocs, (ulong) _malloc_totalavail,
+ (ulong) sbrk(0));
+ (void) fputs(_malloc_statsbuf, fp);
+ (void) fflush(fp);
+}