X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/74ad5c7fde70fae699f0ec355c6043a28f95c660..9c0c2af5a157eca18c86f644121f7eac5488dbda:/src/gmalloc.c diff --git a/src/gmalloc.c b/src/gmalloc.c index 7e7a893923..99fa36d073 100644 --- a/src/gmalloc.c +++ b/src/gmalloc.c @@ -5,7 +5,7 @@ /* The malloc headers and source files from the C library follow here. */ /* Declarations for `malloc' and friends. - Copyright 1990, 91, 92, 93, 95, 96 Free Software Foundation, Inc. + Copyright 1990, 91, 92, 93, 95, 96, 99 Free Software Foundation, Inc. Written May 1989 by Mike Haertel. This library is free software; you can redistribute it and/or @@ -36,16 +36,16 @@ Cambridge, MA 02139, USA. #include #endif -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) -#undef __P -#define __P(args) args +#if ((defined __cplusplus || (defined (__STDC__) && __STDC__) \ + || defined STDC_HEADERS || defined PROTOTYPES) \ + && ! defined (BROKEN_PROTOTYPES)) +#undef PP +#define PP(args) args #undef __ptr_t #define __ptr_t void * #else /* Not C++ or ANSI C. */ -#undef __P -#define __P(args) () -#undef const -#define const +#undef PP +#define PP(args) () #undef __ptr_t #define __ptr_t char * #endif /* C++ or ANSI C. */ @@ -61,13 +61,12 @@ Cambridge, MA 02139, USA. #endif #endif -#if defined (__GNU_LIBRARY__) || (defined (__STDC__) && __STDC__) +#ifdef HAVE_LIMITS_H #include -#else +#endif #ifndef CHAR_BIT #define CHAR_BIT 8 #endif -#endif #ifdef HAVE_UNISTD_H #include @@ -81,12 +80,20 @@ extern "C" { #endif -#if defined (__STDC__) && __STDC__ +#ifdef STDC_HEADERS #include #define __malloc_size_t size_t #define __malloc_ptrdiff_t ptrdiff_t #else +#ifdef __GNUC__ +#include +#ifdef __SIZE_TYPE__ +#define __malloc_size_t __SIZE_TYPE__ +#endif +#endif +#ifndef __malloc_size_t #define __malloc_size_t unsigned int +#endif #define __malloc_ptrdiff_t int #endif @@ -94,26 +101,30 @@ extern "C" #define NULL 0 #endif +#ifndef FREE_RETURN_TYPE +#define FREE_RETURN_TYPE void +#endif + /* Allocate SIZE bytes of memory. */ -extern __ptr_t malloc __P ((__malloc_size_t __size)); +extern __ptr_t malloc PP ((__malloc_size_t __size)); /* Re-allocate the previously allocated block in __ptr_t, making the new block SIZE bytes long. */ -extern __ptr_t realloc __P ((__ptr_t __ptr, __malloc_size_t __size)); +extern __ptr_t realloc PP ((__ptr_t __ptr, __malloc_size_t __size)); /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ -extern __ptr_t calloc __P ((__malloc_size_t __nmemb, __malloc_size_t __size)); +extern __ptr_t calloc PP ((__malloc_size_t __nmemb, __malloc_size_t __size)); /* Free a block allocated by `malloc', `realloc' or `calloc'. */ -extern void free __P ((__ptr_t __ptr)); +extern FREE_RETURN_TYPE free PP ((__ptr_t __ptr)); /* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ #if ! (defined (_MALLOC_INTERNAL) && __DJGPP__ - 0 == 1) /* Avoid conflict. */ -extern __ptr_t memalign __P ((__malloc_size_t __alignment, - __malloc_size_t __size)); +extern __ptr_t memalign PP ((__malloc_size_t __alignment, + __malloc_size_t __size)); #endif /* Allocate SIZE bytes on a page boundary. */ #if ! (defined (_MALLOC_INTERNAL) && defined (GMALLOC_INHIBIT_VALLOC)) -extern __ptr_t valloc __P ((__malloc_size_t __size)); +extern __ptr_t valloc PP ((__malloc_size_t __size)); #endif @@ -213,26 +224,26 @@ extern __malloc_size_t _bytes_free; /* Internal versions of `malloc', `realloc', and `free' used when these functions need to call each other. They are the same but don't call the hooks. */ -extern __ptr_t _malloc_internal __P ((__malloc_size_t __size)); -extern __ptr_t _realloc_internal __P ((__ptr_t __ptr, __malloc_size_t __size)); -extern void _free_internal __P ((__ptr_t __ptr)); +extern __ptr_t _malloc_internal PP ((__malloc_size_t __size)); +extern __ptr_t _realloc_internal PP ((__ptr_t __ptr, __malloc_size_t __size)); +extern void _free_internal PP ((__ptr_t __ptr)); #endif /* _MALLOC_INTERNAL. */ /* Given an address in the middle of a malloc'd object, return the address of the beginning of the object. */ -extern __ptr_t malloc_find_object_address __P ((__ptr_t __ptr)); +extern __ptr_t malloc_find_object_address PP ((__ptr_t __ptr)); /* Underlying allocation function; successive calls should return contiguous pieces of memory. */ -extern __ptr_t (*__morecore) __P ((__malloc_ptrdiff_t __size)); +extern __ptr_t (*__morecore) PP ((__malloc_ptrdiff_t __size)); /* Default value of `__morecore'. */ -extern __ptr_t __default_morecore __P ((__malloc_ptrdiff_t __size)); +extern __ptr_t __default_morecore PP ((__malloc_ptrdiff_t __size)); /* If not NULL, this function is called after each time `__morecore' is called to increase the data size. */ -extern void (*__after_morecore_hook) __P ((void)); +extern void (*__after_morecore_hook) PP ((void)); /* Number of extra blocks to get each time we ask for more core. This reduces the frequency of calling `(*__morecore)'. */ @@ -241,15 +252,15 @@ extern __malloc_size_t __malloc_extra_blocks; /* Nonzero if `malloc' has been called and done its initialization. */ extern int __malloc_initialized; /* Function called to initialize malloc data structures. */ -extern int __malloc_initialize __P ((void)); +extern int __malloc_initialize PP ((void)); /* Hooks for debugging versions. */ -extern void (*__malloc_initialize_hook) __P ((void)); -extern void (*__free_hook) __P ((__ptr_t __ptr)); -extern __ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); -extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); -extern __ptr_t (*__memalign_hook) __P ((__malloc_size_t __size, - __malloc_size_t __alignment)); +extern void (*__malloc_initialize_hook) PP ((void)); +extern void (*__free_hook) PP ((__ptr_t __ptr)); +extern __ptr_t (*__malloc_hook) PP ((__malloc_size_t __size)); +extern __ptr_t (*__realloc_hook) PP ((__ptr_t __ptr, __malloc_size_t __size)); +extern __ptr_t (*__memalign_hook) PP ((__malloc_size_t __size, + __malloc_size_t __alignment)); /* Return values for `mprobe': these are the kinds of inconsistencies that `mcheck' enables detection of. */ @@ -266,16 +277,16 @@ enum mcheck_status 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)))); +extern int mcheck PP ((void (*__abortfunc) PP ((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)); +extern enum mcheck_status mprobe PP ((__ptr_t __ptr)); /* Activate a standard collection of tracing hooks. */ -extern void mtrace __P ((void)); -extern void muntrace __P ((void)); +extern void mtrace PP ((void)); +extern void muntrace PP ((void)); /* Statistics available to the user. */ struct mstats @@ -288,23 +299,23 @@ struct mstats }; /* Pick up the current statistics. */ -extern struct mstats mstats __P ((void)); +extern struct mstats mstats PP ((void)); /* Call WARNFUN with a warning message when memory usage is high. */ -extern void memory_warnings __P ((__ptr_t __start, - void (*__warnfun) __P ((const char *)))); +extern void memory_warnings PP ((__ptr_t __start, + void (*__warnfun) PP ((const char *)))); /* Relocating allocator. */ /* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ -extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); +extern __ptr_t r_alloc PP ((__ptr_t *__handleptr, __malloc_size_t __size)); /* Free the storage allocated in HANDLEPTR. */ -extern void r_alloc_free __P ((__ptr_t *__handleptr)); +extern void r_alloc_free PP ((__ptr_t *__handleptr)); /* Adjust the block at HANDLEPTR to be SIZE bytes long. */ -extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, __malloc_size_t __size)); +extern __ptr_t r_re_alloc PP ((__ptr_t *__handleptr, __malloc_size_t __size)); #ifdef __cplusplus @@ -341,10 +352,10 @@ Cambridge, MA 02139, USA. #include /* How to really get more memory. */ -__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore; +__ptr_t (*__morecore) PP ((ptrdiff_t __size)) = __default_morecore; /* Debugging hook for `malloc'. */ -__ptr_t (*__malloc_hook) __P ((__malloc_size_t __size)); +__ptr_t (*__malloc_hook) PP ((__malloc_size_t __size)); /* Pointer to the base of the first block. */ char *_heapbase; @@ -375,12 +386,59 @@ int __malloc_initialized; __malloc_size_t __malloc_extra_blocks; -void (*__malloc_initialize_hook) __P ((void)); -void (*__after_morecore_hook) __P ((void)); +void (*__malloc_initialize_hook) PP ((void)); +void (*__after_morecore_hook) PP ((void)); + +#if defined GC_MALLOC_CHECK && defined GC_PROTECT_MALLOC_STATE + +/* Some code for hunting a bug writing into _heapinfo. + + Call this macro with argument PROT non-zero to protect internal + malloc state against writing to it, call it with a zero argument to + make it readable and writable. + + Note that this only works if BLOCKSIZE == page size, which is + the case on the i386. */ + +#include +#include + +static int state_protected_p; +static __malloc_size_t last_state_size; +static malloc_info *last_heapinfo; + +void +protect_malloc_state (protect_p) + int protect_p; +{ + /* If _heapinfo has been relocated, make sure its old location + isn't left read-only; it will be reused by malloc. */ + if (_heapinfo != last_heapinfo + && last_heapinfo + && state_protected_p) + mprotect (last_heapinfo, last_state_size, PROT_READ | PROT_WRITE); + + last_state_size = _heaplimit * sizeof *_heapinfo; + last_heapinfo = _heapinfo; + + if (protect_p != state_protected_p) + { + state_protected_p = protect_p; + if (mprotect (_heapinfo, last_state_size, + protect_p ? PROT_READ : PROT_READ | PROT_WRITE) != 0) + abort (); + } +} + +#define PROTECT_MALLOC_STATE(PROT) protect_malloc_state(PROT) + +#else +#define PROTECT_MALLOC_STATE(PROT) /* empty */ +#endif /* Aligned allocation. */ -static __ptr_t align __P ((__malloc_size_t)); +static __ptr_t align PP ((__malloc_size_t)); static __ptr_t align (size) __malloc_size_t size; @@ -388,7 +446,14 @@ align (size) __ptr_t result; unsigned long int adj; - result = (*__morecore) (size); + /* align accepts an unsigned argument, but __morecore accepts a + signed one. This could lead to trouble if SIZE overflows a + signed int type accepted by __morecore. We just punt in that + case, since they are requesting a ludicrous amount anyway. */ + if ((__malloc_ptrdiff_t)size < 0) + result = 0; + else + result = (*__morecore) (size); adj = (unsigned long int) ((unsigned long int) ((char *) result - (char *) NULL)) % BLOCKSIZE; if (adj != 0) @@ -408,7 +473,7 @@ align (size) /* Get SIZE bytes, if we can get them starting at END. Return the address of the space we got. If we cannot get space at END, fail and return 0. */ -static __ptr_t get_contiguous_space __P ((__malloc_ptrdiff_t, __ptr_t)); +static __ptr_t get_contiguous_space PP ((__malloc_ptrdiff_t, __ptr_t)); static __ptr_t get_contiguous_space (size, position) __malloc_ptrdiff_t size; @@ -442,7 +507,7 @@ get_contiguous_space (size, position) /* This is called when `_heapinfo' and `heapsize' have just been set to describe a new info table. Set up the table to describe itself and account for it in the statistics. */ -static void register_heapinfo __P ((void)); +static void register_heapinfo PP ((void)); #ifdef __GNUC__ __inline__ #endif @@ -473,6 +538,10 @@ __malloc_initialize () if (__malloc_initialized) return 0; +#ifdef GC_MCHECK + mcheck (NULL); +#endif + if (__malloc_initialize_hook) (*__malloc_initialize_hook) (); @@ -490,6 +559,7 @@ __malloc_initialize () register_heapinfo (); __malloc_initialized = 1; + PROTECT_MALLOC_STATE (1); return 1; } @@ -497,7 +567,7 @@ static int morecore_recursing; /* Get neatly aligned memory, initializing or growing the heap info table as necessary. */ -static __ptr_t morecore __P ((__malloc_size_t)); +static __ptr_t morecore PP ((__malloc_size_t)); static __ptr_t morecore (size) __malloc_size_t size; @@ -514,6 +584,8 @@ morecore (size) if (result == NULL) return NULL; + PROTECT_MALLOC_STATE (0); + /* Check if we need to grow the info table. */ if ((__malloc_size_t) BLOCK ((char *) result + size) > heapsize) { @@ -597,6 +669,7 @@ morecore (size) it can relocate or resize the info table. */ _heaplimit = 0; _free_internal (oldinfo); + PROTECT_MALLOC_STATE (0); /* The new heap limit includes the new table just allocated. */ _heaplimit = BLOCK ((char *) newinfo + heapsize * sizeof (malloc_info)); @@ -630,6 +703,8 @@ _malloc_internal (size) return NULL; #endif + PROTECT_MALLOC_STATE (0); + if (size < sizeof (struct list)) size = sizeof (struct list); @@ -676,9 +751,17 @@ _malloc_internal (size) { /* No free fragments of the desired size, so get a new block and break it into fragments, returning the first. */ +#ifdef GC_MALLOC_CHECK + result = _malloc_internal (BLOCKSIZE); + PROTECT_MALLOC_STATE (0); +#else result = malloc (BLOCKSIZE); +#endif if (result == NULL) - return NULL; + { + PROTECT_MALLOC_STATE (1); + return NULL; + } /* Link all fragments but the first into the free list. */ next = (struct list *) ((char *) result + (1 << log)); @@ -797,6 +880,7 @@ _malloc_internal (size) _heapinfo[block + blocks].busy.info.size = -blocks; } + PROTECT_MALLOC_STATE (1); return result; } @@ -875,14 +959,14 @@ Cambridge, MA 02139, USA. #define __malloc_safe_bcopy safe_bcopy #endif /* This function is defined in realloc.c. */ -extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); +extern void __malloc_safe_bcopy PP ((__ptr_t, __ptr_t, __malloc_size_t)); #define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) #endif #endif /* Debugging hook for free. */ -void (*__free_hook) __P ((__ptr_t __ptr)); +void (*__free_hook) PP ((__ptr_t __ptr)); /* List of blocks allocated by memalign. */ struct alignlist *_aligned_blocks = NULL; @@ -907,6 +991,8 @@ _free_internal (ptr) if (ptr == NULL) return; + PROTECT_MALLOC_STATE (0); + for (l = _aligned_blocks; l != NULL; l = l->next) if (l->aligned == ptr) { @@ -1029,6 +1115,7 @@ _free_internal (ptr) /* Allocate new space for the info table and move its data. */ newinfo = (malloc_info *) _malloc_internal (info_blocks * BLOCKSIZE); + PROTECT_MALLOC_STATE (0); memmove (newinfo, _heapinfo, info_blocks * BLOCKSIZE); _heapinfo = newinfo; @@ -1090,7 +1177,11 @@ _free_internal (ptr) _chunks_free -= BLOCKSIZE >> type; _bytes_free -= BLOCKSIZE; +#ifdef GC_MALLOC_CHECK + _free_internal (ADDRESS (block)); +#else free (ADDRESS (block)); +#endif } else if (_heapinfo[block].busy.info.frag.nfree != 0) { @@ -1123,10 +1214,13 @@ _free_internal (ptr) } break; } + + PROTECT_MALLOC_STATE (1); } /* Return memory to the heap. */ -void + +FREE_RETURN_TYPE free (ptr) __ptr_t ptr; { @@ -1248,7 +1342,7 @@ __malloc_safe_bcopy (afrom, ato, size) #endif /* emacs */ #ifndef memmove -extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); +extern void __malloc_safe_bcopy PP ((__ptr_t, __ptr_t, __malloc_size_t)); #define memmove(to, from, size) __malloc_safe_bcopy ((from), (to), (size)) #endif @@ -1258,7 +1352,7 @@ extern void __malloc_safe_bcopy __P ((__ptr_t, __ptr_t, __malloc_size_t)); #define min(A, B) ((A) < (B) ? (A) : (B)) /* Debugging hook for realloc. */ -__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size)); +__ptr_t (*__realloc_hook) PP ((__ptr_t __ptr, __malloc_size_t __size)); /* Resize the given region to the new size, returning a pointer to the (possibly moved) region. This is optimized for speed; @@ -1285,6 +1379,8 @@ _realloc_internal (ptr, size) block = BLOCK (ptr); + PROTECT_MALLOC_STATE (0); + type = _heapinfo[block].busy.type; switch (type) { @@ -1333,6 +1429,7 @@ _realloc_internal (ptr, size) _heaplimit = 0; _free_internal (ptr); result = _malloc_internal (size); + PROTECT_MALLOC_STATE (0); if (_heaplimit == 0) _heaplimit = oldlimit; if (result == NULL) @@ -1376,6 +1473,7 @@ _realloc_internal (ptr, size) break; } + PROTECT_MALLOC_STATE (1); return result; } @@ -1460,7 +1558,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ systems with potentially hostile include files. */ #include -extern __ptr_t __sbrk __P ((ptrdiff_t increment)); +extern __ptr_t __sbrk PP ((ptrdiff_t increment)); #endif #ifndef NULL @@ -1508,7 +1606,8 @@ Cambridge, MA 02139, USA. */ #else -__ptr_t (*__memalign_hook) __P ((size_t __size, size_t __alignment)); +__ptr_t (*__memalign_hook) PP ((__malloc_size_t __size, + __malloc_size_t __alignment)); __ptr_t memalign (alignment, size) @@ -1612,7 +1711,11 @@ Cambridge, MA 02139, USA. #if defined (__GNU_LIBRARY__) || defined (_LIBC) #include #include -extern size_t __getpagesize __P ((void)); +#if defined (__GLIBC__) && __GLIBC__ >= 2 +/* __getpagesize is already declared in with return type int */ +#else +extern size_t __getpagesize PP ((void)); +#endif #else #include "getpagesize.h" #define __getpagesize() getpagesize() @@ -1636,3 +1739,245 @@ valloc (size) } #endif /* Not ELIDE_VALLOC. */ + +#ifdef GC_MCHECK + +/* Standard debugging hooks for `malloc'. + Copyright 1990, 1991, 1992, 1993, 1994 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., 675 Mass Ave, +Cambridge, MA 02139, 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. */ + +#ifdef emacs +#include +#else +#ifndef _MALLOC_INTERNAL +#define _MALLOC_INTERNAL +#include +#include +#endif +#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; +{ + struct hdr *hdr; + + if (ptr) + { + hdr = ((struct hdr *) ptr) - 1; + checkhdr (hdr); + hdr->magic = MAGICFREE; + flood (ptr, FREEFLOOD, hdr->size); + } + else + hdr = NULL; + + __free_hook = old_free_hook; + free (hdr); + __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 = NULL; + __malloc_size_t osize = 0; + + if (ptr) + { + hdr = ((struct hdr *) ptr) - 1; + osize = hdr->size; + + checkhdr (hdr); + if (size < osize) + flood ((char *) ptr + size, FREEFLOOD, osize - size); + } + + __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 (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 __GNU_LIBRARY__ + __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; +} + +#endif /* GC_MCHECK */ + +/* arch-tag: 93dce5c0-f49a-41b5-86b1-f91c4169c02e + (do not change this comment) */