Improve test coverage (RHEL-106562)

Resolves: RHEL-106562
This commit is contained in:
Arjun Shankar 2025-08-06 15:02:01 +02:00
parent 0d5bc43414
commit 5e0f6b30b8
25 changed files with 5062 additions and 1 deletions

69
glibc-RHEL-106562-1.patch Normal file
View File

@ -0,0 +1,69 @@
commit f942a732d37a96217ef828116ebe64a644db18d7
Author: Joe Talbott <joetalbott@gmail.com>
Date: Tue May 14 14:39:38 2024 +0000
math: Add GLIBC_TEST_LIBM_VERBOSE environment variable support.
Allow the libm-test-driver based tests to have their verbosity set based
on the GLIBC_TEST_LIBM_VERBOSE environment variable. This allows the entire
testsuite to be run with a non-default verbosity.
While here check the conversion for the verbose option as well.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/math/libm-test-support.c b/math/libm-test-support.c
index 1d60ac783be6fb65..0cae545f86ac1352 100644
--- a/math/libm-test-support.c
+++ b/math/libm-test-support.c
@@ -130,7 +130,7 @@ static int noTests; /* number of tests (without testing exceptions) */
static int noExcTests; /* number of tests for exception flags */
static int noErrnoTests;/* number of tests for errno values */
-static int verbose;
+static unsigned int verbose;
static int output_max_error; /* Should the maximal errors printed? */
static int output_points; /* Should the single function results printed? */
static int ignore_max_ulp; /* Should we ignore max_ulp? */
@@ -1057,7 +1057,14 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 'v':
if (optarg)
- verbose = (unsigned int) strtoul (optarg, NULL, 0);
+ {
+ char *optstr_conv = optarg;
+ unsigned int opt_verbose;
+
+ opt_verbose = (unsigned int) strtoul (optarg, &optstr_conv, 0);
+ if (*optstr_conv == '\0' && optstr_conv != optarg)
+ verbose = opt_verbose;
+ }
else
verbose = 3;
break;
@@ -1139,6 +1146,7 @@ libm_test_init (int argc, char **argv)
int remaining;
char *ulps_file_path;
size_t dir_len = 0;
+ char *envstr_verbose;
verbose = 1;
output_ulps = 0;
@@ -1148,6 +1156,17 @@ libm_test_init (int argc, char **argv)
/* XXX set to 0 for releases. */
ignore_max_ulp = 0;
+ envstr_verbose = getenv("GLIBC_TEST_LIBM_VERBOSE");
+ if (envstr_verbose != NULL)
+ {
+ char *envstr_conv = envstr_verbose;
+ unsigned int env_verbose;
+
+ env_verbose = (unsigned int) strtoul (envstr_verbose, &envstr_conv, 0);
+ if (*envstr_conv == '\0' && envstr_conv != envstr_verbose)
+ verbose = env_verbose;
+ }
+
/* Parse and process arguments. */
argp_parse (&argp, argc, argv, 0, &remaining, NULL);

View File

@ -0,0 +1,20 @@
commit 79f44e1a47e87907fb8e97bbd098e01c4adc26a5
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Aug 26 16:45:31 2024 +0200
inet: Avoid label at end of compound statement in tst-if_nameindex
This fails to compile with GCC 8.
diff --git a/inet/tst-if_nameindex.c b/inet/tst-if_nameindex.c
index b025cdb3a7c6b68c..5b905601245bef34 100644
--- a/inet/tst-if_nameindex.c
+++ b/inet/tst-if_nameindex.c
@@ -105,6 +105,7 @@ do_test (void)
TEST_VERIFY (errno == ENODEV);
not_this_one:
+ ;
}

288
glibc-RHEL-106562-11.patch Normal file
View File

@ -0,0 +1,288 @@
commit 4945ffc88a8ad49280bae64165683ddfd12b2390
Author: DJ Delorie <dj@redhat.com>
Date: Wed Aug 7 16:55:16 2024 -0400
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 c822434293b7e809..6b52fd3e0d818960 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -209,6 +209,7 @@ tests := \
tst-fdopen2 \
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 0000000000000000..5b78447ea9aa3cbe
--- /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>

View File

@ -0,0 +1,90 @@
commit 83fd4149ffdae86c8864a6828f39dd942956636f
Author: Aaron Merey <amerey@redhat.com>
Date: Thu Sep 19 11:11:39 2024 -0400
Test that errno is set to 0 at program startup
Add new testcase elf/tst-startup-errno.c which tests that errno is set
to 0 at first ELF constructor execution and at the start of the
program's main function.
Tested for x86_64
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/Makefile b/elf/Makefile
index a46c4f69d98553f7..92da608da1ebc175 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -457,6 +457,7 @@ tests += \
tst-single_threaded-pthread \
tst-sonamemove-dlopen \
tst-sonamemove-link \
+ tst-startup-errno \
tst-thrlock \
tst-tls-dlinfo \
tst-tls-ie \
diff --git a/elf/tst-startup-errno.c b/elf/tst-startup-errno.c
new file mode 100644
index 0000000000000000..59a1005fb674a5c3
--- /dev/null
+++ b/elf/tst-startup-errno.c
@@ -0,0 +1,58 @@
+/* Test the value of errno at program startup.
+ 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Verify that errno is 0 at first ELF constructor execution and at
+ the start of main. */
+
+static void set_ctor_errno (void) __attribute__((constructor));
+static int ctor_errno = -1;
+
+static void
+set_ctor_errno (void)
+{
+ ctor_errno = errno;
+}
+
+static int
+get_ctor_errno (void)
+{
+ return ctor_errno;
+}
+
+int
+main (void)
+{
+ if (errno != 0)
+ {
+ printf ("At start of main errno set to %d != 0\n", errno);
+ exit (1);
+ }
+
+ if (get_ctor_errno () != 0)
+ {
+ printf ("At ctor exec errno set to %d != 0\n", get_ctor_errno ());
+ exit (1);
+ }
+
+ return 0;
+}
+

301
glibc-RHEL-106562-13.patch Normal file
View File

