Third file, third bug. SO FAR, EACH AND EVERY BLOODY PLACE I LOOKED AT WAS BROKEN.
When fputwc(3) encounters an encoding error, it neglects to set the error indicator, just like fgetwc(3) did before i fixed it today. Setting the error indicator is required by the manual and by the standard. Instead, it overrides errno again. That's pointless because wcrtomb(3) already did that, and is required to do so by the standard. It is even slightly dangerous because it might hide internal coding errors in libc. For example, if libc would ever neglect to initialize the state object correctly, wcrtomb(3) might fail with EINVAL. That should NOT be plastered over by setting errno to EILSEQ. Consider this test program: #include <err.h> #include <stdio.h> #include <wchar.h> int main(void) { wchar_t ws[2]; int irc; ws[0] = 0xdc00; /* UTF-16 surrogate, invalid code point. */ ws[1] = L'\0'; irc = fputws(ws, stdout); printf("fputws returned %d\n", irc); printf("error status %d\n", ferror(stdout)); err(1, "fputws"); } Output before: $ ./putws fputws returned -1 error status 0 putws: fputws: Illegal byte sequence Output with the patch below: $ ./putws fputws returned -1 error status 1 putws: fputws: Illegal byte sequence OK? Ingo Index: fputwc.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/fputwc.c,v retrieving revision 1.6 diff -u -p -r1.6 fputwc.c --- fputwc.c 1 Oct 2015 02:32:07 -0000 1.6 +++ fputwc.c 24 Dec 2015 21:01:10 -0000 @@ -62,7 +62,7 @@ __fputwc_unlock(wchar_t wc, FILE *fp) size = wcrtomb(buf, wc, st); if (size == (size_t)-1) { - errno = EILSEQ; + fp->_flags |= __SERR; return WEOF; }