From 16b22fef423afedf034460a0f811abf50d0c5f3e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Tue, 25 Sep 2012 13:50:01 +0200 Subject: [PATCH] Fix handling of fatal signals and exceptions on MS-Windows. src/w32proc.c (sys_signal): Handle all signals defined by the MS-Windows runtime, not just SIGCHLD. Actually install the signal handlers for signals supported by Windows. Don't override term_ntproc as the handler for SIGABRT. (sigaction): Rewrite to call sys_signal instead of duplicating its code. (sys_kill): Improve commentary. src/w32.c (term_ntproc): Accept (and ignore) one argument, for consistency with a signature of a signal handler. All callers changed. (init_ntproc): Accept an argument DUMPING. If dumping, don't install term_ntproc as a signal handler for SIGABRT, as that should be done by the dumped Emacs. src/w32.h (init_ntproc, term_ntproc): Adjust prototypes. src/w32select.c (term_w32select): Protect against repeated invocation by setting clipboard_owner to NULL after calling DestroyWindow. src/emacs.c (shut_down_emacs, main): Adapt the calls to init_ntproc and term_ntproc to their modified signatures. --- src/ChangeLog | 24 ++++++++++++++++++++++++ src/emacs.c | 4 ++-- src/w32.c | 8 +++++--- src/w32.h | 4 ++-- src/w32proc.c | 44 ++++++++++++++++++++++++++++++++++---------- src/w32select.c | 5 ++++- 6 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index ca9ca808c7..9d048beeec 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,29 @@ 2012-09-25 Eli Zaretskii + * w32proc.c (sys_signal): Handle all signals defined by the + MS-Windows runtime, not just SIGCHLD. Actually install the signal + handlers for signals supported by Windows. Don't override + term_ntproc as the handler for SIGABRT. + (sigaction): Rewrite to call sys_signal instead of duplicating its + code. + (sys_kill): Improve commentary. + + * w32.c (term_ntproc): Accept (and ignore) one argument, for + consistency with a signature of a signal handler. All callers + changed. + (init_ntproc): Accept an argument DUMPING. If dumping, don't + install term_ntproc as a signal handler for SIGABRT, as that + should be done by the dumped Emacs. + + * w32.h (init_ntproc, term_ntproc): Adjust prototypes. + + * w32select.c (term_w32select): Protect against repeated + invocation by setting clipboard_owner to NULL after calling + DestroyWindow. + + * emacs.c (shut_down_emacs, main): Adapt the calls to init_ntproc + and term_ntproc to their modified signatures. + * character.c (char_string, string_char): Remove calls to MAYBE_UNIFY_CHAR. See the discussion starting at http://lists.gnu.org/archive/html/emacs-devel/2012-09/msg00433.html diff --git a/src/emacs.c b/src/emacs.c index cf3d50b4f8..686a884cdb 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1258,7 +1258,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem globals_of_w32 (); /* Initialize environment from registry settings. */ init_environment (argv); - init_ntproc (); /* must precede init_editfns. */ + init_ntproc (dumping); /* must precede init_editfns. */ #endif /* Initialize and GC-protect Vinitial_environment and @@ -1906,7 +1906,7 @@ shut_down_emacs (int sig, Lisp_Object stuff) ignore_sigio (); #ifdef WINDOWSNT - term_ntproc (); + term_ntproc (0); #endif /* Do this only if terminating normally, we want glyph matrices diff --git a/src/w32.c b/src/w32.c index 8775a366e6..f7e1635479 100644 --- a/src/w32.c +++ b/src/w32.c @@ -6624,8 +6624,9 @@ check_windows_init_file (void) } void -term_ntproc (void) +term_ntproc (int ignored) { + (void)ignored; /* shutdown the socket interface if necessary */ term_winsock (); @@ -6633,7 +6634,7 @@ term_ntproc (void) } void -init_ntproc (void) +init_ntproc (int dumping) { /* Initialize the socket interface now if available and requested by the user by defining PRELOAD_WINSOCK; otherwise loading will be @@ -6710,7 +6711,8 @@ init_ntproc (void) /* unfortunately, atexit depends on implementation of malloc */ /* atexit (term_ntproc); */ - signal (SIGABRT, term_ntproc); + if (!dumping) + signal (SIGABRT, term_ntproc); /* determine which drives are fixed, for GetCachedVolumeInformation */ { diff --git a/src/w32.h b/src/w32.h index 39409e3808..18625cea95 100644 --- a/src/w32.h +++ b/src/w32.h @@ -127,8 +127,8 @@ extern void reset_standard_handles (int in, int out, /* Return the string resource associated with KEY of type TYPE. */ extern LPBYTE w32_get_resource (char * key, LPDWORD type); -extern void init_ntproc (void); -extern void term_ntproc (void); +extern void init_ntproc (int); +extern void term_ntproc (int); extern void globals_of_w32 (void); extern void syms_of_w32term (void); extern void syms_of_w32fns (void); diff --git a/src/w32proc.c b/src/w32proc.c index 8dbd063a96..b367b42d8c 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -86,19 +86,34 @@ typedef void (_CALLBACK_ *signal_handler) (int); /* Signal handlers...SIG_DFL == 0 so this is initialized correctly. */ static signal_handler sig_handlers[NSIG]; -/* Fake signal implementation to record the SIGCHLD handler. */ +/* Improve on the CRT 'signal' implementation so that we could record + the SIGCHLD handler. */ signal_handler sys_signal (int sig, signal_handler handler) { signal_handler old; - if (sig != SIGCHLD) + /* SIGCHLD is needed for supporting subprocesses, see sys_kill + below. All the others are the only ones supported by the MS + runtime. */ + if (!(sig == SIGCHLD || sig == SIGSEGV || sig == SIGILL + || sig == SIGFPE || sig == SIGABRT || sig == SIGTERM)) { errno = EINVAL; return SIG_ERR; } old = sig_handlers[sig]; - sig_handlers[sig] = handler; + /* SIGABRT is treated specially because w32.c installs term_ntproc + as its handler, so we don't want to override that afterwards. + Aborting Emacs works specially anyway: either by calling + emacs_abort directly or through terminate_due_to_signal, which + calls emacs_abort through emacs_raise. */ + if (!(sig == SIGABRT && old == term_ntproc)) + { + sig_handlers[sig] = handler; + if (sig != SIGCHLD) + signal (sig, handler); + } return old; } @@ -106,23 +121,26 @@ sys_signal (int sig, signal_handler handler) int sigaction (int sig, const struct sigaction *act, struct sigaction *oact) { - signal_handler old; + signal_handler old = SIG_DFL; + int retval = 0; + + if (act) + old = sys_signal (sig, act->sa_handler); + else if (oact) + old = sig_handlers[sig]; - if (sig != SIGCHLD) + if (old == SIG_ERR) { errno = EINVAL; - return -1; + retval = -1; } - old = sig_handlers[sig]; - if (act) - sig_handlers[sig] = act->sa_handler; if (oact) { oact->sa_handler = old; oact->sa_flags = 0; oact->sa_mask = empty_mask; } - return 0; + return retval; } /* Defined in which conflicts with the local copy */ @@ -1420,6 +1438,7 @@ find_child_console (HWND hwnd, LPARAM arg) return TRUE; } +/* Emulate 'kill', but only for other processes. */ int sys_kill (int pid, int sig) { @@ -1438,6 +1457,11 @@ sys_kill (int pid, int sig) cp = find_child_pid (pid); if (cp == NULL) { + /* We were passed a PID of something other than our subprocess. + If that is our own PID, we will send to ourself a message to + close the selected frame, which does not necessarily + terminates Emacs. But then we are not supposed to call + sys_kill with our own PID. */ proc_hand = OpenProcess (PROCESS_TERMINATE, 0, pid); if (proc_hand == NULL) { diff --git a/src/w32select.c b/src/w32select.c index 061f5a4a0a..66f9f7ab04 100644 --- a/src/w32select.c +++ b/src/w32select.c @@ -474,7 +474,10 @@ term_w32select (void) { /* This is needed to trigger WM_RENDERALLFORMATS. */ if (clipboard_owner != NULL) - DestroyWindow (clipboard_owner); + { + DestroyWindow (clipboard_owner); + clipboard_owner = NULL; + } } static void -- 2.20.1