malloc.h hygiene

This attempts to future-proof Emacs a bit against possible glibc
changes, by having Emacs use <malloc.h> declarations rather than
coding them up by hand.  Problem noted by Florian Weimer in:
https://sourceware.org/ml/libc-alpha/2016-01/msg00777.html
Implement this mainly by moving malloc.h-related functions from
emacs.c (which does not include <malloc.h>) to alloc.c (which does).
* src/alloc.c (my_heap_start) [DOUG_LEA_MALLOC || GNU_LINUX]:
New function.
The remaining changes to this file apply only if DOUG_LEA_MALLOC.
(alloc_unexec_pre, alloc_unexec_post): New functions.
(malloc_initialize_hook): Use my_heap_start and alloc_unexec_post.
(__MALLOC_HOOK_VOLATILE): New macro, if not already defined.
(__malloc_initialize_hook): Use it.
(malloc_state_ptr, malloc_initialize_hook, __malloc_initialize_hook):
Move here from ...
* src/emacs.c: ... here.
(malloc_get_state, malloc_set_state): Remove extern decls.
(my_heap_start) [DOUG_LEA_MALLOC || GNU_LINUX]: Remove static var.
All uses changed to similarly-named new function.
(Fdump_emacs): Use new functions alloc_unexec_pre, alloc_unexec_post.
* src/lisp.h (my_heap_start, alloc_unexec_pre, alloc_unexec_post):
New decls.
This commit is contained in:
Paul Eggert 2016-01-26 23:00:10 -08:00
parent cf17002326
commit b88e9cded7
3 changed files with 88 additions and 74 deletions

View file

@ -92,6 +92,18 @@ static bool valgrind_p;
#include "w32heap.h" /* for sbrk */
#endif
#if defined DOUG_LEA_MALLOC || defined GNU_LINUX
/* The address where the heap starts. */
void *
my_heap_start (void)
{
static void *start;
if (! start)
start = sbrk (0);
return start;
}
#endif
#ifdef DOUG_LEA_MALLOC
#include <malloc.h>
@ -101,7 +113,69 @@ static bool valgrind_p;
#define MMAP_MAX_AREAS 100000000
#endif /* not DOUG_LEA_MALLOC */
/* A pointer to the memory allocated that copies that static data
inside glibc's malloc. */
static void *malloc_state_ptr;
/* Get and free this pointer; useful around unexec. */
void
alloc_unexec_pre (void)
{
malloc_state_ptr = malloc_get_state ();
}
void
alloc_unexec_post (void)
{
free (malloc_state_ptr);
}
/* Restore the dumped malloc state. Because malloc can be invoked
even before main (e.g. by the dynamic linker), the dumped malloc
state must be restored as early as possible using this special hook. */
static void
malloc_initialize_hook (void)
{
static bool malloc_using_checking;
if (! initialized)
{
my_heap_start ();
malloc_using_checking = getenv ("MALLOC_CHECK_") != NULL;
}
else
{
if (!malloc_using_checking)
{
/* Work around a bug in glibc's malloc. MALLOC_CHECK_ must be
ignored if the heap to be restored was constructed without
malloc checking. Can't use unsetenv, since that calls malloc. */
char **p = environ;
if (p)
for (; *p; p++)
if (strncmp (*p, "MALLOC_CHECK_=", 14) == 0)
{
do
*p = p[1];
while (*++p);
break;
}
}
malloc_set_state (malloc_state_ptr);
# ifndef XMALLOC_OVERRUN_CHECK
alloc_unexec_post ();
# endif
}
}
# ifndef __MALLOC_HOOK_VOLATILE
# define __MALLOC_HOOK_VOLATILE
# endif
voidfuncptr __MALLOC_HOOK_VOLATILE __malloc_initialize_hook
= malloc_initialize_hook;
#endif
/* Mark, unmark, query mark bit of a Lisp string. S must be a pointer
to a struct Lisp_String. */

View file

