mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-06 06:20:55 -08:00
Improve stack-top heuristic
This is needed for gcc -Os -flto on x86-64; otherwise, GC misses part of the stack when scanning for heap roots, causing Emacs to crash later (Bug#28213). The problem is that Emacs's hack for getting an address near the stack top does not work when link-time optimization moves stack variables around. * configure.ac (HAVE___BUILTIN_FRAME_ADDRESS): New macro. * lib-src/make-docfile.c (DEFUN_noinline): New constant. (write_globals, scan_c_stream): Support noinline. * src/alloc.c (NEAR_STACK_TOP): New macro. (SET_STACK_TOP_ADDRESS): Use it. (flush_stack_call_func, Fgarbage_collect): Now noinline.
This commit is contained in:
parent
f1fdb5bc57
commit
9baeed3514
3 changed files with 31 additions and 7 deletions
|
|
@ -3958,6 +3958,15 @@ AC_CHECK_FUNCS([aligned_alloc posix_memalign], [break])
|
|||
AC_CHECK_DECLS([aligned_alloc], [], [], [[#include <stdlib.h>]])
|
||||
|
||||
dnl Cannot use AC_CHECK_FUNCS
|
||||
AC_CACHE_CHECK([for __builtin_frame_address],
|
||||
[emacs_cv_func___builtin_frame_address],
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([], [__builtin_frame_address (0);])],
|
||||
[emacs_cv_func___builtin_frame_address=yes],
|
||||
[emacs_cv_func___builtin_frame_address=no])])
|
||||
if test $emacs_cv_func___builtin_frame_address = yes; then
|
||||
AC_DEFINE([HAVE___BUILTIN_FRAME_ADDRESS], 1,
|
||||
[Define to 1 if you have the '__builtin_frame_address' function.])
|
||||
fi
|
||||
AC_CACHE_CHECK([for __builtin_unwind_init],
|
||||
emacs_cv_func___builtin_unwind_init,
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([], [__builtin_unwind_init ();])],
|
||||
|
|
|
|||
|
|
@ -592,7 +592,7 @@ struct global
|
|||
};
|
||||
|
||||
/* Bit values for FLAGS field from the above. Applied for DEFUNs only. */
|
||||
enum { DEFUN_noreturn = 1, DEFUN_const = 2 };
|
||||
enum { DEFUN_noreturn = 1, DEFUN_const = 2, DEFUN_noinline = 4 };
|
||||
|
||||
/* All the variable names we saw while scanning C sources in `-g'
|
||||
mode. */
|
||||
|
|
@ -742,6 +742,8 @@ write_globals (void)
|
|||
{
|
||||
if (globals[i].flags & DEFUN_noreturn)
|
||||
fputs ("_Noreturn ", stdout);
|
||||
if (globals[i].flags & DEFUN_noinline)
|
||||
fputs ("NO_INLINE ", stdout);
|
||||
|
||||
printf ("EXFUN (%s, ", globals[i].name);
|
||||
if (globals[i].v.value == -1)
|
||||
|
|
@ -1062,7 +1064,8 @@ scan_c_stream (FILE *infile)
|
|||
attributes: attribute1 attribute2 ...)
|
||||
(Lisp_Object arg...)
|
||||
|
||||
Now only 'noreturn' and 'const' attributes are used. */
|
||||
Now only ’const’, ’noinline’ and 'noreturn' attributes
|
||||
are used. */
|
||||
|
||||
/* Advance to the end of docstring. */
|
||||
c = getc (infile);
|
||||
|
|
@ -1108,6 +1111,8 @@ scan_c_stream (FILE *infile)
|
|||
g->flags |= DEFUN_noreturn;
|
||||
if (strstr (input_buffer, "const"))
|
||||
g->flags |= DEFUN_const;
|
||||
if (strstr (input_buffer, "noinline"))
|
||||
g->flags |= DEFUN_noinline;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
20
src/alloc.c
20
src/alloc.c
|
|
@ -5061,22 +5061,31 @@ typedef union
|
|||
# endif
|
||||
#endif
|
||||
|
||||
/* Yield an address close enough to the top of the stack that the
|
||||
garbage collector need not scan above it. Callers should be
|
||||
declared NO_INLINE. */
|
||||
#ifdef HAVE___BUILTIN_FRAME_ADDRESS
|
||||
# define NEAR_STACK_TOP(addr) ((void) (addr), __builtin_frame_address (0))
|
||||
#else
|
||||
# define NEAR_STACK_TOP(addr) (addr)
|
||||
#endif
|
||||
|
||||
/* Set *P to the address of the top of the stack. This must be a
|
||||
macro, not a function, so that it is executed in the caller’s
|
||||
environment. It is not inside a do-while so that its storage
|
||||
survives the macro. */
|
||||
survives the macro. Callers should be declared NO_INLINE. */
|
||||
#ifdef HAVE___BUILTIN_UNWIND_INIT
|
||||
# define SET_STACK_TOP_ADDRESS(p) \
|
||||
stacktop_sentry sentry; \
|
||||
__builtin_unwind_init (); \
|
||||
*(p) = &sentry
|
||||
*(p) = NEAR_STACK_TOP (&sentry)
|
||||
#else
|
||||
# define SET_STACK_TOP_ADDRESS(p) \
|
||||
stacktop_sentry sentry; \
|
||||
__builtin_unwind_init (); \
|
||||
test_setjmp (); \
|
||||
sys_setjmp (sentry.j); \
|
||||
*(p) = &sentry + (stack_bottom < &sentry.c)
|
||||
*(p) = NEAR_STACK_TOP (&sentry + (stack_bottom < &sentry.c))
|
||||
#endif
|
||||
|
||||
/* Mark live Lisp objects on the C stack.
|
||||
|
|
@ -5148,7 +5157,7 @@ mark_stack (char *bottom, char *end)
|
|||
It is invalid to run any Lisp code or to allocate any GC memory
|
||||
from FUNC. */
|
||||
|
||||
void
|
||||
NO_INLINE void
|
||||
flush_stack_call_func (void (*func) (void *arg), void *arg)
|
||||
{
|
||||
void *end;
|
||||
|
|
@ -6097,7 +6106,8 @@ where each entry has the form (NAME SIZE USED FREE), where:
|
|||
to return them to the OS).
|
||||
However, if there was overflow in pure space, `garbage-collect'
|
||||
returns nil, because real GC can't be done.
|
||||
See Info node `(elisp)Garbage Collection'. */)
|
||||
See Info node `(elisp)Garbage Collection'. */
|
||||
attributes: noinline)
|
||||
(void)
|
||||
{
|
||||
void *end;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue