emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r117741: Handle C stack overflow caused by too neste


From: Dmitry Antipov
Subject: [Emacs-diffs] trunk r117741: Handle C stack overflow caused by too nested Lisp evaluation.
Date: Tue, 26 Aug 2014 06:27:32 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 117741
revision-id: address@hidden
parent: address@hidden
committer: Dmitry Antipov <address@hidden>
branch nick: trunk
timestamp: Tue 2014-08-26 10:25:59 +0400
message:
  Handle C stack overflow caused by too nested Lisp evaluation.
  * configure.ac: Check for sigaltstack and related sigaction
  support.  Unconditionally check for sigsetjmp and siglongjmp.
  (HAVE_STACK_OVERFLOW_HANDLING): Define if we can support it.
  * src/lisp.h (toplevel) [HAVE_STACK_OVERFLOW_HANDLING]: Declare
  siglongjmp point to transfer control from SIGSEGV handler.
  * src/keyboard.c (return_to_command_loop, recover_top_level_message)
  [HAVE_STACK_OVERFLOW_HANDLING]: New variables.
  (regular_top_level_message): New variable.
  (command_loop) [HAVE_STACK_OVERFLOW_HANDLING]: Handle non-local
  exit from SIGSEGV handler and adjust message displayed by Vtop_level
  if appropriate.
  (syms_of_keyboard): DEFVAR Vtop_level_message and initialize
  new variables described above.
  * src/sysdep.c [HAVE_SYS_RESOURCE_H]: Include sys/resource.h as such.
  (stack_grows_down, sigsegv_stack, handle_sigsegv)
  [HAVE_STACK_OVERFLOW_HANDLING]: New variables and function.
  (init_sigsegv): New function.
  (init_signals): Use it.
  * lisp/startup.el (normal-top-level): Use top-level-message.
modified:
  ChangeLog                      changelog-20091113204419-o5vbwnq5f7feedwu-1538
  configure.ac                   
configure.in-20091113204419-o5vbwnq5f7feedwu-783
  lisp/ChangeLog                 changelog-20091113204419-o5vbwnq5f7feedwu-1432
  lisp/startup.el                startup.el-20091113204419-o5vbwnq5f7feedwu-260
  src/ChangeLog                  changelog-20091113204419-o5vbwnq5f7feedwu-1438
  src/keyboard.c                 keyboard.c-20091113204419-o5vbwnq5f7feedwu-449
  src/lisp.h                     lisp.h-20091113204419-o5vbwnq5f7feedwu-253
  src/sysdep.c                   sysdep.c-20091113204419-o5vbwnq5f7feedwu-448
=== modified file 'ChangeLog'
--- a/ChangeLog 2014-08-25 20:49:52 +0000
+++ b/ChangeLog 2014-08-26 06:25:59 +0000
@@ -1,3 +1,10 @@
+2014-08-26  Dmitry Antipov  <address@hidden>
+
+       Detect features needed to handle C stack overflows.
+       * configure.ac: Check for sigaltstack and related sigaction
+       support.  Unconditionally check for sigsetjmp and siglongjmp.
+       (HAVE_STACK_OVERFLOW_HANDLING): Define if we can support it.
+
 2014-08-25  Ken Brown  <address@hidden>
 
        * configure.ac (G_SLICE_ALWAYS_MALLOC): Remove obsolete macro.

=== modified file 'configure.ac'
--- a/configure.ac      2014-08-25 20:55:37 +0000
+++ b/configure.ac      2014-08-26 06:25:59 +0000
@@ -3728,6 +3728,22 @@
     [Define to 1 if timerfd functions are supported as in GNU/Linux.])
 fi
 
