This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH v1.1][BZ #15362] Correctly return bytes written out in _IO_new_file_write
- From: Siddhesh Poyarekar <siddhesh at redhat dot com>
- To: libc-alpha at sourceware dot org
- Cc: ebiggers3 at gmail dot com
- Date: Fri, 12 Apr 2013 14:03:32 +0530
- Subject: [PATCH v1.1][BZ #15362] Correctly return bytes written out in _IO_new_file_write
- References: <20130412080539 dot GA9444 at spoyarek dot pnq dot redhat dot com>
On Fri, Apr 12, 2013 at 01:35:39PM +0530, Siddhesh Poyarekar wrote:
> Hi,
>
> In my fix to pr#11741 I was overzealous about forwarding a failed
> write syscall and ignored an important case.
>
> I overlooked the possibility of there having been a previous
> successful partial write and hence returned a failure when it
> shouldn't. Attached patch causes _IO_new_file_write to return a short
> write if such a situation occurs and return a complete failure only if
> nothing was written to file in this function.
>
> I also made an additional change in _IO_new_file_xsputn to explicitly
> return failure if new_do_write returns a failure. I had relied on an
> ugly hack (n == to_do and adding 1 to to_do as a result of an error
> results in n - to_do == -1, hence returning error), which is wrong.
>
> Tested on x86_64 to verify that the fix works for the reproducer
> mentioned in the bug report. I have also verified that this patch
> does not cause regressions in the testsuite.
>
I missed a subtle detail - count is _IO_size_t and it should be
_IO_ssize_t to make the (count < 0) work. Also, we return EOF and not
-1. Updated patch.
Siddhesh
[BZ #15362]
* libio/fileops.c (_IO_new_file_write): Correctly return short
write.
(_IO_new_file_xsputn): Explicitly return EOF on write error.
diff --git a/libio/fileops.c b/libio/fileops.c
index 61b61b3..96a62e0 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -1263,7 +1263,17 @@ _IO_new_file_write (f, data, n)
n -= to_do;
if (f->_offset >= 0)
f->_offset += n;
- return count < 0 ? count : n;
+
+ /* The last syscall resulted in an error, but we did succeed in writing some
+ bits. Send back a short write and let them try again if needed. */
+ if (count < 0 && n > 0)
+ return n;
+
+ /* We didn't succeed in writing anything. */
+ if (count < 0)
+ return count;
+
+ return n;
}
_IO_size_t
@@ -1275,7 +1285,7 @@ _IO_new_file_xsputn (f, data, n)
register const char *s = (const char *) data;
_IO_size_t to_do = n;
int must_flush = 0;
- _IO_size_t count = 0;
+ _IO_ssize_t count = 0;
if (n <= 0)
return 0;
@@ -1336,6 +1346,10 @@ _IO_new_file_xsputn (f, data, n)
if (do_write)
{
count = new_do_write (f, s, do_write);
+
+ if (count < 0)
+ return EOF;
+
to_do -= count;
if (count < do_write)
return n - to_do;