1
Fork 0
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:
Paul Eggert 2017-08-29 14:20:47 -07:00
parent f1fdb5bc57
commit 9baeed3514
3 changed files with 31 additions and 7 deletions

View file

@ -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 ();])],

View file

@ -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;
}

View file

@ -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 callers
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;