Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 28 Feb 2018 13:31:26 +0100
From:      Dimitry Andric <dim@FreeBSD.org>
To:        Gary Jennejohn <gljennjohn@gmail.com>
Cc:        Chris Torek <torek@elf.torek.net>, freebsd-hackers@freebsd.org
Subject:   Re: Marking select(2) as restrict
Message-ID:  <584CE3E6-98F4-4D19-8371-979654F38A3C@FreeBSD.org>
In-Reply-To: <20180228104039.1680ca80@ernst.home>
References:  <20180227210110.GA76452@stack.nl> <201802272230.w1RMUOmL079462@elf.torek.net> <20180228104039.1680ca80@ernst.home>

next in thread | previous in thread | raw e-mail | index | archive | help

--Apple-Mail=_226320BA-6BA4-4D12-8831-3EF9CEF758A9
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
	charset=us-ascii

On 28 Feb 2018, at 10:40, Gary Jennejohn <gljennjohn@gmail.com> wrote:
> 
> On Tue, 27 Feb 2018 14:30:24 -0800 (PST)
> Chris Torek <torek@elf.torek.net> wrote:
> 
>> If we can back up a bit, there are (at least) two mostly-separate
>> issues:
>> 
>> * What types and qualfiiers to use for various parameters:
>>   These are dictated by standards, and we should just conform
>>   to whatever is in the standard unless there's some major
>>   reason to do otherwise.
>> 
>>   POSIX says that we *should* use "restrict" here:
>>   http://pubs.opengroup.org/onlinepubs/009696699/functions/pselect.html
>> 
>>   so if no one has a major reason to do otherwise (such as
>>   "no conforming program can tell that we didn't and all it will
>>   achieve is nothing" :-) ) I'd say add the restrict.
>> 
>>   (As kib and others have noted, it achieves a lot of nothing, so
>>   the priority for this particular conformance seems low.)
>> 
>> * Select itself: it makes no sense *in the caller* to pass
>>   the same &fd_set argument to more than one parameter unless
>>   they are all input-only.  The kernel is going to write on them,
>>   and there is no guarantee that the kernel will write them in any
>>   particular order.  Hence if you write:
>> 
>>        ret = select(nfds, &a, &a, &a, timeout);
>> 
>>   you are nearly guaranteed to have a bug: this call can only
>>   be correct if the only value you intend to inspect is "ret".
>> 
>>   (That, in fact, is what devd was doing: if ret==0, daemonize,
>>   and in any case throw away the returned results in the by-pointer
>>   arguments.  Hence not a bug -- unless ... well, read on.)
>> 
>>   The remaining question is: can even that be correct?  In
>>   particular, should the kernel be required to use copy-in/copy-out
>>   semantics, or can it do the equivalent (minus error checking
>>   and a lot of other important details) of:
>> 
>>        int select(int nfds, fd_set *in, fd_set *out, fd_set *ex,
>>            struct timeval *tvp) {
>>                some_complicated_type v_in, v_out, v_ex;
>> 
>>                v1 = op(*in);
>>                *in = function(v1);
>>                v2 = op(*out);
>>                ...
>>        }
>> 
>>   ?  If the latter is *permitted*, then the call passing "&a"
>>   three times is *always* wrong, since *in might have been
>>   clobbered before *out is ever loaded.  If a program breaks
>>   because it was doing this, well, it was already broken, we were
>>   just lucky that it worked anyway.  (Was this good luck, or bad
>>   luck? :-) )
>> 
>>   Currently, the kernel does in fact copy them all in,
>>   then futz with them, then copy them all out (for good reasons).
>>   So the devd usage always works.  But will the kernel *always*
>>   do this, or is that an accident of the implementation?
>> 
> 
> Linux also does a copyin (copy_from_user) of each FD_SET.  Linux
> also does not use restrict in select.

Not in the kernel, where it is effectively declared as:

asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
                       	fd_set __user *exp, struct timeval __user *tvp);

but definitely in userland, where glibc has:

extern int __select (int __nfds, fd_set *__restrict __readfds,
		     fd_set *__restrict __writefds,
		     fd_set *__restrict __exceptfds,
		     struct timeval *__restrict __timeout);

So for any normal program the entry point to select() is certainly
using restrict.


> It would be a very bad
> design decision to not copy each FD_SET separately into the
> kernel.

Indeed, Linux's sys_select allocates 6 separate bitmaps, 3 for the
incoming fd_sets, and 3 for the outgoing ones.

If the outgoing ones would all use the same pointer, it is just going
to end up calling copy_to_user() 3 times on the same area, overwriting
the previous results.  That would still be unsafe for some situations.


> It would be good to explicitly state that it is only safe to
> use pointers to a single FD_SET when only the error return is of
> interest and the results in the FD_SET will be ignored.

Agreed.

-Dimitry


--Apple-Mail=_226320BA-6BA4-4D12-8831-3EF9CEF758A9
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename=signature.asc
Content-Type: application/pgp-signature;
	name=signature.asc
Content-Description: Message signed with OpenPGP

-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.2

iF0EARECAB0WIQR6tGLSzjX8bUI5T82wXqMKLiCWowUCWpahHgAKCRCwXqMKLiCW
o4BjAJ9lJeyAjTRLq0q9p5/snjjbVvpo9QCgoyRbGrTdgQnsuRsaTgn1GT+Lc/Q=
=1awd
-----END PGP SIGNATURE-----

--Apple-Mail=_226320BA-6BA4-4D12-8831-3EF9CEF758A9--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?584CE3E6-98F4-4D19-8371-979654F38A3C>