[v6,4/7] tests: replace fread by xfread

Message ID 20230602152812.108497-5-fberat@redhat.com (mailing list archive)
State Superseded
Delegated to: Siddhesh Poyarekar
Headers
Series Fix warn unused result |

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-arm success Testing passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm pending Patch applied
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 pending Patch applied

Commit Message

Frédéric Bérat June 2, 2023, 3:28 p.m. UTC
  With fortification enabled, fread calls return result needs to be checked,
has it gets the __wur macro enabled.
---
Changes since v4/v5:
 - Rebased

 libio/bug-fseek.c            |  7 ++++---
 stdio-common/bug12.c         | 12 ++++++-----
 stdio-common/bug3.c          |  4 +++-
 stdio-common/bug4.c          |  4 +++-
 stdio-common/tst-cookie.c    |  5 ++++-
 stdio-common/tst-fmemopen3.c |  4 +++-
 support/Makefile             |  1 +
 support/xfread.c             | 39 ++++++++++++++++++++++++++++++++++++
 support/xstdio.h             |  1 +
 9 files changed, 65 insertions(+), 12 deletions(-)
 create mode 100644 support/xfread.c
  

Comments

Siddhesh Poyarekar June 6, 2023, 12:18 p.m. UTC | #1
On 2023-06-02 11:28, Frédéric Bérat wrote:
> With fortification enabled, fread calls return result needs to be checked,
> has it gets the __wur macro enabled.
> ---
> Changes since v4/v5:
>   - Rebased
> 
>   libio/bug-fseek.c            |  7 ++++---
>   stdio-common/bug12.c         | 12 ++++++-----
>   stdio-common/bug3.c          |  4 +++-
>   stdio-common/bug4.c          |  4 +++-
>   stdio-common/tst-cookie.c    |  5 ++++-
>   stdio-common/tst-fmemopen3.c |  4 +++-
>   support/Makefile             |  1 +
>   support/xfread.c             | 39 ++++++++++++++++++++++++++++++++++++
>   support/xstdio.h             |  1 +
>   9 files changed, 65 insertions(+), 12 deletions(-)
>   create mode 100644 support/xfread.c
> 
> diff --git a/libio/bug-fseek.c b/libio/bug-fseek.c
> index 1b60580b53..19d5e2429e 100644
> --- a/libio/bug-fseek.c
> +++ b/libio/bug-fseek.c
> @@ -3,6 +3,7 @@
>   #include <stdlib.h>
>   #include <unistd.h>
>   
> +#include <support/xstdio.h>
>   
>   static char *fname;
>   
> @@ -48,7 +49,7 @@ do_test (void)
>         perror ("fopen(\"r\")");
>       }
>   
> -  fread (buf, 3, 1, f);
> +  xfread (buf, 3, 1, f);
>     errno = 0;
>     if (fseek (f, -10, SEEK_CUR) == 0)
>       {
> @@ -72,7 +73,7 @@ Got %d instead\n",
>         perror ("fopen(\"r+\")");
>       }
>   
> -  fread (buf, 3, 1, f);
> +  xfread (buf, 3, 1, f);
>     errno = 0;
>     if (fseek (f, -10, SEEK_CUR) == 0)
>       {
> @@ -96,7 +97,7 @@ Got %d instead\n",
>         perror ("fopen(\"r+\")");
>       }
>   
> -  fread (buf, 3, 1, f);
> +  xfread (buf, 3, 1, f);
>     if (ftell (f) != 3)
>       {
>         puts ("ftell failed");
> diff --git a/stdio-common/bug12.c b/stdio-common/bug12.c
> index 48610c0e78..1ba296deb4 100644
> --- a/stdio-common/bug12.c
> +++ b/stdio-common/bug12.c
> @@ -1,6 +1,8 @@
>   #include <stdio.h>
>   #include <string.h>
>   
> +#include <support/xstdio.h>
> +
>   char x[4096], z[4096], b[21], m[4096 * 4];
>   
>   int
> @@ -20,24 +22,24 @@ main (void)
>       }
>     rewind (f);
>   
> -  fread (m, 4096 * 4 - 10, 1, f);
> -  fread (b, 20, 1, f);
> +  xfread (m, 4096 * 4 - 10, 1, f);
> +  xfread (b, 20, 1, f);
>     printf ("got %s (should be %s)\n", b, "zzzzzzzzzzxxxxxxxxxx");
>     if (strcmp (b, "zzzzzzzzzzxxxxxxxxxx"))
>       failed = 1;
>   
>     fseek (f, -40, SEEK_CUR);
> -  fread (b, 20, 1, f);
> +  xfread (b, 20, 1, f);
>     printf ("got %s (should be %s)\n", b, "zzzzzzzzzzzzzzzzzzzz");
>     if (strcmp (b, "zzzzzzzzzzzzzzzzzzzz"))
>       failed = 1;
>   
> -  fread (b, 20, 1, f);
> +  xfread (b, 20, 1, f);
>     printf ("got %s (should be %s)\n", b, "zzzzzzzzzzxxxxxxxxxx");
>     if (strcmp (b, "zzzzzzzzzzxxxxxxxxxx"))
>       failed = 1;
>   
> -  fread (b, 20, 1, f);
> +  xfread (b, 20, 1, f);
>     printf ("got %s (should be %s)\n", b, "xxxxxxxxxxxxxxxxxxxx");
>     if (strcmp (b, "xxxxxxxxxxxxxxxxxxxx"))
>       failed = 1;
> diff --git a/stdio-common/bug3.c b/stdio-common/bug3.c
> index 62a6cab330..deabd00572 100644
> --- a/stdio-common/bug3.c
> +++ b/stdio-common/bug3.c
> @@ -1,6 +1,8 @@
>   #include <stdio.h>
>   #include <string.h>
>   
> +#include <support/xstdio.h>
> +
>   int
>   main (void)
>   {
> @@ -32,7 +34,7 @@ main (void)
>   	      char buf[25];
>   
>   	      buf[0] = j;
> -	      fread (buf + 1, 1, 23, f);
> +	      xfread (buf + 1, 1, 23, f);
>   	      buf[24] = '\0';
>   	      if (strcmp (buf, "Where does this text go?") != 0)
>   		{
> diff --git a/stdio-common/bug4.c b/stdio-common/bug4.c
> index cf7fe116eb..4059ff75b3 100644
> --- a/stdio-common/bug4.c
> +++ b/stdio-common/bug4.c
> @@ -2,6 +2,8 @@
>   #include <unistd.h>
>   #include <string.h>
>   
> +#include <support/xstdio.h>
> +
>   int stdio_block_read = 1, stdio_block_write = 1;
>   
>   int
> @@ -30,7 +32,7 @@ main (int argc, char *argv[])
>     fseek (f, 8180L, 0);
>     fwrite ("Where does this text come from?", 1, 31, f);
>     fseek (f, 8180L, 0);
> -  fread (buffer, 1, 31, f);
> +  xfread (buffer, 1, 31, f);
>     fwrite (buffer, 1, 31, stdout);
>     fclose (f);
>     remove (filename);
> diff --git a/stdio-common/tst-cookie.c b/stdio-common/tst-cookie.c
> index 030e684562..90ebc8e58c 100644
> --- a/stdio-common/tst-cookie.c
> +++ b/stdio-common/tst-cookie.c
> @@ -5,6 +5,8 @@
>   
>   #include <stdio.h>
>   
> +#include <support/xstdio.h>
> +
>   
>   #define THE_COOKIE ((void *) 0xdeadbeeful)
>   
> @@ -77,7 +79,8 @@ do_test (void)
>   
>     f = fopencookie (THE_COOKIE, "r+", fcts);
>   
> -  fread (buf, 1, 1, f);
> +  xfread (buf, 1, 1, f);
> +
>     fwrite (buf, 1, 1, f);
>     fseek (f, 0, SEEK_CUR);
>     fclose (f);
> diff --git a/stdio-common/tst-fmemopen3.c b/stdio-common/tst-fmemopen3.c
> index bef87b712a..1627f17f59 100644
> --- a/stdio-common/tst-fmemopen3.c
> +++ b/stdio-common/tst-fmemopen3.c
> @@ -21,6 +21,8 @@
>   #include <string.h>
>   #include <sys/types.h>
>   
> +#include <support/xstdio.h>
> +
>   static void
>   print_buffer (const char *s, size_t n)
>   {
> @@ -153,7 +155,7 @@ do_test_read_seek_neg (const char *mode, const char *expected)
>   
>     FILE *fp = fmemopen (buf, sizeof (buf), mode);
>     fseek (fp, offset, SEEK_END);
> -  fread (tmp, tmps, 1, fp);
> +  xfread (tmp, tmps, 1, fp);
>   
>     if (memcmp (tmp, expected, tmps) != 0)
>       {
> diff --git a/support/Makefile b/support/Makefile
> index fbbc305423..3eed2deb1a 100644
> --- a/support/Makefile
> +++ b/support/Makefile
> @@ -126,6 +126,7 @@ libsupport-routines = \
>     xfopen \
>     xfork \
>     xfreopen \
> +  xfread \
>     xftruncate \
>     xgetline \
>     xgetsockname \
> diff --git a/support/xfread.c b/support/xfread.c
> new file mode 100644
> index 0000000000..c21187d476
> --- /dev/null
> +++ b/support/xfread.c
> @@ -0,0 +1,39 @@
> +/* fread with error checking.
> +   Copyright (C) 2016-2023 Free Software Foundation, Inc.

Only 2023.

> +   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 <support/xstdio.h>
> +
> +#include <support/check.h>
> +#include <stdlib.h>
> +
> +void
> +xfread (void *ptr, size_t size, size_t nmemb, FILE *stream)
> +{
> +  size_t count = 0;
> +  char *p = ptr;
> +
> +  while (count < nmemb)
> +    {
> +      size_t ret = fread (p, size, nmemb - count, stream);
> +      if (ret <= 0 && ferror(stream))
> +        FAIL_EXIT1 ("read of %zu bytes failed after %td: %m",
> +                    size * nmemb, p - (char *) ptr);
> +      count += ret;
> +      p += size * ret;
> +    }
> +}
> diff --git a/support/xstdio.h b/support/xstdio.h
> index 5410d42579..633c342c82 100644
> --- a/support/xstdio.h
> +++ b/support/xstdio.h
> @@ -27,6 +27,7 @@ __BEGIN_DECLS
>   FILE *xfopen (const char *path, const char *mode);
>   void xfclose (FILE *);
>   FILE *xfreopen (const char *path, const char *mode, FILE *stream);
> +void xfread (void *ptr, size_t size, size_t nmemb, FILE *stream);
>   
>   /* Read a line from FP, using getline.  *BUFFER must be NULL, or a
>      heap-allocated pointer of *LENGTH bytes.  Return the number of
  
Frédéric Bérat June 7, 2023, 7:03 p.m. UTC | #2
On Fri, Jun 2, 2023 at 5:28 PM Frédéric Bérat <fberat@redhat.com> wrote:
>
> With fortification enabled, fread calls return result needs to be checked,
> has it gets the __wur macro enabled.
> ---
> Changes since v4/v5:
>  - Rebased
>
>  libio/bug-fseek.c            |  7 ++++---
>  stdio-common/bug12.c         | 12 ++++++-----
>  stdio-common/bug3.c          |  4 +++-
>  stdio-common/bug4.c          |  4 +++-
>  stdio-common/tst-cookie.c    |  5 ++++-
>  stdio-common/tst-fmemopen3.c |  4 +++-
>  support/Makefile             |  1 +
>  support/xfread.c             | 39 ++++++++++++++++++++++++++++++++++++
>  support/xstdio.h             |  1 +
>  9 files changed, 65 insertions(+), 12 deletions(-)
>  create mode 100644 support/xfread.c
>
> diff --git a/libio/bug-fseek.c b/libio/bug-fseek.c
> index 1b60580b53..19d5e2429e 100644
> --- a/libio/bug-fseek.c
> +++ b/libio/bug-fseek.c
> @@ -3,6 +3,7 @@
>  #include <stdlib.h>
>  #include <unistd.h>
>
> +#include <support/xstdio.h>
>
>  static char *fname;
>
> @@ -48,7 +49,7 @@ do_test (void)
>        perror ("fopen(\"r\")");
>      }
>
> -  fread (buf, 3, 1, f);
> +  xfread (buf, 3, 1, f);
>    errno = 0;
>    if (fseek (f, -10, SEEK_CUR) == 0)
>      {
> @@ -72,7 +73,7 @@ Got %d instead\n",
>        perror ("fopen(\"r+\")");
>      }
>
> -  fread (buf, 3, 1, f);
> +  xfread (buf, 3, 1, f);
>    errno = 0;
>    if (fseek (f, -10, SEEK_CUR) == 0)
>      {
> @@ -96,7 +97,7 @@ Got %d instead\n",
>        perror ("fopen(\"r+\")");
>      }
>
> -  fread (buf, 3, 1, f);
> +  xfread (buf, 3, 1, f);
>    if (ftell (f) != 3)
>      {
>        puts ("ftell failed");
> diff --git a/stdio-common/bug12.c b/stdio-common/bug12.c
> index 48610c0e78..1ba296deb4 100644
> --- a/stdio-common/bug12.c
> +++ b/stdio-common/bug12.c
> @@ -1,6 +1,8 @@
>  #include <stdio.h>
>  #include <string.h>
>
> +#include <support/xstdio.h>
> +
>  char x[4096], z[4096], b[21], m[4096 * 4];
>
>  int
> @@ -20,24 +22,24 @@ main (void)
>      }
>    rewind (f);
>
> -  fread (m, 4096 * 4 - 10, 1, f);
> -  fread (b, 20, 1, f);
> +  xfread (m, 4096 * 4 - 10, 1, f);
> +  xfread (b, 20, 1, f);
>    printf ("got %s (should be %s)\n", b, "zzzzzzzzzzxxxxxxxxxx");
>    if (strcmp (b, "zzzzzzzzzzxxxxxxxxxx"))
>      failed = 1;
>
>    fseek (f, -40, SEEK_CUR);
> -  fread (b, 20, 1, f);
> +  xfread (b, 20, 1, f);
>    printf ("got %s (should be %s)\n", b, "zzzzzzzzzzzzzzzzzzzz");
>    if (strcmp (b, "zzzzzzzzzzzzzzzzzzzz"))
>      failed = 1;
>
> -  fread (b, 20, 1, f);
> +  xfread (b, 20, 1, f);
>    printf ("got %s (should be %s)\n", b, "zzzzzzzzzzxxxxxxxxxx");
>    if (strcmp (b, "zzzzzzzzzzxxxxxxxxxx"))
>      failed = 1;
>
> -  fread (b, 20, 1, f);
> +  xfread (b, 20, 1, f);
>    printf ("got %s (should be %s)\n", b, "xxxxxxxxxxxxxxxxxxxx");
>    if (strcmp (b, "xxxxxxxxxxxxxxxxxxxx"))
>      failed = 1;
> diff --git a/stdio-common/bug3.c b/stdio-common/bug3.c
> index 62a6cab330..deabd00572 100644
> --- a/stdio-common/bug3.c
> +++ b/stdio-common/bug3.c
> @@ -1,6 +1,8 @@
>  #include <stdio.h>
>  #include <string.h>
>
> +#include <support/xstdio.h>
> +
>  int
>  main (void)
>  {
> @@ -32,7 +34,7 @@ main (void)
>               char buf[25];
>
>               buf[0] = j;
> -             fread (buf + 1, 1, 23, f);
> +             xfread (buf + 1, 1, 23, f);
>               buf[24] = '\0';
>               if (strcmp (buf, "Where does this text go?") != 0)
>                 {
> diff --git a/stdio-common/bug4.c b/stdio-common/bug4.c
> index cf7fe116eb..4059ff75b3 100644
> --- a/stdio-common/bug4.c
> +++ b/stdio-common/bug4.c
> @@ -2,6 +2,8 @@
>  #include <unistd.h>
>  #include <string.h>
>
> +#include <support/xstdio.h>
> +
>  int stdio_block_read = 1, stdio_block_write = 1;
>
>  int
> @@ -30,7 +32,7 @@ main (int argc, char *argv[])
>    fseek (f, 8180L, 0);
>    fwrite ("Where does this text come from?", 1, 31, f);
>    fseek (f, 8180L, 0);
> -  fread (buffer, 1, 31, f);
> +  xfread (buffer, 1, 31, f);
>    fwrite (buffer, 1, 31, stdout);
>    fclose (f);
>    remove (filename);
> diff --git a/stdio-common/tst-cookie.c b/stdio-common/tst-cookie.c
> index 030e684562..90ebc8e58c 100644
> --- a/stdio-common/tst-cookie.c
> +++ b/stdio-common/tst-cookie.c
> @@ -5,6 +5,8 @@
>
>  #include <stdio.h>
>
> +#include <support/xstdio.h>
> +
>
>  #define THE_COOKIE ((void *) 0xdeadbeeful)
>
> @@ -77,7 +79,8 @@ do_test (void)
>
>    f = fopencookie (THE_COOKIE, "r+", fcts);
>
> -  fread (buf, 1, 1, f);
> +  xfread (buf, 1, 1, f);
> +
>    fwrite (buf, 1, 1, f);
>    fseek (f, 0, SEEK_CUR);
>    fclose (f);
> diff --git a/stdio-common/tst-fmemopen3.c b/stdio-common/tst-fmemopen3.c
> index bef87b712a..1627f17f59 100644
> --- a/stdio-common/tst-fmemopen3.c
> +++ b/stdio-common/tst-fmemopen3.c
> @@ -21,6 +21,8 @@
>  #include <string.h>
>  #include <sys/types.h>
>
> +#include <support/xstdio.h>
> +
>  static void
>  print_buffer (const char *s, size_t n)
>  {
> @@ -153,7 +155,7 @@ do_test_read_seek_neg (const char *mode, const char *expected)
>
>    FILE *fp = fmemopen (buf, sizeof (buf), mode);
>    fseek (fp, offset, SEEK_END);
> -  fread (tmp, tmps, 1, fp);
> +  xfread (tmp, tmps, 1, fp);
>
>    if (memcmp (tmp, expected, tmps) != 0)
>      {
> diff --git a/support/Makefile b/support/Makefile
> index fbbc305423..3eed2deb1a 100644
> --- a/support/Makefile
> +++ b/support/Makefile
> @@ -126,6 +126,7 @@ libsupport-routines = \
>    xfopen \
>    xfork \
>    xfreopen \
> +  xfread \

xfread must be before xfreopen

>    xftruncate \
>    xgetline \
>    xgetsockname \
> diff --git a/support/xfread.c b/support/xfread.c
> new file mode 100644
> index 0000000000..c21187d476
> --- /dev/null
> +++ b/support/xfread.c
> @@ -0,0 +1,39 @@
> +/* fread with error checking.
> +   Copyright (C) 2016-2023 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 <support/xstdio.h>
> +
> +#include <support/check.h>
> +#include <stdlib.h>
> +
> +void
> +xfread (void *ptr, size_t size, size_t nmemb, FILE *stream)
> +{
> +  size_t count = 0;
> +  char *p = ptr;
> +
> +  while (count < nmemb)
> +    {
> +      size_t ret = fread (p, size, nmemb - count, stream);
> +      if (ret <= 0 && ferror(stream))
> +        FAIL_EXIT1 ("read of %zu bytes failed after %td: %m",
> +                    size * nmemb, p - (char *) ptr);
> +      count += ret;
> +      p += size * ret;
> +    }
> +}
> diff --git a/support/xstdio.h b/support/xstdio.h
> index 5410d42579..633c342c82 100644
> --- a/support/xstdio.h
> +++ b/support/xstdio.h
> @@ -27,6 +27,7 @@ __BEGIN_DECLS
>  FILE *xfopen (const char *path, const char *mode);
>  void xfclose (FILE *);
>  FILE *xfreopen (const char *path, const char *mode, FILE *stream);
> +void xfread (void *ptr, size_t size, size_t nmemb, FILE *stream);
>
>  /* Read a line from FP, using getline.  *BUFFER must be NULL, or a
>     heap-allocated pointer of *LENGTH bytes.  Return the number of
> --
> 2.40.1
>
  

Patch

diff --git a/libio/bug-fseek.c b/libio/bug-fseek.c
index 1b60580b53..19d5e2429e 100644
--- a/libio/bug-fseek.c
+++ b/libio/bug-fseek.c
@@ -3,6 +3,7 @@ 
 #include <stdlib.h>
 #include <unistd.h>
 
+#include <support/xstdio.h>
 
 static char *fname;
 
@@ -48,7 +49,7 @@  do_test (void)
       perror ("fopen(\"r\")");
     }
 
-  fread (buf, 3, 1, f);
+  xfread (buf, 3, 1, f);
   errno = 0;
   if (fseek (f, -10, SEEK_CUR) == 0)
     {
@@ -72,7 +73,7 @@  Got %d instead\n",
       perror ("fopen(\"r+\")");
     }
 
-  fread (buf, 3, 1, f);
+  xfread (buf, 3, 1, f);
   errno = 0;
   if (fseek (f, -10, SEEK_CUR) == 0)
     {
@@ -96,7 +97,7 @@  Got %d instead\n",
       perror ("fopen(\"r+\")");
     }
 
-  fread (buf, 3, 1, f);
+  xfread (buf, 3, 1, f);
   if (ftell (f) != 3)
     {
       puts ("ftell failed");
diff --git a/stdio-common/bug12.c b/stdio-common/bug12.c
index 48610c0e78..1ba296deb4 100644
--- a/stdio-common/bug12.c
+++ b/stdio-common/bug12.c
@@ -1,6 +1,8 @@ 
 #include <stdio.h>
 #include <string.h>
 
+#include <support/xstdio.h>
+
 char x[4096], z[4096], b[21], m[4096 * 4];
 
 int
@@ -20,24 +22,24 @@  main (void)
     }
   rewind (f);
 
-  fread (m, 4096 * 4 - 10, 1, f);
-  fread (b, 20, 1, f);
+  xfread (m, 4096 * 4 - 10, 1, f);
+  xfread (b, 20, 1, f);
   printf ("got %s (should be %s)\n", b, "zzzzzzzzzzxxxxxxxxxx");
   if (strcmp (b, "zzzzzzzzzzxxxxxxxxxx"))
     failed = 1;
 
   fseek (f, -40, SEEK_CUR);
-  fread (b, 20, 1, f);
+  xfread (b, 20, 1, f);
   printf ("got %s (should be %s)\n", b, "zzzzzzzzzzzzzzzzzzzz");
   if (strcmp (b, "zzzzzzzzzzzzzzzzzzzz"))
     failed = 1;
 
-  fread (b, 20, 1, f);
+  xfread (b, 20, 1, f);
   printf ("got %s (should be %s)\n", b, "zzzzzzzzzzxxxxxxxxxx");
   if (strcmp (b, "zzzzzzzzzzxxxxxxxxxx"))
     failed = 1;
 
-  fread (b, 20, 1, f);
+  xfread (b, 20, 1, f);
   printf ("got %s (should be %s)\n", b, "xxxxxxxxxxxxxxxxxxxx");
   if (strcmp (b, "xxxxxxxxxxxxxxxxxxxx"))
     failed = 1;
diff --git a/stdio-common/bug3.c b/stdio-common/bug3.c
index 62a6cab330..deabd00572 100644
--- a/stdio-common/bug3.c
+++ b/stdio-common/bug3.c
@@ -1,6 +1,8 @@ 
 #include <stdio.h>
 #include <string.h>
 
+#include <support/xstdio.h>
+
 int
 main (void)
 {
@@ -32,7 +34,7 @@  main (void)
 	      char buf[25];
 
 	      buf[0] = j;
-	      fread (buf + 1, 1, 23, f);
+	      xfread (buf + 1, 1, 23, f);
 	      buf[24] = '\0';
 	      if (strcmp (buf, "Where does this text go?") != 0)
 		{
diff --git a/stdio-common/bug4.c b/stdio-common/bug4.c
index cf7fe116eb..4059ff75b3 100644
--- a/stdio-common/bug4.c
+++ b/stdio-common/bug4.c
@@ -2,6 +2,8 @@ 
 #include <unistd.h>
 #include <string.h>
 
+#include <support/xstdio.h>
+
 int stdio_block_read = 1, stdio_block_write = 1;
 
 int
@@ -30,7 +32,7 @@  main (int argc, char *argv[])
   fseek (f, 8180L, 0);
   fwrite ("Where does this text come from?", 1, 31, f);
   fseek (f, 8180L, 0);
-  fread (buffer, 1, 31, f);
+  xfread (buffer, 1, 31, f);
   fwrite (buffer, 1, 31, stdout);
   fclose (f);
   remove (filename);
diff --git a/stdio-common/tst-cookie.c b/stdio-common/tst-cookie.c
index 030e684562..90ebc8e58c 100644
--- a/stdio-common/tst-cookie.c
+++ b/stdio-common/tst-cookie.c
@@ -5,6 +5,8 @@ 
 
 #include <stdio.h>
 
+#include <support/xstdio.h>
+
 
 #define THE_COOKIE ((void *) 0xdeadbeeful)
 
@@ -77,7 +79,8 @@  do_test (void)
 
   f = fopencookie (THE_COOKIE, "r+", fcts);
 
-  fread (buf, 1, 1, f);
+  xfread (buf, 1, 1, f);
+
   fwrite (buf, 1, 1, f);
   fseek (f, 0, SEEK_CUR);
   fclose (f);
diff --git a/stdio-common/tst-fmemopen3.c b/stdio-common/tst-fmemopen3.c
index bef87b712a..1627f17f59 100644
--- a/stdio-common/tst-fmemopen3.c
+++ b/stdio-common/tst-fmemopen3.c
@@ -21,6 +21,8 @@ 
 #include <string.h>
 #include <sys/types.h>
 
+#include <support/xstdio.h>
+
 static void
 print_buffer (const char *s, size_t n)
 {
@@ -153,7 +155,7 @@  do_test_read_seek_neg (const char *mode, const char *expected)
 
   FILE *fp = fmemopen (buf, sizeof (buf), mode);
   fseek (fp, offset, SEEK_END);
-  fread (tmp, tmps, 1, fp);
+  xfread (tmp, tmps, 1, fp);
 
   if (memcmp (tmp, expected, tmps) != 0)
     {
diff --git a/support/Makefile b/support/Makefile
index fbbc305423..3eed2deb1a 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -126,6 +126,7 @@  libsupport-routines = \
   xfopen \
   xfork \
   xfreopen \
+  xfread \
   xftruncate \
   xgetline \
   xgetsockname \
diff --git a/support/xfread.c b/support/xfread.c
new file mode 100644
index 0000000000..c21187d476
--- /dev/null
+++ b/support/xfread.c
@@ -0,0 +1,39 @@ 
+/* fread with error checking.
+   Copyright (C) 2016-2023 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 <support/xstdio.h>
+
+#include <support/check.h>
+#include <stdlib.h>
+
+void
+xfread (void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+  size_t count = 0;
+  char *p = ptr;
+
+  while (count < nmemb)
+    {
+      size_t ret = fread (p, size, nmemb - count, stream);
+      if (ret <= 0 && ferror(stream))
+        FAIL_EXIT1 ("read of %zu bytes failed after %td: %m",
+                    size * nmemb, p - (char *) ptr);
+      count += ret;
+      p += size * ret;
+    }
+}
diff --git a/support/xstdio.h b/support/xstdio.h
index 5410d42579..633c342c82 100644
--- a/support/xstdio.h
+++ b/support/xstdio.h
@@ -27,6 +27,7 @@  __BEGIN_DECLS
 FILE *xfopen (const char *path, const char *mode);
 void xfclose (FILE *);
 FILE *xfreopen (const char *path, const char *mode, FILE *stream);
+void xfread (void *ptr, size_t size, size_t nmemb, FILE *stream);
 
 /* Read a line from FP, using getline.  *BUFFER must be NULL, or a
    heap-allocated pointer of *LENGTH bytes.  Return the number of