@ -0,0 +1,301 @@
commit cfb35f5f7f32cec8fa4e16b99e35b7d70fa13f1f
Author: DJ Delorie <dj@redhat.com>
Date: Tue Sep 17 22:52:37 2024 -0400
rt: more clock_nanosleep tests
Test that clock_nanosleep rejects out of range time values.
Test that clock_nanosleep actually sleeps for at least the
requested time relative to the requested clock.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/rt/Makefile b/rt/Makefile
index 7b50c64f7664c07f..bc5f28c6d03722a3 100644
--- a/rt/Makefile
+++ b/rt/Makefile
@@ -77,6 +77,7 @@ tests := tst-shm tst-timer tst-timer2 \
tst-bz28213 \
tst-timer3 tst-timer4 tst-timer5 \
tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \
+ tst-clock_nanosleep2 \
tst-shm-cancel \
tst-mqueue10
tests-internal := tst-timer-sigmask
@@ -84,6 +85,7 @@ tests-internal := tst-timer-sigmask
tests-time64 := \
tst-aio6-time64 \
tst-cpuclock2-time64 \
+ tst-clock_nanosleep2-time64 \
tst-mqueue1-time64 \
tst-mqueue2-time64 \
tst-mqueue4-time64 \
diff --git a/rt/tst-clock_nanosleep2-time64.c b/rt/tst-clock_nanosleep2-time64.c
new file mode 100644
index 0000000000000000..8deb4201f38b094a
--- /dev/null
+++ b/rt/tst-clock_nanosleep2-time64.c
@@ -0,0 +1 @@
+#include "tst-clock_nanosleep2.c"
diff --git a/rt/tst-clock_nanosleep2.c b/rt/tst-clock_nanosleep2.c
new file mode 100644
index 0000000000000000..10c822fd54668531
--- /dev/null
+++ b/rt/tst-clock_nanosleep2.c
@@ -0,0 +1,255 @@
+/* Test program for process CPU clocks - invalid inputs, minimum time
+ 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/>. */
+
+/* This test has two primary goals - first, to validate that invalid
+ inputs to clock_nanosleep are caught, and second, to validate that
+ clock_nanosleep sleeps for at least the amount of time requested.
+ It is assumed that the system may sleep for an arbitrary additional
+ amount of time beyond the requested time. */
+
+#include <unistd.h>
+#include <stdint.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <support/xthread.h>
+#include <support/timespec.h>
+
+/* This is 1 ms per test, we have 10 tests, so this file runs in on
+ the order of 0.01 seconds. */
+#define TEST_NSEC 1000000
+
+/* Nanoseconds per second. */
+#define NSECMAX 1000000000L
+
+static pthread_barrier_t barrier;
+
+/* This function is intended to rack up both user and system time. */
+static void *
+chew_cpu (void *arg)
+{
+ pthread_barrier_wait (&barrier);
+
+ while (1)
+ {
+ static volatile char buf[4096];
+ for (int i = 0; i < 100; ++i)
+ for (size_t j = 0; j < sizeof buf; ++j)
+ buf[j] = 0xaa;
+ int nullfd = xopen ("/dev/null", O_WRONLY, 0);
+ for (int i = 0; i < 100; ++i)
+ for (size_t j = 0; j < sizeof buf; ++j)
+ buf[j] = 0xbb;
+ xwrite (nullfd, (char *) buf, sizeof buf);
+ close (nullfd);
+ }
+
+ return NULL;
+}
+
+static void
+ptime_1 (const char *n, struct timespec t)
+{
+ /* This is only for debugging failed test cases. */
+ printf ("%12s: %lld.%09lld\n", n, (long long int) t.tv_sec,
+ (long long int) t.tv_nsec);
+}
+#define ptime(t) ptime_1 (#t, t)
+
+static void
+test_interval_1 (const char *n_clock, clockid_t t_clock)
+{
+ struct timespec me_before, me_after, quantum, me_sleep, me_slept;
+ long long int slept, min_slept;
+
+ /* Arbitrary to ensure our time period is sufficiently bigger than
+ the time step. */
+ TEST_VERIFY (clock_getres (t_clock, &quantum) == 0);
+ printf("Clock quantum: %lld ns, test time: %lld ns\n",
+ (long long int) quantum.tv_nsec, (long long int) TEST_NSEC);
+ TEST_VERIFY (quantum.tv_nsec <= TEST_NSEC / 10);
+
+ min_slept = TEST_NSEC;
+
+ me_sleep = make_timespec (0, min_slept);
+
+ printf ("test clock %s for %lld.%09lld sec relative\n",
+ n_clock, (long long int) me_sleep.tv_sec,
+ (long long int) me_sleep.tv_nsec);
+
+ TEST_COMPARE (clock_gettime (t_clock, &me_before), 0);
+ TEST_COMPARE (clock_nanosleep (t_clock, 0, &me_sleep, NULL), 0);
+ TEST_COMPARE (clock_gettime (t_clock, &me_after), 0);
+
+ me_slept = timespec_sub (me_after, me_before);
+ slept = support_timespec_ns (me_slept);
+
+ ptime (me_before);
+ ptime (me_after);
+ ptime (me_sleep);
+ ptime (me_slept);
+ printf ("test slept %lld nsec >= asked for %lld ?\n", slept, min_slept);
+
+ /* This is the important part - verify that the time slept is at
+ least as much as the time requested. */
+ TEST_VERIFY (slept >= min_slept);
+}
+
+static void
+test_abs_1 (const char *n_clock, clockid_t t_clock)
+{
+ struct timespec me_before, me_after, quantum, me_sleep;
+
+ /* Arbitrary to ensure our time period is sufficiently bigger than
+ the time step. */
+ TEST_VERIFY (clock_getres (t_clock, &quantum) == 0);
+ printf("Clock quantum: %lld ns, test time: %lld ns\n",
+ (long long int) quantum.tv_nsec, (long long int) TEST_NSEC);
+ TEST_VERIFY (quantum.tv_nsec <= TEST_NSEC / 10);
+
+ me_sleep = make_timespec (0, TEST_NSEC);
+
+ printf ("test clock %s for %lld.%09lld sec absolute\n",
+ n_clock, (long long int) me_sleep.tv_sec,
+ (long long int) me_sleep.tv_nsec);
+
+ TEST_COMPARE (clock_gettime (t_clock, &me_before), 0);
+ me_sleep = timespec_add (me_sleep, me_before);
+ TEST_COMPARE (clock_nanosleep (t_clock, TIMER_ABSTIME, &me_sleep, NULL), 0);
+ TEST_COMPARE (clock_gettime (t_clock, &me_after), 0);
+
+ ptime (me_before);
+ ptime (me_sleep);
+ ptime (me_after);
+
+ printf("test slept until %lld.%09lld after requested %lld.%09lld ?\n",
+ (long long int) me_after.tv_sec, (long long int) me_after.tv_nsec,
+ (long long int) me_sleep.tv_sec, (long long int) me_sleep.tv_nsec);
+
+ /* This is the important part - verify that the time slept is at
+ least as much as the time requested. */
+ TEST_TIMESPEC_EQUAL_OR_AFTER (me_after, me_sleep);
+}
+
+static void
+test_invalids_1 (const char *the_clock_name, int the_clock,
+ const char *flags_name, int flags)
+{
+ struct timespec me_before;
+
+ /* Note: do not use make_timespec() in case that function tries to
+ normalize the fields. */
+
+ printf ("%s: %s: test tv 0, 0\n", the_clock_name, flags_name);
+ me_before.tv_sec = 0;
+ me_before.tv_nsec = 0;
+ TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), 0);
+
+ printf ("%s: %s: test tv -1, 0\n", the_clock_name, flags_name);
+ me_before.tv_sec = -1;
+ me_before.tv_nsec = 0;
+ TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL);
+
+ printf ("%s: %s: test tv 0, -1\n", the_clock_name, flags_name);
+ me_before.tv_sec = 0;
+ me_before.tv_nsec = -1;
+ TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL);
+
+ printf ("%s: %s: test tv -1, -1\n", the_clock_name, flags_name);
+ me_before.tv_sec = -1;
+ me_before.tv_nsec = -1;
+ TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL);
+
+ printf ("%s: %s: test tv 0, MAX\n", the_clock_name, flags_name);
+ me_before.tv_sec = 0;
+ me_before.tv_nsec = NSECMAX;
+ TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL);
+}
+
+static int
+do_test (void)
+{
+ pthread_t th;
+
+ pthread_barrier_init (&barrier, NULL, 2);
+
+ /* Test for proper error detection. */
+
+#define test_invalids(c, f) test_invalids_1 (#c, c, #f, f)
+ test_invalids (CLOCK_REALTIME, 0);
+#ifdef CLOCK_TAI
+ test_invalids (CLOCK_TAI, 0);
+#endif
+ test_invalids (CLOCK_MONOTONIC, 0);
+#ifdef CLOCK_BOOTTIME
+ test_invalids (CLOCK_BOOTTIME, 0);
+#endif
+ test_invalids (CLOCK_PROCESS_CPUTIME_ID, 0);
+ test_invalids (CLOCK_REALTIME, TIMER_ABSTIME);
+#ifdef CLOCK_TAI
+ test_invalids (CLOCK_TAI, TIMER_ABSTIME);
+#endif
+ test_invalids (CLOCK_MONOTONIC, TIMER_ABSTIME);
+#ifdef CLOCK_BOOTTIME
+ test_invalids (CLOCK_BOOTTIME, TIMER_ABSTIME);
+#endif
+ test_invalids (CLOCK_PROCESS_CPUTIME_ID, TIMER_ABSTIME);
+
+ /* Test for various clocks "working". */
+
+#define test_interval(c) test_interval_1 (#c, c)
+ test_interval (CLOCK_REALTIME);
+#ifdef CLOCK_TAI
+ test_interval (CLOCK_TAI);
+#endif
+ test_interval (CLOCK_MONOTONIC);
+#ifdef CLOCK_BOOTTIME
+ test_interval (CLOCK_BOOTTIME);
+#endif
+
+ th = xpthread_create (NULL, chew_cpu, NULL);
+ xpthread_barrier_wait (&barrier);
+ test_interval (CLOCK_PROCESS_CPUTIME_ID);
+ xpthread_cancel (th);
+
+#define test_abs(c) test_abs_1 (#c, c)
+ test_abs (CLOCK_REALTIME);
+#ifdef CLOCK_TAI
+ test_abs (CLOCK_TAI);
+#endif
+ test_abs (CLOCK_MONOTONIC);
+#ifdef CLOCK_BOOTTIME
+ test_abs (CLOCK_BOOTTIME);
+#endif
+
+ th = xpthread_create (NULL, chew_cpu, NULL);
+ xpthread_barrier_wait (&barrier);
+ test_abs (CLOCK_PROCESS_CPUTIME_ID);
+ xpthread_cancel (th);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -0,0 +1,18 @@
commit 1895a35e7092713b224166d36b9bc26e8eb3371f
Author: DJ Delorie <dj@redhat.com>
Date: Tue Oct 8 14:30:21 2024 -0400
rt: more clock_nanosleep tests addendum
Forgot to change the first-line description.
diff --git a/rt/tst-clock_nanosleep2.c b/rt/tst-clock_nanosleep2.c
index 10c822fd54668531..e9b2a2716d6e9016 100644
--- a/rt/tst-clock_nanosleep2.c
+++ b/rt/tst-clock_nanosleep2.c
@@ -1,4 +1,4 @@
-/* Test program for process CPU clocks - invalid inputs, minimum time
+/* Test for clock_nanosleep parameter checks and sleep duration.
Copyright (C) 2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.

218
glibc-RHEL-106562-15.patch Normal file
View File

@ -0,0 +1,218 @@
commit 99671e72bb27a3cb98860bdc4c0e25961ce96b3e
Author: Joseph Myers <josmyers@redhat.com>
Date: Fri Nov 22 16:58:51 2024 +0000
Add multithreaded test of sem_getvalue
Test coverage of sem_getvalue is fairly limited. Add a test that runs
it on threads on each CPU. For this purpose I adapted
tst-skeleton-thread-affinity.c; it didn't seem very suitable to use
as-is or include directly in a different test doing things per-CPU,
but did seem a suitable starting point (thus sharing
tst-skeleton-affinity.c) for such testing.
Tested for x86_64.
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index eee91c7b64d79fe7..47bf050759bd2b4e 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -653,6 +653,7 @@ ifeq ($(subdir),nptl)
tests += \
tst-align-clone \
tst-getpid1 \
+ tst-sem_getvalue-affinity \
# tests
# tst-rseq-nptl is an internal test because it requires a definition of
diff --git a/sysdeps/unix/sysv/linux/tst-sem_getvalue-affinity.c b/sysdeps/unix/sysv/linux/tst-sem_getvalue-affinity.c
new file mode 100644
index 0000000000000000..4176f67533357909
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-sem_getvalue-affinity.c
@@ -0,0 +1,185 @@
+/* Test sem_getvalue across CPUs. Based on tst-skeleton-thread-affinity.c.
+ Copyright (C) 2015-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 <errno.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <support/xthread.h>
+#include <sys/time.h>
+
+struct conf;
+static bool early_test (struct conf *);
+
+static int
+setaffinity (size_t size, const cpu_set_t *set)
+{
+ int ret = pthread_setaffinity_np (pthread_self (), size, set);
+ if (ret != 0)
+ {
+ errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+static int
+getaffinity (size_t size, cpu_set_t *set)
+{
+ int ret = pthread_getaffinity_np (pthread_self (), size, set);
+ if (ret != 0)
+ {
+ errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+#include "tst-skeleton-affinity.c"
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static sem_t sem;
+
+static void *
+tf (void *arg)
+{
+ void *ret = NULL;
+ xpthread_mutex_lock (&lock);
+ int semval;
+ if (sem_getvalue (&sem, &semval) != 0)
+ {
+ printf ("sem_getvalue failed: %m\n");
+ ret = (void *) 1;
+ }
+ else if (semval != 12345)
+ {
+ printf ("sem_getvalue returned %d not 12345\n", semval);
+ ret = (void *) 1;
+ }
+ xpthread_mutex_unlock (&lock);
+ return ret;
+}
+
+static int
+stop_and_join_threads (struct conf *conf, cpu_set_t *set,
+ pthread_t *pinned_first, pthread_t *pinned_last)
+{
+ int failed = 0;
+ for (pthread_t *p = pinned_first; p < pinned_last; ++p)
+ {
+ int cpu = p - pinned_first;
+ if (!CPU_ISSET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), set))
+ continue;
+
+ void *retval = (void *) 1;
+ int ret = pthread_join (*p, &retval);
+ if (ret != 0)
+ {
+ printf ("error: Failed to join thread %d: %s\n", cpu, strerror (ret));
+ fflush (stdout);
+ /* Cannot shut down cleanly with threads still running. */
+ abort ();
+ }
+ if (retval != NULL)
+ failed = 1;
+ }
+ return failed;
+}
+
+static bool
+early_test (struct conf *conf)
+{
+ int ret;
+ ret = sem_init (&sem, 0, 12345);
+ if (ret != 0)
+ {
+ printf ("error: sem_init failed: %m\n");
+ return false;
+ }
+ xpthread_mutex_lock (&lock);
+ pthread_t *pinned_threads
+ = calloc (conf->last_cpu + 1, sizeof (*pinned_threads));
+ cpu_set_t *initial_set = CPU_ALLOC (conf->set_size);
+ cpu_set_t *scratch_set = CPU_ALLOC (conf->set_size);
+
+ if (pinned_threads == NULL || initial_set == NULL || scratch_set == NULL)
+ {
+ puts ("error: Memory allocation failure");
+ return false;
+ }
+ if (getaffinity (CPU_ALLOC_SIZE (conf->set_size), initial_set) < 0)
+ {
+ printf ("error: pthread_getaffinity_np failed: %m\n");
+ return false;
+ }
+
+ pthread_attr_t attr;
+ ret = pthread_attr_init (&attr);
+ if (ret != 0)
+ {
+ printf ("error: pthread_attr_init failed: %s\n", strerror (ret));
+ return false;
+ }
+ support_set_small_thread_stack_size (&attr);
+
+ /* Spawn a thread pinned to each available CPU. */
+ for (int cpu = 0; cpu <= conf->last_cpu; ++cpu)
+ {
+ if (!CPU_ISSET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), initial_set))
+ continue;
+ CPU_ZERO_S (CPU_ALLOC_SIZE (conf->set_size), scratch_set);
+ CPU_SET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), scratch_set);
+ ret = pthread_attr_setaffinity_np
+ (&attr, CPU_ALLOC_SIZE (conf->set_size), scratch_set);
+ if (ret != 0)
+ {
+ printf ("error: pthread_attr_setaffinity_np for CPU %d failed: %s\n",
+ cpu, strerror (ret));
+ stop_and_join_threads (conf, initial_set,
+ pinned_threads, pinned_threads + cpu);
+ return false;
+ }
+ ret = pthread_create (pinned_threads + cpu, &attr,
+ tf, (void *) (uintptr_t) cpu);
+ if (ret != 0)
+ {
+ printf ("error: pthread_create for CPU %d failed: %s\n",
+ cpu, strerror (ret));
+ stop_and_join_threads (conf, initial_set,
+ pinned_threads, pinned_threads + cpu);
+ return false;
+ }
+ }
+
+ /* Main thread. */
+ xpthread_mutex_unlock (&lock);
+ int failed = stop_and_join_threads (conf, initial_set,
+ pinned_threads,
+ pinned_threads + conf->last_cpu + 1);
+
+ printf ("info: Main thread ran on %d CPU(s) of %d available CPU(s)\n",
+ CPU_COUNT_S (CPU_ALLOC_SIZE (conf->set_size), scratch_set),
+ CPU_COUNT_S (CPU_ALLOC_SIZE (conf->set_size), initial_set));
+
+ pthread_attr_destroy (&attr);
+ CPU_FREE (scratch_set);
+ CPU_FREE (initial_set);
+ free (pinned_threads);
+ return failed == 0;
+}

View File

@ -0,0 +1,65 @@
commit 4b7cfcc3fbfab55a1bbb32a2da69c048060739d6
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Nov 25 17:32:54 2024 +0100
debug: Wire up tst-longjmp_chk3
The test was added in commit ac8cc9e300a002228eb7e660df3e7b333d9a7414
without all the required Makefile scaffolding. Tweak the test
so that it actually builds (including with dynamic SIGSTKSZ).
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/debug/Makefile b/debug/Makefile
index 3903cc97a3706354..76c311d2845df9c1 100644
--- a/debug/Makefile
+++ b/debug/Makefile
@@ -287,6 +287,7 @@ tests = \
tst-fortify-wide \
tst-longjmp_chk \
tst-longjmp_chk2 \
+ tst-longjmp_chk3 \
tst-realpath-chk \
tst-sprintf-fortify-rdonly \
tst-sprintf-fortify-unchecked \
diff --git a/debug/tst-longjmp_chk3.c b/debug/tst-longjmp_chk3.c
index 9ff99772075926ce..7bf1646b354fd2fe 100644
--- a/debug/tst-longjmp_chk3.c
+++ b/debug/tst-longjmp_chk3.c
@@ -18,9 +18,12 @@
#include <setjmp.h>
#include <signal.h>
+#include <stdio.h>
#include <string.h>
-static char buf[SIGSTKSZ * 4];
+#include <support/support.h>
+
+static char *buf;
static jmp_buf jb;
static void
@@ -49,8 +52,10 @@ do_test (void)
set_fortify_handler (handler);
/* Create a valid signal stack and enable it. */
+ size_t bufsize = SIGSTKSZ * 4;
+ buf = xmalloc (bufsize);
ss.ss_sp = buf;
- ss.ss_size = sizeof (buf);
+ ss.ss_size = bufsize;
ss.ss_flags = 0;
if (sigaltstack (&ss, NULL) < 0)
{
@@ -65,8 +70,8 @@ do_test (void)
/* Shrink the signal stack so the jmpbuf is now invalid.
We adjust the start & end to handle stacks that grow up & down. */
- ss.ss_sp = buf + sizeof (buf) / 2;
- ss.ss_size = sizeof (buf) / 4;
+ ss.ss_sp = buf + bufsize / 2;
+ ss.ss_size = bufsize / 4;
if (sigaltstack (&ss, NULL) < 0)
{
printf ("second sigaltstack failed: %m\n");

View File

@ -0,0 +1,20 @@
commit 4836a9af89f1b4d482e6c72ff67e36226d36434c
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Nov 26 19:26:13 2024 +0100
debug: Fix tst-longjmp_chk3 build failure on Hurd
Explicitly include <unistd.h> for _exit and getpid.
diff --git a/debug/tst-longjmp_chk3.c b/debug/tst-longjmp_chk3.c
index 7bf1646b354fd2fe..9b9db3b9e9e37d54 100644
--- a/debug/tst-longjmp_chk3.c
+++ b/debug/tst-longjmp_chk3.c
@@ -20,6 +20,7 @@
#include <signal.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include <support/support.h>

111
glibc-RHEL-106562-18.patch Normal file
View File

@ -0,0 +1,111 @@
commit bde47662b74b883149c3001e2c052dea5d3cd92f
Author: Sergey Kolosov <skolosov@redhat.com>
Date: Wed Nov 6 15:24:06 2024 +0100
nptl: Add new test for pthread_spin_trylock
Add a threaded test for pthread_spin_trylock attempting to lock already
acquired spin lock and checking for correct return code.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index 04ea56559ef3a79b..8c80b7a606da4c94 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -265,6 +265,7 @@ tests += \
tst-spin2 \
tst-spin3 \
tst-spin4 \
+ tst-spin5 \
tst-stack1 \
tst-stdio1 \
tst-stdio2 \
diff --git a/sysdeps/pthread/tst-spin5.c b/sysdeps/pthread/tst-spin5.c
new file mode 100644
index 0000000000000000..5c23bd48ef27b3ce
--- /dev/null
+++ b/sysdeps/pthread/tst-spin5.c
@@ -0,0 +1,82 @@
+/* Threaded test the pthread_spin_trylock function.
+ 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 <stdio.h>
+#include <errno.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <support/xthread.h>
+
+pthread_spinlock_t lock;
+
+void *
+thread (void *arg)
+{
+ int ret;
+ int thr_id = *(int *) arg;
+
+ ret = pthread_spin_trylock (&lock);
+ if (thr_id == 1)
+ /* thread with already acquired lock. */
+ {
+ if (ret != EBUSY)
+ {
+ FAIL_EXIT1 ("pthread_spin_trylock should fail with EBUSY");
+ }
+ }
+ else if (thr_id == 2)
+ /* thread with released spin lock. */
+ {
+ if (ret != 0)
+ {
+ FAIL_EXIT1 ("pthread_spin_trylock should be able to acquire lock");
+ }
+ }
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ pthread_t thr1, thr2;
+ int ret;
+ int thr1_id = 1, thr2_id = 2;
+
+ pthread_spin_init (&lock, PTHREAD_PROCESS_PRIVATE);
+ /* lock spin in main thread. */
+ ret = pthread_spin_trylock (&lock);
+ if (ret != 0)
+ {
+ FAIL_EXIT1 ("Main thread should be able to acquire spin lock");
+ }
+
+ /* create first thread to try locking already acquired spin lock. */
+ thr1 = xpthread_create (NULL, thread, &thr1_id);
+ xpthread_join (thr1);
+
+ /* release spin lock and create thread to acquire released spin lock. */
+ pthread_spin_unlock (&lock);
+ thr2 = xpthread_create (NULL, thread, &thr2_id);
+ xpthread_join (thr2);
+
+ pthread_spin_destroy (&lock);
+ return 0;
+}
+
+#include <support/test-driver.c>

575
glibc-RHEL-106562-19.patch Normal file
View File

@ -0,0 +1,575 @@
commit 45c42b65c29422b773ac94771aa71165e245f8f8
Author: Martin Coufal <mcoufal@redhat.com>
Date: Thu Jan 23 13:04:06 2025 +0100
Add new tests for fopen
Adding some basic tests for fopen, testing different modes, stream
positioning and concurrent read/write operation on files.
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 6b52fd3e0d818960..f44562df75cb98bc 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -215,6 +215,7 @@ tests := \
tst-fmemopen2 \
tst-fmemopen3 \
tst-fmemopen4 \
+ tst-fopen \
tst-fphex \
tst-fphex-wide \
tst-fread \
diff --git a/stdio-common/tst-fopen.c b/stdio-common/tst-fopen.c
new file mode 100644
index 0000000000000000..8c1fefd116f9f581
--- /dev/null
+++ b/stdio-common/tst-fopen.c
@@ -0,0 +1,279 @@
+/* Basic test for fopen.
+ Copyright (C) 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 <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/xstdio.h>
+
+#define APPENDED_TEXT "This is appended text. "
+#define DEFAULT_TEXT "Lorem ipsum dolor sit amet, consectetur " \
+ "adipiscing elit, sed do eiusmod tempor incididunt ut labore et " \
+ "dolore magna aliqua."
+#define MAX_BUFFER_SIZE 300
+
+
+static int
+do_test (void)
+{
+ char *temp_file;
+ FILE *fd_file = NULL;
+ char read_buffer[MAX_BUFFER_SIZE] = "";
+ size_t ret;
+
+ /* Prepare files. */
+ int fd = create_temp_file ("tst-fopen.", &temp_file);
+ TEST_VERIFY_EXIT (fd != -1);
+ fd_file = fdopen (fd, "w");
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ xfclose (fd_file);
+
+ /* Test 1: This checks for fopen with mode "r". Open text file for
+ reading. The stream is positioned at the beginning of the file. */
+ printf ("Test 1: This checks for fopen with mode \"r\".\n");
+ fd_file = fopen (temp_file, "r");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+ /* Read should succeed. */
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT) == 0);
+ /* Write should fail. */
+ errno = 0;
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
+ TEST_VERIFY (ferror (fd_file) != 0);
+ TEST_COMPARE (errno, EBADF);
+ TEST_COMPARE (ret, 0);
+ clearerr (fd_file);
+ /* Opening non-existent file should fail. */
+ xfclose (fd_file);
+ errno = 0;
+ fd_file = fopen ("file-that-does-not-exist", "r");
+ TEST_VERIFY (fd_file == NULL);
+ TEST_COMPARE (errno, ENOENT);
+ TEST_VERIFY (fd_file == NULL);
+
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 2: This checks for fopen with mode "r+". Open for reading and
+ writing. The stream is positioned at the beginning of the file. */
+ printf ("Test 2: This checks for fopen with mode \"r+\".\n");
+ fd_file = fopen (temp_file, "r+");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+ /* Read should succeed. */
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT) == 0);
+ fflush (fd_file);
+ /* File position indicator expected at 0 + read bytes. */
+ TEST_COMPARE (ftell (fd_file), ret);
+ /* Write should succeed. */
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ /* Opening non-existent file should fail. */
+ xfclose (fd_file);
+ errno = 0;
+ fd_file = fopen ("file-that-does-not-exist", "r+");
+ TEST_VERIFY (fd_file == NULL);
+ TEST_COMPARE (errno, ENOENT);
+ TEST_VERIFY (fd_file == NULL);
+
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 3: This checks for fopen with mode "w". Truncate file to zero
+ length or create text file for writing. The stream is positioned
+ at the beginning of the file. */
+ printf ("Test 3: This checks for fopen with mode \"w\".\n");
+ fd_file = fopen (temp_file, "w");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+ /* Read should fail. */
+ errno = 0;
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_VERIFY (ferror (fd_file) != 0);
+ TEST_COMPARE (errno, EBADF);
+ TEST_COMPARE (ret, 0);
+ clearerr (fd_file);
+ /* Write should succeed. */
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ /* Opening non-existent file should succeed. */
+ xfclose (fd_file);
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "w");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+
+ xfclose (fd_file);
+ remove ("/tmp/file-that-does-not-exist");
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 4: This checks for fopen with mode "w+". Open for reading and
+ writing. The file is created if it does not exist, otherwise it is
+ truncated. The stream is positioned at the beginning of the file.
+ */
+ printf ("Test 4: This checks for fopen with mode \"w+\".\n");
+ fd_file = fopen (temp_file, "w+");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+ /* Read should succeed. */
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, 0);
+ TEST_VERIFY (read_buffer[0] == '\0');
+ /* Write should succeed. */
+ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT));
+ /* Opening non-existent file should succeed. */
+ xfclose (fd_file);
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "w+");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+
+ xfclose (fd_file);
+ remove ("/tmp/file-that-does-not-exist");
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 5: This checks for fopen with mode "a". Open for appending
+ (writing at end of file). The file is created if it does not
+ exist. The stream is positioned at the end of the file. */
+ printf ("Test 5: This checks for fopen with mode \"a\".\n");
+ fd_file = fopen (temp_file, "a");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), strlen (DEFAULT_TEXT));
+ /* Read should fail. */
+ errno = 0;
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_VERIFY (ferror (fd_file) != 0);
+ TEST_COMPARE (errno, EBADF);
+ TEST_COMPARE (ret, 0);
+ clearerr (fd_file);
+ /* Write should succeed. */
+ ret = fwrite (APPENDED_TEXT, sizeof (char), strlen (APPENDED_TEXT), fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (APPENDED_TEXT));
+ /* The file position indicator for the stream is advanced by the
+ * number of bytes successfully read or written. */
+ TEST_COMPARE (ftell (fd_file), strlen (DEFAULT_TEXT) + ret);
+ /* Opening non-existent file should succeed. */
+ xfclose (fd_file);
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "a");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+
+ xfclose (fd_file);
+ remove ("/tmp/file-that-does-not-exist");
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 6: This checks for fopen with mode "a+". Open for reading and
+ appending (writing at end of file). The file is created if it does
+ not exist. Output is always appended to the end of the file. The
+ initial file position for reading is at the beginning of the file,
+ but it is advanced to the end prior to each write. */
+ printf ("Test 6: This checks for fopen with mode \"a+\".\n");
+ errno = 0;
+ fd_file = fopen (temp_file, "a+");
+ TEST_COMPARE (errno, 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+ /* Read should succeed. */
+ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (DEFAULT_TEXT) + strlen (APPENDED_TEXT));
+ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT APPENDED_TEXT) == 0);
+ /* Write should succeed. */
+ const char* SECOND_APPEND = "This is second append.";
+ ret = fwrite (SECOND_APPEND, sizeof (char), strlen (SECOND_APPEND), fd_file);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_COMPARE (ret, strlen (SECOND_APPEND));
+ /* The file position indicator for the stream is advanced by the
+ number of bytes successfully read or written. */
+ TEST_COMPARE (ftell (fd_file),
+ strlen (DEFAULT_TEXT) + strlen (APPENDED_TEXT) + ret);
+ /* Opening non-existent file should succeed. */
+ xfclose (fd_file);
+ fd_file = fopen ("/tmp/file-that-does-not-exist", "a+");
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ TEST_COMPARE (ftell (fd_file), 0);
+
+ xfclose (fd_file);
+ remove ("/tmp/file-that-does-not-exist");
+ memset (read_buffer, 0, MAX_BUFFER_SIZE);
+
+ /* Test 7: This checks for fopen with other valid modes set, such as
+ "rc", "we" or "am". The test calls fopen with these modes and
+ checks that no errors appear. */
+ printf ("Test 7: This checks for fopen with other valid modes set, "
+ "such as \"rc\", \"we\" or \"am\".\n");
+ /* These modes all operate correctly with the file already present. */
+ static const char *valid_modes[] =
+ { "rc", "we", "am", "r+x", "wb+", "ab", 0 };
+ const char **p = valid_modes;
+ while (*p != 0)
+ {
+ fd_file = fopen (temp_file, *p);
+ TEST_COMPARE (ferror (fd_file), 0);
+ TEST_VERIFY (fd_file != NULL);
+ xfclose (fd_file);
+ ++p;
+ }
+
+ /* Test 8: This checks for fopen with invalid modes. The test calls
+ fopen with these modes and checks that opening existing files with
+ invalid mode fails and that opening non-existing files with invalid
+ mode doesn't create a new file. */
+ printf ("Test 8: This checks for fopen with invalid modes.\n");
+ static const char *invalid_modes[] = { "0", "tr", "z", "x", " ", 0 };
+ p = invalid_modes;
+ while (*p != 0)
+ {
+ errno = 0;
+ fd_file = fopen (temp_file, *p);
+ TEST_VERIFY (fd_file == NULL);
+ TEST_COMPARE (errno, EINVAL);
+ errno = 0;
+ fd_file = fopen ("/tmp/file-that-does-not-exist", *p);
+ TEST_VERIFY (fd_file == NULL);
+ TEST_COMPARE (errno, EINVAL);
+ ++p;
+ TEST_VERIFY (access ("/tmp/file-that-does-not-exist", F_OK) == -1);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
index 8c80b7a606da4c94..ef3035cea8e1344b 100644
--- a/sysdeps/pthread/Makefile
+++ b/sysdeps/pthread/Makefile
@@ -154,6 +154,7 @@ tests += \
tst-exit3 \
tst-flock1 \
tst-flock2 \
+ tst-fopen-threaded \
tst-fork1 \
tst-fork2 \
tst-fork3 \
diff --git a/sysdeps/pthread/tst-fopen-threaded.c b/sysdeps/pthread/tst-fopen-threaded.c
new file mode 100644
index 0000000000000000..5c792c93e3711621
--- /dev/null
+++ b/sysdeps/pthread/tst-fopen-threaded.c
@@ -0,0 +1,250 @@
+/* Test for fread and fwrite with multiple threads.
+ Copyright (C) 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/>. */
+
+/* Description of test intent.
+ The test creates NUM_THREADS threads for reading and writing to the
+ prepared file. The prepared file contains 'NUM_THREADS - 1' bytes
+ where each byte is unique number from 0 to 'NUM_THREADS - 2'. If all
+ operations are correctly multi-threaded safe then all concurent read
+ operations should succeed and read a unique 1 byte value. The last
+ thread to read should get an EOF. In concurrent write, all write
+ operations should succeed and the file should contain all unique 1
+ byte values from 0 to 'NUM_THREADS - 1'. Both concurrent read and
+ concurrent write tests are repeated ITERS times to increase
+ the probability of detecting concurrency issues. */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/xstdio.h>
+#include <support/xthread.h>
+
+#define NUM_THREADS 100
+#define ITERS 10
+
+char *temp_file;
+pthread_barrier_t barrier;
+
+struct thread_data
+{
+ FILE *fd;
+ /* Read value or value to be written. */
+ unsigned char value;
+ bool eof;
+};
+
+static void *
+threadReadRoutine (void *argv)
+{
+ struct thread_data *my_data;
+ unsigned char read_buffer;
+ int ret = 0;
+ my_data = (struct thread_data *) argv;
+ /* Wait for all threads to be ready to read. */
+ xpthread_barrier_wait (&barrier);
+
+ ret =
+ fread (&read_buffer, sizeof (char), sizeof (read_buffer), my_data->fd);
+ if (feof (my_data->fd) != 0)
+ {
+ clearerr (my_data->fd);
+ my_data->eof = true;
+ }
+ else
+ {
+ TEST_COMPARE (ret, 1);
+ /* Save the read value. */
+ my_data->value = read_buffer;
+ }
+ TEST_COMPARE (ferror (my_data->fd), 0);
+ return NULL;
+}
+
+void *
+threadWriteRoutine (void *argv)
+{
+ struct thread_data *my_data;
+ int ret = 0;
+ my_data = (struct thread_data *) argv;
+ /* Wait for all threads to be ready to write. */
+ xpthread_barrier_wait (&barrier);
+
+ ret = fwrite (&my_data->value, sizeof (unsigned char), 1, my_data->fd);
+ TEST_COMPARE (ferror (my_data->fd), 0);
+ TEST_COMPARE (feof (my_data->fd), 0);
+ TEST_COMPARE (ret, 1);
+ return NULL;
+}
+
+void *
+threadOpenCloseRoutine (void *argv)
+{
+ /* Wait for all threads to be ready to call fopen and fclose. */
+ xpthread_barrier_wait (&barrier);
+
+ FILE *fd = xfopen ("/tmp/openclosetest", "w+");
+ xfclose (fd);
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ FILE *fd_file = NULL;
+ unsigned char buffer[NUM_THREADS] = "0";
+ size_t ret = 0;
+ pthread_t threads[NUM_THREADS];
+ struct thread_data thread_data_array[NUM_THREADS];
+ bool present_values[NUM_THREADS] = { false };
+
+ /* Prepare files. */
+ for (int i = 0; i < NUM_THREADS; i++)
+ buffer[i] = i;
+ int fd = create_temp_file ("tst-fopen.", &temp_file);
+ TEST_VERIFY_EXIT (fd != -1);
+ fd_file = fdopen (fd, "w");
+ /* NUM_THREADS - 1: last thread will read EOF */
+ ret = fwrite (buffer, sizeof (unsigned char), NUM_THREADS - 1, fd_file);
+ TEST_COMPARE (ret, NUM_THREADS - 1);
+ xfclose (fd_file);
+
+ /* Test 1: Concurrent read. */
+ for (int reps = 1; reps <= ITERS; reps++)
+ {
+ fd_file = xfopen (temp_file, "r");
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ thread_data_array[i].fd = fd_file;
+ /* Initialize with highest possible value so it's easier to debug if
+ anything goes wrong. */
+ thread_data_array[i].value = 255;
+ thread_data_array[i].eof = false;
+
+ threads[i] =
+ xpthread_create (support_small_stack_thread_attribute (),
+ threadReadRoutine,
+ (void *) &thread_data_array[i]);
+ }
+
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ xpthread_join (threads[i]);
+ }
+ xpthread_barrier_destroy (&barrier);
+ xfclose (fd_file);
+
+ /* Verify read values. */
+ int eof_cnt = 0;
+ for (int i = 0; i < NUM_THREADS; i++)
+ present_values[i] = false;
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ if (thread_data_array[i].eof)
+ {
+ /* EOF was read. */
+ present_values[NUM_THREADS - 1] = true;
+ eof_cnt++;
+ }
+ else
+ {
+ /* The same value shouldn't be read twice. */
+ TEST_VERIFY (!present_values[thread_data_array[i].value]);
+ present_values[thread_data_array[i].value] = true;
+ }
+ }
+ /* EOF is read exactly once. */
+ TEST_COMPARE (eof_cnt, 1);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ /* All values should be read. */
+ TEST_VERIFY (present_values[i]);
+ }
+ }
+
+ /* Test 2: Concurrent write. */
+ for (int reps = 1; reps <= ITERS; reps++)
+ {
+ fd_file = xfopen (temp_file, "w");
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ thread_data_array[i].fd = fd_file;
+ thread_data_array[i].value = i;
+
+ threads[i] =
+ xpthread_create (support_small_stack_thread_attribute (),
+ threadWriteRoutine,
+ (void *) &thread_data_array[i]);
+ }
+
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ xpthread_join (threads[i]);
+ }
+ xpthread_barrier_destroy (&barrier);
+ xfclose (fd_file);
+
+ /* Verify written values. */
+ for (int i = 0; i < NUM_THREADS; i++)
+ present_values[i] = false;
+ memset (buffer, 0, NUM_THREADS);
+ fd_file = xfopen (temp_file, "r");
+ ret = fread (buffer, sizeof (unsigned char), NUM_THREADS, fd_file);
+ TEST_COMPARE (ret, NUM_THREADS);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ /* The same value shouldn't be written twice. */
+ TEST_VERIFY (!present_values[buffer[i]]);
+ present_values[buffer[i]] = true;
+ }
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ /* All values should be written. */
+ TEST_VERIFY (present_values[i]);
+ }
+ xfclose (fd_file);
+ }
+
+ /* Test 3: Concurrent open/close. */
+ for (int reps = 1; reps <= ITERS; reps++)
+ {
+ xpthread_barrier_init (&barrier, NULL, NUM_THREADS);
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ threads[i] =
+ xpthread_create (support_small_stack_thread_attribute (),
+ threadOpenCloseRoutine, NULL);
+ }
+ for (int i = 0; i < NUM_THREADS; i++)
+ {
+ xpthread_join (threads[i]);
+ }
+ xpthread_barrier_destroy (&barrier);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>

529
glibc-RHEL-106562-2.patch Normal file
View File

@ -0,0 +1,529 @@
commit ae18044f95271ed422ed847bd8d8c6d8e84674ce
Author: Joe Simmons-Talbott <josimmon@redhat.com>
Date: Mon May 20 14:09:35 2024 +0000
math: Add more details to the test driver output.
Add start and end indicators that identify the test being run in the
verbose output. Better identify the tests for max errors in the
summary output. Count each exception checked for each test. Remove
double counting of tests for the check_<type> functions other than
check_float_internal. Rename print_max_error and
print_complex_max_error to check_max_error and check_complex_max_error
respectively since they have side effects.
Co-Authored-By: Carlos O'Donell <carlos@redhat.com>
Reviewed-By: Joseph Myers <josmyers@redhat.com>
diff --git a/math/libm-test-driver.c b/math/libm-test-driver.c
index 3356f9b10d7f364e..dfb56e8cde13519a 100644
--- a/math/libm-test-driver.c
+++ b/math/libm-test-driver.c
@@ -1083,9 +1083,9 @@ struct test_Ff_b1_data
= STR_CON3 (FUN, SUFF, TEST_SUFF) TEST_SUFF_STR; \
init_max_error (this_func, EXACT, TEST_COND_any_ibm128)
#define END \
- print_max_error (this_func)
+ check_max_error (this_func)
#define END_COMPLEX \
- print_complex_max_error (this_func)
+ check_complex_max_error (this_func)
/* Run tests for a given function in all rounding modes. */
#define ALL_RM_TEST(FUNC, EXACT, ARRAY, LOOP_MACRO, END_MACRO, ...) \
diff --git a/math/libm-test-support.c b/math/libm-test-support.c
index 0cae545f86ac1352..0796f9d4956e3818 100644
--- a/math/libm-test-support.c
+++ b/math/libm-test-support.c
@@ -112,6 +112,7 @@
#include <argp.h>
#include <errno.h>
#include <string.h>
+#include <assert.h>
/* This header defines func_ulps, func_real_ulps and func_imag_ulps
arrays. */
@@ -125,10 +126,13 @@ static FILE *ulps_file; /* File to document difference. */
static int output_ulps; /* Should ulps printed? */
static char *output_dir; /* Directory where generated files will be written. */
-static int noErrors; /* number of errors */
-static int noTests; /* number of tests (without testing exceptions) */
-static int noExcTests; /* number of tests for exception flags */
-static int noErrnoTests;/* number of tests for errno values */
+#define TEST_INPUT 1
+#define TEST_MAXERROR 2
+static int noErrors; /* number of errors */
+static int noTests; /* number of tests (without testing exceptions) */
+static int noMaxErrorTests; /* number of max error tests */
+static int noExcTests; /* number of tests for exception flags */
+static int noErrnoTests; /* number of tests for errno values */
static unsigned int verbose;
static int output_max_error; /* Should the maximal errors printed? */
@@ -299,9 +303,19 @@ print_screen_max_error (int ok)
/* Update statistic counters. */
static void
-update_stats (int ok)
+update_stats (int ok, int testType)
{
- ++noTests;
+ switch (testType)
+ {
+ case TEST_INPUT:
+ ++noTests;
+ break;
+ case TEST_MAXERROR:
+ ++noMaxErrorTests;
+ break;
+ default:
+ abort();
+ }
if (!ok)
++noErrors;
}
@@ -367,11 +381,30 @@ fpstack_test (const char *test_name)
#endif
}
+static void
+print_test_start (int test_num, const char *test_name, int test_type)
+{
+ if (print_screen (1))
+ printf ("--- Start of%s test # %d, named \"%s\" ---\n",
+ test_type == TEST_MAXERROR ? " max error" : "", test_num, test_name);
+}
+static void
+print_test_end (int test_num, const char *test_name, int test_type)
+{
+ if (print_screen (1))
+ printf ("--- End of%s test # %d, named \"%s\" ---\n",
+ test_type == TEST_MAXERROR ? " max error" : "", test_num, test_name);
+}
+
+/* This is a builtin test of overall max error. */
void
-print_max_error (const char *func_name)
+check_max_error (const char *func_name)
{
int ok = 0;
+ int thisTest = noMaxErrorTests;
+
+ print_test_start (thisTest, func_name, TEST_MAXERROR);
if (max_error == 0.0 || (max_error <= prev_max_error && !ignore_max_ulp))
{
@@ -392,14 +425,19 @@ print_max_error (const char *func_name)
printf (" accepted: %s ulp\n", pmestr);
}
- update_stats (ok);
-}
+ update_stats (ok, TEST_MAXERROR);
+ print_test_end (thisTest, func_name, TEST_MAXERROR);
+}
+/* This is a builtin test of overall max error. */
void
-print_complex_max_error (const char *func_name)
+check_complex_max_error (const char *func_name)
{
int real_ok = 0, imag_ok = 0, ok;
+ int thisTest = noMaxErrorTests;
+
+ print_test_start (thisTest, func_name, TEST_MAXERROR);
if (real_max_error == 0
|| (real_max_error <= prev_real_max_error && !ignore_max_ulp))
@@ -436,7 +474,8 @@ print_complex_max_error (const char *func_name)
printf (" accepted: %s ulp\n", pimestr);
}
- update_stats (ok);
+ update_stats (ok, TEST_MAXERROR);
+ print_test_end (thisTest, func_name, TEST_MAXERROR);
}
@@ -477,12 +516,13 @@ test_single_exception (const char *test_name,
else
{
if (print_screen (1))
- printf ("%s: Exception \"%s\" not set\n", test_name,
+ printf ("Pass: %s: Exception \"%s\" not set\n", test_name,
flag_name);
}
}
if (!ok)
++noErrors;
+ ++noExcTests;
}
#endif
@@ -494,23 +534,32 @@ test_exceptions (const char *test_name, int exception)
{
if (flag_test_exceptions && EXCEPTION_TESTS (FLOAT))
{
- ++noExcTests;
+ int ran = 0;
#ifdef FE_DIVBYZERO
if ((exception & DIVIDE_BY_ZERO_EXCEPTION_OK) == 0)
- test_single_exception (test_name, exception,
- DIVIDE_BY_ZERO_EXCEPTION, FE_DIVBYZERO,
- "Divide by zero");
+ {
+ test_single_exception (test_name, exception,
+ DIVIDE_BY_ZERO_EXCEPTION, FE_DIVBYZERO,
+ "Divide by zero");
+ ran = 1;
+ }
#endif
#ifdef FE_INVALID
if ((exception & INVALID_EXCEPTION_OK) == 0)
- test_single_exception (test_name, exception,
- INVALID_EXCEPTION, FE_INVALID,
- "Invalid operation");
+ {
+ test_single_exception (test_name, exception,
+ INVALID_EXCEPTION, FE_INVALID,
+ "Invalid operation");
+ ran = 1;
+ }
#endif
#ifdef FE_OVERFLOW
if ((exception & OVERFLOW_EXCEPTION_OK) == 0)
- test_single_exception (test_name, exception, OVERFLOW_EXCEPTION,
- FE_OVERFLOW, "Overflow");
+ {
+ test_single_exception (test_name, exception, OVERFLOW_EXCEPTION,
+ FE_OVERFLOW, "Overflow");
+ ran = 1;
+ }
#endif
/* Spurious "underflow" and "inexact" exceptions are always
allowed for IBM long double, in line with the underlying
@@ -519,17 +568,30 @@ test_exceptions (const char *test_name, int exception)
if ((exception & UNDERFLOW_EXCEPTION_OK) == 0
&& !(test_ibm128
&& (exception & UNDERFLOW_EXCEPTION) == 0))
- test_single_exception (test_name, exception, UNDERFLOW_EXCEPTION,
- FE_UNDERFLOW, "Underflow");
+ {
+ test_single_exception (test_name, exception, UNDERFLOW_EXCEPTION,
+ FE_UNDERFLOW, "Underflow");
+ ran = 1;
+ }
+
#endif
#ifdef FE_INEXACT
if ((exception & (INEXACT_EXCEPTION | NO_INEXACT_EXCEPTION)) != 0
&& !(test_ibm128
&& (exception & NO_INEXACT_EXCEPTION) != 0))
- test_single_exception (test_name, exception, INEXACT_EXCEPTION,
- FE_INEXACT, "Inexact");
+ {
+ test_single_exception (test_name, exception, INEXACT_EXCEPTION,
+ FE_INEXACT, "Inexact");
+ ran = 1;
+ }
#endif
+ assert (ran == 1);
}
+ else
+ {
+ if (print_screen (1))
+ printf ("Info: %s: No exceptions tested\n", test_name);
+ }
feclearexcept (FE_ALL_EXCEPT);
}
@@ -552,6 +614,7 @@ test_single_errno (const char *test_name, int errno_value,
printf ("Failure: %s: errno set to %d, expected %d (%s)\n",
test_name, errno_value, expected_value, expected_name);
}
+ ++noErrnoTests;
}
/* Test whether errno (value ERRNO_VALUE) has been for TEST_NAME set
@@ -561,13 +624,39 @@ test_errno (const char *test_name, int errno_value, int exceptions)
{
if (flag_test_errno)
{
- ++noErrnoTests;
+ int ran = 0;
+
+ if ((exceptions & (ERRNO_UNCHANGED|ERRNO_EDOM|ERRNO_ERANGE)) == 0)
+ {
+ if (print_screen (1))
+ printf ("Info: %s: The value of errno was not tested\n",
+ test_name);
+ return;
+ }
+
+
if (exceptions & ERRNO_UNCHANGED)
- test_single_errno (test_name, errno_value, 0, "unchanged");
+ {
+ test_single_errno (test_name, errno_value, 0, "unchanged");
+ ran = 1;
+ }
if (exceptions & ERRNO_EDOM)
- test_single_errno (test_name, errno_value, EDOM, "EDOM");
+ {
+ test_single_errno (test_name, errno_value, EDOM, "EDOM");
+ ran = 1;
+ }
if (exceptions & ERRNO_ERANGE)
- test_single_errno (test_name, errno_value, ERANGE, "ERANGE");
+ {
+ test_single_errno (test_name, errno_value, ERANGE, "ERANGE");
+ ran = 1;
+ }
+
+ assert (ran == 1);
+ }
+ else
+ {
+ if (print_screen (1))
+ printf ("Info: %s: No errno tests\n", test_name);
}
}
@@ -619,6 +708,9 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
FLOAT diff = 0;
FLOAT ulps = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
@@ -716,12 +808,13 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
printf (" max.ulp : %s\n", mustrn);
}
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -776,12 +869,14 @@ check_int (const char *test_name, int computed, int expected,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if (computed == expected)
ok = 1;
@@ -795,11 +890,12 @@ check_int (const char *test_name, int computed, int expected,
printf (" should be: %d\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -810,12 +906,14 @@ check_long (const char *test_name, long int computed, long int expected,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if (computed == expected)
ok = 1;
@@ -829,11 +927,12 @@ check_long (const char *test_name, long int computed, long int expected,
printf (" should be: %ld\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -844,12 +943,14 @@ check_bool (const char *test_name, int computed, int expected,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if ((computed == 0) == (expected == 0))
ok = 1;
@@ -863,11 +964,12 @@ check_bool (const char *test_name, int computed, int expected,
printf (" should be: %d\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -879,12 +981,14 @@ check_longlong (const char *test_name, long long int computed,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if (computed == expected)
ok = 1;
@@ -898,11 +1002,12 @@ check_longlong (const char *test_name, long long int computed,
printf (" should be: %lld\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -913,12 +1018,14 @@ check_intmax_t (const char *test_name, intmax_t computed,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if (computed == expected)
ok = 1;
@@ -932,11 +1039,12 @@ check_intmax_t (const char *test_name, intmax_t computed,
printf (" should be: %jd\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
@@ -947,12 +1055,14 @@ check_uintmax_t (const char *test_name, uintmax_t computed,
{
int ok = 0;
int errno_value = errno;
+ int thisTest = noTests;
+
+ print_test_start (thisTest, test_name, TEST_INPUT);
test_exceptions (test_name, exceptions);
test_errno (test_name, errno_value, exceptions);
if (exceptions & IGNORE_RESULT)
goto out;
- noTests++;
if (computed == expected)
ok = 1;
@@ -966,11 +1076,12 @@ check_uintmax_t (const char *test_name, uintmax_t computed,
printf (" should be: %ju\n", expected);
}
- update_stats (ok);
+ update_stats (ok, TEST_INPUT);
out:
fpstack_test (test_name);
feclearexcept (FE_ALL_EXCEPT);
errno = 0;
+ print_test_end (thisTest, test_name, TEST_INPUT);
}
/* Return whether a test with flags EXCEPTIONS should be run. */
@@ -1211,9 +1322,11 @@ libm_test_finish (void)
fclose (ulps_file);
printf ("\nTest suite completed:\n");
- printf (" %d test cases plus %d tests for exception flags and\n"
- " %d tests for errno executed.\n",
- noTests, noExcTests, noErrnoTests);
+ printf (" %d max error test cases,\n", noMaxErrorTests);
+ printf (" %d input tests,\n", noTests);
+ printf (" - with %d tests for exception flags,\n", noExcTests);
+ printf (" - with %d tests for errno executed.\n", noErrnoTests);
+
if (noErrors)
{
printf (" %d errors occurred.\n", noErrors);
diff --git a/math/libm-test-support.h b/math/libm-test-support.h
index 8baf7e1817157b2a..efb9523e9e91f64f 100644
--- a/math/libm-test-support.h
+++ b/math/libm-test-support.h
@@ -170,8 +170,8 @@ extern const char doc[];
int enable_test (int);
void init_max_error (const char *, int, int);
-void print_max_error (const char *);
-void print_complex_max_error (const char *);
+void check_max_error (const char *);
+void check_complex_max_error (const char *);
void check_float (const char *, FLOAT, FLOAT, int);
void check_complex (const char *, CFLOAT, CFLOAT, int);
void check_int (const char *, int, int, int);

151
glibc-RHEL-106562-20.patch Normal file
View File

@ -0,0 +1,151 @@
commit a9017caff3b77032d04e2e439f7c04a63241e63e
Author: Sergey Kolosov <skolosov@redhat.com>
Date: Tue Jan 28 23:56:26 2025 +0100
nptl: extend test coverage for sched_yield
We add sched_yield() API testing to the existing thread affinity
test case because it allows us to test sched_yield() operation
in the following scenarios:
* On a main thread.
* On multiple threads simultaneously.
* On every CPU the system reports simultaneously.
The ensures we exercise sched_yield() in as many scenarios as
we would exercise calls to the affinity functions.
Additionally, the test is improved by adding a semaphore to coordinate
all the threads running, so that an early starter thread won't consume
cpu resources that could be used to start the other threads.
Co-authored-by: DJ Delorie <dj@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c b/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c
index 2f921ed397a1a4d9..7276fd8fef06d620 100644
--- a/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c
+++ b/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c
@@ -38,6 +38,7 @@
#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
+#include <support/test-driver.h>
/* CPU set configuration determined. Can be used from early_test. */
struct conf
@@ -253,12 +254,12 @@ do_test (void)
if (getaffinity (sizeof (set), &set) < 0 && errno == ENOSYS)
{
puts ("warning: getaffinity not supported, test cannot run");
- return 0;
+ return EXIT_UNSUPPORTED;
}
if (sched_getcpu () < 0 && errno == ENOSYS)
{
puts ("warning: sched_getcpu not supported, test cannot run");
- return 0;
+ return EXIT_UNSUPPORTED;
}
}
diff --git a/sysdeps/unix/sysv/linux/tst-skeleton-thread-affinity.c b/sysdeps/unix/sysv/linux/tst-skeleton-thread-affinity.c
index 5a1e84431a30132d..507c5c94ba89e47b 100644
--- a/sysdeps/unix/sysv/linux/tst-skeleton-thread-affinity.c
+++ b/sysdeps/unix/sysv/linux/tst-skeleton-thread-affinity.c
@@ -45,10 +45,14 @@ static int still_running;
/* 0 if no scheduling failures, 1 if failures are encountered. */
static int failed;
+/* Used to synchronize the threads. */
+static pthread_barrier_t barrier;
+
static void *
thread_burn_one_cpu (void *closure)
{
int cpu = (uintptr_t) closure;
+ xpthread_barrier_wait (&barrier);
while (__atomic_load_n (&still_running, __ATOMIC_RELAXED) == 0)
{
int current = sched_getcpu ();
@@ -61,6 +65,11 @@ thread_burn_one_cpu (void *closure)
__atomic_store_n (&still_running, 1, __ATOMIC_RELAXED);
}
}
+ if (sched_yield () != 0)
+ {
+ printf ("error: sched_yield() failed for cpu %d\n", cpu);
+ __atomic_store_n (&failed, 1, __ATOMIC_RELAXED);
+ }
return NULL;
}
@@ -78,6 +87,7 @@ thread_burn_any_cpu (void *closure)
{
struct burn_thread *param = closure;
+ xpthread_barrier_wait (&barrier);
/* Schedule this thread around a bit to see if it lands on another
CPU. Run this for 2 seconds, once with sched_yield, once
without. */
@@ -99,7 +109,11 @@ thread_burn_any_cpu (void *closure)
CPU_SET_S (cpu, CPU_ALLOC_SIZE (param->conf->set_size),
param->seen_set);
if (pass == 1)
- sched_yield ();
+ if (sched_yield () != 0)
+ {
+ printf ("error: sched_yield() failed for cpu %d\n", cpu);
+ __atomic_store_n (&failed, 1, __ATOMIC_RELAXED);
+ }
}
}
return NULL;
@@ -156,6 +170,7 @@ early_test (struct conf *conf)
= calloc (conf->last_cpu + 1, sizeof (*other_threads));
cpu_set_t *initial_set = CPU_ALLOC (conf->set_size);
cpu_set_t *scratch_set = CPU_ALLOC (conf->set_size);
+ int num_available_cpus = 0;
if (pinned_threads == NULL || other_threads == NULL
|| initial_set == NULL || scratch_set == NULL)
@@ -172,6 +187,7 @@ early_test (struct conf *conf)
{
if (!CPU_ISSET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), initial_set))
continue;
+ num_available_cpus ++;
other_threads[cpu].conf = conf;
other_threads[cpu].initial_set = initial_set;
other_threads[cpu].thread = cpu;
@@ -194,6 +210,15 @@ early_test (struct conf *conf)
}
support_set_small_thread_stack_size (&attr);
+ /* This count assumes that all the threads below are created
+ successfully, and call pthread_barrier_wait(). If any threads
+ fail to be created, this function will return FALSE (failure) and
+ the waiting threads will eventually time out the whole test.
+ This is acceptable because we're not testing thread creation and
+ assume all threads will be created, and failure here implies a
+ failure outside the test's scope. */
+ xpthread_barrier_init (&barrier, NULL, num_available_cpus * 2 + 1);
+
/* Spawn a thread pinned to each available CPU. */
for (int cpu = 0; cpu <= conf->last_cpu; ++cpu)
{
@@ -245,6 +270,15 @@ early_test (struct conf *conf)
}
}
+ /* Test that sched_yield() works correctly in the main thread. This
+ also gives the kernel an opportunity to run the other threads,
+ randomizing thread startup a bit. */
+ if (sched_yield () != 0)
+ {
+ printf ("error: sched_yield() failed for main thread\n");
+ __atomic_store_n (&failed, 1, __ATOMIC_RELAXED);
+ }
+
/* Main thread. */
struct burn_thread main_thread;
main_thread.conf = conf;

View File

@ -0,0 +1,62 @@
commit 10af00f7a135c85796a9c4c75228358b8898da5c
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Fri Mar 14 10:18:21 2025 -0400
tst-fopen-threaded: Only check EOF for failing read
The fread race checker looks for EOF in every thread, which is incorrect
since threads calling fread successfully could lag behind and read the
EOF condition, resulting in multiple threads thinking that they
encountered an EOF.
Only look for EOF condition if fread fails to read a char. Also drop
the clearerr() since it could mask the failure of another reader, thus
hiding a test failure.
Finally, also check for error in the stream for completeness.
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/sysdeps/pthread/tst-fopen-threaded.c b/sysdeps/pthread/tst-fopen-threaded.c
index 5c792c93e3711621..ade58ad19eb209d1 100644
--- a/sysdeps/pthread/tst-fopen-threaded.c
+++ b/sysdeps/pthread/tst-fopen-threaded.c
@@ -64,19 +64,27 @@ threadReadRoutine (void *argv)
/* Wait for all threads to be ready to read. */
xpthread_barrier_wait (&barrier);
- ret =
- fread (&read_buffer, sizeof (char), sizeof (read_buffer), my_data->fd);
- if (feof (my_data->fd) != 0)
+ ret = fread (&read_buffer, 1, sizeof (read_buffer), my_data->fd);
+ /* If no data is returned (we read only 1 byte, so there's no short read
+ situation here), look for EOF flag and record it in MY_DATA. The EOF flag
+ is not cleared because that could result in a test failure being masked
+ when two threads fail to read and one of them clears error/EOF flags
+ before the second one has the chance to observe it.
+
+ Successful readers could still see the EOF if they fall behind the failing
+ read when calling feof(), which could result in a false test failure. To
+ avoid this race, we only make the failing reader check for EOF or
+ error. */
+ if (ret == 0)
{
- clearerr (my_data->fd);
- my_data->eof = true;
+ if (feof (my_data->fd) != 0)
+ my_data->eof = true;
+ else
+ FAIL_EXIT1 ("fread failed (ferror: %d): %m", ferror (my_data->fd));
}
else
- {
- TEST_COMPARE (ret, 1);
- /* Save the read value. */
- my_data->value = read_buffer;
- }
+ /* Save the read value. */
+ my_data->value = read_buffer;
TEST_COMPARE (ferror (my_data->fd), 0);
return NULL;
}

121
glibc-RHEL-106562-22.patch Normal file
View File

