diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/keyboard.c | 6 | ||||
| -rw-r--r-- | src/sysdep.c | 6 | ||||
| -rw-r--r-- | src/w32fns.c | 61 |
3 files changed, 67 insertions, 6 deletions
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 | ||
| 1713 | static bool | 1713 | static bool |
| 1714 | init_sigsegv (void) | 1714 | init_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 | ||
| 1721 | static void | 1721 | static void |
| 1722 | deliver_arith_signal (int sig) | 1722 | deliver_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; | |||
| 9239 | static PVOID except_addr; | 9239 | static 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. */ | ||
| 9249 | void | ||
| 9250 | w32_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 | |||
| 9260 | static void | ||
| 9261 | stack_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. */ | ||
| 9248 | static LONG CALLBACK | 9282 | static LONG CALLBACK |
| 9249 | my_exception_handler (EXCEPTION_POINTERS * exception_data) | 9283 | my_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 |