diff --git a/src/alloc.c b/src/alloc.c index 89fe96a2349..77d5d2839a2 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -655,24 +655,22 @@ buffer_memory_full (ptrdiff_t nbytes) #define COMMON_MULTIPLE(a, b) \ ((a) % (b) == 0 ? (a) : (b) % (a) == 0 ? (b) : (a) * (b)) -/* A lower bound on the alignment of malloc. Although this bound is - incorrect for some buggy malloc implementations (e.g., MinGW circa - 2020), the bugs should not matter for the way this bound is used - since the correct bound is also a multiple of LISP_ALIGNMENT on the - buggy platforms. */ -enum { MALLOC_ALIGNMENT_BOUND = alignof (max_align_t) }; - -/* A lower bound on the alignment of Lisp objects allocated on the heap. - All such objects must have an address that is a multiple of LISP_ALIGNMENT; - otherwise maybe_lisp_pointer can issue false negatives, causing crashes. - On all practical Emacs targets, sizeof (struct Lisp_Float) == 8 and - since GCALIGNMENT also equals 8 there's little point to optimizing - for impractical targets. */ -enum { LISP_ALIGNMENT = GCALIGNMENT }; +/* Alignment needed for memory blocks that are allocated via malloc + and that contain Lisp objects. On typical hosts malloc already + aligns sufficiently, but extra work is needed on oddball hosts + where Emacs would crash if malloc returned a non-GCALIGNED pointer. */ +enum { LISP_ALIGNMENT = alignof (union { union emacs_align_type x; + GCALIGNED_UNION_MEMBER }) }; +verify (LISP_ALIGNMENT % GCALIGNMENT == 0); /* True if malloc (N) is known to return storage suitably aligned for - Lisp objects whenever N is a multiple of LISP_ALIGNMENT. */ -enum { MALLOC_IS_LISP_ALIGNED = MALLOC_ALIGNMENT_BOUND % LISP_ALIGNMENT == 0 }; + Lisp objects whenever N is a multiple of LISP_ALIGNMENT. In + practice this is true whenever alignof (max_align_t) is also a + multiple of LISP_ALIGNMENT. This works even for buggy platforms + like MinGW circa 2020, where alignof (max_align_t) is 16 even though + the malloc alignment is only 8, and where Emacs still works because + it never does anything that requires an alignment of 16. */ +enum { MALLOC_IS_LISP_ALIGNED = alignof (max_align_t) % LISP_ALIGNMENT == 0 }; /* If compiled with XMALLOC_BLOCK_INPUT_CHECK, define a symbol BLOCK_INPUT_IN_MEMORY_ALLOCATORS that is visible to the debugger. @@ -4653,12 +4651,12 @@ mark_maybe_objects (Lisp_Object const *array, ptrdiff_t nelts) collected, and false otherwise (i.e., false if it is easy to see that P cannot point to Lisp data that can be garbage collected). Symbols are implemented via offsets not pointers, but the offsets - are also multiples of LISP_ALIGNMENT. */ + are also multiples of GCALIGNMENT. */ static bool maybe_lisp_pointer (void *p) { - return (uintptr_t) p % LISP_ALIGNMENT == 0; + return (uintptr_t) p % GCALIGNMENT == 0; } /* If P points to Lisp data, mark that as live if it isn't already 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 !; allocation in a containing union that has GCALIGNED_UNION_MEMBER) and does not contain a GC-aligned struct or union, putting GCALIGNED_STRUCT after its closing '}' can help the compiler - generate better code. + generate better code. Also, such structs should be added to the + emacs_align_type union. Although these macros are reasonably portable, they are not guaranteed on non-GCC platforms, as C11 does not require support @@ -5059,6 +5060,46 @@ maybe_gc (void) maybe_garbage_collect (); } +/* A type with alignment at least as large as any object that Emacs + allocates. This is not max_align_t because some platforms (e.g., + mingw) have buggy malloc implementations that do not align for + max_align_t. This union contains types of all GCALIGNED_STRUCT + components visible here. */ +union emacs_align_type +{ + struct Lisp_Bool_Vector Lisp_Bool_Vector; + struct Lisp_Char_Table Lisp_Char_Table; + struct Lisp_CondVar Lisp_CondVar; + struct Lisp_Finalizer Lisp_Finalizer; + struct Lisp_Float Lisp_Float; + struct Lisp_Hash_Table Lisp_Hash_Table; + struct Lisp_Marker Lisp_Marker; + struct Lisp_Misc_Ptr Lisp_Misc_Ptr; + struct Lisp_Mutex Lisp_Mutex; + struct Lisp_Overlay Lisp_Overlay; + struct Lisp_Sub_Char_Table Lisp_Sub_Char_Table; + struct Lisp_Subr Lisp_Subr; + struct Lisp_User_Ptr Lisp_User_Ptr; + struct Lisp_Vector Lisp_Vector; + struct thread_state thread_state; + + /* Omit the following since they would require including bignum.h, + frame.h etc., and in practice their alignments never exceed that + of the structs already listed. */ +#if 0 + struct frame frame; + struct Lisp_Bignum Lisp_Bignum; + struct Lisp_Module_Function Lisp_Module_Function; + struct Lisp_Process Lisp_Process; + struct save_window_data save_window_data; + struct scroll_bar scroll_bar; + struct terminal terminal; + struct window window; + struct xwidget xwidget; + struct xwidget_view xwidget_view; +#endif +}; + INLINE_HEADER_END #endif /* EMACS_LISP_H */