summaryrefslogtreecommitdiff
path: root/libc/libio
diff options
context:
space:
mode:
authorjoseph <joseph@7b3dc134-2b1b-0410-93df-9e9f96275f8d>2014-02-07 21:04:10 +0000
committerjoseph <joseph@7b3dc134-2b1b-0410-93df-9e9f96275f8d>2014-02-07 21:04:10 +0000
commit85f4cc52a11508e42daa5625283410e0d6f3a993 (patch)
treedeca25a1076f1a24479cbca3bd7d162123fae742 /libc/libio
parenta1055d384d75c28f09a47c2d8628bc330f892955 (diff)
downloadeglibc2-master.tar.gz
Merge changes between r25087 and r25236 from /fsf/trunk.HEADmaster
git-svn-id: svn://svn.eglibc.org/trunk@25237 7b3dc134-2b1b-0410-93df-9e9f96275f8d
Diffstat (limited to 'libc/libio')
-rw-r--r--libc/libio/Makefile2
-rw-r--r--libc/libio/tst-ftell-partial-wide.c107
-rw-r--r--libc/libio/wfileops.c11
3 files changed, 115 insertions, 5 deletions
diff --git a/libc/libio/Makefile b/libc/libio/Makefile
index b2aa50f0d..7c8036207 100644
--- a/libc/libio/Makefile
+++ b/libc/libio/Makefile
@@ -78,7 +78,7 @@ tests-$(OPTION_POSIX_WIDE_CHAR_DEVICE_IO) \
bug-wfflush bug-wmemstream1 tst-fopenloc2 \
tst_getwc \
tst_putwc tst_wprintf tst_wprintf2 tst_wscanf \
- tst-fgetwc bug-wsetpos tst-fseek
+ tst-fgetwc bug-wsetpos tst-fseek tst-ftell-partial-wide
tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
+= tst_swprintf tst_swscanf \
tst-sscanf \
diff --git a/libc/libio/tst-ftell-partial-wide.c b/libc/libio/tst-ftell-partial-wide.c
new file mode 100644
index 000000000..3734e774a
--- /dev/null
+++ b/libc/libio/tst-ftell-partial-wide.c
@@ -0,0 +1,107 @@
+/* Verify that ftell does not go into an infinite loop when a conversion fails
+ due to insufficient space in the buffer.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <wchar.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <errno.h>
+#include <unistd.h>
+
+static int do_test (void);
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+/* Arbitrary number large enough so that the target buffer during conversion is
+ not large enough. */
+#define STRING_SIZE (1400)
+#define NSTRINGS (2)
+
+static int
+do_test (void)
+{
+ FILE *fp = NULL;
+ wchar_t *inputs[NSTRINGS] = {NULL};
+ int ret = 1;
+
+ if (setlocale (LC_ALL, "en_US.UTF-8") == NULL)
+ {
+ printf ("Cannot set en_US.UTF-8 locale.\n");
+ goto out;
+ }
+
+
+ /* Generate input from one character, chosen because it has an odd number of
+ bytes in UTF-8, making it easier to reproduce the problem:
+
+ NAME Hiragana letter GO
+ CHAR ご
+ UTF-8 E38194
+ UCS 3054
+ MARC-8 692434 */
+ wchar_t seed = L'ご';
+ for (int i = 0; i < NSTRINGS; i++)
+ {
+ inputs[i] = malloc (STRING_SIZE * sizeof (wchar_t));
+ if (inputs[i] == NULL)
+ {
+ printf ("Failed to allocate memory for inputs: %m\n");
+ goto out;
+ }
+ wmemset (inputs[i], seed, STRING_SIZE - 1);
+ inputs[i][STRING_SIZE - 1] = L'\0';
+ }
+
+ char *filename;
+ int fd = create_temp_file ("tst-fseek-wide-partial.out", &filename);
+
+ if (fd == -1)
+ {
+ printf ("create_temp_file: %m\n");
+ goto out;
+ }
+
+ fp = fdopen (fd, "w+");
+ if (fp == NULL)
+ {
+ printf ("fopen: %m\n");
+ close (fd);
+ goto out;
+ }
+
+ for (int i = 0; i < NSTRINGS; i++)
+ {
+ printf ("offset: %ld\n", ftell (fp));
+ if (fputws (inputs[i], fp) == -1)
+ {
+ perror ("fputws");
+ goto out;
+ }
+ }
+ ret = 0;
+
+out:
+ if (fp != NULL)
+ fclose (fp);
+ for (int i = 0; i < NSTRINGS; i++)
+ free (inputs[i]);
+
+ return ret;
+}
diff --git a/libc/libio/wfileops.c b/libc/libio/wfileops.c
index 87d3cdcf3..877fc1f82 100644
--- a/libc/libio/wfileops.c
+++ b/libc/libio/wfileops.c
@@ -715,7 +715,7 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
- fp->_wide_data->_IO_write_base) / clen;
else
{
- enum __codecvt_result status;
+ enum __codecvt_result status = __codecvt_ok;
delta = (fp->_wide_data->_IO_write_ptr
- fp->_wide_data->_IO_write_base);
const wchar_t *write_base = fp->_wide_data->_IO_write_base;
@@ -728,9 +728,12 @@ _IO_wfile_seekoff (fp, offset, dir, mode)
flush buffers for every ftell. */
do
{
- /* Ugh, no point trying to avoid the flush. Just do it
- and go back to how it was with the read mode. */
- if (delta > 0 && new_write_ptr == fp->_IO_buf_end)
+ /* There is not enough space in the buffer to do the entire
+ conversion, so there is no point trying to avoid the
+ buffer flush. Just do it and go back to how it was with
+ the read mode. */
+ if (status == __codecvt_partial
+ || (delta > 0 && new_write_ptr == fp->_IO_buf_end))
{
if (_IO_switch_to_wget_mode (fp))
return WEOF;