Fix core dumps with gcc -fsanitize=address and GNU/Linux.

On my Fedora 19 platform the core dumps were so big that
my desktop became nearly catatonic.
* configure.ac: Check whether addresses are sanitized.
(CANNOT_DUMP): Warn if addresses are sanitized and not CANNOT_DUMP.
(DOUG_LEA_MALLOC): Do not define if addresses are sanitized.
(SYSTEM_MALLOC): Define if addresses are sanitized.
* src/alloc.c (no_sanitize_memcpy) [MAX_SAVE_STACK > 0]: New function.
(Fgarbage_collect) [MAX_SAVE_STACK > 0]: Use it.
(USE_ALIGNED_MALLOC): Do not define if addresses are sanitized.
(mark_memory): Use ATTRIBUTE_NO_SANITIZE_ADDRESS rather than
a clang-only syntax.
* src/conf_post.h (__has_feature): New macro, if not already defined.
(ADDRESS_SANITIZER, ADDRESS_SANITIZER_WORKAROUND)
(ATTRIBUTE_NO_SANITIZE_ADDRESS): New macros.
This commit is contained in:
Paul Eggert 2013-12-26 00:57:28 -08:00
parent 2200a8c91d
commit e76119d754
5 changed files with 127 additions and 31 deletions

View file

@ -1,3 +1,11 @@
2013-12-26 Paul Eggert <eggert@cs.ucla.edu>
Fix core dumps with gcc -fsanitize=address and GNU/Linux.
* configure.ac: Check whether addresses are sanitized.
(CANNOT_DUMP): Warn if addresses are sanitized and not CANNOT_DUMP.
(DOUG_LEA_MALLOC): Do not define if addresses are sanitized.
(SYSTEM_MALLOC): Define if addresses are sanitized.
2013-12-24 Paul Eggert <eggert@cs.ucla.edu>
Automate the procedure for updating copyright year.

View file

@ -1048,6 +1048,21 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],
LDFLAGS="$late_LDFLAGS"
AC_CACHE_CHECK([whether addresses are sanitized],
[emacs_cv_sanitize_address],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#ifndef __has_feature
#define __has_feature(f) 0
#endif
#if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer)
#else
#error "Addresses are not sanitized."
#endif
]])],
[emacs_cv_sanitize_address=yes],
[emacs_cv_sanitize_address=no])])
dnl The function dump-emacs will not be defined and temacs will do
dnl (load "loadup") automatically unless told otherwise.
test "x$CANNOT_DUMP" = "x" && CANNOT_DUMP=no
@ -1055,8 +1070,11 @@ case "$opsys" in
your-opsys-here) CANNOT_DUMP=yes ;;
esac
test "$CANNOT_DUMP" = "yes" && \
if test "$CANNOT_DUMP" = "yes"; then
AC_DEFINE(CANNOT_DUMP, 1, [Define if Emacs cannot be dumped on your system.])
elif test "$emacs_cv_sanitize_address" = yes; then
AC_MSG_WARN([[Addresses are sanitized; suggest CANNOT_DUMP=yes]])
fi
AC_SUBST(CANNOT_DUMP)
@ -1888,20 +1906,21 @@ GNU_MALLOC=yes
AC_CACHE_CHECK(
[whether malloc is Doug Lea style],
[emacs_cv_var_doug_lea_malloc],
[AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <malloc.h>
static void hook (void) {}]],
[[malloc_set_state (malloc_get_state ());
__after_morecore_hook = hook;
__malloc_initialize_hook = hook;]])],
[emacs_cv_var_doug_lea_malloc=yes],
[emacs_cv_var_doug_lea_malloc=no])])
[emacs_cv_var_doug_lea_malloc=no
dnl Hooks do not work with address sanitization.
if test "$emacs_cv_sanitize_address" != yes; then
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <malloc.h>
static void hook (void) {}]],
[[malloc_set_state (malloc_get_state ());
__after_morecore_hook = hook;
__malloc_initialize_hook = hook;]])],
[emacs_cv_var_doug_lea_malloc=yes])])
fi
doug_lea_malloc=$emacs_cv_var_doug_lea_malloc
dnl See comments in aix4-2.h about maybe using system malloc there.
system_malloc=no
system_malloc=$emacs_cv_sanitize_address
case "$opsys" in
## darwin ld insists on the use of malloc routines in the System framework.
darwin|sol2-10) system_malloc=yes ;;

View file

@ -1,3 +1,17 @@
2013-12-26 Paul Eggert <eggert@cs.ucla.edu>
Fix core dumps with gcc -fsanitize=address and GNU/Linux.
On my Fedora 19 platform the core dumps were so big that
my desktop became nearly catatonic.
* alloc.c (no_sanitize_memcpy) [MAX_SAVE_STACK > 0]: New function.
(Fgarbage_collect) [MAX_SAVE_STACK > 0]: Use it.
(USE_ALIGNED_MALLOC): Do not define if addresses are sanitized.
(mark_memory): Use ATTRIBUTE_NO_SANITIZE_ADDRESS rather than
a clang-only syntax.
* conf_post.h (__has_feature): New macro, if not already defined.
(ADDRESS_SANITIZER, ADDRESS_SANITIZER_WORKAROUND)
(ATTRIBUTE_NO_SANITIZE_ADDRESS): New macros.
2013-12-25 Eli Zaretskii <eliz@gnu.org>
* w32fns.c (Fw32_shell_execute): Make DOCUMENT absolute only if it

