@@ -61,7 +61,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
bug-memstream1 bug-wmemstream1 \
tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
- tst-ftell-append tst-fputws
+ tst-ftell-append tst-fputws tst-big-read-after-write
ifeq (yes,$(build-shared))
# Add test-fopenloc only if shared library is enabled since it depends on
# shared localedata objects.
@@ -1375,6 +1375,13 @@ _IO_file_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n)
_IO_doallocbuf (fp);
}
+ /* If we were in put mode, switch to get mode. __underflow does that for us,
+ but only if the request sizes fit into the buffer. For larger requests,
+ unbuffered requests go unnoticed. */
+ if (_IO_in_put_mode (fp))
+ if (_IO_switch_to_get_mode (fp) == EOF)
+ return EOF;
+
while (want > 0)
{
have = fp->_IO_read_end - fp->_IO_read_ptr;
new file mode 100644
@@ -0,0 +1,91 @@
+/* Verify that reads on large block sizes immediately after writes don't fail
+ to flush buffer and switch correctly to read mode.
+ Copyright (C) 2015 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <locale.h>
+
+/* It is very unlikely that the block size (and hence buffer size) would be
+ equal to or greater than 64MB. */
+#define BUF_LEN (64 * 1024 * 1024)
+char foo[BUF_LEN];
+static const char *data = "abcdefghijklmnopqrstuvwxyz";
+
+static int do_test (void);
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+static int
+do_one_test (const char *filename, const char *mode)
+{
+ FILE *f;
+ size_t n;
+
+ f = fopen (filename, mode);
+ if (f == NULL)
+ {
+ printf ("Failed to open %s in %s mode\n", filename, mode);
+ return 1;
+ }
+
+ fwrite(data, 1, strlen (data), f);
+
+ n = fread(foo, 1, BUF_LEN, f);
+ if (n != 0)
+ {
+ printf ("fread before seek: expected %d but got %zu\n", 0, n);
+ return 1;
+ }
+
+ fseek(f, 0, SEEK_SET);
+ n = fread(foo, 1, BUF_LEN, f);
+ if (n != strlen (data))
+ {
+ printf ("fread after seek: expected %zu but got %zu\n", strlen (data), n);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ int ret = 0;
+ char *filename;
+ int fd = create_temp_file ("tst-big-read-after-write-tmp.", &filename);
+
+ if (fd == -1)
+ {
+ printf ("create_temp_file: %m\n");
+ return 1;
+ }
+
+ close (fd);
+
+ ret |= do_one_test (filename, "a+");
+ ret |= do_one_test (filename, "r+");
+ ret |= do_one_test (filename, "w+");
+
+ return ret;
+}