Fix leaking of file descriptors due to pipe processes on MS-Windows

* src/w32proc.c (reader_thread): Wait for 'sys_close' to finish
processing the pipe read descriptor, before trying to close it.

* src/w32.c (sys_close): Attempt to detect when the reader thread
already exited, so that it would be possible to close descriptors
open by pipe processes for reading from the pipe.  (Bug#56606)
This commit is contained in:
Eli Zaretskii 2022-07-17 15:44:50 +03:00
parent 202c12a24b
commit 637436970f
2 changed files with 32 additions and 8 deletions

View file

@ -8573,6 +8573,7 @@ int
sys_close (int fd)
{
int rc = -1;
bool reader_thread_exited = false;
if (fd < 0)
{
@ -8583,6 +8584,13 @@ sys_close (int fd)
if (fd < MAXDESC && fd_info[fd].cp)
{
child_process * cp = fd_info[fd].cp;
DWORD thrd_status = STILL_ACTIVE;
/* Thread handle will be NULL if we already called delete_child. */
if (cp->thrd != NULL
&& GetExitCodeThread (cp->thrd, &thrd_status)
&& thrd_status != STILL_ACTIVE)
reader_thread_exited = true;
fd_info[fd].cp = NULL;
@ -8633,7 +8641,11 @@ sys_close (int fd)
because socket handles are fully fledged kernel handles. */
if (fd < MAXDESC)
{
if ((fd_info[fd].flags & FILE_DONT_CLOSE) == 0)
if ((fd_info[fd].flags & FILE_DONT_CLOSE) == 0
/* If the reader thread already exited, close the descriptor,
since otherwise no one will close it, and we will be
leaking descriptors. */
|| reader_thread_exited)
{
fd_info[fd].flags = 0;
rc = _close (fd);
@ -8641,10 +8653,11 @@ sys_close (int fd)
else
{
/* We don't close here descriptors open by pipe processes
for reading from the pipe, because the reader thread
might be stuck in _sys_read_ahead, and then we will hang
here. If the reader thread exits normally, it will close
the descriptor; otherwise we will leave a zombie thread
for reading from the pipe when the reader thread might
still be running, since that thread might be stuck in
_sys_read_ahead, and then we will hang here. If the
reader thread exits normally, it will close the
descriptor; otherwise we will leave a zombie thread
hanging around. */
rc = 0;
/* Leave the flag set for the reader thread to close the

View file

@ -1287,10 +1287,21 @@ reader_thread (void *arg)
}
/* If this thread was reading from a pipe process, close the
descriptor used for reading, as sys_close doesn't in that case. */
if (fd_info[fd].flags == FILE_DONT_CLOSE)
if ((fd_info[fd].flags & FILE_DONT_CLOSE) == FILE_DONT_CLOSE)
{
fd_info[fd].flags = 0;
_close (fd);
int i;
/* If w32.c:sys_close is still processing this descriptor, wait
for a while for it to finish. */
for (i = 0; i < 5; i++)
{
if (fd_info[fd].flags == FILE_DONT_CLOSE)
{
fd_info[fd].flags = 0;
_close (fd);
break;
}
Sleep (5);
}
}
return 0;
}