summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorache <ache@FreeBSD.org>2016-09-08 06:53:18 +0000
committerache <ache@FreeBSD.org>2016-09-08 06:53:18 +0000
commit03b1daba27fb8c06bc29e353b28b6c313d8f4aa6 (patch)
treee408ec16facaf005fb06906751e2e1781f5b527f
parentc029b6df14458c9aeb61ab62bcb24d5fb1102ebf (diff)
downloadFreeBSD-src-03b1daba27fb8c06bc29e353b28b6c313d8f4aa6.zip
FreeBSD-src-03b1daba27fb8c06bc29e353b28b6c313d8f4aa6.tar.gz
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.
-rw-r--r--lib/libc/stdio/fgetws.c34
1 files changed, 25 insertions, 9 deletions
diff --git a/lib/libc/stdio/fgetws.c b/lib/libc/stdio/fgetws.c
index f7a63fe..8513a37 100644
--- a/lib/libc/stdio/fgetws.c
+++ b/lib/libc/stdio/fgetws.c
@@ -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, FILE * __restrict fp, locale_t locale)
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, FILE * __restrict fp, locale_t locale)
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)
{
OpenPOWER on IntegriCloud