- Update fseek fix (#854337)

This commit is contained in:
Jeff Law 2012-09-05 22:35:57 -06:00
parent 9564fbf78d
commit e063906d55
2 changed files with 71 additions and 141 deletions

View File

@ -1,78 +1,7 @@
From libc-alpha-return-32469-listarch-libc-alpha=sources dot redhat dot com at sourceware dot org Tue Sep 04 16:35:13 2012
Return-Path: <libc-alpha-return-32469-listarch-libc-alpha=sources dot redhat dot com at sourceware dot org>
Delivered-To: listarch-libc-alpha at sources dot redhat dot com
Received: (qmail 31908 invoked by alias); 4 Sep 2012 16:35:07 -0000
Received: (qmail 31178 invoked by uid 22791); 4 Sep 2012 16:35:03 -0000
X-SWARE-Spam-Status: No, hits=-6.8 required=5.0
tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,RCVD_IN_DNSWL_HI,RCVD_IN_HOSTKARMA_W,RP_MATCHES_RCVD,SPF_HELO_PASS,TW_SW,TW_TV,TW_TW,TW_VB
X-Spam-Check-By: sourceware.org
Date: Tue, 4 Sep 2012 22:03:55 +0530
From: Siddhesh Poyarekar <siddhesh at redhat dot com>
To: libc-alpha at sourceware dot org
Subject: [PATCH][BZ #14543] Fix fseek behaviour when called in wide mode
Message-ID: <20120904220355.5ef5d279@spoyarek>
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="MP_/nT+8opq/57jsIpH2GwJ_t+V"
Mailing-List: contact libc-alpha-help at sourceware dot org; run by ezmlm
Precedence: bulk
List-Id: <libc-alpha.sourceware.org>
List-Subscribe: <mailto:libc-alpha-subscribe at sourceware dot org>
List-Archive: <http://sourceware.org/ml/libc-alpha/>
List-Post: <mailto:libc-alpha at sourceware dot org>
List-Help: <mailto:libc-alpha-help at sourceware dot org>, <http://sourceware dot org/ml/#faqs>
Sender: libc-alpha-owner at sourceware dot org
Delivered-To: mailing list libc-alpha at sourceware dot org
--MP_/nT+8opq/57jsIpH2GwJ_t+V
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Hi,
This is a patch to fix the problem Jeff Law had posted about in July:
http://sourceware.org/ml/libc-alpha/2012-07/msg00179.html
When fseek is called in wide mode, i.e. when the locale uses a
multibyte character set, it does not set the internal buffer state
correctly due to which, an ftell following it returns an invalid file
offset. This can be reproduced reliably with the reproducer program in
the bugzilla.
The attached patch sets the internal buffer state correctly whenever
the external buffer state is modified by fseek. This involves either
computing the current _IO_read_ptr/end for the internal buffer based on
the new _IO_read_ptr in the external buffer or converting the content
read into the external buffer, up to the extent of the requested fseek
offset.
The patch also includes a test case that verifies the fix. I have
verified that the patch does not cause a regression in the testsuite on
my F16 x86_64.
Regards,
Siddhesh
ChangeLog:
* libio/Makefile (tests): New test case tst-fseek.
* libio/tst-fseek.c: New test case to verify that fseek/ftell
combination works in wide mode.
* libio/wfileops.c (_IO_wfile_seekoff): Adjust internal buffer
state when the external buffer state changes.
--MP_/nT+8opq/57jsIpH2GwJ_t+V
Content-Type: text/x-patch
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=wide-fseek.patch
diff --git a/libio/Makefile b/libio/Makefile
index c555dd0..e760ddc 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -57,7 +57,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
diff -Nrup a/libio/Makefile b/libio/Makefile
--- a/libio/Makefile 2012-06-30 13:12:34.000000000 -0600
+++ b/libio/Makefile 2012-09-05 22:26:34.675086743 -0600
@@ -57,7 +57,7 @@ tests = tst_swprintf tst_wprintf tst_sws
tst-memstream1 tst-memstream2 \
tst-wmemstream1 tst-wmemstream2 \
bug-memstream1 bug-wmemstream1 \
@ -81,12 +10,10 @@ index c555dd0..e760ddc 100644
test-srcs = test-freopen
all: # Make this the default target; it will be defined in Rules.
diff --git a/libio/tst-fseek.c b/libio/tst-fseek.c
new file mode 100644
index 0000000..e7984b0
--- /dev/null
+++ b/libio/tst-fseek.c
@@ -0,0 +1,152 @@
diff -Nrup a/libio/tst-fseek.c b/libio/tst-fseek.c
--- a/libio/tst-fseek.c 1969-12-31 17:00:00.000000000 -0700
+++ b/libio/tst-fseek.c 2012-09-05 22:26:11.237181749 -0600
@@ -0,0 +1,153 @@
+/* Verify that fseek/ftell combination works for wide chars.
+
+ Copyright (C) 2012 Free Software Foundation, Inc.
@ -112,6 +39,7 @@ index 0000000..e7984b0
+#include <errno.h>
+#include <wchar.h>
+#include <unistd.h>
+#include <string.h>
+
+/* Defined in test-skeleton.c. */
+static int create_temp_file (const char *base, char **filename);
@ -239,85 +167,84 @@ index 0000000..e7984b0
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/libio/wfileops.c b/libio/wfileops.c
index 3f628bf..96debc6 100644
--- a/libio/wfileops.c
+++ b/libio/wfileops.c
@@ -684,13 +684,25 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
- (fp->_IO_read_end - fp->_IO_buf_base));
if (offset >= start_offset && offset < fp->_offset)
{
+ struct _IO_codecvt *cv = fp->_codecvt;
+ _IO_off64_t off;
diff -Nrup a/libio/wfileops.c b/libio/wfileops.c
--- a/libio/wfileops.c 2012-06-30 13:12:34.000000000 -0600
+++ b/libio/wfileops.c 2012-09-05 22:26:11.540180521 -0600
@@ -545,6 +545,55 @@ _IO_wfile_sync (fp)
}
libc_hidden_def (_IO_wfile_sync)
+/* Adjust the internal buffer pointers to reflect the state in the external
+ buffer. The content between fp->_IO_read_base and fp->_IO_read_ptr is
+ assumed to be converted and available in the range
+ fp->_wide_data->_IO_read_base and fp->_wide_data->_IO_read_end. */
+static inline int
+adjust_wide_data (_IO_FILE *fp, bool do_convert)
+{
+ struct _IO_codecvt *cv = fp->_codecvt;
+
_IO_setg (fp, fp->_IO_buf_base,
fp->_IO_buf_base + (offset - start_offset),
fp->_IO_read_end);
_IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
+ int clen = (*cv->__codecvt_do_encoding) (cv);
+
+ /* Get corresponding offset for the _wide_data. */
+ fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
+ off = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
+ fp->_IO_read_base, fp->_IO_read_ptr,
+ (fp->_wide_data->_IO_buf_end
+ - fp->_wide_data->_IO_buf_base));
+ /* Take the easy way out for constant length encodings if we don't need to
+ convert. */
+ if (!do_convert && clen > 0)
+ {
+ fp->_wide_data->_IO_read_end += ((fp->_IO_read_ptr - fp->_IO_read_base)
+ / clen);
+ goto done;
+ }
+
_IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
- fp->_wide_data->_IO_buf_base,
- fp->_wide_data->_IO_buf_base);
+ fp->_wide_data->_IO_buf_base + off,
+ fp->_wide_data->_IO_buf_base + off);
+
_IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
fp->_wide_data->_IO_buf_base);
_IO_mask_flags (fp, 0, _IO_EOF_SEEN);
@@ -727,11 +739,43 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
goto dumb;
}
}
- _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base + delta,
- fp->_IO_buf_base + count);
- _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
+
+ /* Convert up to the location we're seeking to. */
+ enum __codecvt_result status;
+ _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base,
+ fp->_IO_buf_base + delta);
_IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
+
+ const char *read_stop = (const char *) fp->_IO_read_base;
+ do
+ {
+ struct _IO_codecvt *cv = fp->_codecvt;
+ const char *read_stop = (const char *) fp->_IO_read_ptr;
+
+ fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
+ status = (*cv->__codecvt_do_in) (cv, &fp->_wide_data->_IO_state,
+ fp->_IO_read_ptr, fp->_IO_read_end,
+ fp->_IO_read_base, fp->_IO_read_ptr,
+ &read_stop,
+ fp->_wide_data->_IO_read_ptr,
+ fp->_wide_data->_IO_read_base,
+ fp->_wide_data->_IO_buf_end,
+ &fp->_wide_data->_IO_read_end);
+
+ /* Should we return EILSEQ instead? */
+ /* Should we return EILSEQ? */
+ if (__builtin_expect (status == __codecvt_error, 0))
+ goto dumb;
+
+ fp->_IO_read_ptr = (char *) read_stop;
+ {
+ fp->_flags |= _IO_ERR_SEEN;
+ return -1;
+ }
+ }
+ while (__builtin_expect (status == __codecvt_partial, 0));
+
+ /* Now seek to the location in the _wide data buffer. */
+done:
+ /* Now seek to the end of the read buffer. */
+ fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
+
+ /* Finally, set _IO_read_end to reflect how much we have actually read in
+ from the file. */
+ fp->_IO_read_end = fp->_IO_buf_base + count;
+ return 0;
+}
+
+ _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
_IO_off64_t
_IO_wfile_seekoff (fp, offset, dir, mode)
_IO_FILE *fp;
@@ -693,6 +742,10 @@ _IO_wfile_seekoff (fp, offset, dir, mode
fp->_wide_data->_IO_buf_base);
_IO_wsetp (fp, fp->_wide_data->_IO_buf_base,
fp->_wide_data->_IO_buf_base);
+
+ if (adjust_wide_data (fp, false))
+ goto dumb;
+
_IO_mask_flags (fp, 0, _IO_EOF_SEEN);
goto resync;
}
@@ -733,6 +786,10 @@ _IO_wfile_seekoff (fp, offset, dir, mode
_IO_wsetg (fp, fp->_wide_data->_IO_buf_base,
fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
_IO_wsetp (fp, fp->_wide_data->_IO_buf_base, fp->_wide_data->_IO_buf_base);
+
+ if (adjust_wide_data (fp, true))
+ goto dumb;
+
fp->_offset = result + count;
_IO_mask_flags (fp, 0, _IO_EOF_SEEN);
--MP_/nT+8opq/57jsIpH2GwJ_t+V--
return offset;

View File

@ -28,7 +28,7 @@
Summary: The GNU libc libraries
Name: glibc
Version: %{glibcversion}
Release: 12%{?dist}
Release: 13%{?dist}
# GPLv2+ is used in a bunch of programs, LGPLv2+ is used for libraries.
# Things that are linked directly into dynamically linked programs
# and shared libraries (e.g. crt files, lib*_nonshared.a) have an additional
@ -1317,6 +1317,9 @@ rm -f *.filelist*
%endif
%changelog
* Tue Sep 4 2012 Jeff Law <law@redhat.com> - 2.16-13
- Update fseek fix (#854337)
* Tue Sep 4 2012 Jeff Law <law@redhat.com> - 2.16-12
- Incorporate ppc64p7 arch changes (#854250)
- Fix fseek in wide mode (#854337)