7

Typing man recv() on my system, I get:

 ssize_t
 recv(int socket, void *buffer, size_t length, int flags);

 …

RETURN VALUES
 These calls return the number of bytes received, or -1 if an error occurred.

Note that length is of unsigned type size_t and the function's result is a signed ssize_t.

If passed a value larger than SSIZE_MAX for length, how theoretical is the situation where recv() would fill the memory pointed by buffer and return a negative value other than -1 ? Are there types of sockets that allow very long messages (Unix domain?)? What about MSG_WAITALL?

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
  • 1
    I think the trick may be that `sizeof(ssize_t) > sizeof(size_t)`. –  Jun 20 '13 at 19:12
  • 1
    @H2CO3 `ptrdiff_t` may or may not be wider than `size_t` to accommodate the sign bit, but `ssize_t` is defined as the signed type corresponding to `size_t`. It should not be wider. – Pascal Cuoq Jun 20 '13 at 19:15
  • (In this case, take my upvote. I have no more ideas.) –  Jun 20 '13 at 19:16
  • @H2CO3 This question is in the context of this blog post: http://blog.frama-c.com/index.php?post/2013/06/20/recv , which links back to this other question about `ssize_t` and `ptrdiff_t`: http://stackoverflow.com/q/8649018/139746 – Pascal Cuoq Jun 20 '13 at 19:22
  • The good news is: you probably won't be able to construct a buffer of size SSIZE_T_MAX. (or the read() will give a shiter return; what ever comes first) – wildplasser Jun 20 '13 at 21:01
  • @wildplasser My 32-bit compiler with 32-bit `ssize_t` lets me `malloc(2500000000)`, no problem. – Pascal Cuoq Jun 20 '13 at 21:04
  • .@PascalCuoq .. But what is the return value from recv() / read() ? – wildplasser Jun 20 '13 at 21:06
  • @wildplasser Well, this is what this question was about finding out. I didn't realize that `read()` also returned a `ssize_t`, but I expect it to never return a value larger than some limit fixed by the kernel. `recv()` seems more interesting, there is a notion of “message” and various types of sockets/options to alter `recv()`'s behavior. – Pascal Cuoq Jun 20 '13 at 21:12
  • Well: the real answer is that ssize_t is an artifact. It is a theorethical type, and ssize_t_max will (in practice) never be hit. The return value from read() et.al used to be int, and ssize_t was introduced as an abstract type to avoid it. (BTW: if physical_space == virtual_space the limit cammot be met, but if user_arena is differnt from syztem)arena, it *could* be) But a conforming implementation could always do a short read/write, and return appropiately. – wildplasser Jun 20 '13 at 21:19

1 Answers1

6

Here's what the Posix 2008 rationale has to say about ssize_t (extracted from B.2.12 Data Types):

ssize_t
This is intended to be a signed analog of size_t. The wording is such that an implementation may either choose to use a longer type or simply to use the signed version of the type that underlies size_t. All functions that return ssize_t (read() and write()) describe as "implementation-defined" the result of an input exceeding {SSIZE_MAX}.

Actually, that's not quite true, since the socket functions which return ssize_t, including recv, don't mention anything about input exceeding SSIZE_MAX. So I'm taking that as a statement of intention, implying that the missing wording in recv is an error which might be corrected some day.

In short, if you want to write portable code, you need to ensure that your I/O segments do not exceed SSIZE_MAX. Furthermore, SSIZE_MAX may be as small as 32767. So portable code shouldn't assume that it might be greater.

However, not everyone cares that much about portability. You might know something about the implementations your code runs on. Posix continues:

It is recognized that some implementations might have ints that are smaller than size_t. A conforming application would be constrained not to perform I/O in pieces larger than {SSIZE_MAX}, but a conforming application using extensions would be able to use the full range if the implementation provided an extended range, while still having a single type-compatible interface.

Posix does guarantee that the only values returned by recv are -1, 0 or the number of bytes received. A conforming implementation, according to the above wording, could map values greater than SSIZE_MAX but less than or equal to 2*SSIZE_MAX onto the negative integers other than -1. (How this might be accomplished is left as an exercise for the interested reader :) ). Linux does not, as far as I know, document any such extension, though.

rici
  • 234,347
  • 28
  • 237
  • 341