aboutsummaryrefslogtreecommitdiffstats
path: root/src/sysdep.c
diff options
context:
space:
mode:
authorDmitry Antipov2014-08-26 10:25:59 +0400
committerDmitry Antipov2014-08-26 10:25:59 +0400
commitebd31792b292f63f09efa498b5df73bf86107259 (patch)
tree8cd196b0c4c03a3e76e00ed6c0fa010af49d3aea /src/sysdep.c
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.
Diffstat (limited to 'src/sysdep.c')
-rw-r--r--src/sysdep.c73
1 files changed, 71 insertions, 2 deletions
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