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)
This commit is contained in:
Eli Zaretskii 2023-01-22 15:07:55 +02:00
parent 808e101fab
commit 8e83604dfe
2 changed files with 47 additions and 25 deletions

View file

@ -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. */

View file

@ -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 <emacs-PID>\" and\n"
"\"continue\" inside GDB before clicking YES.)"
"\n\n(Before clicking YES, type\n"
"\"gdb -p <emacs-PID>\", 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: