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 /src | |
| 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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 14 | ||||
| -rw-r--r-- | src/alloc.c | 52 | ||||
| -rw-r--r-- | src/conf_post.h | 39 |
3 files changed, 87 insertions, 18 deletions
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 |