Bug 91421

Summary: FD_ISSET returns long, not int.
Product: Base System Reporter: akr <akr>
Component: ia64Assignee: freebsd-ia64 (Nobody) <ia64>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 6.0-RELEASE   
Hardware: Any   
OS: Any   

Description akr 2006-01-06 21:10:02 UTC
On IA64 (and other LP64 environments),
(int)FD_ISSET(32, &fds) is evaluated to 0, even if 32 is set in fds.

Since SUSv3 defines FD_ISSET defines as follows, cast to int should be safe.

    int FD_ISSET(int fd, fd_set *fdset);

This problem is caused because FD_ISSET() returns single unsigned long bitmap.
(__fds_bits is an array of unsigned long)

td150.testdrive.hp.com> grep FD_ISSET /usr/include/sys/select.h
#define FD_ISSET(n, p)  ((p)->__fds_bits[(n)/_NFDBITS] & __fdset_mask(n))

Since unsigned long is longer than int on LP64, 
(int)FD_ISSET() discards upper 32bits.

Fix: 

add "!= 0".

#define FD_ISSET(n, p)  (((p)->__fds_bits[(n)/_NFDBITS] & __fdset_mask(n)) != 0)
How-To-Repeat: td150.testdrive.hp.com> cat tst.c
#include <stdio.h>
#include <sys/select.h>

int main()
{
  fd_set fds;
  FD_ZERO(&fds);
  FD_SET(32, &fds);
  printf("%d\n", (int)FD_ISSET(32, &fds));
  printf("%lx\n", (long)FD_ISSET(32, &fds));
  return 0;
}
td150.testdrive.hp.com> gcc tst.c
td150.testdrive.hp.com> ./a.out
0
100000000
Comment 1 Marcel Moolenaar freebsd_committer freebsd_triage 2006-01-06 22:13:20 UTC
State Changed
From-To: open->patched

Fix committed to -CURRENT and will be merged onto the 6.x branch in a week. 
Thanks!
Comment 2 Marcel Moolenaar freebsd_committer freebsd_triage 2006-01-13 03:12:14 UTC
State Changed
From-To: patched->closed

Fixed as of version 6.1.