summaryrefslogtreecommitdiff
path: root/malloc
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1996-12-20 01:39:50 +0000
committerUlrich Drepper <drepper@redhat.com>1996-12-20 01:39:50 +0000
commit6d52618b15cbe25ed4822ac51321db292f28ccda (patch)
treebafef072c0f5cb67c09d7c1789888d4310ac568f /malloc
parent10dc2a90b7f86d9bc1be9d1b9305a781882f7ac5 (diff)
Update from main archive 961219cvs/libc-961220
Thu Dec 19 23:28:33 1996 Ulrich Drepper <drepper@cygnus.com> * resolv/resolv.h: Update from BIND 4.9.5-P1. * resolv/res_comp.c: Likewise. * resolv/res_debug.c: Likewise. * resolv/Banner: Update version number. Thu Dec 19 20:58:53 1996 Ulrich Drepper <drepper@cygnus.com> * elf/dlfcn.h: Add extern "C" wrapper. * io/utime.h: Don't define NULL since this isn't allowed in POSIX. * io/sys/stat.h: Declare `lstat' only if __USE_BSD || __USE_XOPEN_EXTENDED. * locale/locale.h: Define NULL. * math/math.c: Don't include <errno.h> to define math errors. * stdlib/stdlib.h: Likewise. * posix/unistd.h: Don't declare environ. * posix/sys/utsname.h (struct utsname): Declare member domainname as __domainname is !__USE_GNU. * signal/signal.h: Declare size_t only if __USE_BSD || __USE_XOPEN_EXTENDED. * stdio/stdio.h: Don't declare cuserid when __USE_POSIX, but instead when __USE_XOPEN. * string/string.h: Define strndup only if __USE_GNU. * sysdeps/unix/sysv/linux/clock.c: New file. * sysdeps/unix/sysv/linux/timebits.h: Define CLOCKS_PER_SEC as 1000000 per X/Open standard. * features.h: Add code to recognize _POSIX_C_SOURCE value 199309. Define __USE_POSIX199309. * posix/unistd.h: Declare fdatasync only if __USE_POSIX199309. * time/time.c: Declare nanosleep only if __USE_POSIX199309. Patches by Rüdiger Helsch <rh@unifix.de>. * locale/locale.h: Add declaration of newlocale and freelocale. * new-malloc/Makefile (distibute): Add mtrace.awk. (dist-routines): Add mcheck and mtrace. (install-lib, non-lib.a): Define as libmcheck.a. * new-malloc/malloc.h: Add declaration of __malloc_initialized. * new-malloc/mcheck.c: New file. * new-malloc/mcheck.h: New file. * new-malloc/mtrace.c: New file. * new-malloc/mtrace.awk: New file. * posix/unistd.h: Correct prototype for usleep. * sysdeps/unix/bsd/usleep.c: De-ANSI-declfy. Correct return type. * sysdeps/unix/sysv/linux/usleep.c: Real implementation based on nanosleep. * signal/signal.h: Change protoype of __sigpause to take two arguments. Remove prototype for sigpause. Add two different macros named sigpause selected when __USE_BSD or __USE_XOPEN are defined. This is necessary since the old BSD definition of theis function collides with the X/Open definition. * sysdeps/posix/sigpause.c: Change function definition to also fit X/Open definition. * sysdeps/libm-i387/e_exp.S: Make sure stack is empty when the function is left. * sysdeps/libm-i387/e_expl.S: Likewise. Patch by HJ Lu. 1996-12-17 Paul Eggert <eggert@twinsun.com> * many, many files: Spelling corrections. * catgets/catgetsinfo.h (mmapped): Renamed from mmaped (in struct catalog_info.status). * mach/err_kern.sub (err_codes_unix), string/stratcliff.c (main): Fix spelling in message. * po/libc.pot: Fix spelling in message for `zic'; this anticipates a fix in the tzcode distribution. Wed Dec 18 15:48:02 1996 Ulrich Drepper <drepper@cygnus.com> * time/strftime.c: Implement ^ flag to cause output be converted to use upper case characters. * time/zic.c: Update from ADO tzcode1996n. Wed Dec 18 14:29:24 1996 Erik Naggum <erik@naggum.no> * time/strftime.c (add): Don't change global `i' until all is over. Define NULL is not already defined. Tue Dec 17 09:49:03 1996 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * libio/iovsprintf.c (_IO_vsprintf): Change `&sf' to `&sf._sbf._f' to avoid the need for a cast. * libio/iovsscanf.c (_IO_vsscanf): Likewise. * sunrpc/rpc/xdr.h: Add prototype for xdr_free.
Diffstat (limited to 'malloc')
-rw-r--r--malloc/Makefile18
-rw-r--r--malloc/malloc.c21
-rw-r--r--malloc/malloc.h3
-rw-r--r--malloc/mcheck-init.c30
-rw-r--r--malloc/mcheck.c232
-rw-r--r--malloc/mcheck.h70
-rw-r--r--malloc/mtrace.awk50
-rw-r--r--malloc/mtrace.c211
8 files changed, 622 insertions, 13 deletions
diff --git a/malloc/Makefile b/malloc/Makefile
index 63fe786168..c98bea686c 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -27,15 +27,27 @@ dist-headers := malloc.h
headers := $(dist-headers) obstack.h
tests := mallocbug
-distribute = thread-m.h
+distribute = thread-m.h mtrace.awk
# Things which get pasted together into gmalloc.c.
gmalloc-routines := malloc morecore
# Things to include in the standalone distribution.
-dist-routines = $(gmalloc-routines)
+dist-routines = $(gmalloc-routines) mcheck mtrace
routines = $(dist-routines) obstack
+install-lib := libmcheck.a
+non-lib.a := libmcheck.a
+
+# These should be removed by `make clean'.
+extra-objs = mcheck-init.o libmcheck.a
+
include ../Rules
+$(objpfx)libmcheck.a: $(objpfx)mcheck-init.o
+ -rm -f $@
+ ln $< $@
+
+lib: $(objpfx)libmcheck.a
+
+
CPPFLAGS-malloc.o += -DMALLOC_DEBUG
-CFLAGS-obstack.c = -Wno-strict-prototypes
diff --git a/malloc/malloc.c b/malloc/malloc.c
index c2a94a4f8d..840655f4db 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -140,7 +140,7 @@
Maximum overhead wastage per allocated chunk: normally 15 bytes
- Alignnment demands, plus the minimum allocatable size restriction
+ Alignment demands, plus the minimum allocatable size restriction
make the normal worst-case wastage 15 bytes (i.e., up to 15
more bytes will be allocated than were requested in malloc), with
two exceptions:
@@ -343,7 +343,7 @@ extern "C" {
checking is fairly extensive, and will slow down execution
noticeably. Calling malloc_stats or mallinfo with MALLOC_DEBUG set will
attempt to check every non-mmapped allocated and free chunk in the
- course of computing the summmaries. (By nature, mmapped regions
+ course of computing the summaries. (By nature, mmapped regions
cannot be checked very much automatically.)
Setting MALLOC_DEBUG may also be helpful if you are trying to modify
@@ -999,7 +999,7 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
the malloc code, but "mem" is the pointer that is returned to the
user. "Nextchunk" is the beginning of the next contiguous chunk.
- Chunks always begin on even word boundries, so the mem portion
+ Chunks always begin on even word boundaries, so the mem portion
(which is returned to the user) is also on an even word boundary, and
thus double-word aligned.
@@ -1144,7 +1144,7 @@ typedef struct _arena {
} arena;
-/* A heap is a single contiguous memory region holding (coalescable)
+/* A heap is a single contiguous memory region holding (coalesceable)
malloc_chunks. It is allocated with mmap() and always starts at an
address aligned to HEAP_MAX_SIZE. Not used unless compiling for
multiple threads. */
@@ -1489,6 +1489,8 @@ static unsigned long max_mmapped_mem = 0;
+/* Already initialized? */
+int __malloc_initialized;
/* Initialization routine. */
@@ -1504,13 +1506,12 @@ void
ptmalloc_init __MALLOC_P((void))
#endif
{
- static int first = 1;
#if defined(_LIBC) || defined(MALLOC_HOOKS)
const char* s;
#endif
- if(!first) return;
- first = 0;
+ if(__malloc_initialized) return;
+ __malloc_initialized = 1;
#if defined(_LIBC)
/* Initialize the pthreads interface. */
if (__pthread_initialize != NULL)
@@ -3589,7 +3590,7 @@ dump_heap(heap) heap_info *heap;
malloc_stats:
- For all arenas seperately and in total, prints on stderr the
+ For all arenas separately and in total, prints on stderr the
amount of space obtained from the system, and the current number
of bytes allocated via malloc (or realloc, etc) but not yet
freed. (Note that this is the number of bytes allocated, not the
@@ -3964,10 +3965,10 @@ History:
Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
* Use last_remainder in more cases.
* Pack bins using idea from colin@nyx10.cs.du.edu
- * Use ordered bins instead of best-fit threshhold
+ * Use ordered bins instead of best-fit threshold
* Eliminate block-local decls to simplify tracing and debugging.
* Support another case of realloc via move into top
- * Fix error occuring when initial sbrk_base not word-aligned.
+ * Fix error occurring when initial sbrk_base not word-aligned.
* Rely on page size for units instead of SBRK_UNIT to
avoid surprises about sbrk alignment conventions.
* Add mallinfo, mallopt. Thanks to Raymond Nijssen
diff --git a/malloc/malloc.h b/malloc/malloc.h
index ad36ca7592..ddbc694491 100644
--- a/malloc/malloc.h
+++ b/malloc/malloc.h
@@ -73,6 +73,9 @@
extern "C" {
#endif
+/* Nonzero if the malloc is already initialized. */
+extern int __malloc_initialized;
+
/* Initialize global configuration. Not needed with GNU libc. */
#ifndef __GLIBC__
extern void ptmalloc_init __MALLOC_P ((void));
diff --git a/malloc/mcheck-init.c b/malloc/mcheck-init.c
new file mode 100644
index 0000000000..a1cb7c9e39
--- /dev/null
+++ b/malloc/mcheck-init.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 1991, 1994, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C 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.
+
+The GNU C 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 the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* The object of this file should be installed as libmcheck.a,
+ so one can do -lmcheck to turn on mcheck. */
+
+#include <malloc.h>
+
+static void
+turn_on_mcheck __P ((void))
+{
+ mcheck (NULL);
+}
+
+void (*__malloc_initialize_hook) __P ((void)) = turn_on_mcheck;
diff --git a/malloc/mcheck.c b/malloc/mcheck.c
new file mode 100644
index 0000000000..7f1112ea8b
--- /dev/null
+++ b/malloc/mcheck.c
@@ -0,0 +1,232 @@
+/* Standard debugging hooks for `malloc'.
+ Copyright (C) 1990,91,92,93,94,95,96 Free Software Foundation, Inc.
+ Written May 1989 by Mike Haertel.
+
+ 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#include <mcheck.h>
+#include <stdio.h>
+#endif
+
+/* Old hook values. */
+static void (*old_free_hook) __P ((__ptr_t ptr));
+static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size));
+static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size));
+
+/* Function to call when something awful happens. */
+static void (*abortfunc) __P ((enum mcheck_status));
+
+/* Arbitrary magical numbers. */
+#define MAGICWORD 0xfedabeeb
+#define MAGICFREE 0xd8675309
+#define MAGICBYTE ((char) 0xd7)
+#define MALLOCFLOOD ((char) 0x93)
+#define FREEFLOOD ((char) 0x95)
+
+struct hdr
+ {
+ __malloc_size_t size; /* Exact size requested by user. */
+ unsigned long int magic; /* Magic number to check header integrity. */
+ };
+
+#if defined(_LIBC) || defined(STDC_HEADERS) || defined(USG)
+#define flood memset
+#else
+static void flood __P ((__ptr_t, int, __malloc_size_t));
+static void
+flood (ptr, val, size)
+ __ptr_t ptr;
+ int val;
+ __malloc_size_t size;
+{
+ char *cp = ptr;
+ while (size--)
+ *cp++ = val;
+}
+#endif
+
+static enum mcheck_status checkhdr __P ((const struct hdr *));
+static enum mcheck_status
+checkhdr (hdr)
+ const struct hdr *hdr;
+{
+ enum mcheck_status status;
+ switch (hdr->magic)
+ {
+ default:
+ status = MCHECK_HEAD;
+ break;
+ case MAGICFREE:
+ status = MCHECK_FREE;
+ break;
+ case MAGICWORD:
+ if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
+ status = MCHECK_TAIL;
+ else
+ status = MCHECK_OK;
+ break;
+ }
+ if (status != MCHECK_OK)
+ (*abortfunc) (status);
+ return status;
+}
+
+static void freehook __P ((__ptr_t));
+static void
+freehook (ptr)
+ __ptr_t ptr;
+{
+ if (ptr)
+ {
+ struct hdr *hdr = ((struct hdr *) ptr) - 1;
+ checkhdr (hdr);
+ hdr->magic = MAGICFREE;
+ flood (ptr, FREEFLOOD, hdr->size);
+ ptr = (__ptr_t) hdr;
+ }
+ __free_hook = old_free_hook;
+ free (ptr);
+ __free_hook = freehook;
+}
+
+static __ptr_t mallochook __P ((__malloc_size_t));
+static __ptr_t
+mallochook (size)
+ __malloc_size_t size;
+{
+ struct hdr *hdr;
+
+ __malloc_hook = old_malloc_hook;
+ hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
+ __malloc_hook = mallochook;
+ if (hdr == NULL)
+ return NULL;
+
+ hdr->size = size;
+ hdr->magic = MAGICWORD;
+ ((char *) &hdr[1])[size] = MAGICBYTE;
+ flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
+ return (__ptr_t) (hdr + 1);
+}
+
+static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t));
+static __ptr_t
+reallochook (ptr, size)
+ __ptr_t ptr;
+ __malloc_size_t size;
+{
+ struct hdr *hdr;
+ __malloc_size_t osize;
+
+ if (ptr)
+ {
+ hdr = ((struct hdr *) ptr) - 1;
+ osize = hdr->size;
+
+ checkhdr (hdr);
+ if (size < osize)
+ flood ((char *) ptr + size, FREEFLOOD, osize - size);
+ }
+ else
+ {
+ osize = 0;
+ hdr = NULL;
+ }
+ __free_hook = old_free_hook;
+ __malloc_hook = old_malloc_hook;
+ __realloc_hook = old_realloc_hook;
+ hdr = (struct hdr *) realloc ((__ptr_t) hdr, sizeof (struct hdr) + size + 1);
+ __free_hook = freehook;
+ __malloc_hook = mallochook;
+ __realloc_hook = reallochook;
+ if (hdr == NULL)
+ return NULL;
+
+ hdr->size = size;
+ hdr->magic = MAGICWORD;
+ ((char *) &hdr[1])[size] = MAGICBYTE;
+ if (size > osize)
+ flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
+ return (__ptr_t) (hdr + 1);
+}
+
+static void mabort __P ((enum mcheck_status status));
+static void
+mabort (status)
+ enum mcheck_status status;
+{
+ const char *msg;
+ switch (status)
+ {
+ case MCHECK_OK:
+ msg = _("memory is consistent, library is buggy");
+ break;
+ case MCHECK_HEAD:
+ msg = _("memory clobbered before allocated block");
+ break;
+ case MCHECK_TAIL:
+ msg = _("memory clobbered past end of allocated block");
+ break;
+ case MCHECK_FREE:
+ msg = _("block freed twice");
+ break;
+ default:
+ msg = _("bogus mcheck_status, library is buggy");
+ break;
+ }
+#ifdef _LIBC
+ __libc_fatal (msg);
+#else
+ fprintf (stderr, "mcheck: %s\n", msg);
+ fflush (stderr);
+ abort ();
+#endif
+}
+
+static int mcheck_used = 0;
+
+int
+mcheck (func)
+ void (*func) __P ((enum mcheck_status));
+{
+ abortfunc = (func != NULL) ? func : &mabort;
+
+ /* These hooks may not be safely inserted if malloc is already in use. */
+ if (!__malloc_initialized && !mcheck_used)
+ {
+ old_free_hook = __free_hook;
+ __free_hook = freehook;
+ old_malloc_hook = __malloc_hook;
+ __malloc_hook = mallochook;
+ old_realloc_hook = __realloc_hook;
+ __realloc_hook = reallochook;
+ mcheck_used = 1;
+ }
+
+ return mcheck_used ? 0 : -1;
+}
+
+enum mcheck_status
+mprobe (__ptr_t ptr)
+{
+ return mcheck_used ? checkhdr (ptr) : MCHECK_DISABLED;
+}
diff --git a/malloc/mcheck.h b/malloc/mcheck.h
new file mode 100644
index 0000000000..17ab0a9ced
--- /dev/null
+++ b/malloc/mcheck.h
@@ -0,0 +1,70 @@
+/* Copyright (C) 1996 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C 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.
+
+ The GNU C 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 the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _MCHECK_H
+#define _MCHECK_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef __P
+#define __P(args) args
+#undef __ptr_t
+#define __ptr_t void *
+#else /* Not C++ or ANSI C. */
+#undef __P
+#define __P(args) ()
+#undef __ptr_t
+#define __ptr_t char *
+#endif /* C++ or ANSI C. */
+
+
+/* Return values for `mprobe': these are the kinds of inconsistencies that
+ `mcheck' enables detection of. */
+enum mcheck_status
+ {
+ MCHECK_DISABLED = -1, /* Consistency checking is not turned on. */
+ MCHECK_OK, /* Block is fine. */
+ MCHECK_FREE, /* Block freed twice. */
+ MCHECK_HEAD, /* Memory before the block was clobbered. */
+ MCHECK_TAIL /* Memory after the block was clobbered. */
+ };
+
+
+/* Activate a standard collection of debugging hooks. This must be called
+ before `malloc' is ever called. ABORTFUNC is called with an error code
+ (see enum above) when an inconsistency is detected. If ABORTFUNC is
+ null, the standard function prints on stderr and then calls `abort'. */
+extern int mcheck __P ((void (*__abortfunc) __P ((enum mcheck_status))));
+
+/* Check for aberrations in a particular malloc'd block. You must have
+ called `mcheck' already. These are the same checks that `mcheck' does
+ when you free or reallocate a block. */
+extern enum mcheck_status mprobe __P ((__ptr_t __ptr));
+
+/* Activate a standard collection of tracing hooks. */
+extern void mtrace __P ((void));
+extern void muntrace __P ((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* mcheck.h */
diff --git a/malloc/mtrace.awk b/malloc/mtrace.awk
new file mode 100644
index 0000000000..06844d1a4b
--- /dev/null
+++ b/malloc/mtrace.awk
@@ -0,0 +1,50 @@
+#
+# Awk program to analyze mtrace.c output.
+#
+{
+ if ($1 == "@") {
+ where = " (" $2 ")"
+ n = 3
+ } else {
+ where = ""
+ n = 1
+ }
+ if ($n == "+") {
+ if (allocated[$(n+1)] != "")
+ print "+", $(n+1), "Alloc", NR, "duplicate:", allocated[$(n+1)], wherewas[$(n+1)], where;
+ else {
+ wherewas[$(n+1)] = where;
+ allocated[$(n+1)] = $(n+2);
+ }
+ } else if ($n == "-") {
+ if (allocated[$(n+1)] != "") {
+ wherewas[$(n+1)] = "";
+ allocated[$(n+1)] = "";
+ if (allocated[$(n+1)] != "")
+ print "DELETE FAILED", $(n+1), allocated[$(n+1)];
+ } else
+ print "-", $(n+1), "Free", NR, "was never alloc'd", where;
+ } else if ($n == "<") {
+ if (allocated[$(n+1)] != "") {
+ wherewas[$(n+1)] = "";
+ allocated[$(n+1)] = "";
+ } else
+ print "-", $(n+1), "Realloc", NR, "was never alloc'd", where;
+ } else if ($n == ">") {
+ if (allocated[$(n+1)] != "")
+ print "+", $(n+1), "Realloc", NR, "duplicate:", allocated[$(n+1)], where;
+ else {
+ wherewas[$(n+1)] = $(n+2);
+ allocated[$(n+1)] = $(n+2);
+ }
+ } else if ($n == "=") {
+ # Ignore "= Start"
+ } else if ($n == "!") {
+ # Ignore failed realloc attempts for now
+ }
+}
+END {
+ for (x in allocated)
+ if (allocated[x] != "")
+ print "+", x, allocated[x], wherewas[x];
+}
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
new file mode 100644
index 0000000000..35380a09a1
--- /dev/null
+++ b/malloc/mtrace.c
@@ -0,0 +1,211 @@
+/* More debugging hooks for `malloc'.
+ Copyright (C) 1991, 1992, 1993, 1994, 1996 Free Software Foundation, Inc.
+ Written April 2, 1991 by John Gilmore of Cygnus Support.
+ Based on mcheck.c by Mike Haertel.
+
+ 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; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#ifndef _MALLOC_INTERNAL
+#define _MALLOC_INTERNAL
+#include <malloc.h>
+#include <mcheck.h>
+#include <libc-lock.h>
+#endif
+
+#include <stdio.h>
+
+#ifndef __GNU_LIBRARY__
+extern char *getenv ();
+#else
+#include <stdlib.h>
+#endif
+
+static FILE *mallstream;
+static char mallenv[]= "MALLOC_TRACE";
+static char mallbuf[BUFSIZ]; /* Buffer for the output. */
+
+__libc_lock_define_initialized (static, lock);
+
+/* Address to breakpoint on accesses to... */
+__ptr_t mallwatch;
+
+/* File name and line number information, for callers that had
+ the foresight to call through a macro. */
+char *_mtrace_file;
+int _mtrace_line;
+
+/* Old hook values. */
+static void (*tr_old_free_hook) __P ((__ptr_t ptr));
+static __ptr_t (*tr_old_malloc_hook) __P ((__malloc_size_t size));
+static __ptr_t (*tr_old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size));
+
+/* This function is called when the block being alloc'd, realloc'd, or
+ freed has an address matching the variable "mallwatch". In a debugger,
+ set "mallwatch" to the address of interest, then put a breakpoint on
+ tr_break. */
+
+void tr_break __P ((void));
+void
+tr_break ()
+{
+}
+
+static void tr_where __P ((void));
+static void
+tr_where ()
+{
+ if (_mtrace_file)
+ {
+ fprintf (mallstream, "@ %s:%d ", _mtrace_file, _mtrace_line);
+ _mtrace_file = NULL;
+ }
+}
+
+static void tr_freehook __P ((__ptr_t));
+static void
+tr_freehook (ptr)
+ __ptr_t ptr;
+{
+ tr_where ();
+ fprintf (mallstream, "- %p\n", ptr); /* Be sure to print it first. */
+ if (ptr == mallwatch)
+ tr_break ();
+ __libc_lock_lock (lock);
+ __free_hook = tr_old_free_hook;
+ free (ptr);
+ __free_hook = tr_freehook;
+ __libc_lock_unlock (lock);
+}
+
+static __ptr_t tr_mallochook __P ((__malloc_size_t));
+static __ptr_t
+tr_mallochook (size)
+ __malloc_size_t size;
+{
+ __ptr_t hdr;
+
+ __libc_lock_lock (lock);
+
+ __malloc_hook = tr_old_malloc_hook;
+ hdr = (__ptr_t) malloc (size);
+ __malloc_hook = tr_mallochook;
+
+ __libc_lock_unlock (lock);
+
+ tr_where ();
+ /* We could be printing a NULL here; that's OK. */
+ fprintf (mallstream, "+ %p %lx\n", hdr, (unsigned long)size);
+
+ if (hdr == mallwatch)
+ tr_break ();
+
+ return hdr;
+}
+
+static __ptr_t tr_reallochook __P ((__ptr_t, __malloc_size_t));
+static __ptr_t
+tr_reallochook (ptr, size)
+ __ptr_t ptr;
+ __malloc_size_t size;
+{
+ __ptr_t hdr;
+
+ if (ptr == mallwatch)
+ tr_break ();
+
+ __libc_lock_lock (lock);
+
+ __free_hook = tr_old_free_hook;
+ __malloc_hook = tr_old_malloc_hook;
+ __realloc_hook = tr_old_realloc_hook;
+ hdr = (__ptr_t) realloc (ptr, size);
+ __free_hook = tr_freehook;
+ __malloc_hook = tr_mallochook;
+ __realloc_hook = tr_reallochook;
+
+ __libc_lock_unlock (lock);
+
+ tr_where ();
+ if (hdr == NULL)
+ /* Failed realloc. */
+ fprintf (mallstream, "! %p %lx\n", ptr, (unsigned long)size);
+ else if (ptr == NULL)
+ fprintf (mallstream, "+ %p %lx\n", hdr, (unsigned long)size);
+ else
+ fprintf (mallstream, "< %p\n> %p %lx\n", ptr, hdr, (unsigned long)size);
+
+ if (hdr == mallwatch)
+ tr_break ();
+
+ return hdr;
+}
+
+/* We enable tracing if either the environment variable MALLOC_TRACE
+ is set, or if the variable mallwatch has been patched to an address
+ that the debugging user wants us to stop on. When patching mallwatch,
+ don't forget to set a breakpoint on tr_break! */
+
+void
+mtrace ()
+{
+ char *mallfile;
+
+ /* Don't panic if we're called more than once. */
+ if (mallstream != NULL)
+ return;
+
+#ifdef _LIBC
+ /* When compiling the GNU libc we use the secure getenv function
+ which prevents the misuse in case of SUID or SGID enabled
+ programs. */
+ mallfile = __secure_getenv (mallenv);
+#else
+ mallfile = getenv (mallenv);
+#endif
+ if (mallfile != NULL || mallwatch != NULL)
+ {
+ mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "w");
+ if (mallstream != NULL)
+ {
+ /* Be sure it doesn't malloc its buffer! */
+ setbuf (mallstream, mallbuf);
+ fprintf (mallstream, "= Start\n");
+ tr_old_free_hook = __free_hook;
+ __free_hook = tr_freehook;
+ tr_old_malloc_hook = __malloc_hook;
+ __malloc_hook = tr_mallochook;
+ tr_old_realloc_hook = __realloc_hook;
+ __realloc_hook = tr_reallochook;
+ }
+ }
+}
+
+void
+muntrace ()
+{
+ if (mallstream == NULL)
+ return;
+
+ fprintf (mallstream, "= End\n");
+ fclose (mallstream);
+ mallstream = NULL;
+ __free_hook = tr_old_free_hook;
+ __malloc_hook = tr_old_malloc_hook;
+ __realloc_hook = tr_old_realloc_hook;
+}