d8307d
commit 32ff397533715988c19cbf3675dcbd727ec13e18
d8307d
Author: Andreas Schwab <schwab@suse.de>
d8307d
Date:   Tue May 14 17:14:59 2019 +0200
d8307d
d8307d
    Fix crash in _IO_wfile_sync (bug 20568)
d8307d
    
d8307d
    When computing the length of the converted part of the stdio buffer, use
d8307d
    the number of consumed wide characters, not the (negative) distance to the
d8307d
    end of the wide buffer.
d8307d
d8307d
Conflicts:
d8307d
	libio/Makefile
d8307d
	  (Usual conflict when adding tests due to missing backports.)
d8307d
d8307d
diff --git a/libio/Makefile b/libio/Makefile
d8307d
index cab0eae946b1f307..cbfaf3832a45fc22 100644
d8307d
--- a/libio/Makefile
d8307d
+++ b/libio/Makefile
d8307d
@@ -64,7 +64,8 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
d8307d
 	bug-memstream1 bug-wmemstream1 \
d8307d
 	tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
d8307d
 	tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
d8307d
-	tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof
d8307d
+	tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
d8307d
+	tst-wfile-sync
d8307d
 
d8307d
 tests-internal = tst-vtables tst-vtables-interposed tst-readline
d8307d
 
d8307d
@@ -207,6 +208,7 @@ $(objpfx)tst-ungetwc1.out: $(gen-locales)
d8307d
 $(objpfx)tst-ungetwc2.out: $(gen-locales)
d8307d
 $(objpfx)tst-widetext.out: $(gen-locales)
d8307d
 $(objpfx)tst_wprintf2.out: $(gen-locales)
d8307d
+$(objpfx)tst-wfile-sync.out: $(gen-locales)
d8307d
 endif
d8307d
 
d8307d
 $(objpfx)test-freopen.out: test-freopen.sh $(objpfx)test-freopen
d8307d
diff --git a/libio/tst-wfile-sync.c b/libio/tst-wfile-sync.c
d8307d
new file mode 100644
d8307d
index 0000000000000000..618682064da4035c
d8307d
--- /dev/null
d8307d
+++ b/libio/tst-wfile-sync.c
d8307d
@@ -0,0 +1,39 @@
d8307d
+/* Test that _IO_wfile_sync does not crash (bug 20568).
d8307d
+   Copyright (C) 2019 Free Software Foundation, Inc.
d8307d
+   This file is part of the GNU C Library.
d8307d
+
d8307d
+   The GNU C Library is free software; you can redistribute it and/or
d8307d
+   modify it under the terms of the GNU Lesser General Public
d8307d
+   License as published by the Free Software Foundation; either
d8307d
+   version 2.1 of the License, or (at your option) any later version.
d8307d
+
d8307d
+   The GNU C Library is distributed in the hope that it will be useful,
d8307d
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
d8307d
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
d8307d
+   Lesser General Public License for more details.
d8307d
+
d8307d
+   You should have received a copy of the GNU Lesser General Public
d8307d
+   License along with the GNU C Library; if not, see
d8307d
+   <http://www.gnu.org/licenses/>.  */
d8307d
+
d8307d
+#include <locale.h>
d8307d
+#include <stdio.h>
d8307d
+#include <wchar.h>
d8307d
+#include <support/check.h>
d8307d
+#include <support/xunistd.h>
d8307d
+
d8307d
+static int
d8307d
+do_test (void)
d8307d
+{
d8307d
+  TEST_VERIFY_EXIT (setlocale (LC_ALL, "de_DE.UTF-8") != NULL);
d8307d
+  /* Fill the stdio buffer and advance the read pointer.  */
d8307d
+  TEST_VERIFY_EXIT (fgetwc (stdin) != WEOF);
d8307d
+  /* This calls _IO_wfile_sync, it should not crash.  */
d8307d
+  TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IONBF, 0) == 0);
d8307d
+  /* Verify that the external file offset has been synchronized.  */
d8307d
+  TEST_COMPARE (xlseek (0, 0, SEEK_CUR), 1);
d8307d
+
d8307d
+  return 0;
d8307d
+}
d8307d
+
d8307d
+#include <support/test-driver.c>
d8307d
diff --git a/libio/tst-wfile-sync.input b/libio/tst-wfile-sync.input
d8307d
new file mode 100644
d8307d
index 0000000000000000..12d0958f7aaa3865
d8307d
--- /dev/null
d8307d
+++ b/libio/tst-wfile-sync.input
d8307d
@@ -0,0 +1 @@
d8307d
+This is a test of _IO_wfile_sync.
d8307d
diff --git a/libio/wfileops.c b/libio/wfileops.c
d8307d
index 63cb687652c72ce1..10e7343f8fdb8781 100644
d8307d
--- a/libio/wfileops.c
d8307d
+++ b/libio/wfileops.c
d8307d
@@ -508,11 +508,12 @@ _IO_wfile_sync (FILE *fp)
d8307d
 	     generate the wide characters up to the current reading
d8307d
 	     position.  */
d8307d
 	  int nread;
d8307d
-
d8307d
+	  size_t wnread = (fp->_wide_data->_IO_read_ptr
d8307d
+			   - fp->_wide_data->_IO_read_base);
d8307d
 	  fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state;
d8307d
 	  nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state,
d8307d
 					      fp->_IO_read_base,
d8307d
-					      fp->_IO_read_end, delta);
d8307d
+					      fp->_IO_read_end, wnread);
d8307d
 	  fp->_IO_read_ptr = fp->_IO_read_base + nread;
d8307d
 	  delta = -(fp->_IO_read_end - fp->_IO_read_base - nread);
d8307d
 	}