This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] fix fgetwc() from unbuffered file (RH bug 457506)
- From: Denys Vlasenko <dvlasenk at redhat dot com>
- To: libc-alpha at sources dot redhat dot com
- Date: Thu, 28 Aug 2008 10:19:48 +0200
- Subject: Re: [PATCH] fix fgetwc() from unbuffered file (RH bug 457506)
- References: <1219831987.3179.5.camel@localhost.localdomain>
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)