@ -0,0 +1,121 @@
commit 81e74c8676479811601b5894d72bb3d7e05f68dd
Author: DJ Delorie <dj@redhat.com>
Date: Fri Mar 14 16:08:12 2025 -0400
add ptmx support to test-container
diff --git a/support/Makefile b/support/Makefile
index 6e3c55394fa212b6..23ce2ccec89743bb 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -313,6 +313,7 @@ tests = \
README-testing \
tst-support-namespace \
tst-support-open-dev-null-range \
+ tst-support-openpty \
tst-support-process_state \
tst-support_blob_repeat \
tst-support_capture_subprocess \
@@ -331,6 +332,10 @@ tests = \
tst-xsigstack \
# tests
+tests-container = \
+ tst-support-openpty-c \
+ # tests-container
+
ifeq ($(run-built-tests),yes)
tests-special = \
$(objpfx)tst-support_record_failure-2.out
diff --git a/support/test-container.c b/support/test-container.c
index adf2b30215273936..1696d676fd101d42 100644
--- a/support/test-container.c
+++ b/support/test-container.c
@@ -1148,6 +1148,9 @@ main (int argc, char **argv)
devmount (new_root_path, "null");
devmount (new_root_path, "zero");
devmount (new_root_path, "urandom");
+#ifdef __linux__
+ devmount (new_root_path, "ptmx");
+#endif
/* We're done with the "old" root, switch to the new one. */
if (chroot (new_root_path) < 0)
@@ -1214,6 +1217,14 @@ main (int argc, char **argv)
maybe_xmkdir ("/tmp", 0755);
+#ifdef __linux__
+ maybe_xmkdir ("/dev/pts", 0777);
+ if (mount ("/dev/pts", "/dev/pts", "devpts", 0, "newinstance,ptmxmode=0666,mode=0666") < 0)
+ FAIL_EXIT1 ("can't mount /dev/pts: %m\n");
+ if (mount ("/dev/pts/ptmx", "/dev/ptmx", "", MS_BIND | MS_REC, NULL) < 0)
+ FAIL_EXIT1 ("can't mount /dev/ptmx\n");
+#endif
+
if (require_pidns)
{
/* Now that we're pid 1 (effectively "root") we can mount /proc */
diff --git a/support/tst-support-openpty-c.c b/support/tst-support-openpty-c.c
new file mode 100644
index 0000000000000000..0a6a428fc3cd3400
--- /dev/null
+++ b/support/tst-support-openpty-c.c
@@ -0,0 +1,2 @@
+/* Same test, but in a test-container. */
+#include "tst-support-openpty.c"
diff --git a/support/tst-support-openpty.c b/support/tst-support-openpty.c
new file mode 100644
index 0000000000000000..1222d7018f9b224f
--- /dev/null
+++ b/support/tst-support-openpty.c
@@ -0,0 +1,49 @@
+/* Basic test for support_openpty support in test-container.
+ Copyright (C) 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 <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <support/tty.h>
+#include <support/check.h>
+#include <support/support.h>
+
+/* Note: the purpose of this test isn't to test if ptys function
+ correctly, but only to verify that test-container's support for
+ them is correct. The many checks in support_openpty.c are
+ sufficient for this. */
+
+int
+do_test (void)
+{
+ int outer, inner;
+ char *name;
+ struct termios term;
+ struct winsize win;
+
+ cfmakeraw (&term);
+ win.ws_row = 24;
+ win.ws_col = 80;
+
+ support_openpty (&outer, &inner, &name, &term, &win);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

1084
glibc-RHEL-106562-23.patch Normal file

File diff suppressed because it is too large Load Diff

112
glibc-RHEL-106562-24.patch Normal file
View File

@ -0,0 +1,112 @@
commit 4fa959d13d21b8f56a43aa0a416100303736c55c
Author: Florian Weimer <fweimer@redhat.com>
Date: Tue Apr 8 10:39:44 2025 +0200
stdio-common: In tst-setvbuf2, close helper thread descriptor only if opened
The helper thread may get canceled before the open system
call succeds. Then ThreadData.fd remains zero, and eventually
the xclose call in end_reader_thread fails because descriptor 0
is not open.
Instead, initialize the fd member to -1 (not a valid descriptor)
and close the descriptor only if valid. Do this in a new end_thread
helper routine.
Also add more error checking to close operations.
Fixes commit 95b780c1d0549678c0a244c6e2112ec97edf0839 ("stdio: Add
more setvbuf tests").
diff --git a/stdio-common/tst-setvbuf2.c b/stdio-common/tst-setvbuf2.c
index 6cc83355f391afab..84d8b43a5811b4be 100644
--- a/stdio-common/tst-setvbuf2.c
+++ b/stdio-common/tst-setvbuf2.c
@@ -240,6 +240,21 @@ typedef struct {
/* It's OK if this is static, we only run one at a time. */
ThreadData thread_data;
+static void
+end_thread (pthread_t *ptid)
+{
+ if (*ptid)
+ {
+ pthread_cancel (*ptid);
+ xpthread_join (*ptid);
+ /* The descriptor was passed in, or the helper thread made
+ sufficient progress and opened the file. */
+ if (thread_data.fd >= 0)
+ xclose (thread_data.fd);
+ *ptid = 0;
+ }
+}
+
static void *
writer_thread_proc (void *closure)
{
@@ -306,7 +321,7 @@ static void
start_writer_thread_n (const char *fname)
{
debug;
- thread_data.fd = 0;
+ thread_data.fd = -1;
thread_data.fname = fname;
writer_thread_tid = xpthread_create (NULL, writer_thread_proc,
(void *)&thread_data);
@@ -316,13 +331,7 @@ static void
end_writer_thread (void)
{
debug;
- if (writer_thread_tid)
- {
- pthread_cancel (writer_thread_tid);
- xpthread_join (writer_thread_tid);
- xclose (thread_data.fd);
- writer_thread_tid = 0;
- }
+ end_thread (&writer_thread_tid);
}
static void
@@ -339,7 +348,7 @@ static void
start_reader_thread_n (const char *fname)
{
debug;
- thread_data.fd = 0;
+ thread_data.fd = -1;
thread_data.fname = fname;
reader_thread_tid = xpthread_create (NULL, reader_thread_proc,
(void *)&thread_data);
@@ -349,13 +358,7 @@ static void
end_reader_thread (void)
{
debug;
- if (reader_thread_tid)
- {
- pthread_cancel (reader_thread_tid);
- xpthread_join (reader_thread_tid);
- xclose (thread_data.fd);
- reader_thread_tid = 0;
- }
+ end_thread (&reader_thread_tid);
}
/*------------------------------------------------------------*/
@@ -852,7 +855,7 @@ do_second_part (FILE *fp,
}
- fclose (fp);
+ xfclose (fp);
return rv;
}
@@ -939,7 +942,7 @@ recurse (FILE *fp,
break;
default: /* parent */
- fclose (fp);
+ xfclose (fp);
xwaitpid (pid, &status, 0);
if (WIFEXITED (status)
&& WEXITSTATUS (status) == 0)

60
glibc-RHEL-106562-3.patch Normal file
View File

@ -0,0 +1,60 @@
commit 3f54e459a633b4247be91b9d0f68a7e08720b8d8
Author: Frédéric Bérat <fberat@redhat.com>
Date: Tue Aug 13 12:01:26 2024 +0200
libio/tst-getdelim: Add new test covering NUL as a delimiter
Add a new test to getdelim to verify that '\0' can be set as a
delimiter.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/libio/tst-getdelim.c b/libio/tst-getdelim.c
index e6dd964b4918b02a..db15bf92855ee9e1 100644
--- a/libio/tst-getdelim.c
+++ b/libio/tst-getdelim.c
@@ -1,4 +1,6 @@
-/* Check that getdelim sets error indicator on error (BZ #29917)
+/* Test getdelim conforming to POSIX specifications.
+
+ Note: Most getdelim use cases are covered by stdio-common/tst-getline.
Copyright (C) 2023-2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,18 +20,36 @@
<https://www.gnu.org/licenses/>. */
#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#include <support/check.h>
+#include <support/support.h>
+#include <support/test-driver.h>
static int
do_test (void)
{
+ /* Check that getdelim sets error indicator on error (BZ #29917) */
clearerr (stdin);
TEST_VERIFY (getdelim (0, 0, '\n', stdin) == -1);
TEST_VERIFY (ferror (stdin) != 0);
TEST_VERIFY (errno == EINVAL);
+ /* Test getdelim with NUL as delimiter */
+ verbose_printf ("Testing NUL delimiter\n");
+ char *lineptr = NULL;
+ size_t linelen = 0;
+ char membuf[] = "abc\0d\nef\0";
+ FILE *memstream = fmemopen (membuf, sizeof (membuf), "r");
+ TEST_VERIFY_EXIT (memstream != NULL);
+ TEST_VERIFY (getdelim (&lineptr, &linelen, '\0', memstream) != -1);
+ TEST_COMPARE_BLOB (lineptr, 4, "abc\0", 4);
+ TEST_VERIFY (getdelim (&lineptr, &linelen, '\0', memstream) != -1);
+ TEST_COMPARE_BLOB (lineptr, 5, "d\nef\0", 5);
+ fclose (memstream);
+ free (lineptr);
+
return 0;
}

29
glibc-RHEL-106562-4.patch Normal file
View File

@ -0,0 +1,29 @@
commit b22923abb046311ac9097a36b97b9b97342bac44
Author: Carlos O'Donell <carlos@redhat.com>
Date: Thu Aug 15 08:12:35 2024 -0400
Report error if setaffinity wrapper fails (Bug 32040)
Previously if the setaffinity wrapper failed the rest of the subtest
would not execute and the current subtest would be reported as passing.
Now if the setaffinity wrapper fails the subtest is correctly reported
as faling. Tested manually by changing the conditions of the affinity
call including setting size to zero, or checking the wrong condition.
No regressions on x86_64.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c b/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c
index 31a15b3ad789a287..2f921ed397a1a4d9 100644
--- a/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c
+++ b/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c
@@ -157,7 +157,7 @@ test_size (const struct conf *conf, size_t size)
if (setaffinity (kernel_size, initial_set) < 0)
{
printf ("error: size %zu: setaffinity: %m\n", size);
- return true;
+ return false;
}
/* Use one-CPU set to test switching between CPUs. */

78
glibc-RHEL-106562-5.patch Normal file
View File

@ -0,0 +1,78 @@
commit 921690512946d73bf66a8c495baff31316e4489f
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 16 16:05:19 2024 +0200
support: Add the xstatx function
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/support/Makefile b/support/Makefile
index aa57207bdccc852d..5b1c96a49e9410f4 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -210,6 +210,7 @@ libsupport-routines = \
xsignal \
xsigstack \
xsocket \
+ xstatx \
xstrdup \
xstrndup \
xsymlink \
diff --git a/support/xstatx.c b/support/xstatx.c
new file mode 100644
index 0000000000000000..621f2440f83b598d
--- /dev/null
+++ b/support/xstatx.c
@@ -0,0 +1,32 @@
+/* Error-checking wrapper for statx.
+ 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 <support/xunistd.h>
+
+#include <fcntl.h>
+#include <support/check.h>
+#include <sys/stat.h>
+
+void
+xstatx (int fd, const char *path, int flags, unsigned int mask,
+ struct statx *stx)
+{
+ if (statx (fd, path, flags, mask, stx) != 0)
+ FAIL_EXIT1 ("statx (AT_FDCWD, \"%s\", 0x%x, 0x%x): %m",
+ path, (unsigned int) flags, mask);
+}
diff --git a/support/xunistd.h b/support/xunistd.h
index 13be9a46a3e6b07b..cc74c4fad07dd088 100644
--- a/support/xunistd.h
+++ b/support/xunistd.h
@@ -30,6 +30,7 @@
__BEGIN_DECLS
struct stat64;
+struct statx;
pid_t xfork (void);
pid_t xwaitpid (pid_t, int *status, int flags);
@@ -51,6 +52,7 @@ void __REDIRECT (xstat, (const char *path, struct stat *), xstat_time64);
void __REDIRECT (xlstat, (const char *path, struct stat *), xlstat_time64);
void __REDIRECT (xfstat, (int fd, struct stat *), xfstat_time64);
#endif
+void xstatx (int, const char *, int, unsigned int, struct statx *);
void xmkdir (const char *path, mode_t);
void xchroot (const char *path);
void xunlink (const char *path);

391
glibc-RHEL-106562-6.patch Normal file
View File

@ -0,0 +1,391 @@
commit bf2927484152e12996af60ea439cf94b66fcd81d
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 16 16:05:20 2024 +0200
io: Use struct statx and xstatx in tests
This avoids the need to define struct_statx to an appropriate
struct stat type variant because struct statx does not change
based on time/file offset flags.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/io/tst-futimens-time64.c b/io/tst-futimens-time64.c
index 88fcb38489b160de..71204a6166eaba56 100644
--- a/io/tst-futimens-time64.c
+++ b/io/tst-futimens-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-futimens.c"
diff --git a/io/tst-futimens.c b/io/tst-futimens.c
index 6204befedd869bb6..075ca42b9378d98f 100644
--- a/io/tst-futimens.c
+++ b/io/tst-futimens.c
@@ -18,26 +18,23 @@
#include <support/check.h>
#include <support/xunistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_futimens_helper (const char *file, int fd, const struct timespec *ts)
{
int result = futimens (fd, ts);
TEST_VERIFY_EXIT (result == 0);
- struct_stat st;
- xfstat (fd, &st);
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
/* Check if seconds for atime match */
- TEST_COMPARE (st.st_atime, ts[0].tv_sec);
+ TEST_COMPARE (st.stx_atime.tv_sec, ts[0].tv_sec);
/* Check if seconds for mtime match */
- TEST_COMPARE (st.st_mtime, ts[1].tv_sec);
+ TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec);
return 0;
}
diff --git a/io/tst-futimes-time64.c b/io/tst-futimes-time64.c
index d489c265d1964196..eeb4bed7c4f5fb12 100644
--- a/io/tst-futimes-time64.c
+++ b/io/tst-futimes-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-futimes.c"
diff --git a/io/tst-futimes.c b/io/tst-futimes.c
index d21acf6a24715a10..612fe460cf505547 100644
--- a/io/tst-futimes.c
+++ b/io/tst-futimes.c
@@ -18,27 +18,24 @@
#include <support/check.h>
#include <support/xunistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_futimens_helper (const char *file, int fd, const struct timeval *tv)
{
int r = futimes (fd, tv);
TEST_VERIFY_EXIT (r == 0);
- struct_stat st;
- xfstat (fd, &st);
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
/* Check if seconds for atime match */
- TEST_COMPARE (st.st_atime, tv[0].tv_sec);
+ TEST_COMPARE (st.stx_atime.tv_sec, tv[0].tv_sec);
/* Check if seconds for mtime match */
- TEST_COMPARE (st.st_mtime, tv[1].tv_sec);
+ TEST_COMPARE (st.stx_mtime.tv_sec, tv[1].tv_sec);
return 0;
}
diff --git a/io/tst-futimesat-time64.c b/io/tst-futimesat-time64.c
index f6c0500eefb9c98b..15853175796e59dd 100644
--- a/io/tst-futimesat-time64.c
+++ b/io/tst-futimesat-time64.c
@@ -1,4 +1 @@
-#define struct_stat struct stat
-#define fstat fstat
-#define fstatat fstatat
#include "io/tst-futimesat.c"
diff --git a/io/tst-futimesat.c b/io/tst-futimesat.c
index 67a8551bebf23190..feae4e7aa76ddee7 100644
--- a/io/tst-futimesat.c
+++ b/io/tst-futimesat.c
@@ -30,12 +30,6 @@
#include <support/temp_file.h>
#include <support/xunistd.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-# define fstat fstat64
-# define fstatat fstatat64
-#endif
-
static int dir_fd;
static void
@@ -118,19 +112,15 @@ do_test (void)
xwrite (fd, "hello", 5);
puts ("file created");
- struct_stat st1;
- if (fstat (fd, &st1) != 0)
- {
- puts ("fstat64 failed");
- return 1;
- }
+ struct statx st1;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st1);
close (fd);
struct timeval tv[2];
- tv[0].tv_sec = st1.st_atime + 1;
+ tv[0].tv_sec = st1.stx_atime.tv_sec + 1;
tv[0].tv_usec = 0;
- tv[1].tv_sec = st1.st_mtime + 1;
+ tv[1].tv_sec = st1.stx_mtime.tv_sec + 1;
tv[1].tv_usec = 0;
if (futimesat (dir_fd, "some-file", tv) != 0)
{
@@ -138,16 +128,12 @@ do_test (void)
return 1;
}
- struct_stat st2;
- if (fstatat (dir_fd, "some-file", &st2, 0) != 0)
- {
- puts ("fstatat64 failed");
- return 1;
- }
+ struct statx st2;
+ xstatx (dir_fd, "some-file", 0, STATX_BASIC_STATS, &st2);
- if (st2.st_mtime != tv[1].tv_sec
+ if (st2.stx_mtime.tv_sec != tv[1].tv_sec
#ifdef _STATBUF_ST_NSEC
- || st2.st_mtim.tv_nsec != 0
+ || st2.stx_mtime.tv_nsec != 0
#endif
)
{
diff --git a/io/tst-lutimes-time64.c b/io/tst-lutimes-time64.c
index 06caec0a91d91b6c..c5bea965dabe6cd7 100644
--- a/io/tst-lutimes-time64.c
+++ b/io/tst-lutimes-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-lutimes.c"
diff --git a/io/tst-lutimes.c b/io/tst-lutimes.c
index edef5ab90e8681c7..78bcc58291fdcdc8 100644
--- a/io/tst-lutimes.c
+++ b/io/tst-lutimes.c
@@ -18,34 +18,32 @@
#include <support/check.h>
#include <support/xunistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_lutimes_helper (const char *testfile, int fd, const char *testlink,
const struct timeval *tv)
{
- struct_stat stfile_orig;
- xlstat (testfile, &stfile_orig);
+ struct statx stfile_orig;
+ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS,
+ &stfile_orig);
TEST_VERIFY_EXIT (lutimes (testlink, tv) == 0);
- struct_stat stlink;
- xlstat (testlink, &stlink);
+ struct statx stlink;
+ xstatx (AT_FDCWD, testlink, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, &stlink);
- TEST_COMPARE (stlink.st_atime, tv[0].tv_sec);
- TEST_COMPARE (stlink.st_mtime, tv[1].tv_sec);
+ TEST_COMPARE (stlink.stx_atime.tv_sec, tv[0].tv_sec);
+ TEST_COMPARE (stlink.stx_mtime.tv_sec, tv[1].tv_sec);
/* Check if the timestamp from original file is not changed. */
- struct_stat stfile;
- xlstat (testfile, &stfile);
+ struct statx stfile;
+ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, &stfile);
- TEST_COMPARE (stfile_orig.st_atime, stfile.st_atime);
- TEST_COMPARE (stfile_orig.st_mtime, stfile.st_mtime);
+ TEST_COMPARE (stfile_orig.stx_atime.tv_sec, stfile.stx_atime.tv_sec);
+ TEST_COMPARE (stfile_orig.stx_mtime.tv_sec, stfile.stx_mtime.tv_sec);
return 0;
}
diff --git a/io/tst-utime-time64.c b/io/tst-utime-time64.c
index eb62f59126564896..8894592a1570a366 100644
--- a/io/tst-utime-time64.c
+++ b/io/tst-utime-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-utime.c"
diff --git a/io/tst-utime.c b/io/tst-utime.c
index e2e6dcd04cebb7fc..f32935828923a47f 100644
--- a/io/tst-utime.c
+++ b/io/tst-utime.c
@@ -19,26 +19,23 @@
#include <utime.h>
#include <support/check.h>
#include <support/xunistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_utime_helper (const char *file, int fd, const struct utimbuf *ut)
{
int result = utime (file, ut);
TEST_VERIFY_EXIT (result == 0);
- struct_stat st;
- xfstat (fd, &st);
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
/* Check if seconds for actime match */
- TEST_COMPARE (st.st_atime, ut->actime);
+ TEST_COMPARE (st.stx_atime.tv_sec, ut->actime);
/* Check if seconds for modtime match */
- TEST_COMPARE (st.st_mtime, ut->modtime);
+ TEST_COMPARE (st.stx_mtime.tv_sec, ut->modtime);
return 0;
}
diff --git a/io/tst-utimensat-time64.c b/io/tst-utimensat-time64.c
index 7ac7d8df1d48f0a0..5d60fce8818f7545 100644
--- a/io/tst-utimensat-time64.c
+++ b/io/tst-utimensat-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-utimensat.c"
diff --git a/io/tst-utimensat.c b/io/tst-utimensat.c
index 3d9a72c4719cc6c9..2a756d7b07b6b07f 100644
--- a/io/tst-utimensat.c
+++ b/io/tst-utimensat.c
@@ -22,10 +22,6 @@
#include <sys/stat.h>
#include <sys/time.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_utimesat_helper (const char *testfile, int fd, const char *testlink,
const struct timespec *ts)
@@ -33,35 +29,38 @@ test_utimesat_helper (const char *testfile, int fd, const char *testlink,
{
TEST_VERIFY_EXIT (utimensat (fd, testfile, ts, 0) == 0);
- struct_stat st;
- xfstat (fd, &st);
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
/* Check if seconds for atime match */
- TEST_COMPARE (st.st_atime, ts[0].tv_sec);
+ TEST_COMPARE (st.stx_atime.tv_sec, ts[0].tv_sec);
/* Check if seconds for mtime match */
- TEST_COMPARE (st.st_mtime, ts[1].tv_sec);
+ TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec);
}
{
- struct_stat stfile_orig;
- xlstat (testfile, &stfile_orig);
+ struct statx stfile_orig;
+ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS,
+ &stfile_orig);
TEST_VERIFY_EXIT (utimensat (0 /* ignored */, testlink, ts,
AT_SYMLINK_NOFOLLOW)
== 0);
- struct_stat stlink;
- xlstat (testlink, &stlink);
+ struct statx stlink;
+ xstatx (AT_FDCWD, testlink, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS,
+ &stlink);
- TEST_COMPARE (stlink.st_atime, ts[0].tv_sec);
- TEST_COMPARE (stlink.st_mtime, ts[1].tv_sec);
+ TEST_COMPARE (stlink.stx_atime.tv_sec, ts[0].tv_sec);
+ TEST_COMPARE (stlink.stx_mtime.tv_sec, ts[1].tv_sec);
/* Check if the timestamp from original file is not changed. */
- struct_stat stfile;
- xlstat (testfile, &stfile);
+ struct statx stfile;
+ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS,
+ &stfile);
- TEST_COMPARE (stfile_orig.st_atime, stfile.st_atime);
- TEST_COMPARE (stfile_orig.st_mtime, stfile.st_mtime);
+ TEST_COMPARE (stfile_orig.stx_atime.tv_sec, stfile.stx_atime.tv_sec);
+ TEST_COMPARE (stfile_orig.stx_mtime.tv_sec, stfile.stx_mtime.tv_sec);
}
return 0;
diff --git a/io/tst-utimes-time64.c b/io/tst-utimes-time64.c
index 234ec02541032017..026ef5f78dd4616c 100644
--- a/io/tst-utimes-time64.c
+++ b/io/tst-utimes-time64.c
@@ -1,2 +1 @@
-#define struct_stat struct stat
#include "tst-utimes.c"
diff --git a/io/tst-utimes.c b/io/tst-utimes.c
index 8edcfabebfbd978d..6cd436c5a0f94d84 100644
--- a/io/tst-utimes.c
+++ b/io/tst-utimes.c
@@ -18,28 +18,25 @@
#include <support/check.h>
#include <support/xunistd.h>
+#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
-#ifndef struct_stat
-# define struct_stat struct stat64
-#endif
-
static int
test_utimes_helper (const char *file, int fd, const struct timeval *tv)
{
int result = utimes (file, tv);
TEST_VERIFY_EXIT (result == 0);
- struct_stat st;
- xfstat (fd, &st);
+ struct statx st;
+ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st);
/* Check if seconds for atime match */
- TEST_COMPARE (st.st_atime, tv[0].tv_sec);
+ TEST_COMPARE (st.stx_atime.tv_sec, tv[0].tv_sec);
/* Check if seconds for mtime match */
- TEST_COMPARE (st.st_mtime, tv[1].tv_sec);
+ TEST_COMPARE (st.stx_mtime.tv_sec, tv[1].tv_sec);
return 0;
}

