public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
* poll() is buggy for duplicate file descriptors inquired for different events
@ 2022-06-26 17:04 Lavrentiev, Anton (NIH/NLM/NCBI) [C]
  2022-06-27  1:50 ` Takashi Yano
  0 siblings, 1 reply; 2+ messages in thread
From: Lavrentiev, Anton (NIH/NLM/NCBI) [C] @ 2022-06-26 17:04 UTC (permalink / raw)
  To: 'cygwin@cygwin.com'

Hi,

It looks like if a file descriptor is inquired a few times in a poll() call with different events (and for one of those events the file descriptor is "ready"),
only that occurrence gets reported correctly, and all other occurrences get the returned event just "copied over" (and thus, it may be incompatible with the
query for that occurrence).

The following simple test case demonstrates this:

$ cat poll.c 
#include <poll.h>
#include <stdio.h>
#include <string.h>

int main()
{
    int n;
    struct pollfd pfd[2];
    memset(pfd, 0, sizeof(pfd));

    pfd[0].fd = 1;
    pfd[0].events = POLLOUT;
    pfd[1].fd = 1;
    pfd[1].events = POLLIN;
    
    n = poll(pfd, 2, 1000);
    printf("n = %d\n"
    "[0].fd = %d\n"
    "[0].event = %d\n"
    "[0].revent = %d\n"
    "[1].fd = %d\n"
    "[1].event = %d\n"
    "[1].revent = %d\n",
    n,
    pfd[0].fd,
    pfd[0].events,
    pfd[0].revents,
    pfd[1].fd,
    pfd[1].events,
    pfd[1].revents);

    pfd[1].revents = 0;
    n = poll(&pfd[1], 1, 1000);
    printf("n = %d\n"
    "[1].fd = %d\n"
    "[1].event = %d\n"
    "[1].revent = %d\n",
    n,
    pfd[1].fd,
    pfd[1].events,
    pfd[1].revents);

    return 0;
}

$ gcc -Wall -o poll poll.c

$ ./poll
n = 2
[0].fd = 1
[0].event = 4
[0].revent = 4
[1].fd = 1
[1].event = 1
[1].revent = 4
n = 0
[1].fd = 1
[1].event = 1
[1].revent = 0

Note that "stdout" is inquired about ready-to-write (in [0]) and ready-to-read (in [1]).
Because it is ready-to-write, poll() returns immediately, but also having the response
ready-to-write in [1], where only "read"-compatible status (POLLIN, or POLLHUP, or POLLERR,
or just 0, if nothing of sorts was available) should have been posted -- but *never* POLLOUT!

Also note that [1] should have never been flagged as "ready", either, so the return code should have been 1, not 2.

Finally note that if [0] and [1] were swapped so that [0] was inquired for POLLIN, and [1] was inquired for POLLOUT,
the result would have still been incorrect on Cygwin ([0] returning POLLOUT for POLLIN inquired).

For the second invocation, when inquired just singly, the response is correct.

Now compare it with the correct behavior of the same code, all through, on Linux:

$ ./poll
n = 1
[0].fd = 1
[0].event = 4
[0].revent = 4
[1].fd = 1
[1].event = 1
[1].revent = 0
n = 0
[1].fd = 1
[1].event = 1
[1].revent = 0

P.S. The manual page for poll(2) says:

The bits returned in revents can include any of those specified in events, or one of the values POLLERR, POLLHUP, or POLLNVAL.

So returning POLLOUT(4) for POLLIN(1) violates the rule: bit 0 is NOT set in the binary representation of 4.

Anton Lavrentiev
Contractor NIH/NLM/NCBI


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: poll() is buggy for duplicate file descriptors inquired for different events
  2022-06-26 17:04 poll() is buggy for duplicate file descriptors inquired for different events Lavrentiev, Anton (NIH/NLM/NCBI) [C]
@ 2022-06-27  1:50 ` Takashi Yano
  0 siblings, 0 replies; 2+ messages in thread