+# Alternate stack for signal handlers.
+AC_CACHE_CHECK([whether signals can be handled on alternate stack],
+              [emacs_cv_alternate_stack],
+  [AC_COMPILE_IFELSE(
+     [AC_LANG_PROGRAM([[#include <signal.h>
+                     ]],
+                     [[stack_t ss;
+                       struct sigaction sa;
+                       ss.ss_sp = malloc (SIGSTKSZ);
+                       ss.ss_size = SIGSTKSZ;
+                       sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
+                       sigaltstack (&ss, 0);
+                       sigaction (SIGSEGV, &sa, 0);]])],
+     [emacs_cv_alternate_stack=yes],
+     [emacs_cv_alternate_stack=no])])
+
 # Do we have res_init, for detecting changes in /etc/resolv.conf?
 # On Darwin, res_init appears not to be useful: see bug#562 and
 # http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg01467.html
@@ -4447,22 +4463,31 @@
      [emacs_cv_func__setjmp=no])])
 if test $emacs_cv_func__setjmp = yes; then
   AC_DEFINE([HAVE__SETJMP], 1, [Define to 1 if _setjmp and _longjmp work.])
-else
-  AC_CACHE_CHECK([for sigsetjmp], [emacs_cv_func_sigsetjmp],
-    [AC_LINK_IFELSE(
-       [AC_LANG_PROGRAM(
-        [[#include <setjmp.h>
-        ]],
-        [[sigjmp_buf j;
-          if (! sigsetjmp (j, 1))
-            siglongjmp (j, 1);]])],
-       [emacs_cv_func_sigsetjmp=yes],
-       [emacs_cv_func_sigsetjmp=no])])
-  if test $emacs_cv_func_sigsetjmp = yes; then
-    AC_DEFINE([HAVE_SIGSETJMP], 1,
-      [Define to 1 if sigsetjmp and siglongjmp work.
-       The value of this symbol is irrelevant if HAVE__SETJMP is defined.])
-  fi
+fi
+
+# We need to preserve signal mask to handle C stack overflows.
+AC_CACHE_CHECK([for sigsetjmp], [emacs_cv_func_sigsetjmp],
+  [AC_LINK_IFELSE(
+     [AC_LANG_PROGRAM(
+       [[#include <setjmp.h>
+       ]],
+       [[sigjmp_buf j;
+         if (! sigsetjmp (j, 1))
+          siglongjmp (j, 1);]])],
+     [emacs_cv_func_sigsetjmp=yes],
+     [emacs_cv_func_sigsetjmp=no])])
+if test $emacs_cv_func_sigsetjmp = yes; then
+  AC_DEFINE([HAVE_SIGSETJMP], 1,
+    [Define to 1 if sigsetjmp and siglongjmp work.])
+fi
+
+# We need all of these features to handle C stack overflows.
+if test "$ac_cv_header_sys_resource_h" = "yes" -a \
+       "$ac_cv_func_getrlimit" = "yes" -a \
+       "$emacs_cv_func_sigsetjmp" = "yes" -a \
+       "$emacs_cv_alternate_stack" = yes; then
+  AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], 1,
+    [Define to 1 if C stack overflow can be handled in some cases.])
 fi
 
 case $opsys in

=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2014-08-25 15:59:38 +0000
+++ b/lisp/ChangeLog    2014-08-26 06:25:59 +0000
@@ -1,3 +1,7 @@
+2014-08-26  Dmitry Antipov  <address@hidden>
+
+       * startup.el (normal-top-level): Use top-level-message.
+
 2014-08-25  Lars Magne Ingebrigtsen  <address@hidden>
 
        * net/shr.el (shr-copy-url): Encode copied URL to avoid getting

