pipe_data_available() is called in the raw_write() and if the pipe
is real_non_blocking_mode in raw_write(), the pipe mode can be
accidentally reverted to blocking mode in some cases by calling
pipe_data_available(). With this patch, pipe_data_available()
reffers current real blocking mode, and restores the pipe mode
to the current state.

Fixes: 7ed9adb356df ("Cygwin: pipe: Switch pipe mode to blocking mode by 
default")
Reported-by: Andrew Ng (@github)
Reviewed-by:
Signed-off-by: Takashi Yano <[email protected]>
---
 winsup/cygwin/fhandler/pipe.cc          |  2 --
 winsup/cygwin/local_includes/fhandler.h |  3 +++
 winsup/cygwin/select.cc                 | 11 ++++++-----
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc
index 4f23bd38c..ea0a8d807 100644
--- a/winsup/cygwin/fhandler/pipe.cc
+++ b/winsup/cygwin/fhandler/pipe.cc
@@ -326,7 +326,6 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
       ULONG_PTR nbytes_now = 0;
       ULONG len1 = (ULONG) (len - nbytes);
       DWORD select_sem_timeout = 0;
-      bool real_non_blocking_mode = false;
 
       FILE_PIPE_LOCAL_INFORMATION fpli;
       status = NtQueryInformationFile (get_handle (), &io,
@@ -453,7 +452,6 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len)
     return 0;
 
   ssize_t avail = pipe_buf_size;
-  bool real_non_blocking_mode = false;
 
   /* Workaround for native ninja. Native ninja creates pipe with size == 0,
      and starts cygwin process with that pipe. */
diff --git a/winsup/cygwin/local_includes/fhandler.h 
b/winsup/cygwin/local_includes/fhandler.h
index 3d9bc9fa5..04e2ca4c3 100644
--- a/winsup/cygwin/local_includes/fhandler.h
+++ b/winsup/cygwin/local_includes/fhandler.h
@@ -1203,6 +1203,7 @@ class fhandler_pipe_fifo: public fhandler_base
  protected:
   size_t pipe_buf_size;
   HANDLE pipe_mtx; /* Used only in the pipe case */
+  bool real_non_blocking_mode; /* Used only in the pipe case */
   virtual void release_select_sem (const char *) {};
 
   IMPLEMENT_STATUS_FLAG (bool, isclosed)
@@ -1212,6 +1213,8 @@ class fhandler_pipe_fifo: public fhandler_base
 
   virtual bool reader_closed () { return false; };
   ssize_t raw_write (const void *ptr, size_t len);
+
+  friend ssize_t pipe_data_available (int, fhandler_base *, HANDLE, int);
 };
 
 class fhandler_pipe: public fhandler_pipe_fifo
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index bb141b065..32c73fd0c 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -644,22 +644,23 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, 
int mode)
        reader is currently trying to read the pipe and it is pending.
        In the latter case, the fact that the reader cannot read the data
        immediately means that the pipe is empty. In the former case,
-       NtSetInformationFile() in set_pipe_non_blocking(true) will fail
-       with STATUS_PIPE_BUSY, while it succeeds in the latter case.
+       NtSetInformationFile() in set_pipe_non_blocking(!orig_mode) will
+       fail with STATUS_PIPE_BUSY, while it succeeds in the latter case.
        Therefore, we can distinguish these cases by calling set_pipe_non_
        blocking(true). If it returns success, the pipe is empty, so we
        return the pipe buffer size. Otherwise, we return 0. */
       if (fh->get_device () == FH_PIPEW && fpli.WriteQuotaAvailable == 0)
        {
+         bool orig_mode = ((fhandler_pipe *) fh)->real_non_blocking_mode;
          NTSTATUS status =
-           ((fhandler_pipe *) fh)->set_pipe_non_blocking (true);
+           ((fhandler_pipe *) fh)->set_pipe_non_blocking (!orig_mode);
          if (status == STATUS_PIPE_BUSY)
            return 0; /* Full */
          else if (!NT_SUCCESS (status))
            /* We cannot know actual write pipe space. */
            return 1;
-         /* Restore pipe mode to blocking mode */
-         ((fhandler_pipe *) fh)->set_pipe_non_blocking (false);
+         /* Restore pipe mode to original blocking mode */
+         ((fhandler_pipe *) fh)->set_pipe_non_blocking (orig_mode);
          /* Empty */
          fpli.WriteQuotaAvailable = fpli.InboundQuota;
        }
-- 
2.45.1

Reply via email to