summary refs log tree commit diff
path: root/malloc/malloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'malloc/malloc.c')
-rw-r--r--malloc/malloc.c598
1 files changed, 501 insertions, 97 deletions
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 8b99da9f28..c2a94a4f8d 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -19,7 +19,7 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-/* VERSION 2.6.4-pt Wed Dec  4 00:35:54 MET 1996
+/* V2.6.4-pt2 Sat Dec 14 1996
 
   This work is mainly derived from malloc-2.6.4 by Doug Lea
   <dl@cs.oswego.edu>, which is available from:
@@ -52,8 +52,8 @@
   ptmalloc_init();
      Initialize global configuration.  When compiled for multiple threads,
      this function must be called once before any other function in the
-     package.  It is not required otherwise. It is called automatically
-     in the Linux/GNU C libray.
+     package.  It is not required otherwise.  It is called automatically
+     in the Linux/GNU C libray or when compiling with MALLOC_HOOKS.
   malloc(size_t n);
      Return a pointer to a newly allocated chunk of at least n bytes, or null
      if no space is available.
@@ -154,7 +154,6 @@
 
     Here are some features that are NOT currently supported
 
-    * No user-definable hooks for callbacks and the like.
     * No automated mechanism for fully checking that all accesses
       to malloced memory stay within their bounds.
     * No support for compaction.
@@ -180,6 +179,9 @@
      Define to enable debugging. Adds fairly extensive assertion-based
      checking to help track down memory errors, but noticeably slows down
      execution.
+  MALLOC_HOOKS              (default: NOT defined)
+     Define to enable support run-time replacement of the allocation
+     functions through user-defined `hooks'.
   REALLOC_ZERO_BYTES_FREES (default: NOT defined)
      Define this if you think that realloc(p, 0) should be equivalent
      to free(p). Otherwise, since malloc returns a unique pointer for
@@ -234,6 +236,10 @@
      These values may also be changed dynamically via mallopt(). The
      preset defaults are those that give best performance for typical
      programs/systems.
+  DEFAULT_CHECK_ACTION
+     When the standard debugging hooks are in place, and a pointer is
+     detected as corrupt, do nothing (0), print an error message (1),
+     or call abort() (2).
 
 
 */
@@ -290,9 +296,12 @@
 #endif /*Void_t*/
 
 #if __STD_C
-#include <stddef.h>   /* for size_t */
+# include <stddef.h>   /* for size_t */
+# if defined(_LIBC) || defined(MALLOC_HOOKS)
+#  include <stdlib.h>  /* for getenv() */
+# endif
 #else
-#include <sys/types.h>
+# include <sys/types.h>
 #endif
 
 /* Macros for handling mutexes and thread-specific data.  This is
@@ -306,6 +315,13 @@ extern "C" {
 
 #include <stdio.h>    /* needed for malloc_stats */
 
+/* We must not pollute the name space in the GNU libc.  */
+#ifdef _LIBC
+#define malloc_stats __malloc_stats
+#define malloc_usable_size __malloc_usable_size
+#define malloc_trim __malloc_trim
+#endif
+
 
 /*
   Compile-time options
@@ -380,7 +396,7 @@ extern "C" {
 
 */
 
-#define HAVE_MEMCPY
+#define HAVE_MEMCPY 1
 
 #ifndef USE_MEMCPY
 #ifdef HAVE_MEMCPY
