From owner-freebsd-standards@FreeBSD.ORG Tue Jul 3 17:17:52 2012 Return-Path: Delivered-To: freebsd-standards@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 71BEB1065670; Tue, 3 Jul 2012 17:17:52 +0000 (UTC) (envelope-from brde@optusnet.com.au) Received: from mail06.syd.optusnet.com.au (mail06.syd.optusnet.com.au [211.29.132.187]) by mx1.freebsd.org (Postfix) with ESMTP id 0799D8FC18; Tue, 3 Jul 2012 17:17:48 +0000 (UTC) Received: from c122-106-171-232.carlnfd1.nsw.optusnet.com.au (c122-106-171-232.carlnfd1.nsw.optusnet.com.au [122.106.171.232]) by mail06.syd.optusnet.com.au (8.13.1/8.13.1) with ESMTP id q63HHdT7003863 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 4 Jul 2012 03:17:41 +1000 Date: Wed, 4 Jul 2012 03:17:39 +1000 (EST) From: Bruce Evans X-X-Sender: bde@besplex.bde.org To: Benjamin Kaduk In-Reply-To: Message-ID: <20120704022929.L2234@besplex.bde.org> References: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed Cc: freebsd-standards@FreeBSD.org Subject: Re: FD_SETSIZE: signed or unsigned? X-BeenThere: freebsd-standards@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Standards compliance List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 03 Jul 2012 17:17:52 -0000 On Mon, 2 Jul 2012, Benjamin Kaduk wrote: > We've had an unsigned FD_SETSIZE since 2002 (r90135, by markm): > %%%%%%%%%%%%%%%%%%%%%%%% > Revision 90135 - (show annotations) > Sun Feb 3 11:36:59 2002 UTC (10 years, 5 months ago) by markm > File MIME type: text/plain > File size: 7279 byte(s) > > Zero functional difference; make some integer constants unsigned, as > they are used in unsigned context. This shuts lint(1) up in a few > significant ways with "signed/unsigned" arithmetic warnings. > %%%%%%%%%%%%%%%%%%%%%%%% > > Yet NetBSD, Linux, and OpenBSD all have signed (plain int) FD_SETSIZEs. > > This has led to various pieces of software introducing casts and workarounds > for the FreeBSD behavior, which (apparently) was itself made in order to > attempt to reduce the occurence of warnings. I didn't like it at the time, and got the similar changes to NBBY and howmany() backed out. Only the unsigned constant in howmany() was obviously wrong. It caused promotion of nearby int args to unsigned, so for example howmany(-1, 1) was UINT_MAX with type unsigned instead of -1 with type int. OTOH, howmany(-1L, 1) was -1L on arches with sizeof(u_int) < sizeof(long) (assume no padding bits throughout), but was (long)UINT_MAX on arches with sizeof(u_int) == sizeof(long). (long)UINT_MAX is implementation-defined and is normally also -1L. Maybe negative howmany()'s aren't useful, but the unsigned constant also makes the type of howmany() unsigned when it should be int, giving the same problem as for FD_SETSIZE. You don't want to know about these complications, and should let the default binary promotions work normally by not having any unusual types hidden in the implementation of howmany(). Especially when previous and other implementations dont't have them. If you really want unsigned behaviour in howmany(), then you can pass it unsigned args (howmany((x), 0U + (y)) would give the same behaviour as the hidden 1U). > Before I go and introduce such workarounds into our codebase for $work, I > wanted to check with the standards gurus to see whether there is any chance > that FreeBSD is what needs fixing, first. I would prefer to change it back to plain int. > Bruce touched on some related issues on freebsd-security a few months later > in 2002 ("[provos@citi.umich.edu: OpenBSD Security Advisory: Select Boundary > Condition]"), but I can't really derive anything decisive from it. I had forgotten about that (but complained about magic casts to `unsigned int' in file descriptor code recently :-)). > In any case, it is clear that a negative value for FD_SETSIZE is nonsensical. But comparing "int fd" with FD_SETSIZE makes sense, and having FD_SIZE a different type than int mainly gives sign extension problems. The problems are mostly only potential, but the compiler doesn't know that and gives actual problems by warning about the potential ones; -Werror then makes these fatal. IMO, unsigned types should never be used just because the values in them are expected to be always nonnegative. Use of unsigned types mainly gives (un)sign extension bugs when unsigned types are mixed with signed types in expressions. > Doing a quick survey, it seems to mostly be used as the first argument to > select(2) (which is an int type argument), and as a bound check on fd numbers > (before using them in select). Given the former, it seems dubious to > consider ever using a value between INT_MAX and UINT_MAX, which does leave > open what the actual type should be. The value of (INT_MAX + 1U) actually makes sense: if you have fds numbered 0 to INT_MAX, then the number of fds is (INT_MAX + 1U). The POSIX history reminded me of this -- old versions had an off-by-1 error for nfds, with nfds >= FD_SETSIZE an error, but it is nfds > FD_SETSIZE that is the error. Anyway, nfds is int, so it cannot be (INT_MAX + 1U), and FD_SETSIZE being (INT_MAX + 1U) is not useful since apart from being more than large enough for anyone (at least with 32 bit ints), nfds can never equal it. > POSIX is delightfully vague: > %%%%%%%%%%%%%%%%%%%%%% > The following shall be defined as a macro: > > FD_SETSIZE > > Maximum number of file descriptors in an fd_set structure. > %%%%%%%%%%%%%%%%%%%%%% The 2001 and 2007 (draft) versions are equally vague. Bruce