aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Antipov2014-08-26 10:25:59 +0400
committerDmitry Antipov2014-08-26 10:25:59 +0400
commitebd31792b292f63f09efa498b5df73bf86107259 (patch)
tree8cd196b0c4c03a3e76e00ed6c0fa010af49d3aea
parent940ac42ae3d5c5c5d80f984278446ab34c0bb26a (diff)
downloademacs-ebd31792b292f63f09efa498b5df73bf86107259.tar.gz
emacs-ebd31792b292f63f09efa498b5df73bf86107259.zip
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.
-rw-r--r--ChangeLog7
-rw-r--r--configure.ac57
-rw-r--r--lisp/ChangeLog4
-rw-r--r--lisp/startup.el2
-rw-r--r--src/ChangeLog19
-rw-r--r--src/keyboard.c33
-rw-r--r--src/lisp.h3
-rw-r--r--src/sysdep.c73
8 files changed, 179 insertions, 19 deletions
diff --git a/ChangeLog b/ChangeLog
index de9f3a0bef4..67fc0b87bcb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
12014-08-26 Dmitry Antipov <dmantipov@yandex.ru>
2
3 Detect features needed to handle C stack overflows.
4 * configure.ac: Check for sigaltstack and related sigaction
5 support. Unconditionally check for sigsetjmp and siglongjmp.
6 (HAVE_STACK_OVERFLOW_HANDLING): Define if we can support it.
7
12014-08-25 Ken Brown <kbrown@cornell.edu> 82014-08-25 Ken Brown <kbrown@cornell.edu>
2 9
3 * configure.ac (G_SLICE_ALWAYS_MALLOC): Remove obsolete macro. 10 * configure.ac (G_SLICE_ALWAYS_MALLOC): Remove obsolete macro.
diff --git a/configure.ac b/configure.ac
index 967f0195d0f..d6476d2e1c7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3728,6 +3728,22 @@ if test "$emacs_cv_have_timerfd" = yes; then
3728 [Define to 1 if timerfd functions are supported as in GNU/Linux.]) 3728 [Define to 1 if timerfd functions are supported as in GNU/Linux.])
3729fi 3729fi
3730 3730
3731# Alternate stack for signal handlers.
3732AC_CACHE_CHECK([whether signals can be handled on alternate stack],
3733 [emacs_cv_alternate_stack],
3734 [AC_COMPILE_IFELSE(
3735 [AC_LANG_PROGRAM([[#include <signal.h>
3736 ]],
3737 [[stack_t ss;
3738 struct sigaction sa;
3739 ss.ss_sp = malloc (SIGSTKSZ);
3740 ss.ss_size = SIGSTKSZ;
3741 sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
3742 sigaltstack (&ss, 0);
3743 sigaction (SIGSEGV, &sa, 0);]])],
3744 [emacs_cv_alternate_stack=yes],
3745 [emacs_cv_alternate_stack=no])])
3746
3731# Do we have res_init, for detecting changes in /etc/resolv.conf? 3747# Do we have res_init, for detecting changes in /etc/resolv.conf?
3732# On Darwin, res_init appears not to be useful: see bug#562 and 3748# On Darwin, res_init appears not to be useful: see bug#562 and
3733# http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg01467.html 3749# http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg01467.html
@@ -4447,22 +4463,31 @@ AC_CACHE_CHECK([for _setjmp], [emacs_cv_func__setjmp],
4447 [emacs_cv_func__setjmp=no])]) 4463 [emacs_cv_func__setjmp=no])])
4448if test $emacs_cv_func__setjmp = yes; then 4464if test $emacs_cv_func__setjmp = yes; then
4449 AC_DEFINE([HAVE__SETJMP], 1, [Define to 1 if _setjmp and _longjmp work.]) 4465 AC_DEFINE([HAVE__SETJMP], 1, [Define to 1 if _setjmp and _longjmp work.])
4450else 4466fi
4451 AC_CACHE_CHECK([for sigsetjmp], [emacs_cv_func_sigsetjmp], 4467
4452 [AC_LINK_IFELSE( 4468# We need to preserve signal mask to handle C stack overflows.
4453 [AC_LANG_PROGRAM( 4469AC_CACHE_CHECK([for sigsetjmp], [emacs_cv_func_sigsetjmp],
4454 [[#include <setjmp.h> 4470 [AC_LINK_IFELSE(
4455 ]], 4471 [AC_LANG_PROGRAM(
4456 [[sigjmp_buf j; 4472 [[#include <setjmp.h>
4457 if (! sigsetjmp (j, 1)) 4473 ]],
4458 siglongjmp (j, 1);]])], 4474 [[sigjmp_buf j;
4459 [emacs_cv_func_sigsetjmp=yes], 4475 if (! sigsetjmp (j, 1))
4460 [emacs_cv_func_sigsetjmp=no])]) 4476 siglongjmp (j, 1);]])],
4461 if test $emacs_cv_func_sigsetjmp = yes; then 4477 [emacs_cv_func_sigsetjmp=yes],
4462 AC_DEFINE([HAVE_SIGSETJMP], 1, 4478 [emacs_cv_func_sigsetjmp=no])])
4463 [Define to 1 if sigsetjmp and siglongjmp work. 4479if test $emacs_cv_func_sigsetjmp = yes; then
4464 The value of this symbol is irrelevant if HAVE__SETJMP is defined.]) 4480 AC_DEFINE([HAVE_SIGSETJMP], 1,
4465 fi 4481 [Define to 1 if sigsetjmp and siglongjmp work.])
4482fi
4483
4484# We need all of these features to handle C stack overflows.
4485if test "$ac_cv_header_sys_resource_h" = "yes" -a \
4486 "$ac_cv_func_getrlimit" = "yes" -a \
4487 "$emacs_cv_func_sigsetjmp" = "yes" -a \
4488 "$emacs_cv_alternate_stack" = yes; then
4489 AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], 1,
4490 [Define to 1 if C stack overflow can be handled in some cases.])
4466fi 4491fi
4467 4492
4468case $opsys in 4493case $opsys in
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 65a59f4da6d..12d283e7120 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,7 @@
12014-08-26 Dmitry Antipov <dmantipov@yandex.ru>
2
3 * startup.el (normal-top-level): Use top-level-message.
4
12014-08-25 Lars Magne Ingebrigtsen <larsi@gnus.org> 52014-08-25 Lars Magne Ingebrigtsen <larsi@gnus.org>
2 6
3 * net/shr.el (shr-copy-url): Encode copied URL to avoid getting 7 * net/shr.el (shr-copy-url): Encode copied URL to avoid getting
diff --git a/lisp/startup.el b/lisp/startup.el
index 144d732272f..1d5ae250505 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -497,7 +497,7 @@ It sets `command-line-processed', processes the command-line,
497reads the initialization files, etc. 497reads the initialization files, etc.
498It is the default value of the variable `top-level'." 498It is the default value of the variable `top-level'."
499 (if command-line-processed 499 (if command-line-processed
500 (message "Back to top level.") 500 (message top-level-message)
501 (setq command-line-processed t) 501 (setq command-line-processed t)
502 502
503 ;; Look in each dir in load-path for a subdirs.el file. If we 503 ;; Look in each dir in load-path for a subdirs.el file. If we
diff --git a/src/ChangeLog b/src/ChangeLog
index 391d2e52100..f618ba02448 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,22 @@
12014-08-26 Dmitry Antipov <dmantipov@yandex.ru>
2
3 Handle C stack overflow caused by too nested Lisp evaluation.
4 * lisp.h (toplevel) [HAVE_STACK_OVERFLOW_HANDLING]: Declare
5 siglongjmp point to transfer control from SIGSEGV handler.
6 * keyboard.c (return_to_command_loop, recover_top_level_message)
7 [HAVE_STACK_OVERFLOW_HANDLING]: New variables.
8 (regular_top_level_message): New variable.
9 (command_loop) [HAVE_STACK_OVERFLOW_HANDLING]: Handle non-local
10 exit from SIGSEGV handler and adjust message displayed by Vtop_level
11 if appropriate.
12 (syms_of_keyboard): DEFVAR Vtop_level_message and initialize
13 new variables described above.
14 * sysdep.c [HAVE_SYS_RESOURCE_H]: Include sys/resource.h as such.
15 (stack_grows_down, sigsegv_stack, handle_sigsegv)
16 [HAVE_STACK_OVERFLOW_HANDLING]: New variables and function.
17 (init_sigsegv): New function.
18 (init_signals): Use it.
19
12014-08-25 Ken Brown <kbrown@cornell.edu> 202014-08-25 Ken Brown <kbrown@cornell.edu>
2 21
3 * emacs.c (main): Remove use of obsolete macro 22 * emacs.c (main): Remove use of obsolete macro
diff --git a/src/keyboard.c b/src/keyboard.c
index 9b0b19ada2f..ed00b38a7db 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -133,6 +133,19 @@ static ptrdiff_t this_single_command_key_start;
133static ptrdiff_t before_command_key_count; 133static ptrdiff_t before_command_key_count;
134static ptrdiff_t before_command_echo_length; 134static ptrdiff_t before_command_echo_length;
135 135
136#ifdef HAVE_STACK_OVERFLOW_HANDLING
137
138/* For longjmp to recover from C stack overflow. */
139sigjmp_buf return_to_command_loop;
140
141/* Message displayed by Vtop_level when recovering from C stack overflow. */
142static Lisp_Object recover_top_level_message;
143
144#endif /* HAVE_STACK_OVERFLOW_HANDLING */
145
146/* Message normally displayed by Vtop_level. */
147static Lisp_Object regular_top_level_message;
148
136/* For longjmp to where kbd input is being done. */ 149/* For longjmp to where kbd input is being done. */
137 150
138static sys_jmp_buf getcjmp; 151static sys_jmp_buf getcjmp;
@@ -1134,6 +1147,17 @@ static Lisp_Object top_level_1 (Lisp_Object);
1134Lisp_Object 1147Lisp_Object
1135command_loop (void) 1148command_loop (void)
1136{ 1149{
1150#ifdef HAVE_STACK_OVERFLOW_HANDLING
1151 /* At least on GNU/Linux, saving signal mask is important here. */
1152 if (sigsetjmp (return_to_command_loop, 1) != 0)
1153 {
1154 /* Comes here from handle_sigsegv, see sysdep.c. */
1155 init_eval ();
1156 Vtop_level_message = recover_top_level_message;
1157 }
1158 else
1159 Vtop_level_message = regular_top_level_message;
1160#endif /* HAVE_STACK_OVERFLOW_HANDLING */
1137 if (command_loop_level > 0 || minibuf_level > 0) 1161 if (command_loop_level > 0 || minibuf_level > 0)
1138 { 1162 {
1139 Lisp_Object val; 1163 Lisp_Object val;
@@ -11000,6 +11024,15 @@ syms_of_keyboard (void)
11000 Vlispy_mouse_stem = build_pure_c_string ("mouse"); 11024 Vlispy_mouse_stem = build_pure_c_string ("mouse");
11001 staticpro (&Vlispy_mouse_stem); 11025 staticpro (&Vlispy_mouse_stem);
11002 11026
11027 regular_top_level_message = build_pure_c_string ("Back to top level");
11028#ifdef HAVE_STACK_OVERFLOW_HANDLING
11029 recover_top_level_message
11030 = build_pure_c_string ("Re-entering top level after C stack overflow");
11031#endif
11032 DEFVAR_LISP ("top-level-message", Vtop_level_message,
11033 doc: /* Message displayed by `normal-top-level'. */);
11034 Vtop_level_message = regular_top_level_message;
11035
11003 /* Tool-bars. */ 11036 /* Tool-bars. */
11004 DEFSYM (QCimage, ":image"); 11037 DEFSYM (QCimage, ":image");
11005 DEFSYM (Qhelp_echo, "help-echo"); 11038 DEFSYM (Qhelp_echo, "help-echo");
diff --git a/src/lisp.h b/src/lisp.h
index 1e2a8b6535f..012e5fad18d 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4093,6 +4093,9 @@ extern Lisp_Object Qdisabled, QCfilter;
4093extern Lisp_Object Qup, Qdown; 4093extern Lisp_Object Qup, Qdown;
4094extern Lisp_Object last_undo_boundary; 4094extern Lisp_Object last_undo_boundary;
4095extern bool input_pending; 4095extern bool input_pending;
4096#ifdef HAVE_STACK_OVERFLOW_HANDLING
4097extern sigjmp_buf return_to_command_loop;
4098#endif
4096extern Lisp_Object menu_bar_items (Lisp_Object); 4099extern Lisp_Object menu_bar_items (Lisp_Object);
4097extern Lisp_Object tool_bar_items (Lisp_Object, int *); 4100extern Lisp_Object tool_bar_items (Lisp_Object, int *);
4098extern void discard_mouse_events (void); 4101extern void discard_mouse_events (void);
diff --git a/src/sysdep.c b/src/sysdep.c
index 25bec264f46..f32bd5d1bb6 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -46,7 +46,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
46# include <sys/user.h> 46# include <sys/user.h>
47# undef frame 47# undef frame
48 48
49# include <sys/resource.h>
50# include <math.h> 49# include <math.h>
51#endif 50#endif
52 51
@@ -72,6 +71,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
72#include "msdos.h" 71#include "msdos.h"
73#endif 72#endif
74 73
74#ifdef HAVE_SYS_RESOURCE_H
75#include <sys/resource.h>
76#endif
75#include <sys/param.h> 77#include <sys/param.h>
76#include <sys/file.h> 78#include <sys/file.h>
77#include <fcntl.h> 79#include <fcntl.h>
@@ -1716,6 +1718,72 @@ handle_arith_signal (int sig)
1716 xsignal0 (Qarith_error); 1718 xsignal0 (Qarith_error);
1717} 1719}
1718 1720
1721#ifdef HAVE_STACK_OVERFLOW_HANDLING
1722
1723/* True if stack grows down as expected on most OS/ABI variants. */
1724
1725static bool stack_grows_down;
1726
1727/* Alternate stack used by SIGSEGV handler below. */
1728
1729static unsigned char sigsegv_stack[SIGSTKSZ];
1730
1731/* Attempt to recover from SIGSEGV caused by C stack overflow. */
1732
1733static void
1734handle_sigsegv (int sig, siginfo_t *siginfo, void *arg)
1735{
1736 /* Hard GC error may lead to stack overflow caused by
1737 too nested calls to mark_object. No way to survive. */
1738 if (!gc_in_progress)
1739 {
1740 struct rlimit rlim;
1741
1742 if (!getrlimit (RLIMIT_STACK, &rlim))
1743 {
1744 enum { STACK_EXTRA = 16 * 1024 };
1745 char *fault_addr = (char *) siginfo->si_addr;
1746 unsigned long used = (stack_grows_down
1747 ? stack_bottom - fault_addr
1748 : fault_addr - stack_bottom);
1749
1750 if (used + STACK_EXTRA > rlim.rlim_cur)
1751 /* Most likely this is it. */
1752 siglongjmp (return_to_command_loop, 1);
1753 }
1754 }
1755}
1756
1757static bool
1758init_sigsegv (void)
1759{
1760 struct sigaction sa;
1761 stack_t ss;
1762
1763 stack_grows_down = ((char *) &ss < stack_bottom);
1764
1765 ss.ss_sp = sigsegv_stack;
1766 ss.ss_size = sizeof (sigsegv_stack);
1767 ss.ss_flags = 0;
1768 if (sigaltstack (&ss, NULL) < 0)
1769 return 0;
1770
1771 sigfillset (&sa.sa_mask);
1772 sa.sa_sigaction = handle_sigsegv;
1773 sa.sa_flags = SA_SIGINFO | SA_ONSTACK | emacs_sigaction_flags ();
1774 return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1;
1775}
1776
1777#else /* not HAVE_STACK_OVERFLOW_HANDLING */
1778
1779static bool
1780init_sigsegv (void)
1781{
1782 return 0;
1783}
1784
1785#endif /* HAVE_STACK_OVERFLOW_HANDLING */
1786
1719static void 1787static void
1720deliver_arith_signal (int sig) 1788deliver_arith_signal (int sig)
1721{ 1789{
@@ -1982,7 +2050,8 @@ init_signals (bool dumping)
1982#ifdef SIGBUS 2050#ifdef SIGBUS
1983 sigaction (SIGBUS, &thread_fatal_action, 0); 2051 sigaction (SIGBUS, &thread_fatal_action, 0);
1984#endif 2052#endif
1985 sigaction (SIGSEGV, &thread_fatal_action, 0); 2053 if (!init_sigsegv ())
2054 sigaction (SIGSEGV, &thread_fatal_action, 0);
1986#ifdef SIGSYS 2055#ifdef SIGSYS
1987 sigaction (SIGSYS, &thread_fatal_action, 0); 2056 sigaction (SIGSYS, &thread_fatal_action, 0);
1988#endif 2057#endif