Siddhesh Poyarekar 8ecbeeb
commit 403ce35141da511898cde550f48ebc68a2a3ac82
Siddhesh Poyarekar 8ecbeeb
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Siddhesh Poyarekar 8ecbeeb
Date:   Mon Jan 6 14:37:21 2014 +0530
Siddhesh Poyarekar 8ecbeeb
Siddhesh Poyarekar 8ecbeeb
    Fix infinite loop in ftell when writing wide char data (BZ #16398)
Siddhesh Poyarekar 8ecbeeb
    
Siddhesh Poyarekar 8ecbeeb
    ftell tries to avoid flushing the buffer when it is in write mode by
Siddhesh Poyarekar 8ecbeeb
    converting the wide char data and placing it into the binary buffer.
Siddhesh Poyarekar 8ecbeeb
    If the output buffer space is full and there is data to write, the
Siddhesh Poyarekar 8ecbeeb
    code reverts to flushing the buffer.  This breaks when there is space
Siddhesh Poyarekar 8ecbeeb
    in the buffer but it is not enough to convert the next character in
Siddhesh Poyarekar 8ecbeeb
    the wide data buffer, due to which __codecvt_do_out returns a
Siddhesh Poyarekar 8ecbeeb
    __codecvt_partial status.  In this case, ftell keeps running in an
Siddhesh Poyarekar 8ecbeeb
    infinite loop.
Siddhesh Poyarekar 8ecbeeb
    
Siddhesh Poyarekar 8ecbeeb
    The fix here is to detect the __codecvt_partial status in addition to
Siddhesh Poyarekar 0a210cc
    checking if the buffer is full.
Siddhesh Poyarekar 8ecbeeb
Siddhesh Poyarekar 8ecbeeb
diff --git a/libio/wfileops.c b/libio/wfileops.c
Siddhesh Poyarekar 8ecbeeb
index 87d3cdc..877fc1f 100644
Siddhesh Poyarekar 8ecbeeb
--- a/libio/wfileops.c
Siddhesh Poyarekar 8ecbeeb
+++ b/libio/wfileops.c
Siddhesh Poyarekar 8ecbeeb
@@ -715,7 +715,7 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
Siddhesh Poyarekar 8ecbeeb
 		       - fp->_wide_data->_IO_write_base) / clen;
Siddhesh Poyarekar 8ecbeeb
 	  else
Siddhesh Poyarekar 8ecbeeb
 	    {
Siddhesh Poyarekar 8ecbeeb
-	      enum __codecvt_result status;
Siddhesh Poyarekar 8ecbeeb
+	      enum __codecvt_result status = __codecvt_ok;
Siddhesh Poyarekar 8ecbeeb
 	      delta = (fp->_wide_data->_IO_write_ptr
Siddhesh Poyarekar 8ecbeeb
 		       - fp->_wide_data->_IO_write_base);
Siddhesh Poyarekar 8ecbeeb
 	      const wchar_t *write_base = fp->_wide_data->_IO_write_base;
Siddhesh Poyarekar 8ecbeeb
@@ -728,9 +728,12 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
Siddhesh Poyarekar 8ecbeeb
 		 flush buffers for every ftell.  */
Siddhesh Poyarekar 8ecbeeb
 	      do
Siddhesh Poyarekar 8ecbeeb
 		{
Siddhesh Poyarekar 8ecbeeb
-		  /* Ugh, no point trying to avoid the flush.  Just do it
Siddhesh Poyarekar 8ecbeeb
-		     and go back to how it was with the read mode.  */
Siddhesh Poyarekar 8ecbeeb
-		  if (delta > 0 && new_write_ptr == fp->_IO_buf_end)
Siddhesh Poyarekar 8ecbeeb
+		  /* There is not enough space in the buffer to do the entire
Siddhesh Poyarekar 8ecbeeb
+		     conversion, so there is no point trying to avoid the
Siddhesh Poyarekar 8ecbeeb
+		     buffer flush.  Just do it and go back to how it was with
Siddhesh Poyarekar 8ecbeeb
+		     the read mode.  */
Siddhesh Poyarekar 8ecbeeb
+		  if (status == __codecvt_partial
Siddhesh Poyarekar 8ecbeeb
+		      || (delta > 0 && new_write_ptr == fp->_IO_buf_end))
Siddhesh Poyarekar 8ecbeeb
 		    {
Siddhesh Poyarekar 8ecbeeb
 		      if (_IO_switch_to_wget_mode (fp))
Siddhesh Poyarekar 8ecbeeb
 			return WEOF;