[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#429021: libc6: fputs can lose data in buffer on signal



On Fri, Jun 15, 2007 at 06:47:55PM +0200, Pierre Habouzit wrote:
>   Nothing in POSIX says what happens wrt to fwrite and signals. At least
> it's very unclear. But indeed the fact that SA_RESTART is the default
> value for linux does not seem to be a POSIX requirement either.

I have studied the source today, and it turned out that the problem
is not signal specific, but how glibc treats any error on writing.
Unfortunately, it loses all data stored in the buffer. Probably,
it does not matter for fatal errors, because you will not able to
write more anyway, but for recoverable errors like EINTR or ENOSPC,
it is not a smart thing to do. Here is a small patch that corrects
this problem:

 
--- glibc-2.3.6/libio/fileops.c.orig	2004-12-07 01:36:56.000000000 +0300
+++ glibc-2.3.6/libio/fileops.c	2007-06-18 12:29:50.739890036 +0400
@@ -516,10 +516,19 @@ new_do_write (fp, data, to_do)
     fp->_cur_column = INTUSE(_IO_adjust_column) (fp->_cur_column - 1, data,
 						 count) + 1;
   _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
-  fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
-  fp->_IO_write_end = (fp->_mode <= 0
+  if (__builtin_expect (count == to_do, 1))
+    {
+      fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
+      fp->_IO_write_end = (fp->_mode <= 0
 		       && (fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
 		       ? fp->_IO_buf_base : fp->_IO_buf_end);
+    }
+  else if (count > 0 && fp->_IO_write_base == data)
+    {
+      memmove (data, data+count, 
+               fp->_IO_write_ptr - fp->_IO_write_base - count);
+      fp->_IO_write_ptr -= count;
+    }
   return count;
 }
 
 
The patch does not change the behavior of new_do_write in the case
of success, but when an error happens, I do not emptify the output
buffer. In fact, in the case when data were partly written (count>0)
and data were from the output buffer (fp->_IO_write_base == data),
I remove written data from the buffer and adjust the write pointer
accordingly.

Warning: I have not tested this patch, but it seems trivial, so
I hope it works.

Also, I should note that though this patch prevents losing buffer
on error, it does not prevent the possibility that fputs can return
an error, while a part of the given string was written, but it is
restriction of the interface. So using fputs with non-restartable
signals is not a good idea anyway, still fwrite can be used in
this way for writing bytes if this bug with losing data in buffer
is fixed.

Thanks,
Dmitry



Reply to: