From 1f05b9769c5a59bded85f38ef18a19b80c19fa4e Mon Sep 17 00:00:00 2001 From: Adam Greloch Date: Thu, 10 Oct 2024 17:30:43 +0200 Subject: [PATCH] sys/select: fix errnos select() should fail with -1 and set errno to: * EBADF when one or more of the fdsets specified an invalid fd * EINVAL if nfds is incorrect and/or if timeout makes no sense (i.e. tv_usec is outside of [0, 999999]) JIRA: RTOS-945 --- sys/select.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/sys/select.c b/sys/select.c index 51f47241..902a1f31 100644 --- a/sys/select.c +++ b/sys/select.c @@ -46,14 +46,29 @@ int select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *to) struct pollfd *pfd; time_t timeout; size_t i, n; - int err; + int rv; + + if ((nfds < 0) || (nfds > FD_SETSIZE)) { + errno = EINVAL; + return -1; + } + + if ((to != NULL) && ((to->tv_usec < 0) || (to->tv_usec > 999999))) { + errno = EINVAL; + return -1; + } for (n = i = 0; i < nfds; ++i) if (SFD_ISSET(i, rd) || SFD_ISSET(i, wr) || SFD_ISSET(i, ex)) ++n; - if (!n) - return usleep(poll_timeout(to)); + rv = poll_timeout(to); + timeout = rv < 0 ? 0 : (time_t)rv; + + if (n == 0) { + rv = usleep(timeout); + return rv < 0 ? -1 : 0; + } pfd = calloc(n, sizeof(*pfd)); if (!pfd) { @@ -76,22 +91,19 @@ int select(int nfds, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *to) ++n; } - if (to) { - if (to->tv_sec < INT_MAX / 1000) { - timeout = ((to->tv_usec + 999) / 1000) + to->tv_sec * 1000; - if (timeout > INT_MAX) - timeout = -1; - } else - timeout = -1; - } else - timeout = -1; + rv = poll(pfd, n, timeout); - err = poll(pfd, n, timeout); + for (i = 0; i < n; ++i) { + if ((pfd[i].revents & POLLNVAL) != 0) { + rv = -EBADF; + break; + } + } - if (err < 0) { + if (rv < 0) { if (pfd) free(pfd); - return err; + return SET_ERRNO(rv); } if (rd)