[v2] libio: Fix fread stream orientation [BZ #22796]

Message ID 20250403074937.333514-1-samuelzeter@gmail.com (mailing list archive)
State New
Headers
Series [v2] libio: Fix fread stream orientation [BZ #22796] |

Checks

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

Commit Message

Samuel Zeter April 3, 2025, 7:48 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.
--- This update moves the stream setting to the external interface
 libio/Makefile      |   1 +
 libio/iofread.c     |   5 +++
 libio/tst-bz22796.c | 101 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 107 insertions(+)
 create mode 100644 libio/tst-bz22796.c
  

Patch

diff --git a/libio/Makefile b/libio/Makefile
index e143ccdb2c..7db9f73f7b 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -91,6 +91,7 @@  tests = \
   tst-asprintf-null \
   tst-atime \
   tst-bz22415 \
+  tst-bz22796 \
   tst-bz24051 \
   tst-bz24153 \
   tst-bz28828 \
diff --git a/libio/iofread.c b/libio/iofread.c
index 46f196de63..59fe064eba 100644
--- a/libio/iofread.c
+++ b/libio/iofread.c
@@ -35,6 +35,11 @@  _IO_fread (void *buf, size_t size, size_t count, FILE *fp)
   if (bytes_requested == 0)
     return 0;
   _IO_acquire_lock (fp);
+
+  /* Set the stream to byte oriented */
+  if (fp->_mode == 0)
+    _IO_fwide (fp, -1);
+
   bytes_read = _IO_sgetn (fp, (char *) buf, bytes_requested);
   _IO_release_lock (fp);
   return bytes_requested == bytes_read ? count : bytes_read / size;
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>