libio: Fix orientation [BZ #22796]

Message ID 20250308054156.13888-1-samuelzeter@gmail.com (mailing list archive)
State Superseded
Headers
Series libio: Fix orientation [BZ #22796] |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
redhat-pt-bot/TryBot-32bit fail Patch caused testsuite regressions
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm fail Test failed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 fail Test failed

Commit Message

Sam Zeter March 8, 2025, 5:41 a.m. UTC
  When using fread, stream orientation is only set in the case when
less than a buffer's worth (4096 bytes) of data is requested. In this
case the __underflow function is called, and the orientation set.

In the case where more than 4096 bytes are needed, the __underflow function
is skipped, and hence the stream's orientation is left unset.

Setting the orientation to byte oriented before any buffer filling logic
ensures that the orientation is set correctly regardless of the amount of
data requested.

Signed-off-by: Samuel Zeter <samuelzeter@gmail.com>
---
 libio/Makefile      |   1 +
 libio/fileops.c     |   4 ++
 libio/genops.c      |   2 -
 libio/tst-bz22796.c | 101 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 106 insertions(+), 2 deletions(-)
 create mode 100644 libio/tst-bz22796.c
  

Patch

diff --git a/libio/Makefile b/libio/Makefile
index e143ccdb2c..4b0450afad 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -93,6 +93,7 @@  tests = \
   tst-bz22415 \
   tst-bz24051 \
   tst-bz24153 \
+  tst-bz22796 \
   tst-bz28828 \
   tst-closeall \
   tst-eof \
diff --git a/libio/fileops.c b/libio/fileops.c
index a59e248142..7921fa0fb2 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -1328,6 +1328,10 @@  _IO_file_xsgetn (FILE *fp, void *data, size_t n)
 
   want = n;
 
+  /* Set the stream to byte oriented */
+  if (fp->_mode == 0)
+    _IO_fwide (fp, -1);
+
   if (fp->_IO_buf_base == NULL)
     {
       /* Maybe we already have a push back pointer.  */
diff --git a/libio/genops.c b/libio/genops.c
index c3178d9a97..8537a20a92 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -296,8 +296,6 @@  __underflow (FILE *fp)
   if (_IO_vtable_offset (fp) == 0 && _IO_fwide (fp, -1) != -1)
     return EOF;
 
-  if (fp->_mode == 0)
-    _IO_fwide (fp, -1);
   if (_IO_in_put_mode (fp))
     if (_IO_switch_to_get_mode (fp) == EOF)
       return EOF;
diff --git a/libio/tst-bz22796.c b/libio/tst-bz22796.c
new file mode 100644
index 0000000000..69d2a7f1b7
--- /dev/null
+++ b/libio/tst-bz22796.c
@@ -0,0 +1,101 @@ 
+/* Test to ensure stream orientation is set when reading large
+   buffer sizes with fread (BZ#22796).
+
+   Copyright (C) 2019-2025 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+
+static int fd;
+static FILE *fp = NULL;
+static char buffer[BUFSIZ] = { 0 };
+
+static void
+setup (void)
+{
+  int ret;
+
+  fd = create_temp_file ("bz22796", NULL);
+  if (fd == -1)
+      FAIL_EXIT1 ("create_temp_file failed");
+
+  fp = fdopen (fd, "w");
+  if (fp == NULL)
+      FAIL_EXIT1 ("fopen for file bz22796 returned NULL.");
+
+  /* The stream should have no orientation set yet */
+  ret = fwide (fp, 0);
+  if (ret != 0)
+      FAIL_EXIT1 (
+          "Error: Orientation already set. fwide returned %d.\n", ret);
+}
+
+static int
+test_read_large_buffer (void)
+{
+  int ret;
+
+  setup ();
+
+  /* Read a large amount of bytes */
+  fread (buffer, 4, BUFSIZ / 4, fp);
+
+  /* Stream should now be byte orientated */
+  ret = fwide (fp, 0);
+  if (ret != -1)
+      FAIL_RET ("fread returned %d, expected -1.\n", ret);
+
+  return 0;
+}
+
+static int
+test_read_small_buffer (void)
+{
+  int ret;
+
+  setup ();
+
+  /* Read a small amount of bytes */
+  fread (buffer, 4, 4, fp);
+
+  /* Stream should now be byte orientated */
+  ret = fwide (fp, 0);
+  if (ret != -1)
+      FAIL_RET ("fread returned %d, expected -1.\n", ret);
+
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  int ret = 0;
+
+  ret = test_read_small_buffer ();
+  ret += test_read_large_buffer ();
+
+  fclose (fp);
+
+  return ret;
+}
+
+#include <support/test-driver.c>