This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH][BZ #11741] printf should return negative value on I/O error


Hi,

Printing padded strings into a file pointer currently succeeds
incorrectly when it should be returning a -1.  I found a number of
problems that together contributed to this bug.  Attached patch fixes
it.  Tested on Fedora 16 x86_64 and also added this case to the current
test case.  No regressions reported resulting from this patch.

I have also added a copyright notice to the test case I modified.  I
got the start date from the ChangeLog.  OK to commit?

Regards,
Siddhesh

ChangeLog:

	[BZ #11741]
	* libio/fileops.c (_IO_new_file_write): Correctly return error.
	* libio/iopadn.c (_IO_padn): Likewise.
	* libio/iowpadn.c (_IO_wpadn): Likewise.
	* stdio-common/tst-put-error.c: Add copyright notice.
	(do_test): Add case for printing padded string.
	* stdio-common/vfprintf [!COMPILE_WPRINTF] (PAD): Flag error if
	_IO_padn returned error.
	[COMPILE_WPRINTF] (PAD): Flag error if _IO_wpadn returned error.

diff --git a/libio/fileops.c b/libio/fileops.c
index 6aabadc..f15e206 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -1253,12 +1253,13 @@ _IO_new_file_write (f, data, n)
      _IO_ssize_t n;
 {
   _IO_ssize_t to_do = n;
+  _IO_ssize_t count = 0;
   while (to_do > 0)
     {
-      _IO_ssize_t count = (__builtin_expect (f->_flags2
-					     & _IO_FLAGS2_NOTCANCEL, 0)
-			   ? write_not_cancel (f->_fileno, data, to_do)
-			   : write (f->_fileno, data, to_do));
+      count = (__builtin_expect (f->_flags2
+				 & _IO_FLAGS2_NOTCANCEL, 0)
+	       ? write_not_cancel (f->_fileno, data, to_do)
+	       : write (f->_fileno, data, to_do));
       if (count < 0)
 	{
 	  f->_flags |= _IO_ERR_SEEN;
@@ -1270,7 +1271,7 @@ _IO_new_file_write (f, data, n)
   n -= to_do;
   if (f->_offset >= 0)
     f->_offset += n;
-  return n;
+  return count < 0 ? count : n;
 }
 
 _IO_size_t
diff --git a/libio/iopadn.c b/libio/iopadn.c
index 7e37450..62fd62c 100644
--- a/libio/iopadn.c
+++ b/libio/iopadn.c
@@ -59,7 +59,7 @@ _IO_padn (fp, pad, count)
       w = _IO_sputn (fp, padptr, PADSIZE);
       written += w;
       if (w != PADSIZE)
-	return written;
+	return w <= 0 ? w :written;
     }
 
   if (i > 0)
diff --git a/libio/iowpadn.c b/libio/iowpadn.c
index 05632d5..334e01a 100644
--- a/libio/iowpadn.c
+++ b/libio/iowpadn.c
@@ -65,7 +65,7 @@ _IO_wpadn (fp, pad, count)
       w = _IO_sputn (fp, (char *) padptr, PADSIZE);
       written += w;
       if (w != PADSIZE)
-	return written;
+	return w <= 0 ? w : written;
     }
 
   if (i > 0)
diff --git a/stdio-common/tst-put-error.c b/stdio-common/tst-put-error.c
index 115dbd5..7b95491 100644
--- a/stdio-common/tst-put-error.c
+++ b/stdio-common/tst-put-error.c
@@ -1,3 +1,22 @@
+/* Verify that print functions return error when there is an I/O error.
+
+   Copyright (C) 2005-2012 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
 #include <errno.h>
 #include <error.h>
 #include <stdio.h>
@@ -26,6 +45,13 @@ do_test (void)
   printf ("fprintf = %d\n", n);
   if (n >= 0)
     error (EXIT_FAILURE, 0, "second fprintf succeeded");
+
+  /* Padded printing takes a different code path.  */
+  n = fprintf (fp, "%10000s", "foo");
+  printf ("fprintf = %d\n", n);
+  if (n >= 0)
+    error (EXIT_FAILURE, 0, "padded fprintf succeeded");
+
   return 0;
 }
 
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 17d3f42..4440166 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -87,8 +87,18 @@
 
 # define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
 # define PAD(Padchar) \
-  if (width > 0)							      \
-    done_add (_IO_padn (s, (Padchar), width))
+  do {									      \
+    if (width > 0)							      \
+      {									      \
+	unsigned int d = _IO_padn (s, (Padchar), width);		      \
+	if (__builtin_expect (d <= 0, 0))				      \
+	  {								      \
+	    done = -1;							      \
+	    goto all_done;						      \
+	  }								      \
+	done_add (d);							      \
+      }									      \
+  } while (0)
 # define PUTC(C, F)	_IO_putc_unlocked (C, F)
 # define ORIENT		if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
 			  return -1
@@ -106,8 +116,18 @@
 
 # define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
 # define PAD(Padchar) \
-  if (width > 0)							      \
-    done_add (_IO_wpadn (s, (Padchar), width))
+  do {									      \
+    if (width > 0)							      \
+      {									      \
+	unsigned int d = _IO_wpadn (s, (Padchar), width);		      \
+	if (__builtin_expect (d <= 0, 0))				      \
+	  {								      \
+	    done = -1;							      \
+	    goto all_done;						      \
+	  }								      \
+	done_add (d);							      \
+      }									      \
+  } while (0)
 # define PUTC(C, F)	_IO_putwc_unlocked (C, F)
 # define ORIENT		if (_IO_fwide (s, 1) != 1) return -1
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]