Ingo Schwarze <schwa...@usta.de> writes: > Fourth file, fourth broken file. > This is the worst bug found so far. > All i'm doing is grepping libc/stdio for "EILSEQ". > So far, every single instance i looked at was buggy. > > I think we should cvs rm libc. > The code quality just isn't up to OpwnBSD standards. > > > When fprintf(fp, "...%ls...", ...) encounters an encoding error, > it trashes fp BEYOND REPAIR, clearing all FILE flags, making the > file unreadable, unwriteable, and probably breaking even more than > that. Calling clearerr(3) is by far insufficient to undo the > devastating damage done. > > Besides, i don't see the point in messing with FILE flags at all > in case of encoding errors. As opposed to fgetwc(3) and fputwc(3), > the manual doesn't document this fiddling, and POSIX doesn't ask > for it. No other conversions in printf(3) set the error indicator. > It isn't required because printf(3) provides a proper error return > (-1) in the first place. Has anybody ever seen any code calling > ferror(3) after printf(3)? That just wouldn't make sense. > Of course, printf(3) can result in the error indicator getting set, > but only if the underlying low-level write calls fail. > > So, don't fp->_flags = __SERR; (sic, no |= here!), > don't even fp->_flags |= __SERR;. > > While here, as usual, remove the pointless and slightly dangerous > errno = EILSEQ overrides after functions that already do that > and are required by the standard to do so.
[...] > Note that all code changes below are in parts guarded with > #ifdef PRINTF_WIDE_CHAR > so there is no risk of breaking printf(3) at large. > > OK? Makes sense to me, ok jca@ (I'll review your next diff later.) > Ingo > > > Index: stdio/vfprintf.c > =================================================================== > RCS file: /cvs/src/lib/libc/stdio/vfprintf.c,v > retrieving revision 1.69 > diff -u -p -r1.69 vfprintf.c > --- stdio/vfprintf.c 29 Sep 2015 03:19:24 -0000 1.69 > +++ stdio/vfprintf.c 24 Dec 2015 22:58:33 -0000 > @@ -165,10 +165,8 @@ __wcsconv(wchar_t *wcsarg, int prec) > memset(&mbs, 0, sizeof(mbs)); > p = wcsarg; > nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); > - if (nbytes == (size_t)-1) { > - errno = EILSEQ; > + if (nbytes == (size_t)-1) > return (NULL); > - } > } else { > /* > * Optimisation: if the output precision is small enough, > @@ -188,10 +186,8 @@ __wcsconv(wchar_t *wcsarg, int prec) > break; > nbytes += clen; > } > - if (clen == (size_t)-1) { > - errno = EILSEQ; > + if (clen == (size_t)-1) > return (NULL); > - } > } > } > if ((convbuf = malloc(nbytes + 1)) == NULL) > @@ -203,7 +199,6 @@ __wcsconv(wchar_t *wcsarg, int prec) > if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, > nbytes, &mbs)) == (size_t)-1) { > free(convbuf); > - errno = EILSEQ; > return (NULL); > } > convbuf[nbytes] = '\0'; > @@ -640,8 +635,7 @@ reswitch: switch (ch) { > mbseqlen = wcrtomb(buf, > (wchar_t)GETARG(wint_t), &mbs); > if (mbseqlen == (size_t)-1) { > - fp->_flags |= __SERR; > - errno = EILSEQ; > + ret = -1; > goto error; > } > cp = buf; > @@ -855,7 +849,7 @@ fp_common: > } else { > convbuf = __wcsconv(wcp, prec); > if (convbuf == NULL) { > - fp->_flags = __SERR; > + ret = -1; > goto error; > } > cp = convbuf; > -- jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE