diff options
| author | Paul Eggert | 2013-12-26 00:57:28 -0800 |
|---|---|---|
| committer | Paul Eggert | 2013-12-26 00:57:28 -0800 |
| commit | e76119d7542b19eb03f8d725480cbf98f7fa03d9 (patch) | |
| tree | bdc730dbcd0f54ca25623960feb8df4dfce073b7 | |
| parent | 2200a8c91de23f9749d1b3c961c4f8bb3145ddfa (diff) | |
| download | emacs-e76119d7542b19eb03f8d725480cbf98f7fa03d9.tar.gz emacs-e76119d7542b19eb03f8d725480cbf98f7fa03d9.zip | |
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.
| -rw-r--r-- | ChangeLog | 8 | ||||
| -rw-r--r-- | configure.ac | 45 | ||||
| -rw-r--r-- | src/ChangeLog | 14 | ||||
| -rw-r--r-- | src/alloc.c | 52 | ||||
| -rw-r--r-- | src/conf_post.h | 39 |
5 files changed, 127 insertions, 31 deletions
| @@ -1,3 +1,11 @@ | |||
| 1 | 2013-12-26 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Fix core dumps with gcc -fsanitize=address and GNU/Linux. | ||
| 4 | * configure.ac: Check whether addresses are sanitized. | ||
| 5 | (CANNOT_DUMP): Warn if addresses are sanitized and not CANNOT_DUMP. | ||
| 6 | (DOUG_LEA_MALLOC): Do not define if addresses are sanitized. | ||
| 7 | (SYSTEM_MALLOC): Define if addresses are sanitized. | ||
| 8 | |||
| 1 | 2013-12-24 Paul Eggert <eggert@cs.ucla.edu> | 9 | 2013-12-24 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 10 | ||
| 3 | Automate the procedure for updating copyright year. | 11 | Automate the procedure for updating copyright year. |
diff --git a/configure.ac b/configure.ac index ea76baf8f8f..8aaf2c6a8ac 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -1048,6 +1048,21 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], | |||
| 1048 | 1048 | ||
| 1049 | LDFLAGS="$late_LDFLAGS" | 1049 | LDFLAGS="$late_LDFLAGS" |
| 1050 | 1050 | ||
| 1051 | AC_CACHE_CHECK([whether addresses are sanitized], | ||
| 1052 | [emacs_cv_sanitize_address], | ||
| 1053 | [AC_COMPILE_IFELSE( | ||
| 1054 | [AC_LANG_PROGRAM( | ||
| 1055 | [[#ifndef __has_feature | ||
| 1056 | #define __has_feature(f) 0 | ||
| 1057 | #endif | ||
| 1058 | #if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer) | ||
| 1059 | #else | ||
| 1060 | #error "Addresses are not sanitized." | ||
| 1061 | #endif | ||
| 1062 | ]])], | ||
| 1063 | [emacs_cv_sanitize_address=yes], | ||
| 1064 | [emacs_cv_sanitize_address=no])]) | ||
| 1065 | |||
| 1051 | dnl The function dump-emacs will not be defined and temacs will do | 1066 | dnl The function dump-emacs will not be defined and temacs will do |
| 1052 | dnl (load "loadup") automatically unless told otherwise. | 1067 | dnl (load "loadup") automatically unless told otherwise. |
| 1053 | test "x$CANNOT_DUMP" = "x" && CANNOT_DUMP=no | 1068 | test "x$CANNOT_DUMP" = "x" && CANNOT_DUMP=no |
| @@ -1055,8 +1070,11 @@ case "$opsys" in | |||
| 1055 | your-opsys-here) CANNOT_DUMP=yes ;; | 1070 | your-opsys-here) CANNOT_DUMP=yes ;; |
| 1056 | esac | 1071 | esac |
| 1057 | 1072 | ||
| 1058 | test "$CANNOT_DUMP" = "yes" && \ | 1073 | if test "$CANNOT_DUMP" = "yes"; then |
| 1059 | AC_DEFINE(CANNOT_DUMP, 1, [Define if Emacs cannot be dumped on your system.]) | 1074 | AC_DEFINE(CANNOT_DUMP, 1, [Define if Emacs cannot be dumped on your system.]) |
| 1075 | elif test "$emacs_cv_sanitize_address" = yes; then | ||
| 1076 | AC_MSG_WARN([[Addresses are sanitized; suggest CANNOT_DUMP=yes]]) | ||
| 1077 | fi | ||
| 1060 | 1078 | ||
| 1061 | AC_SUBST(CANNOT_DUMP) | 1079 | AC_SUBST(CANNOT_DUMP) |
| 1062 | 1080 | ||
| @@ -1888,20 +1906,21 @@ GNU_MALLOC=yes | |||
| 1888 | AC_CACHE_CHECK( | 1906 | AC_CACHE_CHECK( |
| 1889 | [whether malloc is Doug Lea style], | 1907 | [whether malloc is Doug Lea style], |
| 1890 | [emacs_cv_var_doug_lea_malloc], | 1908 | [emacs_cv_var_doug_lea_malloc], |
| 1891 | [AC_LINK_IFELSE( | 1909 | [emacs_cv_var_doug_lea_malloc=no |
| 1892 | [AC_LANG_PROGRAM( | 1910 | dnl Hooks do not work with address sanitization. |
| 1893 | [[#include <malloc.h> | 1911 | if test "$emacs_cv_sanitize_address" != yes; then |
| 1894 | static void hook (void) {}]], | 1912 | AC_LINK_IFELSE( |
| 1895 | [[malloc_set_state (malloc_get_state ()); | 1913 | [AC_LANG_PROGRAM( |
| 1896 | __after_morecore_hook = hook; | 1914 | [[#include <malloc.h> |
| 1897 | __malloc_initialize_hook = hook;]])], | 1915 | static void hook (void) {}]], |
| 1898 | [emacs_cv_var_doug_lea_malloc=yes], | 1916 | [[malloc_set_state (malloc_get_state ()); |
| 1899 | [emacs_cv_var_doug_lea_malloc=no])]) | 1917 | __after_morecore_hook = hook; |
| 1918 | __malloc_initialize_hook = hook;]])], | ||
| 1919 | [emacs_cv_var_doug_lea_malloc=yes])]) | ||
| 1920 | fi | ||
| 1900 | doug_lea_malloc=$emacs_cv_var_doug_lea_malloc | 1921 | doug_lea_malloc=$emacs_cv_var_doug_lea_malloc |
| 1901 | 1922 | ||
| 1902 | 1923 | system_malloc=$emacs_cv_sanitize_address | |
| 1903 | dnl See comments in aix4-2.h about maybe using system malloc there. | ||
| 1904 | system_malloc=no | ||
| 1905 | case "$opsys" in | 1924 | case "$opsys" in |
| 1906 | ## darwin ld insists on the use of malloc routines in the System framework. | 1925 | ## darwin ld insists on the use of malloc routines in the System framework. |
| 1907 | darwin|sol2-10) system_malloc=yes ;; | 1926 | darwin|sol2-10) system_malloc=yes ;; |
diff --git a/src/ChangeLog b/src/ChangeLog index 1e8684c4ddb..70df9cd3641 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,17 @@ | |||
| 1 | 2013-12-26 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Fix core dumps with gcc -fsanitize=address and GNU/Linux. | ||
| 4 | On my Fedora 19 platform the core dumps were so big that | ||
| 5 | my desktop became nearly catatonic. | ||
| 6 | * alloc.c (no_sanitize_memcpy) [MAX_SAVE_STACK > 0]: New function. | ||
| 7 | (Fgarbage_collect) [MAX_SAVE_STACK > 0]: Use it. | ||
| 8 | (USE_ALIGNED_MALLOC): Do not define if addresses are sanitized. | ||
| 9 | (mark_memory): Use ATTRIBUTE_NO_SANITIZE_ADDRESS rather than | ||
| 10 | a clang-only syntax. | ||
| 11 | * conf_post.h (__has_feature): New macro, if not already defined. | ||
| 12 | (ADDRESS_SANITIZER, ADDRESS_SANITIZER_WORKAROUND) | ||
| 13 | (ATTRIBUTE_NO_SANITIZE_ADDRESS): New macros. | ||
| 14 | |||
| 1 | 2013-12-25 Eli Zaretskii <eliz@gnu.org> | 15 | 2013-12-25 Eli Zaretskii <eliz@gnu.org> |
| 2 | 16 | ||
| 3 | * w32fns.c (Fw32_shell_execute): Make DOCUMENT absolute only if it | 17 | * w32fns.c (Fw32_shell_execute): Make DOCUMENT absolute only if it |
diff --git a/src/alloc.c b/src/alloc.c index 447b465a076..14c322a3a64 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -203,7 +203,27 @@ const char *pending_malloc_warning; | |||
| 203 | #if MAX_SAVE_STACK > 0 | 203 | #if MAX_SAVE_STACK > 0 |
| 204 | static char *stack_copy; | 204 | static char *stack_copy; |
| 205 | static ptrdiff_t stack_copy_size; | 205 | static ptrdiff_t stack_copy_size; |
| 206 | #endif | 206 | |
| 207 | /* Copy to DEST a block of memory from SRC of size SIZE bytes, | ||
| 208 | avoiding any address sanitization. */ | ||
| 209 | |||
| 210 | static void * ATTRIBUTE_NO_SANITIZE_ADDRESS | ||
| 211 | no_sanitize_memcpy (void *dest, void const *src, size_t size) | ||
| 212 | { | ||
| 213 | if (! ADDRESS_SANITIZER) | ||
| 214 | return memcpy (dest, src, size); | ||
| 215 | else | ||
| 216 | { | ||
| 217 | size_t i; | ||
| 218 | char *d = dest; | ||
| 219 | char const *s = src; | ||
| 220 | for (i = 0; i < size; i++) | ||
| 221 | d[i] = s[i]; | ||
| 222 | return dest; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | #endif /* MAX_SAVE_STACK > 0 */ | ||
| 207 | 227 | ||
| 208 | static Lisp_Object Qconses; | 228 | static Lisp_Object Qconses; |
| 209 | static Lisp_Object Qsymbols; | 229 | static Lisp_Object Qsymbols; |
| @@ -920,20 +940,26 @@ lisp_free (void *block) | |||
| 920 | /* The entry point is lisp_align_malloc which returns blocks of at most | 940 | /* The entry point is lisp_align_malloc which returns blocks of at most |
| 921 | BLOCK_BYTES and guarantees they are aligned on a BLOCK_ALIGN boundary. */ | 941 | BLOCK_BYTES and guarantees they are aligned on a BLOCK_ALIGN boundary. */ |
| 922 | 942 | ||
| 923 | #if !defined SYSTEM_MALLOC && !defined DOUG_LEA_MALLOC | 943 | /* Use aligned_alloc if it or a simple substitute is available. |
| 924 | # define USE_ALIGNED_ALLOC 1 | 944 | Address sanitization breaks aligned allocation, as of gcc 4.8.2 and |
| 945 | clang 3.3 anyway. */ | ||
| 946 | |||
| 947 | #if ! ADDRESS_SANITIZER | ||
| 948 | # if !defined SYSTEM_MALLOC && !defined DOUG_LEA_MALLOC | ||
| 949 | # define USE_ALIGNED_ALLOC 1 | ||
| 925 | /* Defined in gmalloc.c. */ | 950 | /* Defined in gmalloc.c. */ |
| 926 | void *aligned_alloc (size_t, size_t); | 951 | void *aligned_alloc (size_t, size_t); |
| 927 | #elif defined HAVE_ALIGNED_ALLOC | 952 | # elif defined HAVE_ALIGNED_ALLOC |
| 928 | # define USE_ALIGNED_ALLOC 1 | 953 | # define USE_ALIGNED_ALLOC 1 |
| 929 | #elif defined HAVE_POSIX_MEMALIGN | 954 | # elif defined HAVE_POSIX_MEMALIGN |
| 930 | # define USE_ALIGNED_ALLOC 1 | 955 | # define USE_ALIGNED_ALLOC 1 |
| 931 | static void * | 956 | static void * |
| 932 | aligned_alloc (size_t alignment, size_t size) | 957 | aligned_alloc (size_t alignment, size_t size) |
| 933 | { | 958 | { |
| 934 | void *p; | 959 | void *p; |
| 935 | return posix_memalign (&p, alignment, size) == 0 ? p : 0; | 960 | return posix_memalign (&p, alignment, size) == 0 ? p : 0; |
| 936 | } | 961 | } |
| 962 | # endif | ||
| 937 | #endif | 963 | #endif |
| 938 | 964 | ||
| 939 | /* BLOCK_ALIGN has to be a power of 2. */ | 965 | /* BLOCK_ALIGN has to be a power of 2. */ |
| @@ -4553,16 +4579,8 @@ mark_maybe_pointer (void *p) | |||
| 4553 | /* Mark Lisp objects referenced from the address range START+OFFSET..END | 4579 | /* Mark Lisp objects referenced from the address range START+OFFSET..END |
| 4554 | or END+OFFSET..START. */ | 4580 | or END+OFFSET..START. */ |
| 4555 | 4581 | ||
| 4556 | static void | 4582 | static void ATTRIBUTE_NO_SANITIZE_ADDRESS |
| 4557 | mark_memory (void *start, void *end) | 4583 | mark_memory (void *start, void *end) |
| 4558 | #if defined (__clang__) && defined (__has_feature) | ||
| 4559 | #if __has_feature(address_sanitizer) | ||
| 4560 | /* Do not allow -faddress-sanitizer to check this function, since it | ||
| 4561 | crosses the function stack boundary, and thus would yield many | ||
| 4562 | false positives. */ | ||
| 4563 | __attribute__((no_address_safety_analysis)) | ||
| 4564 | #endif | ||
| 4565 | #endif | ||
| 4566 | { | 4584 | { |
| 4567 | void **pp; | 4585 | void **pp; |
| 4568 | int i; | 4586 | int i; |
| @@ -5477,7 +5495,7 @@ See Info node `(elisp)Garbage Collection'. */) | |||
| 5477 | stack_copy = xrealloc (stack_copy, stack_size); | 5495 | stack_copy = xrealloc (stack_copy, stack_size); |
| 5478 | stack_copy_size = stack_size; | 5496 | stack_copy_size = stack_size; |
| 5479 | } | 5497 | } |
| 5480 | memcpy (stack_copy, stack, stack_size); | 5498 | no_sanitize_memcpy (stack_copy, stack, stack_size); |
| 5481 | } | 5499 | } |
| 5482 | } | 5500 | } |
| 5483 | #endif /* MAX_SAVE_STACK > 0 */ | 5501 | #endif /* MAX_SAVE_STACK > 0 */ |
diff --git a/src/conf_post.h b/src/conf_post.h index 66dd9a36f00..04c4f4f5f15 100644 --- a/src/conf_post.h +++ b/src/conf_post.h | |||
| @@ -50,8 +50,19 @@ typedef bool bool_bf; | |||
| 50 | #endif | 50 | #endif |
| 51 | #endif | 51 | #endif |
| 52 | 52 | ||
| 53 | /* When not using Clang, assume its attributes and features are absent. */ | ||
| 53 | #ifndef __has_attribute | 54 | #ifndef __has_attribute |
| 54 | # define __has_attribute(a) false /* non-clang */ | 55 | # define __has_attribute(a) false |
| 56 | #endif | ||
| 57 | #ifndef __has_feature | ||
| 58 | # define __has_feature(a) false | ||
| 59 | #endif | ||
| 60 | |||
| 61 | /* True if addresses are being sanitized. */ | ||
| 62 | #if defined __SANITIZE_ADDRESS__ || __has_feature (address_sanitizer) | ||
| 63 | # define ADDRESS_SANITIZER true | ||
| 64 | #else | ||
| 65 | # define ADDRESS_SANITIZER false | ||
| 55 | #endif | 66 | #endif |
| 56 | 67 | ||
| 57 | #ifdef DARWIN_OS | 68 | #ifdef DARWIN_OS |
| @@ -204,6 +215,32 @@ extern void _DebPrint (const char *fmt, ...); | |||
| 204 | 215 | ||
| 205 | #define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST | 216 | #define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST |
| 206 | 217 | ||
| 218 | /* Work around GCC bug 59600: when a function is inlined, the inlined | ||
| 219 | code may have its addresses sanitized even if the function has the | ||
| 220 | no_sanitize_address attribute. This bug is present in GCC 4.8.2 | ||
| 221 | and clang 3.3, the latest releases as of December 2013, and the | ||
| 222 | only platforms known to support address sanitization. When the bug | ||
| 223 | is fixed the #if can be updated accordingly. */ | ||
| 224 | #if ADDRESS_SANITIZER | ||
| 225 | # define ADDRESS_SANITIZER_WORKAROUND NO_INLINE | ||
| 226 | #else | ||
| 227 | # define ADDRESS_SANITIZER_WORKAROUND | ||
| 228 | #endif | ||
| 229 | |||
| 230 | /* Attribute of functions whose code should not have addresses | ||
| 231 | sanitized. */ | ||
| 232 | |||
| 233 | #if (__has_attribute (no_sanitize_address) \ | ||
| 234 | || 4 < __GNUC__ + (8 <= __GNUC_MINOR__)) | ||
| 235 | # define ATTRIBUTE_NO_SANITIZE_ADDRESS \ | ||
| 236 | __attribute__ ((no_sanitize_address)) ADDRESS_SANITIZER_WORKAROUND | ||
| 237 | #elif __has_attribute (no_address_safety_analysis) | ||
| 238 | # define ATTRIBUTE_NO_SANITIZE_ADDRESS \ | ||
| 239 | __attribute__ ((no_address_safety_analysis)) ADDRESS_SANITIZER_WORKAROUND | ||
| 240 | #else | ||
| 241 | # define ATTRIBUTE_NO_SANITIZE_ADDRESS | ||
| 242 | #endif | ||
| 243 | |||
| 207 | /* Some versions of GNU/Linux define noinline in their headers. */ | 244 | /* Some versions of GNU/Linux define noinline in their headers. */ |
| 208 | #ifdef noinline | 245 | #ifdef noinline |
| 209 | #undef noinline | 246 | #undef noinline |