View file

@ -203,7 +203,27 @@ const char *pending_malloc_warning;
#if MAX_SAVE_STACK > 0
static char *stack_copy;
static ptrdiff_t stack_copy_size;
#endif
/* Copy to DEST a block of memory from SRC of size SIZE bytes,
avoiding any address sanitization. */
static void * ATTRIBUTE_NO_SANITIZE_ADDRESS
no_sanitize_memcpy (void *dest, void const *src, size_t size)
{
if (! ADDRESS_SANITIZER)
return memcpy (dest, src, size);
else
{
size_t i;
char *d = dest;
char const *s = src;
for (i = 0; i < size; i++)
d[i] = s[i];
return dest;
}
}
#endif /* MAX_SAVE_STACK > 0 */
static Lisp_Object Qconses;
static Lisp_Object Qsymbols;
@ -920,20 +940,26 @@ lisp_free (void *block)
/* The entry point is lisp_align_malloc which returns blocks of at most
BLOCK_BYTES and guarantees they are aligned on a BLOCK_ALIGN boundary. */
#if !defined SYSTEM_MALLOC && !defined DOUG_LEA_MALLOC
# define USE_ALIGNED_ALLOC 1
/* Use aligned_alloc if it or a simple substitute is available.
Address sanitization breaks aligned allocation, as of gcc 4.8.2 and
clang 3.3 anyway. */
#if ! ADDRESS_SANITIZER
# if !defined SYSTEM_MALLOC && !defined DOUG_LEA_MALLOC
# define USE_ALIGNED_ALLOC 1
/* Defined in gmalloc.c. */
void *aligned_alloc (size_t, size_t);
#elif defined HAVE_ALIGNED_ALLOC
# define USE_ALIGNED_ALLOC 1
#elif defined HAVE_POSIX_MEMALIGN
# define USE_ALIGNED_ALLOC 1
# elif defined HAVE_ALIGNED_ALLOC
# define USE_ALIGNED_ALLOC 1
# elif defined HAVE_POSIX_MEMALIGN
# define USE_ALIGNED_ALLOC 1
static void *
aligned_alloc (size_t alignment, size_t size)
{
void *p;
return posix_memalign (&p, alignment, size) == 0 ? p : 0;
}
# endif
#endif
/* BLOCK_ALIGN has to be a power of 2. */
@ -4553,16 +4579,8 @@ mark_maybe_pointer (void *p)
/* Mark Lisp objects referenced from the address range START+OFFSET..END
or END+OFFSET..START. */
static void
static void ATTRIBUTE_NO_SANITIZE_ADDRESS
mark_memory (void *start, void *end)
#if defined (__clang__) && defined (__has_feature)
#if __has_feature(address_sanitizer)
/* Do not allow -faddress-sanitizer to check this function, since it
crosses the function stack boundary, and thus would yield many
false positives. */
__attribute__((no_address_safety_analysis))
#endif
#endif
{
void **pp;
int i;
@ -5477,7 +5495,7 @@ See Info node `(elisp)Garbage Collection'. */)
stack_copy = xrealloc (stack_copy, stack_size);
stack_copy_size = stack_size;
}
memcpy (stack_copy, stack, stack_size);
no_sanitize_memcpy (stack_copy, stack, stack_size);
}
}
#endif /* MAX_SAVE_STACK > 0 */

View file

@ -50,8 +50,19 @@ typedef bool bool_bf;
#endif
#endif
/* When not using Clang, assume its attributes and features are absent. */
#ifndef __has_attribute
# define __has_attribute(a) false /* non-clang */
# define __has_attribute(a) false
#endif
#ifndef __has_feature
# define __has_feature(a) false
#endif
/* True if addresses are being sanitized. */
#if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer)
# define ADDRESS_SANITIZER true
#else
# define ADDRESS_SANITIZER false
#endif
#ifdef DARWIN_OS
@ -204,6 +215,32 @@ extern void _DebPrint (const char *fmt, ...);
#define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST
/* Work around GCC bug 59600: when a function is inlined, the inlined
code may have its addresses sanitized even if the function has the
no_sanitize_address attribute. This bug is present in GCC 4.8.2
and clang 3.3, the latest releases as of December 2013, and the
only platforms known to support address sanitization. When the bug
is fixed the #if can be updated accordingly. */
#if ADDRESS_SANITIZER
# define ADDRESS_SANITIZER_WORKAROUND NO_INLINE
#else
# define ADDRESS_SANITIZER_WORKAROUND
#endif
/* Attribute of functions whose code should not have addresses
sanitized. */
#if (__has_attribute (no_sanitize_address) \
|| 4 < __GNUC__ + (8 <= __GNUC_MINOR__))
# define ATTRIBUTE_NO_SANITIZE_ADDRESS \
__attribute__ ((no_sanitize_address)) ADDRESS_SANITIZER_WORKAROUND
#elif __has_attribute (no_address_safety_analysis)
# define ATTRIBUTE_NO_SANITIZE_ADDRESS \
__attribute__ ((no_address_safety_analysis)) ADDRESS_SANITIZER_WORKAROUND
#else
# define ATTRIBUTE_NO_SANITIZE_ADDRESS
#endif
/* Some versions of GNU/Linux define noinline in their headers. */
#ifdef noinline
#undef noinline