Subject: bug#79201: 30.1.90; set-process-thread can permanently break fd_callback_info slots

From: Eli Zaretskii <[email-masked]>
Date: Wed, 13 Aug 2025 14:52:04 +0300

> From: Spencer Baugh <[email-masked]>
> Cc: [email-masked],  [email-masked],  [email-masked],
>    [email-masked]
> 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?

I'm not sure I understand your idea behind
assert_fd_callback_info_unused.  wait_reading_process_output calls
thread_select in a loop, so a given thread which called
wait_reading_process_output could spend more than one loop iteration
without leaving the function.  Each iteration, such a thread will call
add_process_read_fd and other similar functions, to set up the
descriptors it will wait on, and then call thread_select.  When it
calls thread_select, it releases the global lock, so some other thread
could grab the lock and start running.  Then this other thread could
see the .waiting_thread member non-NULL, because the thread which
marked the descriptor as being waited on by it is stuck in a pselect
call, called from wait_reading_process_output via thread_select.

Could the above scenario be the reason for what you see?  IOW, why did
you expect to find the .waiting_thread members cleared whenever some
thread calls assert_fd_callback_info_unused, and why did you say "even
after the thread has left wait_reading_process_output"?