X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/795e7a5b3202851a89a042578ee572962a723d65..249635f0dfb22bcae4c7134e95f01640a6a0d149:/src/gmalloc.c diff --git a/src/gmalloc.c b/src/gmalloc.c index bc1d85ac5f..3456ff0ec6 100644 --- a/src/gmalloc.c +++ b/src/gmalloc.c @@ -1,5 +1,5 @@ /* Declarations for `malloc' and friends. - Copyright (C) 1990-1993, 1995-1996, 1999, 2002-2007, 2013 Free + Copyright (C) 1990-1993, 1995-1996, 1999, 2002-2007, 2013-2014 Free Software Foundation, Inc. Written May 1989 by Mike Haertel. @@ -21,13 +21,18 @@ License along with this library. If not, see . #include -#ifdef HAVE_PTHREAD +#if defined HAVE_PTHREAD && !defined HYBRID_MALLOC #define USE_PTHREAD #endif #include #include #include + +#ifdef HYBRID_GET_CURRENT_DIR_NAME +#undef get_current_dir_name +#endif + #include #ifdef USE_PTHREAD @@ -38,6 +43,45 @@ License along with this library. If not, see . #include /* for sbrk */ #endif +#ifdef emacs +extern void emacs_abort (void); +#endif + +/* If HYBRID_MALLOC is defined, then temacs will use malloc, + realloc... as defined in this file (and renamed gmalloc, + grealloc... via the macros that follow). The dumped emacs, + however, will use the system malloc, realloc.... In other source + files, malloc, realloc... are renamed hybrid_malloc, + hybrid_realloc... via macros in conf_post.h. hybrid_malloc and + friends are wrapper functions defined later in this file. + aligned_alloc is defined as a macro only in alloc.c. + + As of this writing (August 2014), Cygwin is the only platform on + which HYBRID_MACRO is defined. Any other platform that wants to + define it will have to define the macros DUMPED and + ALLOCATED_BEFORE_DUMPING, defined below for Cygwin. */ +#ifdef HYBRID_MALLOC +#undef malloc +#undef realloc +#undef calloc +#undef free +#define malloc gmalloc +#define realloc grealloc +#define calloc gcalloc +#define aligned_alloc galigned_alloc +#define free gfree +#endif /* HYBRID_MALLOC */ + +#ifdef CYGWIN +extern void *bss_sbrk (ptrdiff_t size); +extern int bss_sbrk_did_unexec; +extern char bss_sbrk_buffer[]; +extern void *bss_sbrk_buffer_end; +#define DUMPED bss_sbrk_did_unexec +#define ALLOCATED_BEFORE_DUMPING(P) \ + ((P) < bss_sbrk_buffer_end && (P) >= (void *) bss_sbrk_buffer) +#endif + #ifdef __cplusplus extern "C" { @@ -47,17 +91,18 @@ extern "C" /* Allocate SIZE bytes of memory. */ -extern void *malloc (size_t size); +extern void *malloc (size_t size) ATTRIBUTE_MALLOC_SIZE ((1)); /* Re-allocate the previously allocated block in ptr, making the new block SIZE bytes long. */ -extern void *realloc (void *ptr, size_t size); +extern void *realloc (void *ptr, size_t size) ATTRIBUTE_ALLOC_SIZE ((2)); /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ -extern void *calloc (size_t nmemb, size_t size); +extern void *calloc (size_t nmemb, size_t size) ATTRIBUTE_MALLOC_SIZE ((1,2)); /* Free a block allocated by `malloc', `realloc' or `calloc'. */ extern void free (void *ptr); /* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ #ifdef MSDOS +extern void *aligned_alloc (size_t, size_t); extern void *memalign (size_t, size_t); extern int posix_memalign (void **, size_t, size_t); #endif @@ -67,6 +112,10 @@ extern int posix_memalign (void **, size_t, size_t); extern void malloc_enable_thread (void); #endif +#ifdef emacs +extern void emacs_abort (void); +#endif + /* The allocator divides the heap into blocks of fixed size; large requests receive one or more whole blocks, and small requests receive a fragment of a block. Fragment sizes are powers of two, @@ -143,11 +192,11 @@ struct list /* Free list headers for each fragment size. */ extern struct list _fraghead[]; -/* List of blocks allocated with `memalign' (or `valloc'). */ +/* List of blocks allocated with aligned_alloc and friends. */ struct alignlist { struct alignlist *next; - void *aligned; /* The address that memaligned returned. */ + void *aligned; /* The address that aligned_alloc returned. */ void *exact; /* The address that malloc returned. */ }; extern struct alignlist *_aligned_blocks; @@ -297,22 +346,6 @@ License along with this library. If not, see . #include -/* On Cygwin there are two heaps. temacs uses the static heap - (defined in sheap.c and managed with bss_sbrk), and the dumped - emacs uses the Cygwin heap (managed with sbrk). When emacs starts - on Cygwin, it reinitializes malloc, and we save the old info for - use by free and realloc if they're called with a pointer into the - static heap. - - Currently (2011-08-16) the Cygwin build doesn't use ralloc.c; if - this is changed in the future, we'll have to similarly deal with - reinitializing ralloc. */ -#ifdef CYGWIN -extern void *bss_sbrk (ptrdiff_t size); -extern int bss_sbrk_did_unexec; -char *bss_sbrk_heapbase; /* _heapbase for static heap */ -malloc_info *bss_sbrk_heapinfo; /* _heapinfo for static heap */ -#endif void *(*__morecore) (ptrdiff_t size) = __default_morecore; /* Debugging hook for `malloc'. */ @@ -524,7 +557,7 @@ malloc_enable_thread (void) malloc_atfork_handler_child); _malloc_thread_enabled_p = 1; } -#endif +#endif /* USE_PTHREAD */ static void malloc_initialize_1 (void) @@ -533,16 +566,6 @@ malloc_initialize_1 (void) mcheck (NULL); #endif -#ifdef CYGWIN - if (bss_sbrk_did_unexec) - /* we're reinitializing the dumped emacs */ - { - bss_sbrk_heapbase = _heapbase; - bss_sbrk_heapinfo = _heapinfo; - memset (_fraghead, 0, BLOCKLOG * sizeof (struct list)); - } -#endif - if (__malloc_initialize_hook) (*__malloc_initialize_hook) (); @@ -977,7 +1000,7 @@ License along with this library. If not, see . /* Debugging hook for free. */ void (*__free_hook) (void *__ptr); -/* List of blocks allocated by memalign. */ +/* List of blocks allocated by aligned_alloc. */ struct alignlist *_aligned_blocks = NULL; /* Return memory to the heap. @@ -999,12 +1022,6 @@ _free_internal_nolock (void *ptr) if (ptr == NULL) return; -#ifdef CYGWIN - if ((char *) ptr < _heapbase) - /* We're being asked to free something in the static heap. */ - return; -#endif - PROTECT_MALLOC_STATE (0); LOCK_ALIGNED_BLOCKS (); @@ -1286,30 +1303,7 @@ License along with this library. If not, see . or (US mail) as Mike Haertel c/o Free Software Foundation. */ #ifndef min -#define min(A, B) ((A) < (B) ? (A) : (B)) -#endif - -/* On Cygwin the dumped emacs may try to realloc storage allocated in - the static heap. We just malloc space in the new heap and copy the - data. */ -#ifdef CYGWIN -void * -special_realloc (void *ptr, size_t size) -{ - void *result; - int type; - size_t block, oldsize; - - block = ((char *) ptr - bss_sbrk_heapbase) / BLOCKSIZE + 1; - type = bss_sbrk_heapinfo[block].busy.type; - oldsize = - type == 0 ? bss_sbrk_heapinfo[block].busy.info.size * BLOCKSIZE - : (size_t) 1 << type; - result = _malloc_internal_nolock (size); - if (result != NULL) - memcpy (result, ptr, min (oldsize, size)); - return result; -} +#define min(a, b) ((a) < (b) ? (a) : (b)) #endif /* Debugging hook for realloc. */ @@ -1336,12 +1330,6 @@ _realloc_internal_nolock (void *ptr, size_t size) else if (ptr == NULL) return _malloc_internal_nolock (size); -#ifdef CYGWIN - if ((char *) ptr < _heapbase) - /* ptr points into the static heap */ - return special_realloc (ptr, size); -#endif - block = BLOCK (ptr); PROTECT_MALLOC_STATE (0); @@ -1487,13 +1475,20 @@ License along with this library. If not, see . /* Allocate an array of NMEMB elements each SIZE bytes long. The entire array is initialized to zeros. */ void * -calloc (register size_t nmemb, register size_t size) +calloc (size_t nmemb, size_t size) { - register void *result = malloc (nmemb * size); + void *result; + size_t bytes = nmemb * size; - if (result != NULL) - (void) memset (result, 0, nmemb * size); + if (size != 0 && bytes / size != nmemb) + { + errno = ENOMEM; + return NULL; + } + result = malloc (bytes); + if (result) + return memset (result, 0, bytes); return result; } /* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. @@ -1531,7 +1526,7 @@ __default_morecore (ptrdiff_t increment) { void *result; #if defined (CYGWIN) - if (!bss_sbrk_did_unexec) + if (!DUMPED) { return bss_sbrk (increment); } @@ -1559,7 +1554,7 @@ License along with this library. If not, see . * void *(*__memalign_hook) (size_t size, size_t alignment); void * -memalign (size_t alignment, size_t size) +aligned_alloc (size_t alignment, size_t size) { void *result; size_t adj, lastadj; @@ -1570,29 +1565,43 @@ memalign (size_t alignment, size_t size) /* Allocate a block with enough extra space to pad the block with up to (ALIGNMENT - 1) bytes if necessary. */ + if (- size < alignment) + { + errno = ENOMEM; + return NULL; + } result = malloc (size + alignment - 1); if (result == NULL) return NULL; /* Figure out how much we will need to pad this particular block to achieve the required alignment. */ - adj = (uintptr_t) result % alignment; + adj = alignment - (uintptr_t) result % alignment; + if (adj == alignment) + adj = 0; - do + if (adj != alignment - 1) { - /* Reallocate the block with only as much excess as it needs. */ - free (result); - result = malloc (adj + size); - if (result == NULL) /* Impossible unless interrupted. */ - return NULL; - - lastadj = adj; - adj = (uintptr_t) result % alignment; - /* It's conceivable we might have been so unlucky as to get a - different block with weaker alignment. If so, this block is too - short to contain SIZE after alignment correction. So we must - try again and get another block, slightly larger. */ - } while (adj > lastadj); + do + { + /* Reallocate the block with only as much excess as it + needs. */ + free (result); + result = malloc (size + adj); + if (result == NULL) /* Impossible unless interrupted. */ + return NULL; + + lastadj = adj; + adj = alignment - (uintptr_t) result % alignment; + if (adj == alignment) + adj = 0; + /* It's conceivable we might have been so unlucky as to get + a different block with weaker alignment. If so, this + block is too short to contain SIZE after alignment + correction. So we must try again and get another block, + slightly larger. */ + } while (adj > lastadj); + } if (adj != 0) { @@ -1618,7 +1627,7 @@ memalign (size_t alignment, size_t size) if (l != NULL) { l->exact = result; - result = l->aligned = (char *) result + alignment - adj; + result = l->aligned = (char *) result + adj; } UNLOCK_ALIGNED_BLOCKS (); if (l == NULL) @@ -1631,6 +1640,18 @@ memalign (size_t alignment, size_t size) return result; } +/* An obsolete alias for aligned_alloc, for any old libraries that use + this alias. */ + +void * +memalign (size_t alignment, size_t size) +{ + return aligned_alloc (alignment, size); +} + +/* If HYBRID_MALLOC is defined, we may want to use the system + posix_memalign below. */ +#ifndef HYBRID_MALLOC int posix_memalign (void **memptr, size_t alignment, size_t size) { @@ -1641,7 +1662,7 @@ posix_memalign (void **memptr, size_t alignment, size_t size) || (alignment & (alignment - 1)) != 0) return EINVAL; - mem = memalign (alignment, size); + mem = aligned_alloc (alignment, size); if (mem == NULL) return ENOMEM; @@ -1649,6 +1670,7 @@ posix_memalign (void **memptr, size_t alignment, size_t size) return 0; } +#endif /* Allocate memory on a page boundary. Copyright (C) 1991, 92, 93, 94, 96 Free Software Foundation, Inc. @@ -1686,9 +1708,116 @@ valloc (size_t size) if (pagesize == 0) pagesize = getpagesize (); - return memalign (pagesize, size); + return aligned_alloc (pagesize, size); +} + +#ifdef HYBRID_MALLOC +#undef malloc +#undef realloc +#undef calloc +#undef aligned_alloc +#undef free + +/* Declare system malloc and friends. */ +extern void *malloc (size_t size); +extern void *realloc (void *ptr, size_t size); +extern void *calloc (size_t nmemb, size_t size); +extern void free (void *ptr); +#ifdef HAVE_ALIGNED_ALLOC +extern void *aligned_alloc (size_t alignment, size_t size); +#elif defined HAVE_POSIX_MEMALIGN +extern int posix_memalign (void **memptr, size_t alignment, size_t size); +#endif + +/* See the comments near the beginning of this file for explanations + of the following functions. */ + +void * +hybrid_malloc (size_t size) +{ + if (DUMPED) + return malloc (size); + return gmalloc (size); +} + +void * +hybrid_calloc (size_t nmemb, size_t size) +{ + if (DUMPED) + return calloc (nmemb, size); + return gcalloc (nmemb, size); } +void +hybrid_free (void *ptr) +{ + if (!DUMPED) + gfree (ptr); + else if (!ALLOCATED_BEFORE_DUMPING (ptr)) + free (ptr); + /* Otherwise the dumped emacs is trying to free something allocated + before dumping; do nothing. */ + return; +} + +#if defined HAVE_ALIGNED_ALLOC || defined HAVE_POSIX_MEMALIGN +void * +hybrid_aligned_alloc (size_t alignment, size_t size) +{ + if (!DUMPED) + return galigned_alloc (alignment, size); + /* The following is copied from alloc.c */ +#ifdef HAVE_ALIGNED_ALLOC + return aligned_alloc (alignment, size); +#else /* HAVE_POSIX_MEMALIGN */ + void *p; + return posix_memalign (&p, alignment, size) == 0 ? p : 0; +#endif +} +#endif + +void * +hybrid_realloc (void *ptr, size_t size) +{ + void *result; + int type; + size_t block, oldsize; + + if (!DUMPED) + return grealloc (ptr, size); + if (!ALLOCATED_BEFORE_DUMPING (ptr)) + return realloc (ptr, size); + + /* The dumped emacs is trying to realloc storage allocated before + dumping. We just malloc new space and copy the data. */ + if (size == 0 || ptr == NULL) + return malloc (size); + block = ((char *) ptr - _heapbase) / BLOCKSIZE + 1; + type = _heapinfo[block].busy.type; + oldsize = + type == 0 ? _heapinfo[block].busy.info.size * BLOCKSIZE + : (size_t) 1 << type; + result = malloc (size); + if (result) + return memcpy (result, ptr, min (oldsize, size)); + return result; +} + +#ifdef HYBRID_GET_CURRENT_DIR_NAME +/* Defined in sysdep.c. */ +char *gget_current_dir_name (void); + +char * +hybrid_get_current_dir_name (void) +{ + if (DUMPED) + return get_current_dir_name (); + return gget_current_dir_name (); +} +#endif + +#endif /* HYBRID_MALLOC */ + #ifdef GC_MCHECK /* Standard debugging hooks for `malloc'. @@ -1765,6 +1894,22 @@ freehook (void *ptr) if (ptr) { + struct alignlist *l; + + /* If the block was allocated by aligned_alloc, its real pointer + to free is recorded in _aligned_blocks; find that. */ + PROTECT_MALLOC_STATE (0); + LOCK_ALIGNED_BLOCKS (); + for (l = _aligned_blocks; l != NULL; l = l->next) + if (l->aligned == ptr) + { + l->aligned = NULL; /* Mark the slot in the list as free. */ + ptr = l->exact; + break; + } + UNLOCK_ALIGNED_BLOCKS (); + PROTECT_MALLOC_STATE (1); + hdr = ((struct hdr *) ptr) - 1; checkhdr (hdr); hdr->magic = MAGICFREE; @@ -1792,8 +1937,7 @@ mallochook (size_t size) hdr->size = size; hdr->magic = MAGICWORD; ((char *) &hdr[1])[size] = MAGICBYTE; - memset (hdr + 1, MALLOCFLOOD, size); - return hdr + 1; + return memset (hdr + 1, MALLOCFLOOD, size); } static void * @@ -1857,7 +2001,11 @@ mabort (enum mcheck_status status) #else fprintf (stderr, "mcheck: %s\n", msg); fflush (stderr); +# ifdef emacs + emacs_abort (); +# else abort (); +# endif #endif }