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
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.
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 most0x7ffff000
(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()
andpread()
may return the following error:
[EINVAL]
nbytes was larger thanSSIZE_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.
-
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?– user313992Dec 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?– user313992Dec 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