diff options
Diffstat (limited to 'malloc')
-rw-r--r-- | malloc/Makefile | 18 | ||||
-rw-r--r-- | malloc/malloc.c | 21 | ||||
-rw-r--r-- | malloc/malloc.h | 3 | ||||
-rw-r--r-- | malloc/mcheck-init.c | 30 | ||||
-rw-r--r-- | malloc/mcheck.c | 232 | ||||
-rw-r--r-- | malloc/mcheck.h | 70 | ||||
-rw-r--r-- | malloc/mtrace.awk | 50 | ||||
-rw-r--r-- | malloc/mtrace.c | 211 |
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; +} |