From cc0b035e0189c23102a7b5208b4e7a501237deeb Mon Sep 17 00:00:00 2001 From: DJ Delorie Date: Tue, 24 Sep 2024 20:41:54 -0400 Subject: [PATCH] Add fgets testcases Resolves: RHEL-46728 --- glibc-RHEL-46728.patch | 287 +++++++++++++++++++++++++++++++++++++++++ glibc.spec | 6 +- 2 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 glibc-RHEL-46728.patch diff --git a/glibc-RHEL-46728.patch b/glibc-RHEL-46728.patch new file mode 100644 index 0000000..439d9ab --- /dev/null +++ b/glibc-RHEL-46728.patch @@ -0,0 +1,287 @@ +From 4945ffc88a8ad49280bae64165683ddfd12b2390 Mon Sep 17 00:00:00 2001 +From: DJ Delorie +Date: Wed, 7 Aug 2024 16:55:16 -0400 +Subject: fgets: more tests + +Add more tests for unusual situations fgets() might see: + +* zero size file +* zero sized buffer +* NULL buffer +* NUL data +* writable stream +* closed stream + +Reviewed-by: Florian Weimer + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index 89871d0de8..03d597f8e6 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -209,6 +209,7 @@ tests := \ + tst-fdopen \ + tst-ferror \ + tst-fgets \ ++ tst-fgets2 \ + tst-fileno \ + tst-fmemopen \ + tst-fmemopen2 \ +diff --git a/stdio-common/tst-fgets2.c b/stdio-common/tst-fgets2.c +new file mode 100644 +index 0000000000..5b78447ea9 +--- /dev/null ++++ b/stdio-common/tst-fgets2.c +@@ -0,0 +1,253 @@ ++/* Test for additional fgets error handling. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* This avoids compiler warnings about passing NULL where a valid ++ pointer is expected. */ ++static void *volatile null = NULL; ++ ++/* Implementation of our FILE stream backend. */ ++ ++static int bytes_read; ++static int cookie_valid = 0; ++struct Cookie { ++ const char *buffer; ++ int bufptr; ++ int bufsz; ++}; ++ ++#define VALIDATE_COOKIE() if (! cookie_valid) { \ ++ FAIL ("call to %s after file closed", __FUNCTION__); \ ++ return -1; \ ++ } ++ ++static ssize_t ++io_read (void *vcookie, char *buf, size_t size) ++{ ++ struct Cookie *cookie = (struct Cookie *) vcookie; ++ ++ VALIDATE_COOKIE (); ++ ++ if (size > cookie->bufsz - cookie->bufptr) ++ size = cookie->bufsz - cookie->bufptr; ++ ++ memcpy (buf, cookie->buffer + cookie->bufptr, size); ++ cookie->bufptr += size; ++ bytes_read += size; ++ return size; ++} ++ ++static ssize_t ++io_write (void *vcookie, const char *buf, size_t size) ++{ ++ VALIDATE_COOKIE (); ++ FAIL_EXIT1 ("io_write called"); ++} ++ ++static int ++io_seek (void *vcookie, off64_t *position, int whence) ++{ ++ VALIDATE_COOKIE (); ++ FAIL_EXIT1 ("io_seek called"); ++} ++ ++static int ++io_clean (void *vcookie) ++{ ++ struct Cookie *cookie = (struct Cookie *) vcookie; ++ ++ VALIDATE_COOKIE (); ++ ++ cookie->buffer = NULL; ++ cookie->bufsz = 0; ++ cookie->bufptr = 0; ++ ++ cookie_valid = 0; ++ free (cookie); ++ return 0; ++} ++ ++cookie_io_functions_t io_funcs = { ++ .read = io_read, ++ .write = io_write, ++ .seek = io_seek, ++ .close = io_clean ++}; ++ ++FILE * ++io_open (const char *buffer, int buflen, const char *mode, void **vcookie) ++{ ++ FILE *f; ++ struct Cookie *cookie; ++ ++ cookie = (struct Cookie *) xcalloc (1, sizeof (struct Cookie)); ++ *vcookie = cookie; ++ cookie_valid = 1; ++ ++ cookie->buffer = buffer; ++ cookie->bufsz = buflen; ++ bytes_read = 0; ++ ++ f = fopencookie (cookie, mode, io_funcs); ++ if (f == NULL) ++ FAIL_EXIT1 ("fopencookie failed"); ++ ++ clearerr (f); ++ return f; ++} ++ ++/* The test cases. */ ++ ++#define my_open(s,l,m) io_open (s, l, m, (void *) &cookie) ++ ++#define TEST_COMPARE_0x11(buf, len) \ ++ TEST_COMPARE_BLOB (buf + (len), sizeof (buf) - (len), \ ++ buf2, sizeof (buf) - (len)); ++ ++#define check_flags(f, expected_eof, expected_err) \ ++ { \ ++ if (expected_eof) \ ++ TEST_VERIFY (feof (f) != 0); \ ++ else \ ++ TEST_VERIFY (feof (f) == 0); \ ++ if (expected_err) \ ++ TEST_VERIFY (ferror (f) != 0); \ ++ else \ ++ TEST_VERIFY (ferror (f) == 0); \ ++ } ++ ++static int ++do_test (void) ++{ ++ FILE *f; ++ struct Cookie *cookie; ++ char buf [10]; ++ char buf2 [10]; ++ char *returned_string; ++ ++ memset (buf2, 0x11, sizeof (buf2)); ++ ++ printf ("testing base operation...\n"); ++ f = my_open ("hello\n", 6, "r"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == buf); ++ TEST_COMPARE_BLOB (buf, bytes_read + 1, "hello\n\0", 7); ++ TEST_COMPARE_0x11 (buf, bytes_read + 1); ++ check_flags (f, 0, 0); ++ ++ fclose (f); ++ ++ printf ("testing zero size file...\n"); ++ f = my_open ("hello\n", 0, "r"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ check_flags (f, 1, 0); ++ fclose (f); ++ ++ printf ("testing zero size buffer...\n"); ++ f = my_open ("hello\n", 6, "r"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, 0, f); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ check_flags (f, 0, 0); ++ fclose (f); ++ ++ printf ("testing NULL buffer with empty stream...\n"); ++ f = my_open ("hello\n", 0, "r"); ++ memset (buf, 0x11, sizeof (buf)); ++ ++ returned_string = fgets (null, sizeof (buf), f); ++ ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ check_flags (f, 1, 0); ++ fclose (f); ++ ++ printf ("testing embedded NUL...\n"); ++ f = my_open ("hel\0lo\n", 7, "r"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == buf); ++ TEST_COMPARE_BLOB (buf, bytes_read + 1, "hel\0lo\n\0", 8); ++ TEST_COMPARE_0x11 (buf, bytes_read + 1); ++ check_flags (f, 0, 0); ++ fclose (f); ++ ++ printf ("testing writable stream...\n"); ++ f = my_open ("hel\0lo\n", 7, "w"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ check_flags (f, 0, 1); ++ fclose (f); ++ ++ printf ("testing closed fd stream...\n"); ++ int fd = open ("/dev/null", O_RDONLY); ++ f = fdopen (fd, "r"); ++ close (fd); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ check_flags (f, 0, 1); ++ fclose (f); ++ ++#ifdef IO_DEBUG ++ /* These tests only pass if glibc is built with -DIO_DEBUG, but are ++ included for reference. */ ++ ++ printf ("testing NULL descriptor...\n"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, null); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ ++ printf ("testing closed descriptor...\n"); ++ f = my_open ("hello\n", 7, "r"); ++ fclose (f); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++#endif ++ ++ return 0; ++} ++ ++#include diff --git a/glibc.spec b/glibc.spec index d34788e..170bc00 100644 --- a/glibc.spec +++ b/glibc.spec @@ -157,7 +157,7 @@ end \ Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: 128%{?dist} +Release: 129%{?dist} # In general, GPLv2+ is used by programs, LGPLv2+ is used for # libraries. @@ -873,6 +873,7 @@ Patch634: glibc-RHEL-59494-1.patch Patch635: glibc-RHEL-59494-2.patch Patch636: glibc-RHEL-59494-3.patch Patch637: glibc-RHEL-41189.patch +Patch638: glibc-RHEL-46728.patch ############################################################################## # Continued list of core "glibc" package information: @@ -3032,6 +3033,9 @@ update_gconv_modules_cache () %endif %changelog +* Tue Sep 24 2024 DJ Delorie - 2.34-129 +- Add fgets testcases (RHEL-46728) + * Tue Sep 24 2024 DJ Delorie - 2.34-128 - manual: Add Descriptor-Relative Access section (RHEL-41189)