Properly set up wide stream buffers for output (bug 20632)

Message ID mvmee231y2t.fsf@suse.de
State New
Headers
Series Properly set up wide stream buffers for output (bug 20632) |

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent
dj/TryBot-32bit success Build for i686
redhat-pt-bot/TryBot-still_applies warning Patch no longer applies to master

Commit Message

Andreas Schwab April 11, 2022, 2:42 p.m. UTC
  Make sure to have valid narrow buffers before allocating the buffers for a
wide stream.
---
 libio/Makefile       |  1 +
 libio/tst-wdoalloc.c | 32 ++++++++++++++++++++++++++++++++
 libio/wfileops.c     |  9 ++++-----
 3 files changed, 37 insertions(+), 5 deletions(-)
 create mode 100644 libio/tst-wdoalloc.c
  

Patch

diff --git a/libio/Makefile b/libio/Makefile
index e97387743f..3471dfa82a 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -67,6 +67,7 @@  tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
 	tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
 	tst-sprintf-ub tst-sprintf-chk-ub tst-bz24051 tst-bz24153 \
 	tst-wfile-sync tst-bz28828
+tests += tst-wdoalloc
 
 tests-internal = tst-vtables tst-vtables-interposed
 
diff --git a/libio/tst-wdoalloc.c b/libio/tst-wdoalloc.c
new file mode 100644
index 0000000000..04cc3e906e
--- /dev/null
+++ b/libio/tst-wdoalloc.c
@@ -0,0 +1,32 @@ 
+/* Test setup of buffers on wide-oriented stream - BZ #20632 */
+
+#include <stdio.h>
+#include <wchar.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  /* This test uses stderr because it is an unbuffered stream where the
+     stdio buffers haven't been set up yet.  */
+
+  /* Close stderr descriptor so that output to it will fail.  */
+  close (2);
+
+  /* Output a long string.  */
+  const int sz = 4096;
+  wchar_t *buff = calloc (sz + 1, sizeof *buff);
+  for (int i = 0; i < sz; i++)
+    buff[i] = L'x';
+  fputws (buff, stderr);
+
+  /* Output shorter strings.  */
+  for (int i = 0; i < 1024; i++)
+    fputws (L"0123456789ABCDEF", stderr);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/libio/wfileops.c b/libio/wfileops.c
index b59a98881f..60ddf36d67 100644
--- a/libio/wfileops.c
+++ b/libio/wfileops.c
@@ -418,16 +418,15 @@  _IO_wfile_overflow (FILE *f, wint_t wch)
       /* Allocate a buffer if needed. */
       if (f->_wide_data->_IO_write_base == 0)
 	{
-	  _IO_wdoallocbuf (f);
-	  _IO_free_wbackup_area (f);
-	  _IO_wsetg (f, f->_wide_data->_IO_buf_base,
-		     f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
-
 	  if (f->_IO_write_base == NULL)
 	    {
 	      _IO_doallocbuf (f);
 	      _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
 	    }
+	  _IO_wdoallocbuf (f);
+	  _IO_free_wbackup_area (f);
+	  _IO_wsetg (f, f->_wide_data->_IO_buf_base,
+		     f->_wide_data->_IO_buf_base, f->_wide_data->_IO_buf_base);
 	}
       else
 	{