@ -133,20 +133,7 @@ bool might_dump;
extern void unexec_init_emacs_zone (void);
#endif
#ifdef DOUG_LEA_MALLOC
/* Preserves a pointer to the memory allocated that copies that
static data inside glibc's malloc. */
static void *malloc_state_ptr;
/* From glibc, a routine that returns a copy of the malloc internal state. */
extern void *malloc_get_state (void);
/* From glibc, a routine that overwrites the malloc internal state. */
extern int malloc_set_state (void *);
/* True if the MALLOC_CHECK_ environment variable was set while
dumping. Used to work around a bug in glibc's malloc. */
static bool malloc_using_checking;
#elif defined HAVE_PTHREAD && !defined SYSTEM_MALLOC && !defined HYBRID_MALLOC
extern void malloc_enable_thread (void);
#endif
/* If true, Emacs should not attempt to use a window-specific code,
but instead should use the virtual terminal under which it was started. */
@ -165,11 +152,6 @@ bool display_arg;
Tells GC how to save a copy of the stack. */
char *stack_bottom;
#if defined (DOUG_LEA_MALLOC) || defined (GNU_LINUX)
/* The address where the heap starts (from the first sbrk (0) call). */
static void *my_heap_start;
#endif
#ifdef GNU_LINUX
/* The gap between BSS end and heap start as far as we can tell. */
static uprintmax_t heap_bss_diff;
@ -651,51 +633,6 @@ argmatch (char **argv, int argc, const char *sstr, const char *lstr,
}
}
#ifdef DOUG_LEA_MALLOC
/* malloc can be invoked even before main (e.g. by the dynamic
linker), so the dumped malloc state must be restored as early as
possible using this special hook. */
static void
malloc_initialize_hook (void)
{
if (initialized)
{
if (!malloc_using_checking)
/* Work around a bug in glibc's malloc. MALLOC_CHECK_ must be
ignored if the heap to be restored was constructed without
malloc checking. Can't use unsetenv, since that calls malloc. */
{
char **p;
for (p = environ; p && *p; p++)
if (strncmp (*p, "MALLOC_CHECK_=", 14) == 0)
{
do
*p = p[1];
while (*++p);
break;
}
}
malloc_set_state (malloc_state_ptr);
#ifndef XMALLOC_OVERRUN_CHECK
free (malloc_state_ptr);
#endif
}
else
{
if (my_heap_start == 0)
my_heap_start = sbrk (0);
malloc_using_checking = getenv ("MALLOC_CHECK_") != NULL;
}
}
void (*__malloc_initialize_hook) (void) EXTERNALLY_VISIBLE = malloc_initialize_hook;
#endif /* DOUG_LEA_MALLOC */
/* Close standard output and standard error, reporting any write
errors as best we can. This is intended for use with atexit. */
static void
@ -743,10 +680,8 @@ main (int argc, char **argv)
#ifdef GNU_LINUX
if (!initialized)
{
if (my_heap_start == 0)
my_heap_start = sbrk (0);
heap_bss_diff = (char *)my_heap_start - max (my_endbss, my_endbss_static);
char *heap_start = my_heap_start ();
heap_bss_diff = heap_start - max (my_endbss, my_endbss_static);
}
#endif
@ -2145,15 +2080,12 @@ You must run Emacs in batch mode in order to dump it. */)
memory_warnings (my_edata, malloc_warning);
#endif /* not WINDOWSNT */
#endif /* not SYSTEM_MALLOC and not HYBRID_MALLOC */
#ifdef DOUG_LEA_MALLOC
malloc_state_ptr = malloc_get_state ();
#endif
alloc_unexec_pre ();
unexec (SSDATA (filename), !NILP (symfile) ? SSDATA (symfile) : 0);
#ifdef DOUG_LEA_MALLOC
free (malloc_state_ptr);
#endif
alloc_unexec_post ();
#ifdef WINDOWSNT
Vlibrary_cache = Qnil;

View file

@ -3590,6 +3590,7 @@ extern void parse_str_as_multibyte (const unsigned char *, ptrdiff_t,
ptrdiff_t *, ptrdiff_t *);
/* Defined in alloc.c. */
extern void *my_heap_start (void);
extern void check_pure_size (void);
extern void free_misc (Lisp_Object);
extern void allocate_string_data (struct Lisp_String *, EMACS_INT, EMACS_INT);
@ -3601,6 +3602,13 @@ extern void mark_object (Lisp_Object);
#if defined REL_ALLOC && !defined SYSTEM_MALLOC && !defined HYBRID_MALLOC
extern void refill_memory_reserve (void);
#endif
#ifdef DOUG_LEA_MALLOC
extern void alloc_unexec_pre (void);
extern void alloc_unexec_post (void);
#else
INLINE void alloc_unexec_pre (void) {}
INLINE void alloc_unexec_post (void) {}
#endif
extern const char *pending_malloc_warning;
extern Lisp_Object zero_vector;
extern Lisp_Object *stack_base;