forked from rpms/glibc
		
	Add fgets testcases
Resolves: RHEL-46728
This commit is contained in:
		
							parent
							
								
									2ba780bc6b
								
							
						
					
					
						commit
						cc0b035e01
					
				
							
								
								
									
										287
									
								
								glibc-RHEL-46728.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								glibc-RHEL-46728.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,287 @@ | ||||
| From 4945ffc88a8ad49280bae64165683ddfd12b2390 Mon Sep 17 00:00:00 2001 | ||||
| From: DJ Delorie <dj@redhat.com> | ||||
| 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 <fweimer@redhat.com> | ||||
| 
 | ||||
| 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
 | ||||
| +   <https://www.gnu.org/licenses/>.  */
 | ||||
| +
 | ||||
| +#include <libc-diag.h>
 | ||||
| +#include <stdio.h>
 | ||||
| +#include <error.h>
 | ||||
| +#include <errno.h>
 | ||||
| +#include <limits.h>
 | ||||
| +#include <mcheck.h>
 | ||||
| +#include <stddef.h>
 | ||||
| +#include <stdlib.h>
 | ||||
| +#include <string.h>
 | ||||
| +#include <ctype.h>
 | ||||
| +#include <fcntl.h>
 | ||||
| +#include <unistd.h>
 | ||||
| +#include <sys/types.h>
 | ||||
| +
 | ||||
| +#include <support/support.h>
 | ||||
| +#include <support/check.h>
 | ||||
| +
 | ||||
| +/* 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 <support/test-driver.c>
 | ||||
| @ -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 <dj@redhat.com> - 2.34-129 | ||||
| - Add fgets testcases (RHEL-46728) | ||||
| 
 | ||||
| * Tue Sep 24 2024 DJ Delorie <dj@redhat.com> - 2.34-128 | ||||
| - manual: Add Descriptor-Relative Access section (RHEL-41189) | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user