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