aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2015-08-08 11:12:06 +0300
committerEli Zaretskii2015-08-08 11:12:06 +0300
commit7afa4f300b9dc38bf3f33b18fa83bfe35e21a479 (patch)
tree032ab5a75ec1ff00cee51ffe6216fceb16a53e6c
parent35656b6fa473a4c422875a61d24ebb736c1be4e9 (diff)
downloademacs-7afa4f300b9dc38bf3f33b18fa83bfe35e21a479.tar.gz
emacs-7afa4f300b9dc38bf3f33b18fa83bfe35e21a479.zip
Support recovery from C stack overflow on MS-Windows
* src/w32fns.c (w32_reset_stack_overflow_guard) (stack_overflow_handler): New functions for handling C stack overflow exceptions. (my_exception_handler): Handle EXCEPTION_STACK_OVERFLOW exceptions specially, and zero out except_addr if we do. (globals_of_w32fns): Initialize dwMainThreadId in non-interactive mode. * src/sysdep.c [HAVE_STACK_OVERFLOW_HANDLING]: Add !WINDOWSNT to the condition, as HAVE_STACK_OVERFLOW_HANDLING is now defined for the MinGW build, but the code guarded by that is for Posix hosts. * src/keyboard.c (command_loop) [WINDOWSNT]: Call w32_reset_stack_overflow_guard. * nt/inc/ms-w32.h (sigjmp_buf): New typedef. (sigsetjmp): New macro. (w32_reset_stack_overflow_guard): Declare the prototype. * configure.ac (HAVE_STACK_OVERFLOW_HANDLING): Set to 1 for MinGW.
-rw-r--r--configure.ac6
-rw-r--r--nt/inc/ms-w32.h14
-rw-r--r--src/keyboard.c6
-rw-r--r--src/sysdep.c6
-rw-r--r--src/w32fns.c61
5 files changed, 87 insertions, 6 deletions
diff --git a/configure.ac b/configure.ac
index 45008d86807..863c9a9fd06 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4563,6 +4563,12 @@ if test "$emacs_cv_func_sigsetjmp" = "yes" &&
4563 [Define to 1 if C stack overflow can be handled in some cases.]) 4563 [Define to 1 if C stack overflow can be handled in some cases.])
4564fi 4564fi
4565 4565
4566# WINDOWSNT can handle C stack overflows even without the above features
4567if test "${opsys}" = "mingw32"; then
4568 AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], 1,
4569 [Define to 1 if C stack overflow can be handled in some cases.])
4570fi
4571
4566case $opsys in 4572case $opsys in
4567 sol2* | unixware ) 4573 sol2* | unixware )
4568 dnl TIOCGPGRP is broken in SysVr4, so we can't send signals to PTY 4574 dnl TIOCGPGRP is broken in SysVr4, so we can't send signals to PTY
diff --git a/nt/inc/ms-w32.h b/nt/inc/ms-w32.h
index 4fb32df0c07..e7a94e81c2d 100644
--- a/nt/inc/ms-w32.h
+++ b/nt/inc/ms-w32.h
@@ -187,6 +187,20 @@ extern struct tm * sys_localtime (const time_t *);
187#undef HAVE__SETJMP 187#undef HAVE__SETJMP
188#endif 188#endif
189 189
190/* The following is needed for recovery from C stack overflows. */
191#include <setjmp.h>
192typedef jmp_buf sigjmp_buf;
193#ifdef MINGW_W64
194/* Evidently, MinGW64's longjmp crashes when invoked from an exception
195 handler, see https://sourceforge.net/p/mingw-w64/mailman/message/32421953/.
196 This seems to be an unsolved problem in the MinGW64 runtime. So we
197 use the GCC intrinsics instead. FIXME. */
198#define sigsetjmp(j,m) __builtin_setjmp(j)
199#else
200#define sigsetjmp(j,m) setjmp(j)
201#endif
202extern void w32_reset_stack_overflow_guard (void);
203
190#ifdef _MSC_VER 204#ifdef _MSC_VER
191#include <sys/timeb.h> 205#include <sys/timeb.h>
192#include <sys/stat.h> 206#include <sys/stat.h>
diff --git a/src/keyboard.c b/src/keyboard.c
index 5f8667586c4..e4fe5b9bb4c 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1092,7 +1092,11 @@ command_loop (void)
1092 /* At least on GNU/Linux, saving signal mask is important here. */ 1092 /* At least on GNU/Linux, saving signal mask is important here. */
1093 if (sigsetjmp (return_to_command_loop, 1) != 0) 1093 if (sigsetjmp (return_to_command_loop, 1) != 0)
1094 { 1094 {
1095 /* Comes here from handle_sigsegv, see sysdep.c. */ 1095 /* Comes here from handle_sigsegv (see sysdep.c) and
1096 stack_overflow_handler (see w32fns.c). */
1097#ifdef WINDOWSNT
1098 w32_reset_stack_overflow_guard ();
1099#endif
1096 init_eval (); 1100 init_eval ();
1097 Vinternal__top_level_message = recover_top_level_message; 1101 Vinternal__top_level_message = recover_top_level_message;
1098 } 1102 }
diff --git a/src/sysdep.c b/src/sysdep.c
index df3e573a6ea..25f111ad0ed 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -1612,7 +1612,7 @@ handle_arith_signal (int sig)
1612 xsignal0 (Qarith_error); 1612 xsignal0 (Qarith_error);
1613} 1613}
1614 1614
1615#ifdef HAVE_STACK_OVERFLOW_HANDLING 1615#if defined HAVE_STACK_OVERFLOW_HANDLING && !defined WINDOWSNT
1616 1616
1617/* Alternate stack used by SIGSEGV handler below. */ 1617/* Alternate stack used by SIGSEGV handler below. */
1618 1618
@@ -1708,7 +1708,7 @@ init_sigsegv (void)
1708 return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1; 1708 return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1;
1709} 1709}
1710 1710
1711#else /* not HAVE_STACK_OVERFLOW_HANDLING */ 1711#else /* not HAVE_STACK_OVERFLOW_HANDLING or WINDOWSNT */
1712 1712
1713static bool 1713static bool
1714init_sigsegv (void) 1714init_sigsegv (void)
@@ -1716,7 +1716,7 @@ init_sigsegv (void)
1716 return 0; 1716 return 0;
1717} 1717}
1718 1718
1719#endif /* HAVE_STACK_OVERFLOW_HANDLING */ 1719#endif /* HAVE_STACK_OVERFLOW_HANDLING && !WINDOWSNT */
1720 1720
1721static void 1721static void
1722deliver_arith_signal (int sig) 1722deliver_arith_signal (int sig)
diff --git a/src/w32fns.c b/src/w32fns.c
index ad93bd41851..4532fb9f469 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -9239,18 +9239,71 @@ static DWORD except_code;
9239static PVOID except_addr; 9239static PVOID except_addr;
9240 9240
9241#ifndef CYGWIN 9241#ifndef CYGWIN
9242
9243/* Stack overflow recovery. */
9244
9245/* Re-establish the guard page at stack limit. This is needed because
9246 when a stack overflow is detected, Windows removes the guard bit
9247 from the guard page, so if we don't re-establish that protection,
9248 the next stack overflow will cause a crash. */
9249void
9250w32_reset_stack_overflow_guard (void)
9251{
9252 /* MinGW headers don't declare this (should be in malloc.h). */
9253 _CRTIMP int __cdecl _resetstkoflw (void);
9254
9255 /* We ignore the return value. If _resetstkoflw fails, the next
9256 stack overflow will crash the program. */
9257 (void)_resetstkoflw ();
9258}
9259
9260static void
9261stack_overflow_handler (void)
9262{
9263 /* Hard GC error may lead to stack overflow caused by
9264 too nested calls to mark_object. No way to survive. */
9265 if (gc_in_progress)
9266 terminate_due_to_signal (SIGSEGV, 40);
9267#ifdef _WIN64
9268 /* See ms-w32.h: MinGW64's longjmp crashes if invoked in this context. */
9269 __builtin_longjmp (return_to_command_loop, 1);
9270#else
9271 sys_longjmp (return_to_command_loop, 1);
9272#endif
9273}
9274
9242/* This handler records the exception code and the address where it 9275/* This handler records the exception code and the address where it
9243 was triggered so that this info could be included in the backtrace. 9276 was triggered so that this info could be included in the backtrace.
9244 Without that, the backtrace in some cases has no information 9277 Without that, the backtrace in some cases has no information
9245 whatsoever about the offending code, and looks as if the top-level 9278 whatsoever about the offending code, and looks as if the top-level
9246 exception handler in the MinGW startup code di the one that 9279 exception handler in the MinGW startup code was the one that
9247 crashed. */ 9280 crashed. We also recover from stack overflow, by calling our stack
9281 overflow handler that jumps back to top level. */
9248static LONG CALLBACK 9282static LONG CALLBACK
9249my_exception_handler (EXCEPTION_POINTERS * exception_data) 9283my_exception_handler (EXCEPTION_POINTERS * exception_data)
9250{ 9284{
9251 except_code = exception_data->ExceptionRecord->ExceptionCode; 9285 except_code = exception_data->ExceptionRecord->ExceptionCode;
9252 except_addr = exception_data->ExceptionRecord->ExceptionAddress; 9286 except_addr = exception_data->ExceptionRecord->ExceptionAddress;
9253 9287
9288 /* If this is a stack overflow exception, attempt to recover. */
9289 if (exception_data->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW
9290 && exception_data->ExceptionRecord->NumberParameters == 2
9291 /* We can only longjmp to top level from the main thread. */
9292 && GetCurrentThreadId () == dwMainThreadId)
9293 {
9294 /* Call stack_overflow_handler (). */
9295#ifdef _WIN64
9296 exception_data->ContextRecord->Rip = (DWORD_PTR) &stack_overflow_handler;
9297#else
9298 exception_data->ContextRecord->Eip = (DWORD_PTR) &stack_overflow_handler;
9299#endif
9300 /* Zero this out, so the stale address of the stack overflow
9301 exception we handled is not displayed in some future
9302 unrelated crash. */
9303 except_addr = 0;
9304 return EXCEPTION_CONTINUE_EXECUTION;
9305 }
9306
9254 if (prev_exception_handler) 9307 if (prev_exception_handler)
9255 return prev_exception_handler (exception_data); 9308 return prev_exception_handler (exception_data);
9256 return EXCEPTION_EXECUTE_HANDLER; 9309 return EXCEPTION_EXECUTE_HANDLER;
@@ -9448,6 +9501,10 @@ globals_of_w32fns (void)
9448 InitCommonControls (); 9501 InitCommonControls ();
9449 9502
9450 syms_of_w32uniscribe (); 9503 syms_of_w32uniscribe ();
9504
9505 /* Needed for recovery from C stack overflows in batch mode. */
9506 if (noninteractive)
9507 dwMainThreadId = GetCurrentThreadId ();
9451} 9508}
9452 9509
9453#ifdef NTGUI_UNICODE 9510#ifdef NTGUI_UNICODE