Module Name:    src
Committed By:   christos
Date:           Sat Aug 27 13:15:48 UTC 2016

Modified Files:
        src/lib/libc/stdio: fgetwln.c

Log Message:
Improvements to fgetwln(3) from Andrey Chernov:

1) Set the stdio error indicator on __slbexpand() failure.

2) fgetwc(3) may succeed even when ferror(3) is already set
   (for example, consider a program using SIG_IGN on SIGTTIN,
   reading from the tty while in the background, getting EIO,
   then coming to the foreground and reading again).
   So do not force fgetwln(3) to fail in such a case either.
   (Yes, the program should probably clearerr(3) before
   reading again, but let's be nicer in case it forgets.)


To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/lib/libc/stdio/fgetwln.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/stdio/fgetwln.c
diff -u src/lib/libc/stdio/fgetwln.c:1.7 src/lib/libc/stdio/fgetwln.c:1.8
--- src/lib/libc/stdio/fgetwln.c:1.7	Mon Aug 22 03:41:10 2016
+++ src/lib/libc/stdio/fgetwln.c	Sat Aug 27 09:15:48 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: fgetwln.c,v 1.7 2016/08/22 07:41:10 christos Exp $	*/
+/*	$NetBSD: fgetwln.c,v 1.8 2016/08/27 13:15:48 christos Exp $	*/
 
 /*-
  * Copyright (c) 2002-2004 Tim J. Robbins.
@@ -31,7 +31,7 @@
 #if 0
 __FBSDID("$FreeBSD: src/lib/libc/stdio/fgetwln.c,v 1.2 2004/08/06 17:00:09 tjr Exp $");
 #else
-__RCSID("$NetBSD: fgetwln.c,v 1.7 2016/08/22 07:41:10 christos Exp $");
+__RCSID("$NetBSD: fgetwln.c,v 1.8 2016/08/27 13:15:48 christos Exp $");
 #endif
 #endif /* LIBC_SCCS and not lint */
 
@@ -88,13 +88,25 @@ fgetwln(FILE * __restrict fp, size_t *le
 	while ((wc = __fgetwc_unlock(fp)) != WEOF) {
 #define	GROW	512
 		if (len * sizeof(wchar_t) >= _EXT(fp)->_fgetstr_len &&
-		    __slbexpand(fp, (len + GROW) * sizeof(wchar_t)))
+		    __slbexpand(fp, (len + GROW) * sizeof(wchar_t))) {
+			fp->_flags |= __SERR;
 			goto error;
+		}
 		*((wchar_t *)(void *)_EXT(fp)->_fgetstr_buf + len++) = wc;
 		if (wc == L'\n')
 			break;
 	}
-	if (len == 0 || fp->_flags & __SERR)
+
+	/*
+	 * The following test assumes that fgetwc() fails when
+	 * feof() is already set, and that fgetwc() will never
+	 * set feof() in the same call where it also sets ferror()
+	 * or returns non-WEOF.
+	 * Testing ferror() would not be better because fgetwc()
+	 * may succeed even when ferror() is already set.
+	 */
+
+	if (len == 0 || (wc == WEOF && !__sfeof(fp)))
 		goto error;
 
 	FUNLOCKFILE(fp);

Reply via email to