@@ -768,6 +784,16 @@ do {                                                                          \
 
 
 
+#ifndef DEFAULT_CHECK_ACTION
+#define DEFAULT_CHECK_ACTION 1
+#endif
+
+/* What to do if the standard debugging hooks are in place and a
+   corrupt pointer is detected: do nothing (0), print an error message
+   (1), or call abort() (2). */
+
+
+
 #define HEAP_MIN_SIZE (32*1024)
 #define HEAP_MAX_SIZE (1024*1024) /* must be a power of two */
 
@@ -813,6 +839,11 @@ static Void_t *(*__morecore)() = __default_morecore;
 #define MORECORE (*__morecore)
 #define MORECORE_FAILURE 0
 #define MORECORE_CLEARS 1
+#define mmap    __mmap
+#define munmap  __munmap
+#define mremap  __mremap
+#undef malloc_getpagesize
+#define malloc_getpagesize __getpagesize()
 
 #else /* _LIBC */
 
@@ -836,7 +867,7 @@ extern Void_t*     sbrk();
 
 #endif /* _LIBC */
 
-#if 0 && defined(_LIBC)
+#ifdef _LIBC
 
 #define cALLOc          __libc_calloc
 #define fREe            __libc_free
@@ -848,17 +879,6 @@ extern Void_t*     sbrk();
 #define mALLINFo        __libc_mallinfo
 #define mALLOPt         __libc_mallopt
 
-#pragma weak calloc = __libc_calloc
-#pragma weak free = __libc_free
-#pragma weak cfree = __libc_free
-#pragma weak malloc = __libc_malloc
-#pragma weak memalign = __libc_memalign
-#pragma weak realloc = __libc_realloc
-#pragma weak valloc = __libc_valloc
-#pragma weak pvalloc = __libc_pvalloc
-#pragma weak mallinfo = __libc_mallinfo
-#pragma weak mallopt = __libc_mallopt
-
 #else
 
 #define cALLOc          calloc
@@ -888,8 +908,11 @@ Void_t* vALLOc(size_t);
 Void_t* pvALLOc(size_t);
 Void_t* cALLOc(size_t, size_t);
 void    cfree(Void_t*);
+int     __malloc_trim(size_t);
 int     malloc_trim(size_t);
+size_t  __malloc_usable_size(Void_t*);
 size_t  malloc_usable_size(Void_t*);
+void    __malloc_stats(void);
 void    malloc_stats(void);
 int     mALLOPt(int, int);
 struct mallinfo mALLINFo(void);
@@ -905,8 +928,11 @@ Void_t* vALLOc();
 Void_t* pvALLOc();
 Void_t* cALLOc();
 void    cfree();
+int     __malloc_trim();
 int     malloc_trim();
+size_t  _malloc_usable_size();
 size_t  malloc_usable_size();
+void    __malloc_stats();
 void    malloc_stats();
 int     mALLOPt();
 struct mallinfo mALLINFo();
@@ -1136,19 +1162,41 @@ typedef struct _heap_info {
 */
 
 #if __STD_C
+
 static void      chunk_free(arena *ar_ptr, mchunkptr p);
 static mchunkptr chunk_alloc(arena *ar_ptr, INTERNAL_SIZE_T size);
+static mchunkptr chunk_realloc(arena *ar_ptr, mchunkptr oldp,
+			       INTERNAL_SIZE_T oldsize, INTERNAL_SIZE_T nb);
+static mchunkptr chunk_align(arena *ar_ptr, INTERNAL_SIZE_T nb,
+			     size_t alignment);
 static int       main_trim(size_t pad);
 #ifndef NO_THREADS
 static int       heap_trim(heap_info *heap, size_t pad);
 #endif
+#if defined(_LIBC) || defined(MALLOC_HOOKS)
+static Void_t*   malloc_check(size_t sz);
+static void      free_check(Void_t* mem);
+static Void_t*   realloc_check(Void_t* oldmem, size_t bytes);
+static Void_t*   memalign_check(size_t alignment, size_t bytes);
+#endif
+
 #else
+
 static void      chunk_free();
 static mchunkptr chunk_alloc();
+static mchunkptr chunk_realloc();
+static mchunkptr chunk_align();
 static int       main_trim();
 #ifndef NO_THREADS
 static int       heap_trim();
 #endif
+#if defined(_LIBC) || defined(MALLOC_HOOKS)
+static Void_t*   malloc_check();
+static void      free_check();
+static Void_t*   realloc_check();
+static Void_t*   memalign_check();
+#endif
+
 #endif
 
 
@@ -1416,6 +1464,7 @@ static unsigned long trim_threshold   = DEFAULT_TRIM_THRESHOLD;
 static unsigned long top_pad          = DEFAULT_TOP_PAD;
 static unsigned int  n_mmaps_max      = DEFAULT_MMAP_MAX;
 static unsigned long mmap_threshold   = DEFAULT_MMAP_THRESHOLD;
+static int           check_action     = DEFAULT_CHECK_ACTION;
 
 /* The first value returned from sbrk */
 static char* sbrk_base = (char*)(-1);
@@ -1444,7 +1493,9 @@ static unsigned long max_mmapped_mem = 0;
 
 /* Initialization routine. */
 #if defined(_LIBC)
+#if 0
 static void ptmalloc_init __MALLOC_P ((void)) __attribute__ ((constructor));
+#endif
 
 static void
 ptmalloc_init __MALLOC_P((void))
@@ -1454,24 +1505,103 @@ 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 defined(_LIBC)
   /* Initialize the pthreads interface. */
   if (__pthread_initialize != NULL)
     __pthread_initialize();
 #endif
-
-  if(first) {
-    first = 0;
 #ifndef NO_THREADS
-    mutex_init(&main_arena.mutex);
-    mutex_init(&list_lock);
-    tsd_key_create(&arena_key, NULL);
-    tsd_setspecific(arena_key, (Void_t *)&main_arena);
-#endif
+  mutex_init(&main_arena.mutex);
+  mutex_init(&list_lock);
+  tsd_key_create(&arena_key, NULL);
+  tsd_setspecific(arena_key, (Void_t *)&main_arena);
+#endif
+#if defined(_LIBC) || defined(MALLOC_HOOKS)
+  s = getenv("MALLOC_CHECK_");
+  if(s) {
+    if(s[0]) mallopt(M_CHECK_ACTION, (int)(s[0] - '0'));
+    malloc_check_init();
   }
+  if(__malloc_initialize_hook != NULL)
+    (*__malloc_initialize_hook)();
+#endif
 }
 
+#if defined(_LIBC) || defined(MALLOC_HOOKS)
+
+/* Hooks for debugging versions.  The initial hooks just call the
+   initialization routine, then do the normal work. */
+
+static Void_t*
+#if __STD_C
+malloc_hook_ini(size_t sz)
+#else
+malloc_hook_ini(sz) size_t sz;
+#endif
+{
+  __malloc_hook = NULL;
+  __realloc_hook = NULL;
+  __memalign_hook = NULL;
+  ptmalloc_init();
+  return mALLOc(sz);
+}
+
+static Void_t*
+#if __STD_C
+realloc_hook_ini(Void_t* ptr, size_t sz)
+#else
+realloc_hook_ini(ptr, sz) Void_t* ptr; size_t sz;
+#endif
+{
+  __malloc_hook = NULL;
+  __realloc_hook = NULL;
+  __memalign_hook = NULL;
+  ptmalloc_init();
+  return rEALLOc(ptr, sz);
+}
+
+static Void_t*
+#if __STD_C
+memalign_hook_ini(size_t sz, size_t alignment)
+#else
+memalign_hook_ini(sz, alignment) size_t sz; size_t alignment;
+#endif
+{
+  __malloc_hook = NULL;
+  __realloc_hook = NULL;
+  __memalign_hook = NULL;
+  ptmalloc_init();
+  return mEMALIGn(sz, alignment);
+}
+
+void (*__malloc_initialize_hook) __MALLOC_P ((void)) = NULL;
+void (*__free_hook) __MALLOC_P ((__malloc_ptr_t __ptr)) = NULL;
+__malloc_ptr_t (*__malloc_hook)
+ __MALLOC_P ((size_t __size)) = malloc_hook_ini;
+__malloc_ptr_t (*__realloc_hook)
+ __MALLOC_P ((__malloc_ptr_t __ptr, size_t __size)) = realloc_hook_ini;
+__malloc_ptr_t (*__memalign_hook)
+ __MALLOC_P ((size_t __size, size_t __alignment)) = memalign_hook_ini;
+
+/* Activate a standard set of debugging hooks. */
+void
+malloc_check_init()
+{
+  __malloc_hook = malloc_check;
+  __free_hook = free_check;
+  __realloc_hook = realloc_check;
+  __memalign_hook = memalign_check;
+  fprintf(stderr, "Using debugging hooks\n");
+}
+
+#endif
+
 
 
 
@@ -2224,9 +2354,19 @@ Void_t* mALLOc(bytes) size_t bytes;
 #endif
 {
   arena *ar_ptr;
-  INTERNAL_SIZE_T nb = request2size(bytes);  /* padded request size; */
+  INTERNAL_SIZE_T nb; /* padded request size */
   mchunkptr victim;
 
+#if defined(_LIBC) || defined(MALLOC_HOOKS)
+  if (__malloc_hook != NULL) {
+    Void_t* result;
+
+    result = (*__malloc_hook)(bytes);
+    return result;
+  }
+#endif
+
+  nb = request2size(bytes);
   arena_get(ar_ptr, nb + top_pad);
   if(!ar_ptr)
     return 0;
@@ -2501,6 +2641,13 @@ void fREe(mem) Void_t* mem;
   arena *ar_ptr;
   mchunkptr p;                          /* chunk corresponding to mem */
 
+#if defined(_LIBC) || defined(MALLOC_HOOKS)
+  if (__free_hook != NULL) {
+    (*__free_hook)(mem);
+    return;
+  }
+#endif
+
   if (mem == 0)                              /* free(0) has no effect */
     return;
 
@@ -2676,38 +2823,33 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
   INTERNAL_SIZE_T    oldsize; /* its size */
 
   mchunkptr newp;             /* chunk to return */
-  INTERNAL_SIZE_T    newsize; /* its size */
-  Void_t*   newmem;           /* corresponding user mem */
-
-  mchunkptr next;             /* next contiguous chunk after oldp */
-  INTERNAL_SIZE_T  nextsize;  /* its size */
 
-  mchunkptr prev;             /* previous contiguous chunk before oldp */
-  INTERNAL_SIZE_T  prevsize;  /* its size */
+#if defined(_LIBC) || defined(MALLOC_HOOKS)
+  if (__realloc_hook != NULL) {
+    Void_t* result;
 
-  mchunkptr remainder;        /* holds split off extra space from newp */
-  INTERNAL_SIZE_T  remainder_size;   /* its size */
-
-  mchunkptr bck;              /* misc temp for linking */
-  mchunkptr fwd;              /* misc temp for linking */
+    result = (*__realloc_hook)(oldmem, bytes);
+    return result;
+  }
+#endif
 
 #ifdef REALLOC_ZERO_BYTES_FREES
   if (bytes == 0) { fREe(oldmem); return 0; }
 #endif
 
-
   /* realloc of null is supposed to be same as malloc */
   if (oldmem == 0) return mALLOc(bytes);
 
-  newp    = oldp    = mem2chunk(oldmem);
-  newsize = oldsize = chunksize(oldp);
-
+  oldp    = mem2chunk(oldmem);
+  oldsize = chunksize(oldp);
 
   nb = request2size(bytes);
 
 #if HAVE_MMAP
   if (chunk_is_mmapped(oldp))
   {
+    Void_t* newmem;
+
 #if HAVE_MREMAP
     newp = mremap_chunk(oldp, nb);
     if(newp) return chunk2mem(newp);
@@ -2738,6 +2880,36 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
   /* As in malloc(), remember this arena for the next allocation. */
   tsd_setspecific(arena_key, (Void_t *)ar_ptr);
 
+  newp = chunk_realloc(ar_ptr, oldp, oldsize, nb);
+
+  (void)mutex_unlock(&ar_ptr->mutex);
+  return newp ? chunk2mem(newp) : NULL;
+}
+
+static mchunkptr
+#if __STD_C
+chunk_realloc(arena* ar_ptr, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
+             INTERNAL_SIZE_T nb)
+#else
+chunk_realloc(ar_ptr, oldp, oldsize, nb)
+arena* ar_ptr; mchunkptr oldp; INTERNAL_SIZE_T oldsize, nb;
+#endif
+{
+  mchunkptr newp = oldp;      /* chunk to return */
+  INTERNAL_SIZE_T newsize = oldsize; /* its size */
+
+  mchunkptr next;             /* next contiguous chunk after oldp */
+  INTERNAL_SIZE_T  nextsize;  /* its size */
+
+  mchunkptr prev;             /* previous contiguous chunk before oldp */
+  INTERNAL_SIZE_T  prevsize;  /* its size */
+
+  mchunkptr remainder;        /* holds split off extra space from newp */
+  INTERNAL_SIZE_T  remainder_size;   /* its size */
+
+  mchunkptr bck;              /* misc temp for linking */
+  mchunkptr fwd;              /* misc temp for linking */
+
   check_inuse_chunk(ar_ptr, oldp);
 
   if ((long)(oldsize) < (long)(nb))
@@ -2759,8 +2931,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
           top(ar_ptr) = chunk_at_offset(oldp, nb);
           set_head(top(ar_ptr), (newsize - nb) | PREV_INUSE);
           set_head_size(oldp, nb);
-          (void)mutex_unlock(&ar_ptr->mutex);
-          return chunk2mem(oldp);
+          return oldp;
         }
       }
 
@@ -2797,13 +2968,11 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
             unlink(prev, bck, fwd);
             newp = prev;
             newsize += prevsize + nextsize;
-            newmem = chunk2mem(newp);
-            MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+            MALLOC_COPY(chunk2mem(newp), chunk2mem(oldp), oldsize - SIZE_SZ);
             top(ar_ptr) = chunk_at_offset(newp, nb);
             set_head(top(ar_ptr), (newsize - nb) | PREV_INUSE);
             set_head_size(newp, nb);
-            (void)mutex_unlock(&ar_ptr->mutex);
-            return newmem;
+            return newp;
           }
         }
 
