diff options
| author | Dmitry Antipov | 2014-08-26 10:25:59 +0400 |
|---|---|---|
| committer | Dmitry Antipov | 2014-08-26 10:25:59 +0400 |
| commit | ebd31792b292f63f09efa498b5df73bf86107259 (patch) | |
| tree | 8cd196b0c4c03a3e76e00ed6c0fa010af49d3aea /src/sysdep.c | |
| parent | 940ac42ae3d5c5c5d80f984278446ab34c0bb26a (diff) | |
| download | emacs-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.c | 73 |
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 | |||
| 1725 | static bool stack_grows_down; | ||
| 1726 | |||
| 1727 | /* Alternate stack used by SIGSEGV handler below. */ | ||
| 1728 | |||
| 1729 | static unsigned char sigsegv_stack[SIGSTKSZ]; | ||
| 1730 | |||
| 1731 | /* Attempt to recover from SIGSEGV caused by C stack overflow. */ | ||
| 1732 | |||
| 1733 | static void | ||
| 1734 | handle_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 | |||
| 1757 | static bool | ||
| 1758 | init_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 | |||
| 1779 | static bool | ||
| 1780 | init_sigsegv (void) | ||
| 1781 | { | ||
| 1782 | return 0; | ||
| 1783 | } | ||
| 1784 | |||
| 1785 | #endif /* HAVE_STACK_OVERFLOW_HANDLING */ | ||
| 1786 | |||
| 1719 | static void | 1787 | static void |
| 1720 | deliver_arith_signal (int sig) | 1788 | deliver_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 |