This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH][BZ #11741] printf should return negative value on I/Oerror
- From: Siddhesh Poyarekar <siddhesh at redhat dot com>
- To: Andreas Schwab <schwab at linux-m68k dot org>
- Cc: libc-alpha at sourceware dot org
- Date: Fri, 19 Oct 2012 18:00:34 +0530
- Subject: Re: [PATCH][BZ #11741] printf should return negative value on I/Oerror
- References: <20121019152056.50cd355f@spoyarek><m2ipa6d6nv.fsf@igel.home>
On Fri, 19 Oct 2012 13:48:20 +0200, Andreas wrote:
> What's the significance of w == 0? sputn should return either the
> amount of written bytes or EOF.
sputn can return 0 if none of the input bytes were written into buffer
and the overflow failed. I wasn't sure if this behaviour was
expected, but I assume now that it isn't. Here's an updated patch with
sputn also fixed.
Thanks,
Siddhesh
ChangeLog:
[BZ #11741]
* libio/fileops.c (_IO_new_file_write): Correctly return error.
(_IO_new_file_xsputn): Also return EOF if none of the input
data was written when overflow failed.
* 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..fb6ac17 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
@@ -1330,9 +1331,10 @@ _IO_new_file_xsputn (f, data, n)
_IO_size_t block_size, do_write;
/* Next flush the (full) buffer. */
if (_IO_OVERFLOW (f, EOF) == EOF)
- /* If nothing else has to be written we must not signal the
- caller that everything has been written. */
- return to_do == 0 ? EOF : n - to_do;
+ /* If nothing else has to be written or nothing has been written, we
+ must not signal the caller that the call was even partially
+ successful. */
+ return (to_do == 0 || to_do == n) ? EOF : n - to_do;
/* Try to maintain alignment: write a whole number of blocks.
dont_write is what gets left over. */
diff --git a/libio/iopadn.c b/libio/iopadn.c
index 7e37450..b7a4c5a 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 == EOF ? w : written;
}
if (i > 0)
diff --git a/libio/iowpadn.c b/libio/iowpadn.c
index 05632d5..46fc085 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 == EOF ? 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..0c1339f 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 == EOF, 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 == EOF, 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