[newlib-cygwin] Cygwin: select: fix overwriting fd sets if poll returns no fd

Corinna Vinschen corinna@sourceware.org
Sun Jan 13 22:16:00 GMT 2019


commit b6694df6198102911980af22721a561c7627ea2a
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Sun Jan 13 22:43:52 2019 +0100

    Cygwin: select: fix overwriting fd sets if poll returns no fd
    There's a long-standing bug in select.  If we have poll-only
    descriptors in the fd set, select overwrites the incoming
    fd sets with the polling result.  If none of the fds is ready,
    select has to loop again.  But now the fd sets are set to all
    zero and select hangs.
    Fix this by utilizing the local fd sets r, w, e as storage for
    the incoming fd sets and use them to initialize select_stuff.
    If we have to loop, overwritung the incoming fd sets doesn't matter.
    While at it, rename r, w, e to readfds_in, writefds_in, exceptfds_in.
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

 winsup/cygwin/release/2.12.0 |  2 ++
 winsup/cygwin/select.cc      | 15 +++++++++------
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/winsup/cygwin/release/2.12.0 b/winsup/cygwin/release/2.12.0
index 15f07e0..dbda788 100644
--- a/winsup/cygwin/release/2.12.0
+++ b/winsup/cygwin/release/2.12.0
@@ -65,3 +65,5 @@ Bug Fixes
   even if file has been deleted.
   Addresses: https://cygwin.com/ml/cygwin/2018-12/msg00125.html
+- Fix a bug in select(2) when polling HANDLE-less descriptors.
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index 0d82a59..6ce679a 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -164,17 +164,20 @@ select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
   select_stuff sel;
   sel.return_on_signal = 0;
-  /* Allocate some fd_set structures using the number of fds as a guide. */
-  fd_set *r = allocfd_set (maxfds);
-  fd_set *w = allocfd_set (maxfds);
-  fd_set *e = allocfd_set (maxfds);
+  /* Allocate fd_set structures to store incoming fd sets. */
+  fd_set *readfds_in = allocfd_set (maxfds);
+  fd_set *writefds_in = allocfd_set (maxfds);
+  fd_set *exceptfds_in = allocfd_set (maxfds);
+  memcpy (readfds_in, readfds, sizeof_fd_set (maxfds));
+  memcpy (writefds_in, writefds, sizeof_fd_set (maxfds));
+  memcpy (exceptfds_in, exceptfds, sizeof_fd_set (maxfds));
       /* Build the select record per fd linked list and set state as
 	 needed. */
       for (int i = 0; i < maxfds; i++)
-	if (!sel.test_and_set (i, readfds, writefds, exceptfds))
+	if (!sel.test_and_set (i, readfds_in, writefds_in, exceptfds_in))
 	    select_printf ("aborting due to test_and_set error");
 	    return -1;	/* Invalid fd, maybe? */
@@ -186,7 +189,7 @@ select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
 	wait_state = select_stuff::select_ok;
 	/* wait for an fd to become active or time out */
-	wait_state = sel.wait (r, w, e, us);
+	wait_state = sel.wait (readfds, writefds, exceptfds, us);
       select_printf ("sel.wait returns %d", wait_state);

More information about the Cygwin-cvs mailing list