@@ -2814,8 +2983,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
           unlink(prev, bck, fwd);
           newp = prev;
           newsize += nextsize + prevsize;
-          newmem = chunk2mem(newp);
-          MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+          MALLOC_COPY(chunk2mem(newp), chunk2mem(oldp), oldsize - SIZE_SZ);
           goto split;
         }
       }
@@ -2826,8 +2994,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
         unlink(prev, bck, fwd);
         newp = prev;
         newsize += prevsize;
-        newmem = chunk2mem(newp);
-        MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+        MALLOC_COPY(chunk2mem(newp), chunk2mem(oldp), oldsize - SIZE_SZ);
         goto split;
       }
     }
@@ -2850,11 +3017,9 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
     }
 
     /* Otherwise copy, free, and exit */
-    newmem = chunk2mem(newp);
-    MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
+    MALLOC_COPY(chunk2mem(newp), chunk2mem(oldp), oldsize - SIZE_SZ);
     chunk_free(ar_ptr, oldp);
-    (void)mutex_unlock(&ar_ptr->mutex);
-    return newmem;
+    return newp;
   }
 
 
@@ -2876,8 +3041,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
   }
 
   check_inuse_chunk(ar_ptr, newp);
-  (void)mutex_unlock(&ar_ptr->mutex);
-  return chunk2mem(newp);
+  return newp;
 }
 
 
