From archer@whichever.org  Wed Jan  9 00:38:55 2002
Return-Path: <archer@whichever.org>
Received: from smtp02.mrf.mail.rcn.net (smtp02.mrf.mail.rcn.net [207.172.4.61])
	by hub.freebsd.org (Postfix) with ESMTP id 274C837B416
	for <FreeBSD-gnats-submit@freebsd.org>; Wed,  9 Jan 2002 00:38:55 -0800 (PST)
Received: from 209-122-220-227.s227.tnt6.nywnj.ny.dialup.rcn.com ([209.122.220.227] helo=unknown.whichever.org)
	by smtp02.mrf.mail.rcn.net with esmtp (Exim 3.33 #10)
	id 16OEG4-0002il-00
	for FreeBSD-gnats-submit@freebsd.org; Wed, 09 Jan 2002 03:38:53 -0500
Received: (from archer@localhost)
	by unknown.whichever.org (8.11.6/8.11.6) id g098cp803252;
	Wed, 9 Jan 2002 03:38:51 -0500 (EST)
	(envelope-from archer)
Message-Id: <200201090838.g098cp803252@unknown.whichever.org>
Date: Wed, 9 Jan 2002 03:38:51 -0500 (EST)
From: "Alexander Litvin"@FreeBSD.ORG, archer@whichever.org
Reply-To: archer@whichever.org
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: select(2) implementation in threaded (-lc_r) library is incorrect
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         33723
>Category:       misc
>Synopsis:       select(2) implementation in threaded (-lc_r) library is incorrect
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-threads
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jan 09 00:40:05 PST 2002
>Closed-Date:    Sat Jul 12 22:56:05 PDT 2003
>Last-Modified:  Sat Jul 12 22:56:05 PDT 2003
>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:
State-Changed-From-To: open->analyzed 
State-Changed-By: asmodai 
State-Changed-When: Mon Apr 8 12:33:39 PDT 2002 
State-Changed-Why:  
I've raised the issue with two of our libc_r heroes. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=33723 
State-Changed-From-To: analyzed->patched 
State-Changed-By: asmodai 
State-Changed-When: Mon Apr 8 22:41:17 PDT 2002 
State-Changed-Why:  
Committed to CURRENT with a small change, provided by Daniel Eischen. 

Thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=33723 
Responsible-Changed-From-To: freebsd-bugs->freebsd-threads 
Responsible-Changed-By: kris 
Responsible-Changed-When: Sat Jul 12 18:37:21 PDT 2003 
Responsible-Changed-Why:  
Assign to threads mailing list 

http://www.freebsd.org/cgi/query-pr.cgi?pr=33723 
State-Changed-From-To: patched->closed 
State-Changed-By: deischen 
State-Changed-When: Sat Jul 12 22:55:24 PDT 2003 
State-Changed-Why:  
Fix was commited over 1 year ago. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=33723 
>Unformatted:
