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]

Re: [PATCH] fix fgetwc() from unbuffered file (RH bug 457506)


On Wed, 2008-08-27 at 12:13 +0200, Denys Vlasenko wrote:
> Hi,
> 
> This is a fix for this RH bug:
> 
> https://bugzilla.redhat.com/show_bug.cgi?id=457506
> 
> Testcase:
> 
> #include <stdio.h>
> #include <locale.h>
> #include <wchar.h>
> int main(void)
> {
>     wint_t c;
>     setlocale(LC_ALL, "en_US.utf8");
>     setvbuf(stdin, NULL, _IONBF, 0);
>     while ((c = fgetwc(stdin)) != WEOF) {
>         fputwc(c, stdout);
>         fflush(stdout);
>     }
>     if (ferror(stdin))
>         perror(NULL);
> }
> 
> # cat zz.txt
> qwerty
> ÐÑÑÐÐÐ
> 
> # LD_LIBRARY_PATH=. ./a.out <zz.txt
> qwerty
> ÐÑÑÐÐÐ  <--- without patch, this is not printed!
> 

Oops.. forgot the patch itself :(
Please find attached.


for Changelog:

2008-08-27  Denys Vlasenko  <dvlasenk@redhat.com>

	* libio/wfileops.c (_IO_wfile_underflow): Use local small
	buffer if input file is unbuffered.

--
vda

diff -urpN glibc-2.8.org/libio/wfileops.c glibc-2.8/libio/wfileops.c
--- glibc-2.8.org/libio/wfileops.c	2006-01-15 18:45:20.000000000 +0100
+++ glibc-2.8/libio/wfileops.c	2008-08-28 09:55:42.000000000 +0200
@@ -125,6 +125,12 @@ _IO_wfile_underflow (fp)
   _IO_ssize_t count;
   int tries;
   const char *read_ptr_copy;
+  char smallbuf[MB_LEN_MAX + 2];
+  char *sv_IO_read_ptr;
+  char *sv_IO_read_end;
+  char *sv_IO_buf_end;
+  char *sv_IO_read_base;
+  wint_t retval;
 
   if (__builtin_expect (fp->_flags & _IO_NO_READS, 0))
     {
@@ -236,26 +242,38 @@ _IO_wfile_underflow (fp)
   fp->_wide_data->_IO_write_base = fp->_wide_data->_IO_write_ptr =
     fp->_wide_data->_IO_write_end = fp->_wide_data->_IO_buf_base;
 
+  /* Unbuffered stream has 1 byte buffer. This is not enough for
+     reading a wchar_t.  Temporarily use local storage.  */
+  sv_IO_read_ptr = NULL;
+  if ((fp->_IO_buf_end - fp->_IO_read_end) < sizeof(smallbuf))
+    {
+      sv_IO_read_ptr = fp->_IO_read_ptr;
+      sv_IO_read_end = fp->_IO_read_end;
+      sv_IO_buf_end = fp->_IO_buf_end;
+      sv_IO_read_base = fp->_IO_read_base;
+      fp->_IO_read_ptr = smallbuf;
+      fp->_IO_read_end = smallbuf;
+      fp->_IO_buf_end = &smallbuf[sizeof(smallbuf) - 1];
+    }
+
   tries = 0;
  again:
   count = _IO_SYSREAD (fp, fp->_IO_read_end,
-		       fp->_IO_buf_end - fp->_IO_read_end);
+		       sv_IO_read_ptr ? 1 : (fp->_IO_buf_end - fp->_IO_read_end));
   if (count <= 0)
     {
       if (count == 0 && tries == 0)
 	fp->_flags |= _IO_EOF_SEEN;
       else
-	fp->_flags |= _IO_ERR_SEEN, count = 0;
-    }
-  fp->_IO_read_end += count;
-  if (count == 0)
-    {
+	fp->_flags |= _IO_ERR_SEEN;
       if (tries != 0)
 	/* There are some bytes in the external buffer but they don't
            convert to anything.  */
 	__set_errno (EILSEQ);
-      return WEOF;
+      retval = WEOF;
+      goto restore_and_ret;
     }
+  fp->_IO_read_end += count;
   if (fp->_offset != _IO_pos_BAD)
     _IO_pos_adjust (fp->_offset, count);
 
@@ -276,7 +294,8 @@ _IO_wfile_underflow (fp)
 	{
 	  __set_errno (EILSEQ);
 	  fp->_flags |= _IO_ERR_SEEN;
-	  return WEOF;
+	  retval = WEOF;
+	  goto restore_and_ret;
 	}
 
       /* The read bytes make no complete character.  Try reading again.  */
@@ -285,7 +304,17 @@ _IO_wfile_underflow (fp)
       goto again;
     }
 
-  return *fp->_wide_data->_IO_read_ptr;
+  retval = *fp->_wide_data->_IO_read_ptr;
+
+restore_and_ret:
+  if (sv_IO_read_ptr)
+    {
+      fp->_IO_read_ptr = sv_IO_read_ptr;
+      fp->_IO_read_end = sv_IO_read_end;
+      fp->_IO_buf_end = sv_IO_buf_end;
+      fp->_IO_read_base = sv_IO_read_base;
+    }
+  return retval;
 }
 INTDEF(_IO_wfile_underflow)
 

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