415
glibc-RHEL-106562-7.patch Normal file
View File

@ -0,0 +1,415 @@
commit e7c14e542d8d858b824b5df4f4e3dc93695e6171
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 16 16:05:20 2024 +0200
support: Use macros for *stat wrappers
Macros will automatically use the correct types, without
having to fiddle with internal glibc macros. It's also
impossible to get the types wrong due to aliasing because
support_check_stat_fd and support_check_stat_path do not
depend on the struct stat* types.
The changes reveal some inconsistencies in tests.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c
index 7f1fbb52523ac1ac..8c2e62ecc2c54c04 100644
--- a/elf/tst-ldconfig-bad-aux-cache.c
+++ b/elf/tst-ldconfig-bad-aux-cache.c
@@ -85,7 +85,7 @@ do_test (void)
support_capture_subprocess_check (&result, "execv", 0, sc_allow_none);
support_capture_subprocess_free (&result);
- xstat (path, &fs);
+ xstat64 (path, &fs);
size = fs.st_size;
/* Run 3 tests, each truncating aux-cache shorter and shorter. */
diff --git a/io/tst-copy_file_range.c b/io/tst-copy_file_range.c
index 9837b7c3395725a5..3d7b0aa90160190a 100644
--- a/io/tst-copy_file_range.c
+++ b/io/tst-copy_file_range.c
@@ -117,7 +117,7 @@ simple_file_copy (void)
TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 6 + length);
struct stat64 st;
- xfstat (outfd, &st);
+ xfstat64 (outfd, &st);
if (length > 0)
TEST_COMPARE (st.st_size, out_skipped + length);
else
diff --git a/io/tst-statx.c b/io/tst-statx.c
index d84568859eb5c604..685924ae76245676 100644
--- a/io/tst-statx.c
+++ b/io/tst-statx.c
@@ -78,7 +78,7 @@ both_implementations_tests (statx_function impl, const char *path, int fd)
struct statx stx = { 0, };
TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &stx), 0);
struct stat64 st;
- xfstat (fd, &st);
+ xfstat64 (fd, &st);
TEST_COMPARE (stx.stx_mode, st.st_mode);
TEST_COMPARE (stx.stx_dev_major, major (st.st_dev));
TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev));
@@ -88,7 +88,7 @@ both_implementations_tests (statx_function impl, const char *path, int fd)
TEST_COMPARE (statx (AT_FDCWD, "/dev/null", 0, STATX_BASIC_STATS, &stx),
0);
struct stat64 st;
- xstat ("/dev/null", &st);
+ xstat64 ("/dev/null", &st);
TEST_COMPARE (stx.stx_mode, st.st_mode);
TEST_COMPARE (stx.stx_dev_major, major (st.st_dev));
TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev));
diff --git a/locale/tst-localedef-path-norm.c b/locale/tst-localedef-path-norm.c
index ffe8cbd46732386f..f592b9a9605bff94 100644
--- a/locale/tst-localedef-path-norm.c
+++ b/locale/tst-localedef-path-norm.c
@@ -84,7 +84,7 @@ run_test (void *closure)
support_capture_subprocess_free (&result);
/* Verify path is present and is a directory. */
- xstat (path, &fs);
+ xstat64 (path, &fs);
if (!S_ISDIR (fs.st_mode))
{
support_record_failure ();
diff --git a/localedata/tst-localedef-hardlinks.c b/localedata/tst-localedef-hardlinks.c
index e88215a1507bb30a..23927b462fc2224a 100644
--- a/localedata/tst-localedef-hardlinks.c
+++ b/localedata/tst-localedef-hardlinks.c
@@ -62,7 +62,7 @@ check_link (struct test_data step)
char *output;
output = xasprintf ("%s/%s", support_complocaledir_prefix, step.output);
- xstat (output, &locale);
+ xstat64 (output, &locale);
free (output);
TEST_COMPARE (locale.st_nlink, step.st_nlink);
}
diff --git a/posix/tst-execveat.c b/posix/tst-execveat.c
index 4565d6b19f41ca63..dde034a9f1356453 100644
--- a/posix/tst-execveat.c
+++ b/posix/tst-execveat.c
@@ -155,7 +155,7 @@ do_test (void)
tmp_sh = xasprintf ("%s/tmp_sh", tmp_dir);
add_temp_file (tmp_sh);
fd_out = xopen (symlink_name, O_CREAT | O_WRONLY, 0);
- xstat ("/bin/sh", &st);
+ xstat64 ("/bin/sh", &st);
fd = xopen ("/bin/sh", O_RDONLY, 0);
xcopy_file_range (fd, 0, fd_out, 0, st.st_size, 0);
xfchmod (fd_out, 0700);
diff --git a/stdio-common/tst-renameat2.c b/stdio-common/tst-renameat2.c
index b65afed75ec65ca4..7f4345f716182552 100644
--- a/stdio-common/tst-renameat2.c
+++ b/stdio-common/tst-renameat2.c
@@ -82,7 +82,7 @@ static void
check_size (const char *path, off64_t expected_size)
{
struct stat64 st;
- xstat (path, &st);
+ xstat64 (path, &st);
if (st.st_size != expected_size)
FAIL_EXIT1 ("file \"%s\": expected size %lld, actual size %lld",
path, (unsigned long long int) expected_size,
diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c
index 47c742f963a1b6b4..b5b630a41b9e4663 100644
--- a/stdlib/tst-system.c
+++ b/stdlib/tst-system.c
@@ -169,7 +169,7 @@ do_test (void)
{
struct stat64 st;
- xstat (_PATH_BSHELL, &st);
+ xstat64 (_PATH_BSHELL, &st);
mode_t mode = st.st_mode;
xchmod (_PATH_BSHELL, mode & ~(S_IXUSR | S_IXGRP | S_IXOTH));
diff --git a/support/Makefile b/support/Makefile
index 5b1c96a49e9410f4..6e3c55394fa212b6 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -42,14 +42,12 @@ libsupport-routines = \
resolv_test \
set_fortify_handler \
support-open-dev-null-range \
- support-xfstat \
- support-xfstat-time64 \
- support-xstat \
- support-xstat-time64 \
support_become_root \
support_can_chroot \
support_capture_subprocess \
support_capture_subprocess_check \
+ support_check_stat_fd \
+ support_check_stat_path \
support_chroot \
support_copy_file \
support_copy_file_range \
@@ -135,8 +133,6 @@ libsupport-routines = \
xgetsockname \
xlisten \
xlseek \
- xlstat \
- xlstat-time64 \
xmalloc \
xmemstream \
xmkdir \
diff --git a/support/support-xfstat-time64.c b/support/support-xfstat-time64.c
deleted file mode 100644
index 589a69bb3e04857d..0000000000000000
--- a/support/support-xfstat-time64.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 64-bit time_t stat with error checking.
- Copyright (C) 2021-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/>. */
-
-/* NB: Non-standard file name to avoid sysdeps override for xstat. */
-
-#include <support/check.h>
-#include <support/xunistd.h>
-#include <sys/stat.h>
-
-#if __TIMESIZE != 64
-void
-xfstat_time64 (int fd, struct __stat64_t64 *result)
-{
- if (__fstat64_time64 (fd, result) != 0)
- FAIL_EXIT1 ("__fstat64_time64 (%d): %m", fd);
-}
-#endif
diff --git a/support/support-xstat-time64.c b/support/support-xstat-time64.c
deleted file mode 100644
index 451948734ae0de0f..0000000000000000
--- a/support/support-xstat-time64.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 64-bit time_t stat with error checking.
- Copyright (C) 2021-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/>. */
-
-/* NB: Non-standard file name to avoid sysdeps override for xstat. */
-
-#include <support/check.h>
-#include <support/xunistd.h>
-#include <sys/stat.h>
-
-#if __TIMESIZE != 64
-void
-xstat_time64 (const char *path, struct __stat64_t64 *result)
-{
- if (__stat64_time64 (path, result) != 0)
- FAIL_EXIT1 ("__stat64_time64 (\"%s\"): %m", path);
-}
-#endif
diff --git a/support/support-xstat.c b/support/support-xstat.c
deleted file mode 100644
index ce866f74d242c07a..0000000000000000
--- a/support/support-xstat.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* stat64 with error checking.
- Copyright (C) 2017-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/>. */
-
-/* NB: Non-standard file name to avoid sysdeps override for xstat. */
-
-#include <support/check.h>
-#include <support/xunistd.h>
-#include <sys/stat.h>
-
-void
-xstat (const char *path, struct stat64 *result)
-{
- if (stat64 (path, result) != 0)
- FAIL_EXIT1 ("stat64 (\"%s\"): %m", path);
-}
diff --git a/support/xlstat.c b/support/support_check_stat_fd.c
similarity index 76%
rename from support/xlstat.c
rename to support/support_check_stat_fd.c
index 87df988879094d5b..4c12adf6b7f68d0c 100644
--- a/support/xlstat.c
+++ b/support/support_check_stat_fd.c
@@ -1,5 +1,5 @@
-/* lstat64 with error checking.
- Copyright (C) 2017-2024 Free Software Foundation, Inc.
+/* Error checking for descriptor-based stat functions.
+ 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
@@ -18,11 +18,10 @@
#include <support/check.h>
#include <support/xunistd.h>
-#include <sys/stat.h>
void
-xlstat (const char *path, struct stat64 *result)
+support_check_stat_fd (const char *name, int fd, int result)
{
- if (lstat64 (path, result) != 0)
- FAIL_EXIT1 ("lstat64 (\"%s\"): %m", path);
+ if (result != 0)
+ FAIL_EXIT1 ("%s (%d): %m", name, fd);
}
diff --git a/support/support-xfstat.c b/support/support_check_stat_path.c
similarity index 81%
rename from support/support-xfstat.c
rename to support/support_check_stat_path.c
index ab4b01c97d7b5f2f..3cf72afe5901dcd5 100644
--- a/support/support-xfstat.c
+++ b/support/support_check_stat_path.c
@@ -1,4 +1,4 @@
-/* fstat64 with error checking.
+/* Error checking for path-based stat functions.
Copyright (C) 2017-2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -18,11 +18,10 @@
#include <support/check.h>
#include <support/xunistd.h>
-#include <sys/stat.h>
void
-xfstat (int fd, struct stat64 *result)
+support_check_stat_path (const char *name, const char *path, int result)
{
- if (fstat64 (fd, result) != 0)
- FAIL_EXIT1 ("fstat64 (%d): %m", fd);
+ if (result != 0)
+ FAIL_EXIT1 ("%s (\"%s\"): %m", name, path);
}
diff --git a/support/xlstat-time64.c b/support/xlstat-time64.c
deleted file mode 100644
index 2bc3ca6593bd397d..0000000000000000
--- a/support/xlstat-time64.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 64-bit time_t stat with error checking.
- Copyright (C) 2021-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/>. */
-
-/* NB: Non-standard file name to avoid sysdeps override for xstat. */
-
-#include <support/check.h>
-#include <support/xunistd.h>
-#include <sys/stat.h>
-
-#if __TIMESIZE != 64
-void
-xlstat_time64 (const char *path, struct __stat64_t64 *result)
-{
- if (__lstat64_time64 (path, result) != 0)
- FAIL_EXIT1 ("__lstat64_time64 (\"%s\"): %m", path);
-}
-#endif
diff --git a/support/xunistd.h b/support/xunistd.h
index cc74c4fad07dd088..204951bce75f576b 100644
--- a/support/xunistd.h
+++ b/support/xunistd.h
@@ -29,7 +29,6 @@
__BEGIN_DECLS
-struct stat64;
struct statx;
pid_t xfork (void);
@@ -37,21 +36,20 @@ pid_t xwaitpid (pid_t, int *status, int flags);
void xpipe (int[2]);
void xdup2 (int, int);
int xopen (const char *path, int flags, mode_t);
-#ifndef __USE_TIME64_REDIRECTS
-# ifdef __USE_FILE_OFFSET64
-void xstat (const char *path, struct stat *);
-void xlstat (const char *path, struct stat *);
-void xfstat (int fd, struct stat *);
-# else
-void xstat (const char *path, struct stat64 *);
-void xlstat (const char *path, struct stat64 *);
-void xfstat (int fd, struct stat64 *);
-# endif
-#else
-void __REDIRECT (xstat, (const char *path, struct stat *), xstat_time64);
-void __REDIRECT (xlstat, (const char *path, struct stat *), xlstat_time64);
-void __REDIRECT (xfstat, (int fd, struct stat *), xfstat_time64);
-#endif
+void support_check_stat_fd (const char *name, int fd, int result);
+void support_check_stat_path (const char *name, const char *path, int result);
+#define xstat(path, st) \
+ (support_check_stat_path ("stat", (path), stat ((path), (st))))
+#define xfstat(fd, st) \
+ (support_check_stat_fd ("fstat", (fd), fstat ((fd), (st))))
+#define xlstat(path, st) \
+ (support_check_stat_path ("lstat", (path), lstat ((path), (st))))
+#define xstat64(path, st) \
+ (support_check_stat_path ("stat64", (path), stat64 ((path), (st))))
+#define xfstat64(fd, st) \
+ (support_check_stat_fd ("fstat64", (fd), fstat64 ((fd), (st))))
+#define xlstat64(path, st) \
+ (support_check_stat_path ("lstat64", (path), lstat64 ((path), (st))))
void xstatx (int, const char *, int, unsigned int, struct statx *);
void xmkdir (const char *path, mode_t);
void xchroot (const char *path);

148
glibc-RHEL-106562-8.patch Normal file
View File

@ -0,0 +1,148 @@
commit 2eee835eca960c9d4119279804214b7a1ed5d156
Author: DJ Delorie <dj@redhat.com>
Date: Thu Aug 8 22:44:56 2024 -0400
inet: test if_nametoindex and if_indextoname
Tests for if_nameindex, if_name2index, and if_index2name
Tests that valid results are consistent.
Tests that invalid parameters fail correctly.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/inet/Makefile b/inet/Makefile
index 2f03e6f7ee211525..cb97b45f0f9d223f 100644
--- a/inet/Makefile
+++ b/inet/Makefile
@@ -91,6 +91,7 @@ tests := \
tst-getni1 \
tst-getni2 \
tst-if_index-long \
+ tst-if_nameindex \
tst-inet6_rth \
tst-network \
tst-ntoa \
diff --git a/inet/tst-if_nameindex.c b/inet/tst-if_nameindex.c
new file mode 100644
index 0000000000000000..b025cdb3a7c6b68c
--- /dev/null
+++ b/inet/tst-if_nameindex.c
@@ -0,0 +1,116 @@
+/* Tests for if_nameindex et al.
+ 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 <stdlib.h>
+#include <errno.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/support.h>
+
+static char *buffer;
+
+static const char *test_names[] = {
+ "testing",
+ "invalid",
+ "dont-match",
+ "",
+ "\001\001\001\177",
+ NULL
+};
+
+static void
+checki (int i)
+{
+ char *ifname;
+
+ /* Test that a known-invalid index returns NULL. */
+ /* BUFFER should not be accessed. */
+
+ printf ("Testing if_indextoname (%d) == NULL\n", i);
+ ifname = if_indextoname (i, NULL);
+ TEST_VERIFY (ifname == NULL);
+ TEST_VERIFY (errno == ENXIO);
+}
+
+static int
+do_test (void)
+{
+ struct if_nameindex *if_ni, *ifp;
+ int min_idx, max_idx, buflen = 0;
+ int i;
+
+ if_ni = if_nameindex ();
+ TEST_VERIFY (if_ni != NULL);
+
+ min_idx = max_idx = if_ni->if_index;
+
+ for (ifp = if_ni; !(ifp->if_index == 0 && ifp->if_name == NULL); ifp++)
+ {
+ printf ("%u: %s\n", ifp->if_index, ifp->if_name);
+ if (ifp->if_index < min_idx)
+ min_idx = ifp->if_index;
+ if (ifp->if_index > max_idx)
+ max_idx = ifp->if_index;
+ if (strlen (ifp->if_name) + 1 > buflen)
+ buflen = strlen (ifp->if_name) + 1;
+ }
+ buffer = (char *) xmalloc (buflen);
+
+ /* Check normal operation. */
+ for (ifp = if_ni; !(ifp->if_index == 0 && ifp->if_name == NULL); ifp++)
+ {
+ unsigned int idx = if_nametoindex (ifp->if_name);
+ TEST_VERIFY (idx == ifp->if_index);
+
+ char *fn = if_indextoname (ifp->if_index, buffer);
+ TEST_VERIFY (strcmp (fn, ifp->if_name) == 0);
+ }
+
+ for (i=-2; i<min_idx; i++)
+ checki (i);
+ for (i=max_idx+1; i<max_idx+3; i++)
+ checki (i);
+
+ /* Check that a known-invalid name returns 0. */
+
+ for (i=0; test_names[i] != NULL; i++)
+ {
+ /* Make sure our "invalid" name is really invalid. */
+ for (ifp = if_ni; !(ifp->if_index == 0 && ifp->if_name == NULL); ifp++)
+ if (strcmp (test_names[i], ifp->if_name) == 0)
+ goto not_this_one;
+
+ printf ("Testing if_nametoindex (%s) == 0\n", test_names[i]);
+
+ unsigned int idx = if_nametoindex (test_names[i]);
+ TEST_VERIFY (idx == 0);
+ TEST_VERIFY (errno == ENODEV);
+
+ not_this_one:
+ }
+
+
+ if_freenameindex (if_ni);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

79
glibc-RHEL-106562-9.patch Normal file
View File

@ -0,0 +1,79 @@
commit 55cd51d971b84fbb2cc0fe8140cc8581f98582c7
Author: Joseph Myers <josmyers@redhat.com>
Date: Thu Aug 22 11:25:14 2024 +0000
Test mkdirat use of mode argument
The test io/tst-mkdirat doesn't verify the permissions on the created
directory (thus, doesn't verify at all anything about how mkdirat uses
the mode argument). Add checks of this to the existing test.
Tested for x86_64.
diff --git a/io/tst-mkdirat.c b/io/tst-mkdirat.c
index 605e51ef1e966b42..b97bc3ca6d0cdf23 100644
--- a/io/tst-mkdirat.c
+++ b/io/tst-mkdirat.c
@@ -53,6 +53,10 @@ prepare (void)
static int
do_test (void)
{
+ /* Find the current umask. */
+ mode_t mask = umask (022);
+ umask (mask);
+
/* fdopendir takes over the descriptor, make a copy. */
int dupfd = dup (dir_fd);
if (dupfd == -1)
@@ -107,6 +111,13 @@ do_test (void)
puts ("mkdirat did not create a directory");
return 1;
}
+ if ((st1.st_mode & 01777) != (~mask & 0777))
+ {
+ printf ("mkdirat created directory with wrong mode %o, expected %o\n",
+ (unsigned int) (st1.st_mode & 01777),
+ (unsigned int) (~mask & 0777));
+ return 1;
+ }
dupfd = dup (dir_fd);
if (dupfd == -1)
@@ -156,6 +167,37 @@ do_test (void)
return 1;
}
+ /* Test again with a different mode. */
+ umask (0);
+ e = mkdirat (dir_fd, "some-dir", 01755);
+ umask (mask);
+ if (e == -1)
+ {
+ puts ("directory creation (different mode) failed");
+ return 1;
+ }
+ if (fstatat64 (dir_fd, "some-dir", &st1, 0) != 0)
+ {
+ puts ("fstat64 (different mode) failed");
+ return 1;
+ }
+ if (!S_ISDIR (st1.st_mode))
+ {
+ puts ("mkdirat (different mode) did not create a directory");
+ return 1;
+ }
+ if ((st1.st_mode & 01777) != 01755)
+ {
+ printf ("mkdirat (different mode) created directory with wrong mode %o\n",
+ (unsigned int) (st1.st_mode & 01777));
+ return 1;
+ }
+ if (unlinkat (dir_fd, "some-dir", AT_REMOVEDIR) != 0)
+ {
+ puts ("unlinkat (different mode) failed");
+ return 1;
+ }
+
close (dir_fd);
return 0;

View File

@ -145,7 +145,7 @@ Version: %{glibcversion}
# - It allows using the Release number without the %%dist tag in the dependency
# generator to make the generated requires interchangeable between Rawhide
# and ELN (.elnYY < .fcXX).
%global baserelease 49
%global baserelease 50
Release: %{baserelease}%{?dist}
# Licenses:
@ -591,6 +591,30 @@ Patch267: glibc-RHEL-72564-2.patch
Patch268: glibc-RHEL-107540-1.patch
Patch269: glibc-RHEL-107540-2.patch
Patch270: glibc-RHEL-107540-3.patch
Patch271: glibc-RHEL-106562-1.patch
Patch272: glibc-RHEL-106562-2.patch
Patch273: glibc-RHEL-106562-3.patch
Patch274: glibc-RHEL-106562-4.patch
Patch275: glibc-RHEL-106562-5.patch
Patch276: glibc-RHEL-106562-6.patch
Patch277: glibc-RHEL-106562-7.patch
Patch278: glibc-RHEL-106562-8.patch
Patch279: glibc-RHEL-106562-9.patch
Patch280: glibc-RHEL-106562-10.patch
Patch281: glibc-RHEL-106562-11.patch
Patch282: glibc-RHEL-106562-12.patch
Patch283: glibc-RHEL-106562-13.patch
Patch284: glibc-RHEL-106562-14.patch
Patch285: glibc-RHEL-106562-15.patch
Patch286: glibc-RHEL-106562-16.patch
Patch287: glibc-RHEL-106562-17.patch
Patch288: glibc-RHEL-106562-18.patch
Patch289: glibc-RHEL-106562-19.patch
Patch290: glibc-RHEL-106562-20.patch
Patch291: glibc-RHEL-106562-21.patch
Patch292: glibc-RHEL-106562-22.patch
Patch293: glibc-RHEL-106562-23.patch
Patch294: glibc-RHEL-106562-24.patch
##############################################################################
# Continued list of core "glibc" package information:
@ -2603,6 +2627,9 @@ update_gconv_modules_cache ()
%endif
%changelog
* Wed Aug 06 2025 Arjun Shankar <arjun@redhat.com> - 2.39-50
- Improve test coverage (RHEL-106562)
* Tue Aug 05 2025 Florian Weimer <fweimer@redhat.com> - 2.39-49
- x86_64, aarch64: More CPU output in ld.so --list-diagnostics (RHEL-107540)