From: Paul Eggert Date: Wed, 27 Jan 2016 07:00:10 +0000 (-0800) Subject: malloc.h hygiene X-Git-Tag: emacs-25.0.90~32 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=b88e9cded7ae3756e3a2ec4a23e8df352a0239f9;p=emacs.git malloc.h hygiene This attempts to future-proof Emacs a bit against possible glibc changes, by having Emacs use 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 ) 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. --- diff --git a/src/alloc.c b/src/alloc.c index 03dacc77c6e..d379761c168 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -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 @@ -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. */ diff --git a/src/emacs.c b/src/emacs.c index 89d8ca784ae..e3cfad0f7f8 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -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; diff --git a/src/lisp.h b/src/lisp.h index 6be2104ef9e..82cbca8e6ba 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -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;