summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorache <ache@FreeBSD.org>2016-09-08 05:13:50 +0000
committerache <ache@FreeBSD.org>2016-09-08 05:13:50 +0000
commit56ade7a489e1dc176faf0206cbed2f8659a92648 (patch)
tree73f2bc0f039911954a4e05204dfd04c1b27395a4 /lib
parent595191c4ea58a782473f4396aa34b53867c70aac (diff)
downloadFreeBSD-src-56ade7a489e1dc176faf0206cbed2f8659a92648.zip
FreeBSD-src-56ade7a489e1dc176faf0206cbed2f8659a92648.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.
Diffstat (limited to 'lib')
-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