Nope! It looks like a behavior of fread. We have to reverse the middle two arguments of fread, so that it's reading an n-sized array of 1-byte objects, rather than one object of size n.
#include <stdio.h> int main(void) { char buf[8192]; while (fread(buf, 1, sizeof buf, stdin) != 0); // ^^^^^^^^^^^^^^ reversed these! return 0; } and now, a behavior closely resembling the issue is reproduced. You can see in the strace that two zero-sized reads are needed to bail out: $ strace ./fread read(0, abc "abc\n", 8192) = 4 read(0, "", 7168) = 0 read(0, "", 8192) = 0 exit_group(0) = ? +++ exited with 0 +++ what happens is that upon receiving the zero byte read, fread is returning the number of bytes it has accumulated to the application. The application calls fread again. This is expected, because fread didn't fail. In my original example, fread is called only once and returns zero, because it was told to read a 128 byte object, during which it received a short read, at which point it is game over. Still, I don't understand. The grep 3.1 and 3.7 code both have 1 as the second argument of fread, and the size as the third. This argument order is necessary, so that fread doesn't discard partial data at EOF. So there is something more there. I'd have to play with the code to see how the second argument is behaving under the buffer resize logic and whatnot. (E.g. if it happens that the second argument is now always 1, that would explain why the behavior is fixed.)