Date: Mon, 26 Feb 2018 21:00:21 +1100 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Mark Millard <marklmi26-fbsd@yahoo.com> Cc: Tijl Coosemans <tijl@freebsd.org>, FreeBSD Standards <freebsd-standards@freebsd.org>, FreeBSD Hackers <freebsd-hackers@freebsd.org>, Kevin Lo <kevlo@freebsd.org> Subject: Re: Marking select(2) as restrict Message-ID: <20180226200951.V2634@besplex.bde.org> In-Reply-To: <1A2830F4-A00B-4C56-8D28-C46715DC7C9E@yahoo.com> References: <CAF6rxg=h_oMiUu7P=GAOQf_OySQM2w31hg6Kas%2B3jeEM3qq_Cg@mail.gmail.com> <CAF6rxgnt9c0n8i-nHQwoKGbZKF2hM5AZqEJnz0CLo26XOO4_sg@mail.gmail.com> <20180221032247.GA81670@ns.kevlo.org> <CAF6rxg=WwqeBnmJzfOZgtwrYesXPfvJFeaVmQwtTa_89_sxaJg@mail.gmail.com> <CANCZdfo46bhfaRpbqOmJjk4%2B=1R2c5kvmrJPENaxNgK==5M4kg@mail.gmail.com> <CAF6rxg=wNVgDUF9o744ngmzPNeHB3hqdrLufy=yS3D4osczxFQ@mail.gmail.com> <20180221104400.GU94212@kib.kiev.ua> <20180222112752.10da7e51@kalimero.tijl.coosemans.org> <20180222105608.GE94212@kib.kiev.ua> <20180225214813.776a9f58@kalimero.tijl.coosemans.org> <2909E983-953A-4463-959C-F3C386BC6C9A@yahoo.com> <20180226135457.B1203@besplex.bde.org> <1A2830F4-A00B-4C56-8D28-C46715DC7C9E@yahoo.com>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, 25 Feb 2018, Mark Millard wrote: > On 2018-Feb-25, at 7:45 PM, Bruce Evans <brde at optusnet.com.au> wrote: >> . . . restrict is not needed for the input-only >> args since const suffices. > > Here you lost me. > > With q and r having both the const and the restrict, > updates to p's "objects" can not change the > "object(s)" q and r validly can be used to access. > That can be important. > > Without the "restrict" for q and r (but still > having the const for each) it is valid for updates > to p's "objects" to change what q and r then can > validly access. Yes, I forgot that all const on a pointer arg does is prevent modification through that pointer. Modifications can still occur through other args. memmove() is a canonical example. Its source arg is const, by the source is _always_ modified in the overlapping case that is the reason for existence of memmove(). memcpy() is another canonical example. Both of its args are declared with restrict, except in its man page. Its source arg is still declared as const. Without that, either arg could be modified. With that and restrict on the other arg, I think it follows that the source arg cannot be modified. It is unclear if restrict on the source arg is needed too. It is now clear(er) that POSIX's restricts for sigaction() are correct and not having them for nanosleep() is a bug. nanosleep()'s args are const struct timespec * and struct timespec *. Nothing prevents these being aliased, just like for memmove(), and unlike for memcpy(), the behaviour is not undefined when aliasing occurs. Aliasing can only occur if the pointers are equal, since unlike for mem*() they don't point to arrays (but the prototype doesn't give this information.) So nanosleep(&ts, &ts) must work, and working involves clobbering the input arg. The implementation must be careful to not write the output before reading the input (if the pointers are not equal), and callers using the same timespec for input and output must not depend on the source being const. This is just like for the non-restrict select() except it is easier to avoid problems (e.g., by copying) with a single small object than with a potentially large array for the input arg. My argument applies better to pointer args of different types. Then const prevents modifications through some pointer args and the different types prevent aliasing of the non-const args to the const args. For select() with restrict, I think the compiler cannot assert that the args don't overlap since (even without the detailed specification and Example 3), the compiler cannot know if select() modifies its args. For all that the compiler knows, select() might be a stub that never modifies or even reads anything. I think doing no accesses satifies the constraints of restrict. It might be valid for the compiler to assert that the (values pointed to by) the fdset args don't change for select(nfd, &fdset, &fdset, &fdset, &tv) (because any write access through an fdset type would give undefined behaviour on the other fdset args; tv can still change since it has a different type). But this is precisely what is wanted for the original example where we only care about the return value -- then fdset is indeterminate after the call so we shouldn't use it; the compiler is unlikely to optimize the non-use of it and the worst that it can do is add a runtime assertion that the arg didn't change. Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20180226200951.V2634>