From: Takashi Yano @ 2022-06-27  1:50 UTC (permalink / raw)
  To: cygwin

On Sun, 26 Jun 2022 17:04:58 +0000
"Lavrentiev, Anton \(NIH/NLM/NCBI\) \[C\] wrote:
> It looks like if a file descriptor is inquired a few times in a poll() call with different events (and for one of those events the file descriptor is "ready"),
> only that occurrence gets reported correctly, and all other occurrences get the returned event just "copied over" (and thus, it may be incompatible with the
> query for that occurrence).
> 
> The following simple test case demonstrates this:
> 
> $ cat poll.c 
> #include <poll.h>
> #include <stdio.h>
> #include <string.h>
> 
> int main()
> {
>     int n;
>     struct pollfd pfd[2];
>     memset(pfd, 0, sizeof(pfd));
> 
>     pfd[0].fd = 1;
>     pfd[0].events = POLLOUT;
>     pfd[1].fd = 1;
>     pfd[1].events = POLLIN;
>     
>     n = poll(pfd, 2, 1000);
>     printf("n = %d\n"
>     "[0].fd = %d\n"
>     "[0].event = %d\n"
>     "[0].revent = %d\n"
>     "[1].fd = %d\n"
>     "[1].event = %d\n"
>     "[1].revent = %d\n",
>     n,
>     pfd[0].fd,
>     pfd[0].events,
>     pfd[0].revents,
>     pfd[1].fd,
>     pfd[1].events,
>     pfd[1].revents);
> 
>     pfd[1].revents = 0;
>     n = poll(&pfd[1], 1, 1000);
>     printf("n = %d\n"
>     "[1].fd = %d\n"
>     "[1].event = %d\n"
>     "[1].revent = %d\n",
>     n,
>     pfd[1].fd,
>     pfd[1].events,
>     pfd[1].revents);
> 
>     return 0;
> }
> 
> $ gcc -Wall -o poll poll.c
> 
> $ ./poll
> n = 2
> [0].fd = 1
> [0].event = 4
> [0].revent = 4
> [1].fd = 1
> [1].event = 1
> [1].revent = 4
> n = 0
> [1].fd = 1
> [1].event = 1
> [1].revent = 0
> 
> Note that "stdout" is inquired about ready-to-write (in [0]) and ready-to-read (in [1]).
> Because it is ready-to-write, poll() returns immediately, but also having the response
> ready-to-write in [1], where only "read"-compatible status (POLLIN, or POLLHUP, or POLLERR,
> or just 0, if nothing of sorts was available) should have been posted -- but *never* POLLOUT!
> 
> Also note that [1] should have never been flagged as "ready", either, so the return code should have been 1, not 2.
> 
> Finally note that if [0] and [1] were swapped so that [0] was inquired for POLLIN, and [1] was inquired for POLLOUT,
> the result would have still been incorrect on Cygwin ([0] returning POLLOUT for POLLIN inquired).
> 
> For the second invocation, when inquired just singly, the response is correct.
> 
> Now compare it with the correct behavior of the same code, all through, on Linux:
> 
> $ ./poll
> n = 1
> [0].fd = 1
> [0].event = 4
> [0].revent = 4
> [1].fd = 1
> [1].event = 1
> [1].revent = 0
> n = 0
> [1].fd = 1
> [1].event = 1
> [1].revent = 0
> 
> P.S. The manual page for poll(2) says:
> 
> The bits returned in revents can include any of those specified in events, or one of the values POLLERR, POLLHUP, or POLLNVAL.
> 
> So returning POLLOUT(4) for POLLIN(1) violates the rule: bit 0 is NOT set in the binary representation of 4.

Thanks for the report.

I will submit a patch to cygwin-patches@cygwin.com for this issue.

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

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-06-27  1:50 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-26 17:04 poll() is buggy for duplicate file descriptors inquired for different events Lavrentiev, Anton (NIH/NLM/NCBI) [C]
2022-06-27  1:50 ` Takashi Yano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).