From 8e83604dfe01e0ea56569c1bc129ecbc67583447 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 22 Jan 2023 15:07:55 +0200 Subject: [PATCH] Avoid crashes in batch Emacs sub-processes on MS-Windows * src/w32.c (shutdown_handler): When run in a separate thread, don't call functions that only the main (a.k.a. "Lisp") thread can call; instead, arrange for maybe_quit to kill Emacs. * src/w32fns.c (emacs_abort): Don't show GUI Abort dialogs in non-interactive sessions. (Bug#60556) --- src/w32.c | 44 +++++++++++++++++++++++++++++++------------- src/w32fns.c | 28 ++++++++++++++++------------ 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/w32.c b/src/w32.c index 47d79abc5b0..213fee15699 100644 --- a/src/w32.c +++ b/src/w32.c @@ -10509,10 +10509,13 @@ init_ntproc (int dumping) } } -/* - shutdown_handler ensures that buffers' autosave files are - up to date when the user logs off, or the system shuts down. -*/ +/* shutdown_handler ensures that buffers' autosave files are up to + date when the user logs off, or the system shuts down. It also + shuts down Emacs when we get killed by another Emacs process, in + which case we get the CTRL_CLOSE_EVENT. */ + +extern DWORD dwMainThreadId; + static BOOL WINAPI shutdown_handler (DWORD type) { @@ -10521,15 +10524,30 @@ shutdown_handler (DWORD type) || type == CTRL_LOGOFF_EVENT /* User logs off. */ || type == CTRL_SHUTDOWN_EVENT) /* User shutsdown. */ { - /* If we are being shut down in noninteractive mode, we don't - care about the message stack, so clear it to avoid abort in - shut_down_emacs. This happens when an noninteractive Emacs - is invoked as a subprocess of Emacs, and the parent wants to - kill us, e.g. because it's about to exit. */ - if (noninteractive) - clear_message_stack (); - /* Shut down cleanly, making sure autosave files are up to date. */ - shut_down_emacs (0, Qnil); + if (GetCurrentThreadId () == dwMainThreadId) + { + /* If we are being shut down in noninteractive mode, we don't + care about the message stack, so clear it to avoid abort in + shut_down_emacs. This happens when an noninteractive Emacs + is invoked as a subprocess of Emacs, and the parent wants to + kill us, e.g. because it's about to exit. */ + if (noninteractive) + clear_message_stack (); + /* Shut down cleanly, making sure autosave files are up to date. */ + shut_down_emacs (0, Qnil); + } + { + /* This handler is run in a thread different from the main + thread. (This is the normal situation when we are killed + by Emacs, for example, which sends us the WM_CLOSE + message). We cannot possibly call functions like + shut_down_emacs or clear_message_stack in that case, since + the main (a.k.a. "Lisp") thread could be in the middle of + some Lisp program. So instead we arrange for maybe_quit to + kill Emacs. */ + Vquit_flag = Qkill_emacs; + Vinhibit_quit = Qnil; + } } /* Allow other handlers to handle this signal. */ diff --git a/src/w32fns.c b/src/w32fns.c index b4192a5ffa6..745f561e6b1 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -11112,20 +11112,24 @@ emacs_abort (void) abort (); int button; - button = MessageBox (NULL, - "A fatal error has occurred!\n\n" - "Would you like to attach a debugger?\n\n" - "Select:\n" - "YES -- to debug Emacs, or\n" - "NO -- to abort Emacs and produce a backtrace\n" - " (emacs_backtrace.txt in current directory)." + + if (noninteractive) + button = IDNO; + else + button = MessageBox (NULL, + "A fatal error has occurred!\n\n" + "Would you like to attach a debugger?\n\n" + "Select:\n" + "YES -- to debug Emacs, or\n" + "NO -- to abort Emacs and produce a backtrace\n" + " (emacs_backtrace.txt in current directory)." #if __GNUC__ - "\n\n(type \"gdb -p \" and\n" - "\"continue\" inside GDB before clicking YES.)" + "\n\n(Before clicking YES, type\n" + "\"gdb -p \", then \"continue\" inside GDB.)" #endif - , "Emacs Abort Dialog", - MB_ICONEXCLAMATION | MB_TASKMODAL - | MB_SETFOREGROUND | MB_YESNO); + , "Emacs Abort Dialog", + MB_ICONEXCLAMATION | MB_TASKMODAL + | MB_SETFOREGROUND | MB_YESNO); switch (button) { case IDYES: -- 2.39.2