diff options
| author | Paul Eggert | 2020-05-25 20:26:14 -0700 |
|---|---|---|
| committer | Paul Eggert | 2020-05-25 20:29:50 -0700 |
| commit | 0dc529175dc027c1567fb9b7cd529d29236aad44 (patch) | |
| tree | 12e250b10b6a14d25c3c6dacc8ee82bd9e8fc4e2 /src | |
| parent | 8b940dac32c2a37f93b8670751a0e5f72ec86cea (diff) | |
| download | emacs-0dc529175dc027c1567fb9b7cd529d29236aad44.tar.gz emacs-0dc529175dc027c1567fb9b7cd529d29236aad44.zip | |
Fix aborts due to GC losing pseudovectors
Problem reported by Eli Zaretskii (Bug#41321).
* src/alloc.c (MALLOC_ALIGNMENT_BOUND): New constant.
(LISP_ALIGNMENT): Lower it to avoid crashes on MinGW and similarly
buggy platforms where malloc returns pointers not aligned to
alignof (max_align_t). But keep it higher on platforms where this
is known to work, as it helps GC performance.
(MALLOC_IS_LISP_ALIGNED): Define in terms of the other two.
* src/alloc.c (stacktop_sentry):
* src/thread.c (run_thread):
Don’t overalign or oversize stack sentries; they need to be
aligned only for pointers and Lisp_Object, not for arbitrary
pseudovector contents.
* src/lisp.h (union emacs_align_type): New type, used for
LISP_ALIGNMENT.
Diffstat (limited to 'src')
| -rw-r--r-- | src/alloc.c | 55 | ||||
| -rw-r--r-- | src/lisp.h | 43 | ||||
| -rw-r--r-- | src/thread.c | 9 |
3 files changed, 78 insertions, 29 deletions
diff --git a/src/alloc.c b/src/alloc.c index d5a6d9167ea..602282e5704 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -112,9 +112,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 112 | adds sizeof (size_t) to SIZE for internal overhead, and then rounds | 112 | adds sizeof (size_t) to SIZE for internal overhead, and then rounds |
| 113 | up to a multiple of MALLOC_ALIGNMENT. Emacs can improve | 113 | up to a multiple of MALLOC_ALIGNMENT. Emacs can improve |
| 114 | performance a bit on GNU platforms by arranging for the resulting | 114 | performance a bit on GNU platforms by arranging for the resulting |
| 115 | size to be a power of two. This heuristic is good for glibc 2.0 | 115 | size to be a power of two. This heuristic is good for glibc 2.26 |
| 116 | (1997) through at least glibc 2.31 (2020), and does not affect | 116 | (2017) and later, and does not affect correctness on other |
| 117 | correctness on other platforms. */ | 117 | platforms. */ |
| 118 | 118 | ||
| 119 | #define MALLOC_SIZE_NEAR(n) \ | 119 | #define MALLOC_SIZE_NEAR(n) \ |
| 120 | (ROUNDUP (max (n, sizeof (size_t)), MALLOC_ALIGNMENT) - sizeof (size_t)) | 120 | (ROUNDUP (max (n, sizeof (size_t)), MALLOC_ALIGNMENT) - sizeof (size_t)) |
| @@ -655,28 +655,30 @@ buffer_memory_full (ptrdiff_t nbytes) | |||
| 655 | #define COMMON_MULTIPLE(a, b) \ | 655 | #define COMMON_MULTIPLE(a, b) \ |
| 656 | ((a) % (b) == 0 ? (a) : (b) % (a) == 0 ? (b) : (a) * (b)) | 656 | ((a) % (b) == 0 ? (a) : (b) % (a) == 0 ? (b) : (a) * (b)) |
| 657 | 657 | ||
| 658 | /* LISP_ALIGNMENT is the alignment of Lisp objects. It must be at | 658 | /* A lower bound on the alignment of malloc. For better performance |
| 659 | least GCALIGNMENT so that pointers can be tagged. It also must be | 659 | this bound should be tighter. For glibc 2.26 and later a tighter |
| 660 | at least as strict as the alignment of all the C types used to | 660 | bound is known. */ |
| 661 | implement Lisp objects; since pseudovectors can contain any C type, | 661 | #if 2 < __GLIBC__ + (26 <= __GLIBC_MINOR__) |
| 662 | this is max_align_t. On recent GNU/Linux x86 and x86-64 this can | 662 | enum { MALLOC_ALIGNMENT_BOUND = MALLOC_ALIGNMENT }; |
| 663 | often waste up to 8 bytes, since alignof (max_align_t) is 16 but | 663 | #else |
| 664 | typical vectors need only an alignment of 8. Although shrinking | 664 | /* A bound known to work for all Emacs porting targets. Tightening |
| 665 | the alignment to 8 would save memory, it cost a 20% hit to Emacs | 665 | this looser bound by using max_align_t instead of long long int |
| 666 | CPU performance on Fedora 28 x86-64 when compiled with gcc -m32. */ | 666 | would break buggy malloc implementations like MinGW circa 2020. */ |
| 667 | enum { LISP_ALIGNMENT = alignof (union { max_align_t x; | 667 | enum { MALLOC_ALIGNMENT_BOUND = alignof (long long int) }; |
| 668 | GCALIGNED_UNION_MEMBER }) }; | 668 | #endif |
| 669 | verify (LISP_ALIGNMENT % GCALIGNMENT == 0); | 669 | |
| 670 | /* A lower bound on the alignment of Lisp objects. All Lisp objects | ||
| 671 | must have an address that is a multiple of LISP_ALIGNMENT; | ||
| 672 | otherwise maybe_lisp_pointer can issue false negatives, causing crashes. | ||
| 673 | It's good to make this bound tight: if Lisp objects are always | ||
| 674 | aligned more strictly than LISP_ALIGNMENT, maybe_lisp_pointer will | ||
| 675 | issue more false positives, hurting performance. */ | ||
| 676 | enum { LISP_ALIGNMENT = max (max (GCALIGNMENT, MALLOC_ALIGNMENT_BOUND), | ||
| 677 | alignof (union emacs_align_type)) }; | ||
| 670 | 678 | ||
| 671 | /* True if malloc (N) is known to return storage suitably aligned for | 679 | /* True if malloc (N) is known to return storage suitably aligned for |
| 672 | Lisp objects whenever N is a multiple of LISP_ALIGNMENT. In | 680 | Lisp objects whenever N is a multiple of LISP_ALIGNMENT. */ |
| 673 | practice this is true whenever alignof (max_align_t) is also a | 681 | enum { MALLOC_IS_LISP_ALIGNED = MALLOC_ALIGNMENT_BOUND % LISP_ALIGNMENT == 0 }; |
| 674 | multiple of LISP_ALIGNMENT. This works even for x86, where some | ||
| 675 | platform combinations (e.g., GCC 7 and later, glibc 2.25 and | ||
| 676 | earlier) have bugs where alignof (max_align_t) is 16 even though | ||
| 677 | the malloc alignment is only 8, and where Emacs still works because | ||
| 678 | it never does anything that requires an alignment of 16. */ | ||
| 679 | enum { MALLOC_IS_LISP_ALIGNED = alignof (max_align_t) % LISP_ALIGNMENT == 0 }; | ||
| 680 | 682 | ||
| 681 | /* If compiled with XMALLOC_BLOCK_INPUT_CHECK, define a symbol | 683 | /* If compiled with XMALLOC_BLOCK_INPUT_CHECK, define a symbol |
| 682 | BLOCK_INPUT_IN_MEMORY_ALLOCATORS that is visible to the debugger. | 684 | BLOCK_INPUT_IN_MEMORY_ALLOCATORS that is visible to the debugger. |
| @@ -4885,9 +4887,10 @@ test_setjmp (void) | |||
| 4885 | as a stack scan limit. */ | 4887 | as a stack scan limit. */ |
| 4886 | typedef union | 4888 | typedef union |
| 4887 | { | 4889 | { |
| 4888 | /* Align the stack top properly. Even if !HAVE___BUILTIN_UNWIND_INIT, | 4890 | /* Make sure stack_top and m_stack_bottom are properly aligned as GC |
| 4889 | jmp_buf may not be aligned enough on darwin-ppc64. */ | 4891 | expects. */ |
| 4890 | max_align_t o; | 4892 | Lisp_Object o; |
| 4893 | void *p; | ||
| 4891 | #ifndef HAVE___BUILTIN_UNWIND_INIT | 4894 | #ifndef HAVE___BUILTIN_UNWIND_INIT |
| 4892 | sys_jmp_buf j; | 4895 | sys_jmp_buf j; |
| 4893 | char c; | 4896 | char c; |
diff --git a/src/lisp.h b/src/lisp.h index 85bdc172b20..937052f6df8 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -277,7 +277,8 @@ error !; | |||
| 277 | allocation in a containing union that has GCALIGNED_UNION_MEMBER) | 277 | allocation in a containing union that has GCALIGNED_UNION_MEMBER) |
| 278 | and does not contain a GC-aligned struct or union, putting | 278 | and does not contain a GC-aligned struct or union, putting |
| 279 | GCALIGNED_STRUCT after its closing '}' can help the compiler | 279 | GCALIGNED_STRUCT after its closing '}' can help the compiler |
| 280 | generate better code. | 280 | generate better code. Also, such structs should be added to the |
| 281 | emacs_align_type union. | ||
| 281 | 282 | ||
| 282 | Although these macros are reasonably portable, they are not | 283 | Although these macros are reasonably portable, they are not |
| 283 | guaranteed on non-GCC platforms, as C11 does not require support | 284 | guaranteed on non-GCC platforms, as C11 does not require support |
| @@ -5059,6 +5060,46 @@ maybe_gc (void) | |||
| 5059 | maybe_garbage_collect (); | 5060 | maybe_garbage_collect (); |
| 5060 | } | 5061 | } |
| 5061 | 5062 | ||
| 5063 | /* A type with alignment at least as large as any object that Emacs | ||
| 5064 | allocates. This is not max_align_t because some platforms (e.g., | ||
| 5065 | mingw) have buggy malloc implementations that do not align for | ||
| 5066 | max_align_t. This union contains types of all GCALIGNED_STRUCT | ||
| 5067 | components visible here. */ | ||
| 5068 | union emacs_align_type | ||
| 5069 | { | ||
| 5070 | struct Lisp_Bool_Vector Lisp_Bool_Vector; | ||
| 5071 | struct Lisp_Char_Table Lisp_Char_Table; | ||
| 5072 | struct Lisp_CondVar Lisp_CondVar; | ||
| 5073 | struct Lisp_Finalizer Lisp_Finalizer; | ||
| 5074 | struct Lisp_Float Lisp_Float; | ||
| 5075 | struct Lisp_Hash_Table Lisp_Hash_Table; | ||
| 5076 | struct Lisp_Marker Lisp_Marker; | ||
| 5077 | struct Lisp_Misc_Ptr Lisp_Misc_Ptr; | ||
| 5078 | struct Lisp_Mutex Lisp_Mutex; | ||
| 5079 | struct Lisp_Overlay Lisp_Overlay; | ||
| 5080 | struct Lisp_Sub_Char_Table Lisp_Sub_Char_Table; | ||
| 5081 | struct Lisp_Subr Lisp_Subr; | ||
| 5082 | struct Lisp_User_Ptr Lisp_User_Ptr; | ||
| 5083 | struct Lisp_Vector Lisp_Vector; | ||
| 5084 | struct thread_state thread_state; | ||
| 5085 | |||
| 5086 | /* Omit the following since they would require including bignum.h, | ||
| 5087 | frame.h etc., and in practice their alignments never exceed that | ||
| 5088 | of the structs already listed. */ | ||
| 5089 | #if 0 | ||
| 5090 | struct frame frame; | ||
| 5091 | struct Lisp_Bignum Lisp_Bignum; | ||
| 5092 | struct Lisp_Module_Function Lisp_Module_Function; | ||
| 5093 | struct Lisp_Process Lisp_Process; | ||
| 5094 | struct save_window_data save_window_data; | ||
| 5095 | struct scroll_bar scroll_bar; | ||
| 5096 | struct terminal terminal; | ||
| 5097 | struct window window; | ||
| 5098 | struct xwidget xwidget; | ||
| 5099 | struct xwidget_view xwidget_view; | ||
| 5100 | #endif | ||
| 5101 | }; | ||
| 5102 | |||
| 5062 | INLINE_HEADER_END | 5103 | INLINE_HEADER_END |
| 5063 | 5104 | ||
| 5064 | #endif /* EMACS_LISP_H */ | 5105 | #endif /* EMACS_LISP_H */ |
diff --git a/src/thread.c b/src/thread.c index df1a7053826..b638dd77f8b 100644 --- a/src/thread.c +++ b/src/thread.c | |||
| @@ -717,12 +717,17 @@ run_thread (void *state) | |||
| 717 | { | 717 | { |
| 718 | /* Make sure stack_top and m_stack_bottom are properly aligned as GC | 718 | /* Make sure stack_top and m_stack_bottom are properly aligned as GC |
| 719 | expects. */ | 719 | expects. */ |
| 720 | max_align_t stack_pos; | 720 | union |
| 721 | { | ||
| 722 | Lisp_Object o; | ||
| 723 | void *p; | ||
| 724 | char c; | ||
| 725 | } stack_pos; | ||
| 721 | 726 | ||
| 722 | struct thread_state *self = state; | 727 | struct thread_state *self = state; |
| 723 | struct thread_state **iter; | 728 | struct thread_state **iter; |
| 724 | 729 | ||
| 725 | self->m_stack_bottom = self->stack_top = (char *) &stack_pos; | 730 | self->m_stack_bottom = self->stack_top = &stack_pos.c; |
| 726 | self->thread_id = sys_thread_self (); | 731 | self->thread_id = sys_thread_self (); |
| 727 | 732 | ||
| 728 | if (self->thread_name) | 733 | if (self->thread_name) |