3.3.0: Possible regression in cygwin DLL (Win10); fixed in snapshot

Takashi Yano takashi.yano@nifty.ne.jp
Sat Nov 6 06:10:47 GMT 2021


# This topic is moved from cygwin@cygwin.com mailing list.

Hi Ken,

On Fri, 5 Nov 2021 16:08:31 -0400
Ken Brown wrote:
> On 11/5/2021 3:41 PM, Takashi Yano via Cygwin wrote:
> > Thanks much for the detailed steps. I could reproduce the problem.
> > 
> > It seems that the cause is the overhaul for the pipe implementation.
> > I also found the workaround for this issue. Please try:
> > export CYGWIN=pipe_byte
> > 
> > Corinna, Ken,
> > What about setting pipe mode to byte by default?
> 
> I have a vague recollection that this caused some other problem, but I'll have 
> to review the email discussions from a few months ago.  I'm traveling at the 
> moment and won't get to this for a few days.
> 
> In the meantime, could you explain (probably on cygwin-developers) why message 
> mode causes the reported issue?  Also, does the problem occur only when there 
> are non-Cygwin apps involved?

I digged deeper this problem and might find the cause.

Perhaps, C# program sometimes writes 0 byte to stdout.
As a result, if stdout is a message pipe, raw_read() returns
0 byte and EOF is falsely detected. So, setting pipe type
to byte solves the issue.

I used the following two test programs. The output of
second test program (do_pipe) is like:
res=1
len=0          <<<<< Look here!!
res=1
len=14
res=0
len=0


/* C# program which is supposed to write 0 byte msg. */
/* Filename: produce.cs */
/* Compile this with "csc produce.cs" */
using System;
namespace Produce
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World.");
        }
    }
}
/* End of produce.cs */


/* Filename: do_pipe.c */
/* Compile this with "x86_64-w64-mingw32-gcc do_pipe.c -o do_pipe" */
#include <windows.h>
#include <stdio.h>

#if 0
#define PTYPE PIPE_TYPE_BYTE
#else
#define PTYPE PIPE_TYPE_MESSAGE
#endif

int main()
{
	HANDLE hr, hw;
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	char buf[1024];
	BOOL res;

	SECURITY_ATTRIBUTES sec_none = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
	hr = CreateNamedPipe("\\\\.\\pipe\\pipe-test1",
			PIPE_ACCESS_INBOUND, PTYPE,
			1, 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, &sec_none);
	hw = CreateFile("\\\\.\\pipe\\pipe-test1",
			GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, &sec_none,
			OPEN_EXISTING, 0, 0);

	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	si.dwFlags = STARTF_USESTDHANDLES;
	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
	si.hStdOutput = hw;
	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
	CreateProcess(NULL, "produce", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);

	CloseHandle(hw);

	do {
		DWORD len;
		res = ReadFile(hr, buf, sizeof(buf), &len, NULL); 
		printf("res=%d\n", res);
		printf("len=%d\n", len);
	} while (res);

	CloseHandle(hr);

	WaitForSingleObject(pi.hProcess, INFINITE);
	return 0;
}
/* End of do_pipe.c */


Therefore, the following patch instead of setting pipe type to byte
also resolves the issue.

diff --git a/winsup/cygwin/fhandler_pipe.cc b/winsup/cygwin/fhandler_pipe.cc
index 43771e8f7..bc06d157c 100644
--- a/winsup/cygwin/fhandler_pipe.cc
+++ b/winsup/cygwin/fhandler_pipe.cc
@@ -393,7 +393,8 @@ fhandler_pipe::raw_read (void *ptr, size_t& len)
 	    }
 	}
 
-      if (nbytes_now == 0 || status == STATUS_BUFFER_OVERFLOW)
+      if ((nbytes_now == 0 && !NT_SUCCESS (status))
+	  || status == STATUS_BUFFER_OVERFLOW)
 	break;
     }
   ReleaseMutex (read_mtx);

I am not sure which is the better solution.


P.S.
Unfortunately, these solutions do not resolve the issue
which is another issue with C# program:
https://cygwin.com/pipermail/cygwin/2021-March/247987.html
This still needs FILE_SYNCHRONOUS_IO_NONALERT flag.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>


More information about the Cygwin-developers mailing list