=== modified file 'lisp/startup.el'
--- a/lisp/startup.el   2014-07-27 13:21:30 +0000
+++ b/lisp/startup.el   2014-08-26 06:25:59 +0000
@@ -497,7 +497,7 @@
 reads the initialization files, etc.
 It is the default value of the variable `top-level'."
   (if command-line-processed
-      (message "Back to top level.")
+      (message top-level-message)
     (setq command-line-processed t)
 
     ;; Look in each dir in load-path for a subdirs.el file.  If we

=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2014-08-25 20:49:52 +0000
+++ b/src/ChangeLog     2014-08-26 06:25:59 +0000
@@ -1,3 +1,22 @@
+2014-08-26  Dmitry Antipov  <address@hidden>
+
+       Handle C stack overflow caused by too nested Lisp evaluation.
+       * lisp.h (toplevel) [HAVE_STACK_OVERFLOW_HANDLING]: Declare
+       siglongjmp point to transfer control from SIGSEGV handler.
+       * keyboard.c (return_to_command_loop, recover_top_level_message)
+       [HAVE_STACK_OVERFLOW_HANDLING]: New variables.
+       (regular_top_level_message): New variable.
+       (command_loop) [HAVE_STACK_OVERFLOW_HANDLING]: Handle non-local
+       exit from SIGSEGV handler and adjust message displayed by Vtop_level
+       if appropriate.
+       (syms_of_keyboard): DEFVAR Vtop_level_message and initialize
+       new variables described above.
+       * sysdep.c [HAVE_SYS_RESOURCE_H]: Include sys/resource.h as such.
+       (stack_grows_down, sigsegv_stack, handle_sigsegv)
+       [HAVE_STACK_OVERFLOW_HANDLING]: New variables and function.
+       (init_sigsegv): New function.
+       (init_signals): Use it.
+
 2014-08-25  Ken Brown  <address@hidden>
 
        * emacs.c (main): Remove use of obsolete macro

=== modified file 'src/keyboard.c'
--- a/src/keyboard.c    2014-08-10 08:26:28 +0000
+++ b/src/keyboard.c    2014-08-26 06:25:59 +0000
@@ -133,6 +133,19 @@
 static ptrdiff_t before_command_key_count;
 static ptrdiff_t before_command_echo_length;
 
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+
+/* For longjmp to recover from C stack overflow.  */
+sigjmp_buf return_to_command_loop;
+
+/* Message displayed by Vtop_level when recovering from C stack overflow.  */
+static Lisp_Object recover_top_level_message;
+
+#endif /* HAVE_STACK_OVERFLOW_HANDLING */
+
+/* Message normally displayed by Vtop_level.  */
+static Lisp_Object regular_top_level_message;
+
 /* For longjmp to where kbd input is being done.  */
 
 static sys_jmp_buf getcjmp;
@@ -1134,6 +1147,17 @@
 Lisp_Object
 command_loop (void)
 {
+#ifdef HAVE_STACK_OVERFLOW_HANDLING  
+  /* At least on GNU/Linux, saving signal mask is important here.  */
+  if (sigsetjmp (return_to_command_loop, 1) != 0)
+    {
+      /* Comes here from handle_sigsegv, see sysdep.c.  */
+      init_eval ();
+      Vtop_level_message = recover_top_level_message;
+    }
+  else
+    Vtop_level_message = regular_top_level_message;
+#endif /* HAVE_STACK_OVERFLOW_HANDLING */
   if (command_loop_level > 0 || minibuf_level > 0)
     {
       Lisp_Object val;
@@ -11000,6 +11024,15 @@
   Vlispy_mouse_stem = build_pure_c_string ("mouse");
   staticpro (&Vlispy_mouse_stem);
 
+  regular_top_level_message = build_pure_c_string ("Back to top level");
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+  recover_top_level_message
+    = build_pure_c_string ("Re-entering top level after C stack overflow");
+#endif  
+  DEFVAR_LISP ("top-level-message", Vtop_level_message,
+              doc: /* Message displayed by `normal-top-level'.  */);
+  Vtop_level_message = regular_top_level_message;
+
   /* Tool-bars.  */
   DEFSYM (QCimage, ":image");
   DEFSYM (Qhelp_echo, "help-echo");

