On Thu, Dec 13, 2018 at 11:01:10AM -0700, Todd C. Miller wrote: > Here's a diff that fakes up a FILE like we do in other parts of > stdio for unbuffered I/O. This lets us call __srefill() normally. > If __srefill() returns an error, copy the flags back to the real > FILE *. > > - todd
I like a lot the way it is done. Using a copy of FILE argument with _bf._size changed to request read size is great. and as juanfra@ said, it solves mercurial problem (I tested it too). some comments inlined. > Index: lib/libc/stdio/fread.c > =================================================================== > RCS file: /cvs/src/lib/libc/stdio/fread.c,v > retrieving revision 1.15 > diff -u -p -u -r1.15 fread.c > --- lib/libc/stdio/fread.c 21 Sep 2016 04:38:56 -0000 1.15 > +++ lib/libc/stdio/fread.c 13 Dec 2018 17:24:34 -0000 > @@ -69,18 +69,39 @@ fread(void *buf, size_t size, size_t cou > total = resid; > p = buf; > > + /* > + * If we're unbuffered we know that the buffer in fp is empty so > + * we can read directly into buf. This is much faster than a > + * series of one byte reads into fp->_nbuf. > + */ > if ((fp->_flags & __SNBF) != 0) { > - /* > - * We know if we're unbuffered that our buffer is empty, so > - * we can just read directly. This is much faster than the > - * loop below which will perform a series of one byte reads. > - */ > - while (resid > 0 && (r = (*fp->_read)(fp->_cookie, p, resid)) > > 0) { > - p += r; > - resid -= r; > + FILE fake; > + struct __sfileext fakeext; > + > + _FILEEXT_SETUP(&fake, &fakeext); > + /* copy the important variables */ > + fake._flags = fp->_flags; > + fake._file = fp->_file; > + fake._cookie = fp->_cookie; > + fake._read = fp->_read; in some cases (but it might be an ill argument passed to fread(): see "if not already reading, have to be reading and writing"), __srefill() could call __sflush(), and it will call _write handler (which is uninitialized data). should we copying others handlers too ? > + > + /* set up the buffer */ > + fake._bf._base = buf; does a test for ill arguments (like buf == NULL) should be done ? else __srefill() will call __smakebuf(), and it will set: fp->_bf._base = fp->_p = fp->_nbuf; using _nbuf which is uninitialized data. > + fake._bf._size = total; > + fake._lbfsize = 0; /* not line buffered */ > + Globally, I think `fake' should be properly initialized by doing a memcpy() with `fp' data. And next, override values to copte with buffer size. This way, it will take care of all ill cases, and no uninitialized data will be used. > + while (resid > 0) { > + if (__srefill(&fake)) { > + /* no more input: return partial result */ > + count = (total - resid) / size; > + fp->_flags |= (fake._flags & (__SERR|__SEOF)); Initially, I wonder why you copied back only __SERR|__SEOF to _flags (__srefill could change few others flags), but as _flags is sole parameter to be copied back it makes sens. > + break; > + } > + fake._p += fake._r; > + resid -= fake._r; > } > FUNLOCKFILE(fp); > - return ((total - resid) / size); > + return (count); > } > > while (resid > (r = fp->_r)) { Thanks. -- Sebastien Marie