Update from main archive 961219
authordrepper <drepper>
Fri, 20 Dec 1996 01:39:16 +0000 (01:39 +0000)
committerdrepper <drepper>
Fri, 20 Dec 1996 01:39:16 +0000 (01:39 +0000)
malloc/mcheck-init.c [new file with mode: 0644]
malloc/mcheck.c [new file with mode: 0644]
malloc/mcheck.h [new file with mode: 0644]
malloc/mtrace.awk [new file with mode: 0644]
malloc/mtrace.c [new file with mode: 0644]

diff --git a/malloc/mcheck-init.c b/malloc/mcheck-init.c
new file mode 100644 (file)
index 0000000..a1cb7c9
--- /dev/null
@@ -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 (file)
index 0000000..7f1112e
--- /dev/null
@@ -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 (file)
index 0000000..17ab0a9
--- /dev/null
@@ -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 (file)
index 0000000..06844d1
--- /dev/null
@@ -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 (file)
index 0000000..35380a0
--- /dev/null
@@ -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;
+}