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