Skip site navigation (1)Skip section navigation (2)
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>