0

I couldn't find any behavior defined in the man page for read(3). My guess would be that it either throws an error or it just returns 0. But if someone could confirm any defined behavior that would be great. Or if the behavior is specified as being undefined somewhere then stating that would be great as well.

2 Answers 2

2

Such a situation cannot happen by definition (at least under POSIX.1-2008 and later). The nbyte argument to read() is a size_t and that's an unsigned integer type.

1

Consider the prototype of the read function:

ssize_t read(int fd, void *buf, size_t count);

Since the count argument is a size_t which is unsigned, if you try to pass a negative number eg. read(fd, buf, -20) (and you're running a 2's complement machine ;-)) that will be interpreted as a very large count, outside the range of successful return values -- read() returns the number of bytes read as a ssize_t, a signed integer of the same size as size_t.

In that case the following applies:

If the value of nbyte is greater than {SSIZE_MAX}, the result is implementation-defined.

This is on linux:

On Linux, read() (and similar system calls) will transfer at most 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes actually transferred. (This is true on both 32-bit and 64-bit systems.)

In practice, a read() with a count larger than SSIZE_MAX results in an EFAULT, because it's impossible to fit the memory block starting at buf and extending for count bytes within the address space of the process.

On *bsd:

read() and pread() may return the following error:

[EINVAL] nbytes was larger than SSIZE_MAX

And the same on solaris:

EINVAL

The nbyte argument overflowed an ssize_t.

Note: the openbsd manpage makes mention of systems where read() could return a negative value on success; if you know such a system, please add info about it here or in the comments.

6
  • 2's complement does not figure in, ISO C defines the result regardless of signed integer representation. Dec 4, 2020 at 20:43
  • On many operating systems, GNU/Linux included, processes can alloate more memory tzhan SSIZE_MAX, so it's not clear why EFAULT would be generated. Additionally, in practise, most operating systems simply reduce the count and simply return fewer octets than requested, which is legal by POSIX (Linux does this for example). Dec 4, 2020 at 20:44
  • @RememberMonica Linux checks before everything if the whole buffer is within the address space of the process, and if not, fails with EFAULT (this is also documented in the manpage; EFAULT could also be returned later, if the buffer is not backed by any memory). Could you give an example of a Linux running machine where you would able to fit a buffer > SSIZE_MAX within the address space of a process?
    – user313992
    Dec 6, 2020 at 4:42
  • As to 2's complement, doesn't the ISO C standard basically say (in a roundabout way) that signed -> unsigned int of the same size should happen as if the same bit pattern would be reinterpreted as an unsigned int on a 2's complement machine?
    – user313992
    Dec 6, 2020 at 4:44
  • the address space of a 32 bit process can be larger (e.g. 3GB) than the largest ssize_t value (er.g. ~2GB). Dec 6, 2020 at 6:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .