Date: Wed, 9 Jan 2002 03:38:51 -0500 (EST) From: "Alexander Litvin"@FreeBSD.ORG, archer@whichever.org To: FreeBSD-gnats-submit@FreeBSD.ORG Subject: misc/33723: select(2) implementation in threaded (-lc_r) library is incorrect Message-ID: <200201090838.g098cp803252@unknown.whichever.org>
next in thread | raw e-mail | index | archive | help
>Number: 33723 >Category: misc >Synopsis: select(2) implementation in threaded (-lc_r) library is incorrect >Confidential: no >Severity: serious >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Jan 09 00:40:05 PST 2002 >Closed-Date: >Last-Modified: >Originator: Alexander Litvin >Release: FreeBSD 5.0-CURRENT i386 >Organization: unknown >Environment: FreeBSD unknown.whichever.org 5.0-CURRENT FreeBSD 5.0-CURRENT #6: Mon Dec 31 16:05:29 EST 2001 root@unknown.whichever.org:/var/src/sys/i386/compile/UNKNOWN i386 System: FreeBSD 5.0-CURRENT (as of Dec 21, 2001) i386 CPU: Pentium/P54C (119.75-MHz 586-class CPU) Origin = "GenuineIntel" Id = 0x526 Stepping = 6 Features=0x1bf<FPU,VME,DE,PSE,TSC,MSR,MCE,CX8> real memory = 33554432 (32768K bytes) avail memory = 29343744 (28656K bytes) >Description: The select(2) in case of libc_r is implemented via poll(2). The implementation is incorrect in two ways: 1. The current implementation returns the number of file descriptors for which there were observed events. So, if the same file descriptor bit is set in different fd_set's when select() is called, it will be counted only once. But select() is supposed to return total number of bits set in all fd_set's. 2. Current implementation checks the result of poll() for POLLNVAL, POLLHUP, POLLERR, POLLRDBAND and POLLPRI events set, and treats those as exceptional condition pending for the socket. But in terms of select(2), the only exceptional condition is OOB data being available for read. That is, POLLRDBAND and POLLPRI are ok, POLLNVAL should be treated as select(2) error (EBADF set in errno, and -1 returned). I'm not sure about POLLHUP and POLLERR -- may be, their place is among read events. >How-To-Repeat: Simple program to demonstrate is below. It indicates select() failure, when compiled without -lc_r, and select() succeds in threaded case. --------------------------------------------- #include <sys/types.h> #include <sys/time.h> #include <unistd.h> #include <stdio.h> int main() { fd_set fdset; struct timeval timeout; timeout.tv_sec = 60; timeout.tv_usec = 0; FD_ZERO(&fdset); FD_SET(10, &fdset); if (-1 == select(11,&fdset,NULL,NULL,&timeout)) perror("select fails "); else printf("select successful\n"); } --------------------------------------------- >Fix: The patch is below: -------------------- *** src/lib/libc_r/uthread/uthread_select.c.orig Wed Jan 9 02:46:17 2002 --- src/lib/libc_r/uthread/uthread_select.c Wed Jan 9 02:57:16 2002 *************** *** 52,58 **** struct pthread *curthread = _get_curthread(); struct timespec ts; int i, ret = 0, f_wait = 1; ! int pfd_index, got_one = 0, fd_count = 0; struct pthread_poll_data data; if (numfds > _thread_dtablesize) { --- 52,58 ---- struct pthread *curthread = _get_curthread(); struct timespec ts; int i, ret = 0, f_wait = 1; ! int pfd_index, got_events = 0, fd_count = 0; struct pthread_poll_data data; if (numfds > _thread_dtablesize) { *************** *** 166,177 **** * this file descriptor from the fdset if * the requested event wasn't ready. */ ! got_one = 0; if (readfds != NULL) { if (FD_ISSET(data.fds[i].fd, readfds)) { if (data.fds[i].revents & (POLLIN | POLLRDNORM)) ! got_one = 1; else FD_CLR(data.fds[i].fd, readfds); } --- 166,187 ---- * this file descriptor from the fdset if * the requested event wasn't ready. */ ! ! /* ! * First check for invalid descriptor. ! * If found, set errno and return -1 ! */ ! if (data.fds[i].revents & POLLNVAL) { ! errno = EBADF; ! return -1; ! } ! ! got_events = 0; if (readfds != NULL) { if (FD_ISSET(data.fds[i].fd, readfds)) { if (data.fds[i].revents & (POLLIN | POLLRDNORM)) ! got_events++; else FD_CLR(data.fds[i].fd, readfds); } *************** *** 180,186 **** if (FD_ISSET(data.fds[i].fd, writefds)) { if (data.fds[i].revents & (POLLOUT | POLLWRNORM | POLLWRBAND)) ! got_one = 1; else FD_CLR(data.fds[i].fd, writefds); --- 190,196 ---- if (FD_ISSET(data.fds[i].fd, writefds)) { if (data.fds[i].revents & (POLLOUT | POLLWRNORM | POLLWRBAND)) ! got_events++; else FD_CLR(data.fds[i].fd, writefds); *************** *** 189,204 **** if (exceptfds != NULL) { if (FD_ISSET(data.fds[i].fd, exceptfds)) { if (data.fds[i].revents & (POLLRDBAND | ! POLLPRI | POLLHUP | POLLERR | ! POLLNVAL)) ! got_one = 1; else FD_CLR(data.fds[i].fd, exceptfds); } } ! if (got_one) ! numfds++; } ret = numfds; } --- 199,213 ---- if (exceptfds != NULL) { if (FD_ISSET(data.fds[i].fd, exceptfds)) { if (data.fds[i].revents & (POLLRDBAND | ! POLLPRI)) ! got_events++; else FD_CLR(data.fds[i].fd, exceptfds); } } ! if (got_events) ! numfds+=got_events; } ret = numfds; } >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200201090838.g098cp803252>