@@ -2910,14 +3074,16 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
 {
   arena *ar_ptr;
   INTERNAL_SIZE_T    nb;      /* padded  request size */
-  char*     m;                /* memory returned by malloc call */
-  mchunkptr p;                /* corresponding chunk */
-  char*     brk;              /* alignment point within p */
-  mchunkptr newp;             /* chunk to return */
-  INTERNAL_SIZE_T  newsize;   /* its size */
-  INTERNAL_SIZE_T  leadsize;  /* leading space befor alignment point */
-  mchunkptr remainder;        /* spare room at end to split off */
-  long      remainder_size;   /* its size */
+  mchunkptr p;
+
+#if defined(_LIBC) || defined(MALLOC_HOOKS)
+  if (__memalign_hook != NULL) {
+    Void_t* result;
+
+    result = (*__memalign_hook)(alignment, bytes);
+    return result;
+  }
+#endif
 
   /* If need less alignment than we give anyway, just relay to malloc */
 
@@ -2927,18 +3093,36 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
 
   if (alignment <  MINSIZE) alignment = MINSIZE;
 
-  /* Call malloc with worst case padding to hit alignment. */
-
   nb = request2size(bytes);
   arena_get(ar_ptr, nb + alignment + MINSIZE);
   if(!ar_ptr)
     return 0;
-  p = chunk_alloc(ar_ptr, nb + alignment + MINSIZE);
+  p = chunk_align(ar_ptr, nb, alignment);
+  (void)mutex_unlock(&ar_ptr->mutex);
+  return p ? chunk2mem(p) : NULL;
+}
 
-  if (p == 0) {
-    (void)mutex_unlock(&ar_ptr->mutex);
+static mchunkptr
+#if __STD_C
+chunk_align(arena* ar_ptr, INTERNAL_SIZE_T nb, size_t alignment)
+#else
+chunk_align(ar_ptr, nb, alignment)
+arena* ar_ptr; INTERNAL_SIZE_T nb; size_t alignment;
+#endif
+{
+  char*     m;                /* memory returned by malloc call */
+  mchunkptr p;                /* corresponding chunk */
+  char*     brk;              /* alignment point within p */
+  mchunkptr newp;             /* chunk to return */
+  INTERNAL_SIZE_T  newsize;   /* its size */
+  INTERNAL_SIZE_T  leadsize;  /* leading space befor alignment point */
+  mchunkptr remainder;        /* spare room at end to split off */
+  long      remainder_size;   /* its size */
+
+  /* Call chunk_alloc with worst case padding to hit alignment. */
+  p = chunk_alloc(ar_ptr, nb + alignment + MINSIZE);
+  if (p == 0)
     return 0; /* propagate failure */
-  }
 
   m = chunk2mem(p);
 
@@ -2946,8 +3130,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
   {
 #if HAVE_MMAP
     if(chunk_is_mmapped(p)) {
-      (void)mutex_unlock(&ar_ptr->mutex);
-      return chunk2mem(p); /* nothing more to do */
+      return p; /* nothing more to do */
     }
 #endif
   }
@@ -2963,7 +3146,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
     */
 
     brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -alignment);
