GNU bug report logs - #79201
30.1.90; set-process-thread can permanently break fd_callback_info slots

Previous Next

Package: emacs;

Reported by: Spencer Baugh <sbaugh <at> janestreet.com>

Date: Fri, 8 Aug 2025 17:07:02 UTC

Severity: normal

Found in version 30.1.90

Full log


Message #44 received at 79201 <at> debbugs.gnu.org (full text, mbox):

From: Spencer Baugh <sbaugh <at> janestreet.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 79201 <at> debbugs.gnu.org, dmitry <at> gutov.dev, johnw <at> gnu.org,
 app-emacs-dev <at> janestreet.com
Subject: Re: bug#79201: 30.1.90; set-process-thread can permanently break
 fd_callback_info slots
Date: Tue, 12 Aug 2025 18:16:12 -0400
Anyway, I found a reproducer for the other bug I mentioned, where
waiting_thread could also get contaminated and break fd_callback_info
slots.  It seems to be quite a bad bug: it will happen spontaneously
just from running multiple threads interacting with processes.

If you run the following simple Lisp code after applying the following
patch (which is just to make the breakage more obvious; without the
patch, Emacs would be left in a silently broken state), Emacs will abort
in a few seconds - though it probably varies based on your system.

This indicates that .waiting_thread is somehow being left at a non-NULL
value even after the thread has left wait_reading_process_output.

Any ideas?

(defun my-break-thread ()
  (let ((proc (make-process
               :name "foo"
               :command '("sleep" "1"))))
    (while (process-live-p proc)
      (accept-process-output proc 0.05))))

(while t
  (make-thread #'my-break-thread "thread1")
  (thread-join (make-thread #'my-break-thread "thread2")))

diff --git a/src/process.c b/src/process.c
index 1a5c99139a6..294c204ae96 100644
--- a/src/process.c
+++ b/src/process.c
@@ -467,6 +467,16 @@ make_lisp_proc (struct Lisp_Process *p)
 } fd_callback_info[FD_SETSIZE];
 
 
+static void
+assert_fd_callback_info_unused(int fd)
+{
+  eassert (0 <= fd && fd < FD_SETSIZE);
+  if (fd_callback_info[fd].waiting_thread != NULL) {
+    fprintf (stderr, "waiting_thread non-NULL\n");
+    terminate_due_to_signal (SIGABRT, INT_MAX);
+  }
+}
+
 /* Add a file descriptor FD to be monitored for when read is possible.
    When read is possible, call FUNC with argument DATA.  */
 
@@ -475,7 +485,6 @@ add_read_fd (int fd, fd_callback func, void *data)
 {
   add_keyboard_wait_descriptor (fd);
 
-  eassert (0 <= fd && fd < FD_SETSIZE);
   fd_callback_info[fd].func = func;
   fd_callback_info[fd].data = data;
 }
@@ -490,14 +499,13 @@ add_non_keyboard_read_fd (int fd, fd_callback func, void *data)
 static void
 add_process_read_fd (int fd)
 {
-  eassert (fd >= 0 && fd < FD_SETSIZE);
+  assert_fd_callback_info_unused(fd);
   eassert (fd_callback_info[fd].func == NULL);
 
   fd_callback_info[fd].flags &= ~KEYBOARD_FD;
   fd_callback_info[fd].flags |= FOR_READ;
   if (fd > max_desc)
     max_desc = fd;
-  eassert (0 <= fd && fd < FD_SETSIZE);
   fd_callback_info[fd].flags |= PROCESS_FD;
 }
 
@@ -522,7 +530,7 @@ delete_read_fd (int fd)
 void
 add_write_fd (int fd, fd_callback func, void *data)
 {
-  eassert (fd >= 0 && fd < FD_SETSIZE);
+  assert_fd_callback_info_unused(fd);
 
   fd_callback_info[fd].func = func;
   fd_callback_info[fd].data = data;
@@ -534,7 +542,7 @@ add_write_fd (int fd, fd_callback func, void *data)
 static void
 add_non_blocking_write_fd (int fd)
 {
-  eassert (fd >= 0 && fd < FD_SETSIZE);
+  assert_fd_callback_info_unused(fd);
   eassert (fd_callback_info[fd].func == NULL);
 
   fd_callback_info[fd].flags |= FOR_WRITE | NON_BLOCKING_CONNECT_FD;
@@ -8266,7 +8274,7 @@ remove_slash_colon (Lisp_Object name)
 add_keyboard_wait_descriptor (int desc)
 {
 #ifdef subprocesses /* Actually means "not MSDOS".  */
-  eassert (desc >= 0 && desc < FD_SETSIZE);
+  assert_fd_callback_info_unused(desc);
   fd_callback_info[desc].flags &= ~PROCESS_FD;
   fd_callback_info[desc].flags |= (FOR_READ | KEYBOARD_FD);
   if (desc > max_desc)




This bug report was last modified today.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.