]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve stack-top heuristic
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 29 Aug 2017 21:20:47 +0000 (14:20 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 29 Aug 2017 21:58:49 +0000 (14:58 -0700)
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.

configure.ac
lib-src/make-docfile.c
src/alloc.c

index 443344de4c233e29b7f144ec3fd88c38c4cf51f5..3dee40704dd2df418169b31379e54b446886b583 100644 (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 ();])],
index ecd6447ab7871f99b9e8a540878080a2a37afccd..c48f202a51152345ed2c928c701ce35dbbf89557 100644 (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;
        }
index 2cee64625641c3ba6f67b464f36bcc7af935e568..6e57b2024bcf2e5f6ebbc61d3acd6e9f9a75f512 100644 (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 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;