-    if ((long)(brk - (char*)(p)) < (long)MINSIZE) brk = brk + alignment;
+    if ((long)(brk - (char*)(p)) < (long)MINSIZE) brk += alignment;
 
     newp = (mchunkptr)brk;
     leadsize = brk - (char*)(p);
@@ -2974,8 +3157,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
     {
       newp->prev_size = p->prev_size + leadsize;
       set_head(newp, newsize|IS_MMAPPED);
-      (void)mutex_unlock(&ar_ptr->mutex);
-      return chunk2mem(newp);
+      return newp;
     }
 #endif
 
@@ -3003,9 +3185,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
   }
 
   check_inuse_chunk(ar_ptr, p);
-  (void)mutex_unlock(&ar_ptr->mutex);
-  return chunk2mem(p);
-
+  return p;
 }
 
 
@@ -3044,7 +3224,7 @@ Void_t* pvALLOc(bytes) size_t bytes;
 
 /*
 
-  calloc calls malloc, then zeroes out the allocated chunk.
+  calloc calls chunk_alloc, then zeroes out the allocated chunk.
 
 */
 
@@ -3056,11 +3236,23 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
 {
   arena *ar_ptr;
   mchunkptr p, oldtop;
-  INTERNAL_SIZE_T csz, oldtopsize;
+  INTERNAL_SIZE_T sz, csz, oldtopsize;
   Void_t* mem;
 
-  INTERNAL_SIZE_T sz = request2size(n * elem_size);
+#if defined(_LIBC) || defined(MALLOC_HOOKS)
+  if (__malloc_hook != NULL) {
+    sz = n * elem_size;
+    mem = (*__malloc_hook)(sz);
+#ifdef HAVE_MEMCPY
+    memset(mem, 0, sz);
+#else
+    while(sz > 0) mem[--sz] = 0; /* rather inefficient */
+#endif
+    return mem;
+  }
+#endif
 
+  sz = request2size(n * elem_size);
   arena_get(ar_ptr, sz);
   if(!ar_ptr)
     return 0;
@@ -3232,7 +3424,7 @@ heap_trim(heap, pad) heap_info *heap; size_t pad;
     assert(p->size == (0|PREV_INUSE)); /* must be fencepost */
     p = prev_chunk(p);
     new_size = chunksize(p) + (MINSIZE-2*SIZE_SZ);
-    assert(new_size>0 && new_size<(long int)(2*MINSIZE));
+    assert(new_size>0 && new_size<(long)(2*MINSIZE));
     if(!prev_inuse(p))
       new_size += p->prev_size;
     assert(new_size>0 && new_size<HEAP_MAX_SIZE);
@@ -3513,29 +3705,241 @@ int mALLOPt(param_number, value) int param_number; int value;
 #else
       if (value != 0) return 0; else  n_mmaps_max = value; return 1;
 #endif
+    case M_CHECK_ACTION:
+      check_action = value; return 1;
 
     default:
       return 0;
   }
 }
+
+#ifdef _LIBC
+weak_alias (__libc_calloc, __calloc) weak_alias (__libc_calloc, calloc)
+weak_alias (__libc_free, __cfree) weak_alias (__libc_free, cfree)
+weak_alias (__libc_free, __free) weak_alias (__libc_free, free)
+weak_alias (__libc_malloc, __malloc) weak_alias (__libc_malloc, malloc)
+weak_alias (__libc_memalign, __memalign) weak_alias (__libc_memalign, memalign)
+weak_alias (__libc_realloc, __realloc) weak_alias (__libc_realloc, realloc)
+weak_alias (__libc_valloc, __valloc) weak_alias (__libc_valloc, valloc)
+weak_alias (__libc_pvalloc, __pvalloc) weak_alias (__libc_pvalloc, pvalloc)
+weak_alias (__libc_mallinfo, __mallinfo) weak_alias (__libc_mallinfo, mallinfo)
+weak_alias (__libc_mallopt, __mallopt) weak_alias (__libc_mallopt, mallopt)
+
+#undef malloc_stats
+weak_alias (__malloc_stats, malloc_stats)
+#undef malloc_usable_size
+weak_alias (__malloc_usable_size, malloc_usable_size)
+#undef malloc_trim
+weak_alias (__malloc_trim, malloc_trim)
+#endif
+
+
+#if defined(_LIBC) || defined(MALLOC_HOOKS)
+
+/* A simple, standard set of debugging hooks.  Overhead is `only' one
+   byte per chunk; still this will catch most cases of double frees or
+   overruns. */
+
+#define MAGICBYTE ((char)0xd7)
 
-#if 0 && defined(_LIBC)
-weak_alias (__libc_calloc, calloc)
-weak_alias (__libc_free, cfree)
-weak_alias (__libc_free, free)
-weak_alias (__libc_malloc, malloc)
-weak_alias (__libc_memalign, memalign)
-weak_alias (__libc_realloc, realloc)
-weak_alias (__libc_valloc, valloc)
-weak_alias (__libc_pvalloc, pvalloc)
-weak_alias (__libc_mallinfo, mallinfo)
-weak_alias (__libc_mallopt, mallopt)
+/* Convert a pointer to be free()d or realloc()ed to a valid chunk
+   pointer.  If the provided pointer is not valid, return NULL.  The
+   goal here is to avoid crashes, unlike in the MALLOC_DEBUG code. */
+
+static mchunkptr
+#if __STD_C
+mem2chunk_check(Void_t* mem)
+#else
+mem2chunk_check(mem) Void_t* mem;
 #endif
+{
+  mchunkptr p;
+  INTERNAL_SIZE_T sz;
+
+  p = mem2chunk(mem);
+  if(!aligned_OK(p)) return NULL;
+  if( (char*)p>=sbrk_base && (char*)p<(sbrk_base+sbrked_mem) ) {
+    /* Must be a chunk in conventional memory. */
+    if(chunk_is_mmapped(p) ||
+       ( (sz = chunksize(p)), ((char*)p + sz)>=(sbrk_base+sbrked_mem) ) ||
+       sz<MINSIZE || sz&MALLOC_ALIGN_MASK || !inuse(p) ) return NULL;
+    if(*((char*)p + sz + (SIZE_SZ-1)) != MAGICBYTE) return NULL;
+    *((char*)p + sz + (SIZE_SZ-1)) = 0;
+  } else {
+    unsigned long offset, page_mask = malloc_getpagesize-1;
+
+    /* mmap()ed chunks have MALLOC_ALIGNMENT or higher power-of two
+       alignment relative to the beginning of a page.  Check this
+       first. */
+    offset = (unsigned long)mem & page_mask;
+    if((offset!=MALLOC_ALIGNMENT && offset!=0 && offset!=0x10 &&
+       offset!=0x20 && offset!=0x40 && offset!=0x80 && offset!=0x100 &&
+       offset!=0x200 && offset!=0x400 && offset!=0x800 && offset!=0x1000 &&
+       offset<0x2000) ||
+       !chunk_is_mmapped(p) || (p->size & PREV_INUSE) ||
+       ( (((unsigned long)p - p->prev_size) & page_mask) != 0 ) ||
+       ( (sz = chunksize(p)), ((p->prev_size + sz) & page_mask) != 0 ) )
+      return NULL;
+    if(*((char*)p + sz - 1) != MAGICBYTE) return NULL;
+    *((char*)p + sz - 1) = 0;
+  }
+  return p;
+}
+
+static Void_t*
+#if __STD_C
+malloc_check(size_t sz)
+#else
+malloc_check(sz) size_t sz;
+#endif
+{
+  mchunkptr victim;
+  INTERNAL_SIZE_T nb = request2size(sz + 1);
+
+  (void)mutex_lock(&main_arena.mutex);
+  victim = chunk_alloc(&main_arena, nb);
+  (void)mutex_unlock(&main_arena.mutex);
+  if(!victim) return NULL;
+  nb = chunksize(victim);
+  if(chunk_is_mmapped(victim))
+    --nb;
+  else
+    nb += SIZE_SZ - 1;
+  *((char*)victim + nb) = MAGICBYTE;
+  return chunk2mem(victim);
+}
+
+static void
+#if __STD_C
+free_check(Void_t* mem)
+#else
+free_check(mem) Void_t* mem;
+#endif
+{
+  mchunkptr p;
+
+  if(!mem) return;
+  p = mem2chunk_check(mem);
+  if(!p) {
+    switch(check_action) {
+    case 1:
+      fprintf(stderr, "free(): invalid pointer %lx!\n", (long)(mem));
+      break;
+    case 2:
+      abort();
+    }
+    return;
+  }
+#if HAVE_MMAP
+  if (chunk_is_mmapped(p)) {
+    munmap_chunk(p);
+    return;
+  }
+#endif
+  (void)mutex_lock(&main_arena.mutex);
+  chunk_free(&main_arena, p);
+  (void)mutex_unlock(&main_arena.mutex);
+}
+
+static Void_t*
+#if __STD_C
+realloc_check(Void_t* oldmem, size_t bytes)
+#else
+realloc_check(oldmem, bytes) Void_t* oldmem; size_t bytes;
+#endif
+{
+  mchunkptr oldp, newp;
+  INTERNAL_SIZE_T nb, oldsize;
+
+  if (oldmem == 0) return malloc_check(bytes);
+  oldp = mem2chunk_check(oldmem);
+  if(!oldp) {
+    switch(check_action) {
+    case 1:
+      fprintf(stderr, "realloc(): invalid pointer %lx!\n", (long)(oldmem));
+      break;
+    case 2:
+      abort();
+    }
+    return malloc_check(bytes);
+  }
+  oldsize = chunksize(oldp);
+
+  nb = request2size(bytes+1);
+
+  (void)mutex_lock(&main_arena.mutex);
+#if HAVE_MMAP
+  if (chunk_is_mmapped(oldp)) {
+#if HAVE_MREMAP
+    newp = mremap_chunk(oldp, nb);
+    if(!newp) {
+#endif
+      /* Note the extra SIZE_SZ overhead. */
+      if(oldsize - SIZE_SZ >= nb) newp = oldp; /* do nothing */
+      else {
+       /* Must alloc, copy, free. */
+       newp = chunk_alloc(&main_arena, nb);
+       if (newp) {
+         MALLOC_COPY(chunk2mem(newp), oldmem, oldsize - 2*SIZE_SZ);
+         munmap_chunk(oldp);
+       }
+      }
+#if HAVE_MREMAP
+    }
+#endif
+  } else
+#endif /* HAVE_MMAP */
+    newp = chunk_realloc(&main_arena, oldp, oldsize, nb);
+  (void)mutex_unlock(&main_arena.mutex);
+
+  if(!newp) return NULL;
+  nb = chunksize(newp);
+  if(chunk_is_mmapped(newp))
+    --nb;
+  else
+    nb += SIZE_SZ - 1;
+  *((char*)newp + nb) = MAGICBYTE;
+  return chunk2mem(newp);
+}
+
+static Void_t*
+#if __STD_C
+memalign_check(size_t alignment, size_t bytes)
+#else
+memalign_check(alignment, bytes) size_t alignment; size_t bytes;
+#endif
+{
+  INTERNAL_SIZE_T nb;
+  mchunkptr p;
+
+  if (alignment <= MALLOC_ALIGNMENT) return malloc_check(bytes);
+  if (alignment <  MINSIZE) alignment = MINSIZE;
+
+  nb = request2size(bytes+1);
+  (void)mutex_lock(&main_arena.mutex);
+  p = chunk_align(&main_arena, nb, alignment);
+  (void)mutex_unlock(&main_arena.mutex);
+  if(!p) return NULL;
+  nb = chunksize(p);
+  if(chunk_is_mmapped(p))
+    --nb;
+  else
+    nb += SIZE_SZ - 1;
+  *((char*)p + nb) = MAGICBYTE;
+  return chunk2mem(p);
+}
+
+#endif /* defined(_LIBC) || defined(MALLOC_HOOKS) */
 
 /*
 
 History:
 
+    V2.6.4-pt2 Sat Dec 14 1996 Wolfram Gloger (wmglo@dent.med.uni-muenchen.de)
+      * Added debugging hooks
+      * Fixed possible deadlock in realloc() when out of memory
+      * Don't pollute namespace in glibc: use __getpagesize, __mmap, etc.
+
     V2.6.4-pt Wed Dec  4 1996 Wolfram Gloger (wmglo@dent.med.uni-muenchen.de)
       * Very minor updates from the released 2.6.4 version.
       * Trimmed include file down to exported data structures.