=== modified file 'src/lisp.h'
--- a/src/lisp.h        2014-08-25 05:44:57 +0000
+++ b/src/lisp.h        2014-08-26 06:25:59 +0000
@@ -4093,6 +4093,9 @@
 extern Lisp_Object Qup, Qdown;
 extern Lisp_Object last_undo_boundary;
 extern bool input_pending;
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+extern sigjmp_buf return_to_command_loop;
+#endif
 extern Lisp_Object menu_bar_items (Lisp_Object);
 extern Lisp_Object tool_bar_items (Lisp_Object, int *);
 extern void discard_mouse_events (void);

=== modified file 'src/sysdep.c'
--- a/src/sysdep.c      2014-08-25 15:55:46 +0000
+++ b/src/sysdep.c      2014-08-26 06:25:59 +0000
@@ -46,7 +46,6 @@
 # include <sys/user.h>
 # undef frame
 
-# include <sys/resource.h>
 # include <math.h>
 #endif
 
@@ -72,6 +71,9 @@
 #include "msdos.h"
 #endif
 
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
 #include <sys/param.h>
 #include <sys/file.h>
 #include <fcntl.h>
@@ -1716,6 +1718,72 @@
   xsignal0 (Qarith_error);
 }
 
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+
+/* True if stack grows down as expected on most OS/ABI variants.  */
+
+static bool stack_grows_down;
+
+/* Alternate stack used by SIGSEGV handler below.  */
+
+static unsigned char sigsegv_stack[SIGSTKSZ];
+
+/* Attempt to recover from SIGSEGV caused by C stack overflow.  */
+
+static void
+handle_sigsegv (int sig, siginfo_t *siginfo, void *arg)
+{
+  /* Hard GC error may lead to stack overflow caused by
+     too nested calls to mark_object.  No way to survive.  */
+  if (!gc_in_progress)
+    {
+      struct rlimit rlim;
+
+      if (!getrlimit (RLIMIT_STACK, &rlim))
+       {
+         enum { STACK_EXTRA = 16 * 1024 };
+         char *fault_addr = (char *) siginfo->si_addr;
+         unsigned long used = (stack_grows_down
+                               ? stack_bottom - fault_addr
+                               : fault_addr - stack_bottom);
+
+         if (used + STACK_EXTRA > rlim.rlim_cur)
+           /* Most likely this is it.  */
+           siglongjmp (return_to_command_loop, 1);
+       }
+    }
+}
+
+static bool
+init_sigsegv (void)
+{
+  struct sigaction sa;
+  stack_t ss;
+
+  stack_grows_down = ((char *) &ss < stack_bottom);
+
+  ss.ss_sp = sigsegv_stack;
+  ss.ss_size = sizeof (sigsegv_stack);
+  ss.ss_flags = 0;
+  if (sigaltstack (&ss, NULL) < 0)
+    return 0;
+
+  sigfillset (&sa.sa_mask);
+  sa.sa_sigaction = handle_sigsegv;
+  sa.sa_flags = SA_SIGINFO | SA_ONSTACK | emacs_sigaction_flags ();
+  return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1;
+}
+
+#else /* not HAVE_STACK_OVERFLOW_HANDLING */
+
+static bool
+init_sigsegv (void)
+{
+  return 0;
+}
+
+#endif /* HAVE_STACK_OVERFLOW_HANDLING */
+
 static void
 deliver_arith_signal (int sig)
 {
@@ -1982,7 +2050,8 @@
 #ifdef SIGBUS
   sigaction (SIGBUS, &thread_fatal_action, 0);
 #endif
-  sigaction (SIGSEGV, &thread_fatal_action, 0);
+  if (!init_sigsegv ())
+    sigaction (SIGSEGV, &thread_fatal_action, 0);
 #ifdef SIGSYS
   sigaction (SIGSYS, &thread_fatal_action, 0);
 #endif


reply via email to

[Prev in Thread] Current Thread [Next in Thread]