cvs commit: src/lib/libc/sys read.2 write.2

Bruce Evans bde at zeta.org.au
Fri Feb 11 10:52:28 GMT 2005


On Thu, 10 Feb 2005, Colin Percival wrote:

> Colin Percival wrote:
> >   read(), pread(), write(), and pwrite() return EINVAL if they are asked
> >   for more than INT_MAX bytes.

Similarly for readv() and writev() if the sum of the counts in the iovec
would exceed SSIZE_MAX.  Strangely, the behaviour is not
implementation-defined for these syscalls -- counts that would exceed
SSIZE_MAX force an error.  Even more strangely, a negative number of
vectors doesn't force an error.  The POSIX wording for readv() in an
old draft is:

%%%
37106              In addition, the readv( ) function shall fail if:
37107              [EINVAL]             The sum of the iov_len values in the iov array overflowed an ssize_t.
37108              The readv( ) function may fail if:
37109              [EINVAL]             The iovcnt argument was less than or equal to 0, or greater than {IOV_MAX}.
%%%

FreeBSD already has this with completely different, less correct wording:

"The sum of the iov_len values in the iov array overflowed a 32-bit
integer."

Similarly for other syscalls that return ssize_t.  In POSIX, these are
about 17 of these, the main other ones being readlink(), recv*() and
send*().  In FreeBSD, at least readlink() still returns int and has
non-POSIX types for all of its 3 args.

The commit has some bugs.  I noticed these read.2:
(0) It is a bug that the limit is INT_MAX.
(1) Text was added to the section that describes read(), readv() and
    pread(), but it doesn't apply to readv() since readv() doesn't
    have an nbytes arg.  A previous commit that added the description
    of EOVERFLOW is even buggier (readv() doesn't have an nbytes arg
    and only pread() has offset arg, but I think the internal file
    offset instead of the offset arg applies to the others).
(2) If the new text actually applied to readv(), then it would describe
    the error twice for readv().
(3) The new text is unsorted at the end of an almost sorted list, so in
    particular all the things that can cause EINVAL aren't together like
    they are for the readv() section.

> According to POSIX, these calls have "implementation-defined behaviour" if
> nbytes is more than SSIZE_MAX (but should presumably operate without complaint
> on sizes up to that limit).  The offending test is in dofilewrite() and
> dofileread() in sys_generic.c, but fixing this might cause problems in lower
> layers if there is any 64-bit unclean code lurking.

The lower layers are completely 64-bit unclean.  They use "int" for
most byte counts starting with uio_resid.

It is a bug that ssize_t is __int64_t on 64-bit arches and __int32_t
on all 32-bit arches except i386.  It should be int on all aches, since
that is what is supported.  Note that ssize_t has very little to do
with size_t.  It is the return type of the read() family.

However, fixing ssize_t would probably cause binary compatibility problems
when it is reduced and larger ones when it is increased after fixing the
type of uio_resid.

Bruce


More information about the cvs-src mailing list