Discussion:
svn commit: r265051 - head/sys/sys
(too old to reply)
Ed Maste
2014-04-28 13:42:48 UTC
Permalink
Author: emaste
Date: Mon Apr 28 13:42:41 2014
New Revision: 265051
URL: http://svnweb.freebsd.org/changeset/base/265051

Log:
Drop explicit unsigned from FD_SETSIZE constant

FD_SETSIZE is often used as an argument to select or compared with an
integer file descriptor. Rather than force 3rd party software to add
explicit casts, just make it a plain (int) constant as on other
operating systems.

Previous discussion:
http://lists.freebsd.org/pipermail/freebsd-standards/2012-July/002410.html

Modified:
head/sys/sys/select.h

Modified: head/sys/sys/select.h
==============================================================================
--- head/sys/sys/select.h Mon Apr 28 13:28:10 2014 (r265050)
+++ head/sys/sys/select.h Mon Apr 28 13:42:41 2014 (r265051)
@@ -56,7 +56,7 @@ typedef __sigset_t sigset_t;
* be enough for most uses.
*/
#ifndef FD_SETSIZE
-#define FD_SETSIZE 1024U
+#define FD_SETSIZE 1024
#endif

#define _NFDBITS (sizeof(__fd_mask) * 8) /* bits per mask */
Bruce Evans
2014-04-29 00:03:02 UTC
Permalink
Post by Ed Maste
Drop explicit unsigned from FD_SETSIZE constant
FD_SETSIZE is often used as an argument to select or compared with an
integer file descriptor. Rather than force 3rd party software to add
explicit casts, just make it a plain (int) constant as on other
operating systems.
http://lists.freebsd.org/pipermail/freebsd-standards/2012-July/002410.html
Thanks.

The above discussion refers to my mail in 2002 about related things.
I just debugged why this is (now) a non-problem for poll(). It is
because the design error of using an unsigned type for a count is
standard for poll(), so the unwanted promotions to unsigned should
already be expected and handled for poll(). They mainly give confusing
differences from select().

% #ifndef _SYS_SYSPROTO_H_
% struct poll_args {
% struct pollfd *fds;
% u_int nfds;
% int timeout;
% };
% #endif

nfds actually has type nfds_t, but nfds_t is just u_int. POSIX
specificies that nfsd_t is an unsigned integer type.

% int
% sys_poll(td, uap)
% struct thread *td;
% struct poll_args *uap;
% {
% struct pollfd *bits;
% struct pollfd smallbits[32];
% sbintime_t asbt, precision, rsbt;
% u_int nfds;

As mentioned in old mail:
The nfsds arg has always had type u_int in FreeBSD. The bounds
checking of the nfds arg worked between 1997 and 2001 since it was
done directly on the arg. However, it was broken for 3 weeks in
Feb 2001, by introducing this local variable nfds and giving it a
wrong type (int). This gave overflow for negative nfds. Other
BSDs apparently had this bug in poll() and/or select() for longer.

% int error;
% size_t ni;
%
% nfds = uap->nfds;
% if (nfds > maxfilesperproc && nfds > FD_SETSIZE)
% return (EINVAL);

The "fix" in Feb 2001 was to bogusly cast "int nfds" back to the
correct type u_int. The behaviour on overflow was stll undefined,
but was benign. Then in Feb 2002, breaking the type of FD_SETSIZE
to u_int would have given the same bogus conversion. Then in Jun
2002, the type of the local variable was fixed (modulo the
assumption than nfds_t == u_int).

So except in the 3 week broken period, we just exploit the arg type
being bogusly unsigned. Promotions still occur, but are harmless.
(maxfilesperproc has the correct type (int), so it gets promoted
to the type of nfds (u_int) in the first comparison. Promotion
preserves its value, except possibly on weird arches where
maxfilesperproc is weirdly large. So the comparison works. Now,
a similar promotion occurs for FD_SETSIZE, and any weirdness in
the first comparison would be compensated for by the second
comparison, provided FD_SETSIZE is not also weirdly large.)

Bruce

Loading...