Hi all! Recently I was working on a program that uses stdio functions heavily. While hunting for a bug, I've temporarily disabled buffering (via setvbuf(f, NULL, _IONBF, 0)) and realized that program behavior was changed heavily. The cause was that fread() stopped setting error flag after hitting EAGAIN. It looks like its code is missing setting EOF/error flags totally in case of unbuffered read, and first patch (below) fixes this.
I'm not sure if "r" variable value should be propagated to fp->_r, or not. I've assumed that since things work without it now, this doesn't need a change. And headache stops me from further investigation for now, sorry. I understand that use stdio functions without buffering is somewhat exotic, and that's for sure is the reason noone found this bug yet. But this is still a bad thing, IMHO. While looking through the libc code I've also found that __sread() drops __SOFF flag unconditionally for all read errors. IMHO, the EAGAIN case shouldn't be affected here, since, obviously current offset doesn't change and is still well-known. So... any comments, or ever okays? :) -- WBR, Vadim Zhukov Index: stdio/fread.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/fread.c,v retrieving revision 1.15 diff -u -p -r1.15 fread.c --- stdio/fread.c 21 Sep 2016 04:38:56 -0000 1.15 +++ stdio/fread.c 5 May 2018 19:02:04 -0000 @@ -79,6 +79,10 @@ fread(void *buf, size_t size, size_t cou p += r; resid -= r; } + if (r == 0) + fp->_flags |= __SEOF; + else if (r < 0) + fp->_flags |= __SERR; FUNLOCKFILE(fp); return ((total - resid) / size); } Index: stdio/stdio.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/stdio.c,v retrieving revision 1.10 diff -u -p -r1.10 stdio.c --- stdio/stdio.c 21 Sep 2016 04:38:56 -0000 1.10 +++ stdio/stdio.c 5 May 2018 19:02:04 -0000 @@ -49,7 +49,7 @@ __sread(void *cookie, char *buf, int n) /* if the read succeeded, update the current offset */ if (ret >= 0) fp->_offset += ret; - else + else if (errno != EAGAIN) fp->_flags &= ~__SOFF; /* paranoia */ return (ret); }