On Thu, Apr 23, 2026 at 14:03 +0200, Alejandro Colomar via Mutt-dev wrote:

+  } while ((res == (size_t) -1) && (errno == EINTR));

This cast is dangerous.  It's safer to compare to literal -1.  I know
you'll get a -Wsign-compare (part of -Wextra) diagnostic, but that's
something that GCC should fix.  I've been using -Wno-error=sign-compare
for some time, precisely for the false negatives.

If for some reason, the type of the cast doesn't match the type of the
variable, we'll get a bug.  On the other hand, non-casted literal -1
will magically convert to any wider unsigned type and do the right
thing.

Short answer: getrandom() returns ssize_t.

Long explanation:

I guess the danger is that, if size_t is unsigned and wider than int, the value's high bits will be 0? And the magic is a special little hack built into the compiler (and language?) that recognizes the idiom, and does something non-standard?

I'd be reluctant to count on the magic. I guess you could do either of:
    ~0ULL
    ~((size_t)0)

But that's still hacking around the problem, which is mixing signed and unsigned. It's probably better not to mix them.

The return value -1 itself is an old hack. It combines two things, a length and an error flag, in one value. Valid lengths are positive or zero; any negative value cannot be a length, so a specific negative value is assigned a different meaning.

That can only work for signed types. In an unsigned type, all possible values are valid lengths, so unsigned types should not be used for that two-meanings hack.

If the length has to be unsigned, then the second meaning -- error flag -- could be put into a separate boolean variable. Or, maybe the two-meanings value can be a plain old int, assuming Mutt won't ask for any huge amount of data. Of course, only Mutt code can be adjusted, not arguments and return values of system library functions.

But maybe there isn't a problem. The complete code is:

  size_t res;

  do
  {
    res = getrandom(random_bytes, length_requested, GRND_NONBLOCK);
  } while ((res == (size_t) -1) && (errno == EINTR));

On FreeBSD, the man page for getrandom() says the return type is not size_t, but ssize_t. I've never heard of ssize_t, but I bet it's signed, and I bet it exists specifically to avoid this problem.

If ssize_t exists everywhere and is guaranteed to be signed, and getrandom() everywhere returns ssize_t, then it should be fine to just use that type and compare it directly to -1, like this:

  ssize_t res;          /* signed */

  do
  {
    res = getrandom(random_bytes, length_requested, GRND_NONBLOCK);
  } while ((res == -1) && (errno == EINTR));

Reply via email to