Author: ache
Date: Thu Sep  8 05:13:50 2016
New Revision: 305577
URL: https://svnweb.freebsd.org/changeset/base/305577

Log:
  MFC r305406,r305409,r305412
  
  1) Fix errors handling.
  
  2) Prevent out of bounds access to ws[-1] (passed buffer) which happens
  when the first mb sequence is incomplete and there are not enougn chars in
  the read buffer. ws[-1] may lead to memory faults or false results, in
  case the memory here contains '\n'.
  
  3) Fix n == 1 case. Here should be no physical read (fill buffer) attempt
  (we read n - 1 chars with the room for NUL, see fgets()),
  and no NULL return.

Modified:
  stable/10/lib/libc/stdio/fgetws.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/lib/libc/stdio/fgetws.c
==============================================================================
--- stable/10/lib/libc/stdio/fgetws.c   Thu Sep  8 02:38:55 2016        
(r305576)
+++ stable/10/lib/libc/stdio/fgetws.c   Thu Sep  8 05:13:50 2016        
(r305577)
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
 wchar_t *
 fgetws_l(wchar_t * __restrict ws, int n, FILE * __restrict fp, locale_t locale)
 {
+       int sret;
        wchar_t *wsp;
        size_t nconv;
        const char *src;
@@ -56,23 +57,31 @@ fgetws_l(wchar_t * __restrict ws, int n,
        ORIENT(fp, 1);
 
        if (n <= 0) {
+               fp->_flags |= __SERR;
                errno = EINVAL;
                goto error;
        }
 
+       wsp = ws;
+       if (n == 1)
+               goto ok;
+
        if (fp->_r <= 0 && __srefill(fp))
-               /* EOF */
+               /* EOF or ferror */
                goto error;
-       wsp = ws;
+
+       sret = 0;
        do {
                src = fp->_p;
                nl = memchr(fp->_p, '\n', fp->_r);
                nconv = l->__mbsnrtowcs(wsp, &src,
                    nl != NULL ? (nl - fp->_p + 1) : fp->_r,
                    n - 1, &fp->_mbstate);
-               if (nconv == (size_t)-1)
+               if (nconv == (size_t)-1) {
                        /* Conversion error */
+                       fp->_flags |= __SERR;
                        goto error;
+               }
                if (src == NULL) {
                        /*
                         * We hit a null byte. Increment the character count,
@@ -88,23 +97,30 @@ fgetws_l(wchar_t * __restrict ws, int n,
                fp->_p = (unsigned char *)src;
                n -= nconv;
                wsp += nconv;
-       } while (wsp[-1] != L'\n' && n > 1 && (fp->_r > 0 ||
-           __srefill(fp) == 0));
-       if (wsp == ws)
-               /* EOF */
+       } while ((wsp == ws || wsp[-1] != L'\n') && n > 1 && (fp->_r > 0 ||
+           (sret = __srefill(fp)) == 0));
+       if (sret && !__sfeof(fp))
+               /* ferror */
                goto error;
-       if (!l->__mbsinit(&fp->_mbstate))
+       if (!l->__mbsinit(&fp->_mbstate)) {
                /* Incomplete character */
+               fp->_flags |= __SERR;
+               errno = EILSEQ;
                goto error;
+       }
+       if (wsp == ws)
+               /* EOF */
+               goto error;
+ok:
        *wsp = L'\0';
        FUNLOCKFILE(fp);
-
        return (ws);
 
 error:
        FUNLOCKFILE(fp);
        return (NULL);
 }
+
 wchar_t *
 fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp)
 {
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to