diff --git a/glibc-RHEL-46736-1.patch b/glibc-RHEL-46736-1.patch new file mode 100644 index 0000000..16146ee --- /dev/null +++ b/glibc-RHEL-46736-1.patch @@ -0,0 +1,67 @@ +commit e3fdbe9f39747206b9c3fbb0219f29fd5b35d020 +Author: Adhemerval Zanella +Date: Thu Apr 8 17:36:07 2021 -0300 + + support: Add xmkfifo + + Wrapper support mkfifo. + +diff --git a/support/Makefile b/support/Makefile +index 25e8bbefd78c2268..0273c0f6306720c9 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -137,6 +137,7 @@ libsupport-routines = \ + xmemstream \ + xmkdir \ + xmkdirp \ ++ xmkfifo \ + xmmap \ + xmprotect \ + xmunmap \ +diff --git a/support/xmkfifo.c b/support/xmkfifo.c +new file mode 100644 +index 0000000000000000..a8e196dbc209a47d +--- /dev/null ++++ b/support/xmkfifo.c +@@ -0,0 +1,29 @@ ++/* mkfifo with error checking. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++void ++xmkfifo (const char *pathname, mode_t mode) ++{ ++ int r = mkfifo (pathname, mode); ++ if (r < 0) ++ FAIL_EXIT1 ("mkfifo (%s, 0%o): %m", pathname, mode); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index a25ecf1cf38ef328..94b1e1eb1b1e8253 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -61,6 +61,7 @@ void xsymlink (const char *target, const char *linkpath); + void xchdir (const char *path); + void xfchmod (int fd, mode_t mode); + void xchmod (const char *pathname, mode_t mode); ++void xmkfifo (const char *pathname, mode_t mode); + + /* Equivalent of "mkdir -p". */ + void xmkdirp (const char *, mode_t); diff --git a/glibc-RHEL-46736-10.patch b/glibc-RHEL-46736-10.patch new file mode 100644 index 0000000..d65bf05 --- /dev/null +++ b/glibc-RHEL-46736-10.patch @@ -0,0 +1,30 @@ +commit 6948ee4edf0c57c556f8d5f394d9191216d05780 +Author: Florian Weimer +Date: Sat Sep 28 21:06:11 2024 +0200 + + stdio-common: Fix memory leak in tst-freopen4* tests on UNSUPPORTED + + The temp_dir allocation leaks if support_can_chroot returns false. + +diff --git a/stdio-common/tst-freopen4-main.c b/stdio-common/tst-freopen4-main.c +index e169442cf4df2e9d..7284677a97e10af6 100644 +--- a/stdio-common/tst-freopen4-main.c ++++ b/stdio-common/tst-freopen4-main.c +@@ -33,7 +33,7 @@ int + do_test (void) + { + mtrace (); +- char *temp_dir = support_create_temp_directory ("tst-freopen4"); ++ char *temp_dir; + FILE *fp; + int ret; + +@@ -45,6 +45,8 @@ do_test (void) + support_become_root (); + if (!support_can_chroot ()) + return EXIT_UNSUPPORTED; ++ ++ temp_dir = support_create_temp_directory ("tst-freopen4"); + xchroot (temp_dir); + + /* Test freopen with NULL, renamed file. This verifies that diff --git a/glibc-RHEL-46736-11.patch b/glibc-RHEL-46736-11.patch new file mode 100644 index 0000000..ed7722a --- /dev/null +++ b/glibc-RHEL-46736-11.patch @@ -0,0 +1,216 @@ +commit 42c810c2cf3554afbdd60885b7da6bb4e702466f +Author: Joseph Myers +Date: Mon Oct 7 19:44:25 2024 +0000 + + Add freopen special-case tests: thread cancellation + + Add tests of freopen adding or removing "c" (non-cancelling I/O) from + the mode string (so completing my planned tests of freopen with + different features used in the mode strings). Note that it's in the + nature of the uncertain time at which cancellation might act (possibly + during freopen, possibly during subsequent reads) that these can leak + memory or file descriptors, so these do not include leak tests. + + Tested for x86_64. + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index c920f55ed2119900..09d3622823203f74 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -180,10 +180,12 @@ tests := \ + tst-freopen4 \ + tst-freopen5 \ + tst-freopen6 \ ++ tst-freopen7 \ + tst-freopen64-2 \ + tst-freopen64-3 \ + tst-freopen64-4 \ + tst-freopen64-6 \ ++ tst-freopen64-7 \ + tst-fseek \ + tst-fwrite \ + tst-getline \ +@@ -480,3 +482,6 @@ $(objpfx)tst-setvbuf1-cmp.out: tst-setvbuf1.expect $(objpfx)tst-setvbuf1.out + + $(objpfx)tst-printf-round: $(libm) + $(objpfx)tst-scanf-round: $(libm) ++ ++$(objpfx)tst-freopen7: $(shared-thread-library) ++$(objpfx)tst-freopen64-7: $(shared-thread-library) +diff --git a/stdio-common/tst-freopen64-7.c b/stdio-common/tst-freopen64-7.c +new file mode 100644 +index 0000000000000000..f34c2805210079b9 +--- /dev/null ++++ b/stdio-common/tst-freopen64-7.c +@@ -0,0 +1,2 @@ ++#define FREOPEN freopen64 ++#include +diff --git a/stdio-common/tst-freopen7-main.c b/stdio-common/tst-freopen7-main.c +new file mode 100644 +index 0000000000000000..965e0b4adce750cc +--- /dev/null ++++ b/stdio-common/tst-freopen7-main.c +@@ -0,0 +1,155 @@ ++/* Test freopen cancellation handling. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++char *file1, *file2, *file3, *fifo; ++ ++sem_t sem; ++ ++void * ++test_rc_to_r (void *p) ++{ ++ int ret; ++ FILE *fp, *fp2; ++ ret = sem_post (&sem); ++ TEST_VERIFY_EXIT (ret == 0); ++ fp = xfopen (file1, "rc"); ++ for (int i = 0; i < 1000000; i++) ++ { ++ fgetc (fp); ++ fseek (fp, 0, SEEK_SET); ++ } ++ fp2 = xfopen (file3, "wc"); ++ fputs ("rc_to_r got to freopen", fp2); ++ xfclose (fp2); ++ /* Cancellation should occur at some point from here onwards ++ (possibly leaking memory and file descriptors associated with the ++ FILE). */ ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ for (;;) ++ { ++ fgetc (fp); ++ fseek (fp, 0, SEEK_SET); ++ } ++} ++ ++void * ++test_r_to_rc (void *p) ++{ ++ int ret; ++ FILE *fp; ++ fp = xfopen (file1, "r"); ++ fp = FREOPEN (fifo, "rc", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = sem_post (&sem); ++ TEST_VERIFY_EXIT (ret == 0); ++ /* No cancellation should occur for I/O on fifo. */ ++ ret = fgetc (fp); ++ /* At this point, the other thread has called pthread_cancel and ++ then written a byte to the fifo, so this thread is cancelled at ++ the next cancellation point. */ ++ TEST_VERIFY (ret == 'x'); ++ xfclose (fp); ++ fp = xfopen (file3, "wc"); ++ fputs ("r_to_rc got to fclose", fp); ++ xfclose (fp); ++ pthread_testcancel (); ++ FAIL_EXIT1 ("test_r_to_rc not cancelled\n"); ++} ++ ++int ++do_test (void) ++{ ++ char *temp_dir = support_create_temp_directory ("tst-freopen-cancel"); ++ file1 = xasprintf ("%s/file1", temp_dir); ++ support_write_file_string (file1, "file1"); ++ add_temp_file (file1); ++ file2 = xasprintf ("%s/file2", temp_dir); ++ support_write_file_string (file2, "file2"); ++ add_temp_file (file2); ++ file3 = xasprintf ("%s/file3", temp_dir); ++ support_write_file_string (file3, "file3"); ++ add_temp_file (file3); ++ fifo = xasprintf ("%s/fifo", temp_dir); ++ xmkfifo (fifo, 0666); ++ add_temp_file (fifo); ++ int ret; ++ pthread_t thr; ++ void *retval; ++ ++ /* Test changing to/from c (cancellation disabled). */ ++ ++ verbose_printf ("Testing rc -> r\n"); ++ ret = sem_init (&sem, 0, 0); ++ TEST_VERIFY_EXIT (ret == 0); ++ thr = xpthread_create (NULL, test_rc_to_r, NULL); ++ ret = sem_wait (&sem); ++ TEST_VERIFY_EXIT (ret == 0); ++ xpthread_cancel (thr); ++ ret = pthread_join (thr, &retval); ++ TEST_COMPARE (ret, 0); ++ TEST_VERIFY (retval == PTHREAD_CANCELED); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file3, "rc_to_r got to freopen"); ++ ++ verbose_printf ("Testing r -> rc\n"); ++ ret = sem_init (&sem, 0, 0); ++ TEST_VERIFY_EXIT (ret == 0); ++ thr = xpthread_create (NULL, test_r_to_rc, NULL); ++ FILE *fp = xfopen (fifo, "w"); ++ ret = sem_wait (&sem); ++ TEST_VERIFY_EXIT (ret == 0); ++ /* This call happens while, or before, the other thread is waiting ++ to read a character from the fifo. It thus verifies that ++ cancellation does not occur from the fgetc call in that thread ++ (it should instead occur only in pthread_testcancel call), ++ because the expected string is only written to file3 after that ++ thread closes the fifo. */ ++ xpthread_cancel (thr); ++ fputc ('x', fp); ++ xfclose (fp); ++ ret = pthread_join (thr, &retval); ++ TEST_COMPARE (ret, 0); ++ TEST_VERIFY (retval == PTHREAD_CANCELED); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file3, "r_to_rc got to fclose"); ++ ++ free (temp_dir); ++ free (file1); ++ free (file2); ++ free (file3); ++ return 0; ++} ++ ++#include +diff --git a/stdio-common/tst-freopen7.c b/stdio-common/tst-freopen7.c +new file mode 100644 +index 0000000000000000..03d0de798e3d2616 +--- /dev/null ++++ b/stdio-common/tst-freopen7.c +@@ -0,0 +1,2 @@ ++#define FREOPEN freopen ++#include diff --git a/glibc-RHEL-46736-2.patch b/glibc-RHEL-46736-2.patch new file mode 100644 index 0000000..9adda66 --- /dev/null +++ b/glibc-RHEL-46736-2.patch @@ -0,0 +1,168 @@ +commit da55fae9e277a0c138d4395fee505e5d2f8b2b84 +Author: Carlos O'Donell +Date: Tue May 23 08:34:56 2023 -0400 + + support: Reformat Makefile. + + Add list end markers. + Sort text using scripts/sort-makefile-lines.py. + + No code generation changes observed in non-test binary artifacts. + No regressions on x86_64 and i686. + +Conflicts: + support/Makefile + (different backport order) + + +diff --git a/support/Makefile b/support/Makefile +index 0273c0f6306720c9..17a4157563f9ecd6 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -41,7 +41,7 @@ libsupport-routines = \ + resolv_response_context_free \ + resolv_test \ + set_fortify_handler \ +- support_stack_alloc \ ++ support-open-dev-null-range \ + support_become_root \ + support_can_chroot \ + support_capture_subprocess \ +@@ -65,12 +65,11 @@ libsupport-routines = \ + support_fuse \ + support_isolate_in_subprocess \ + support_need_proc \ ++ support_openpty \ + support_path_support_time64 \ ++ support_paths \ + support_process_state \ + support_ptrace \ +- support-open-dev-null-range \ +- support_openpty \ +- support_paths \ + support_quote_blob \ + support_quote_blob_wide \ + support_quote_string \ +@@ -84,6 +83,8 @@ libsupport-routines = \ + support_shared_allocate \ + support_small_stack_thread_attribute \ + support_socket_so_timestamp_time64 \ ++ support_stack_alloc \ ++ support_stack_alloc \ + support_stat_nanoseconds \ + support_subprocess \ + support_test_compare_blob \ +@@ -96,11 +97,11 @@ libsupport-routines = \ + support_write_file_string \ + temp_file \ + timespec \ +- timespec-time64 \ + timespec-add \ + timespec-add-time64 \ + timespec-sub \ + timespec-sub-time64 \ ++ timespec-time64 \ + write_message \ + xaccept \ + xaccept4 \ +@@ -108,6 +109,8 @@ libsupport-routines = \ + xbind \ + xcalloc \ + xchdir \ ++ xchmod \ ++ xchmod \ + xchroot \ + xclock_gettime \ + xclock_gettime_time64 \ +@@ -116,7 +119,6 @@ libsupport-routines = \ + xclone \ + xclose \ + xclosedir \ +- xchmod \ + xconnect \ + xcopy_file_range \ + xdlfcn \ +@@ -147,11 +149,17 @@ libsupport-routines = \ + xpipe \ + xpoll \ + xposix_memalign \ ++ xposix_spawn \ ++ xposix_spawn \ ++ xposix_spawn_file_actions_addclose \ ++ xposix_spawn_file_actions_addclose \ ++ xposix_spawn_file_actions_adddup2 \ ++ xposix_spawn_file_actions_adddup2 \ + xpthread_attr_destroy \ + xpthread_attr_init \ ++ xpthread_attr_setaffinity_np \ + xpthread_attr_setdetachstate \ + xpthread_attr_setguardsize \ +- xpthread_attr_setaffinity_np \ + xpthread_attr_setstack \ + xpthread_attr_setstacksize \ + xpthread_barrier_destroy \ +@@ -162,8 +170,8 @@ libsupport-routines = \ + xpthread_barrierattr_setpshared \ + xpthread_cancel \ + xpthread_check_return \ +- xpthread_cond_wait \ + xpthread_cond_signal \ ++ xpthread_cond_wait \ + xpthread_create \ + xpthread_detach \ + xpthread_join \ +@@ -182,8 +190,8 @@ libsupport-routines = \ + xpthread_mutexattr_setrobust \ + xpthread_mutexattr_settype \ + xpthread_once \ +- xpthread_rwlock_init \ + xpthread_rwlock_destroy \ ++ xpthread_rwlock_init \ + xpthread_rwlock_rdlock \ + xpthread_rwlock_unlock \ + xpthread_rwlock_wrlock \ +@@ -204,9 +212,6 @@ libsupport-routines = \ + xsigstack \ + xsocket \ + xstatx \ +- xposix_spawn \ +- xposix_spawn_file_actions_addclose \ +- xposix_spawn_file_actions_adddup2 \ + xstrdup \ + xstrndup \ + xsymlink \ +@@ -215,6 +220,7 @@ libsupport-routines = \ + xuselocale \ + xwaitpid \ + xwrite \ ++ # libsupport-routines + + libsupport-static-only-routines := $(libsupport-routines) + # Only build one variant of the library. +@@ -278,8 +284,16 @@ LDLIBS-test-container = $(libsupport) + others += test-container + others-noinstall += test-container + +-others += shell-container echo-container true-container +-others-noinstall += shell-container echo-container true-container ++others += \ ++ echo-container \ ++ shell-container \ ++ true-container \ ++ # others ++others-noinstall += \ ++ echo-container \ ++ shell-container \ ++ true-container \ ++ # others-noinstall + + others += $(LINKS_DSO_PROGRAM) + others-noinstall += $(LINKS_DSO_PROGRAM) +@@ -317,6 +331,7 @@ tests = \ + tst-xdirent \ + tst-xreadlink \ + tst-xsigstack \ ++ # tests + + ifeq ($(run-built-tests),yes) + tests-special = \ diff --git a/glibc-RHEL-46736-3.patch b/glibc-RHEL-46736-3.patch new file mode 100644 index 0000000..2dde8b5 --- /dev/null +++ b/glibc-RHEL-46736-3.patch @@ -0,0 +1,261 @@ +commit 96d0bf98cafd0b63721f369ca21ec64590551d47 +Author: Joseph Myers +Date: Tue Sep 3 13:53:01 2024 +0000 + + Add support/ code for checking file contents + + For use in freopen tests, add various support/ helper interfaces for + use in checking file contents. + + Tested for x86_64. + +diff --git a/support/Makefile b/support/Makefile +index 38ad266a0dec8e36..e70322cea06f137b 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -48,6 +48,8 @@ libsupport-routines = \ + support_check_stat_fd \ + support_check_stat_path \ + support_chroot \ ++ support_compare_file_bytes \ ++ support_compare_file_string \ + support_copy_file \ + support_copy_file_range \ + support_create_timer \ +@@ -64,6 +66,8 @@ libsupport-routines = \ + support_fuse \ + support_isolate_in_subprocess \ + support_need_proc \ ++ support_open_and_compare_file_bytes \ ++ support_open_and_compare_file_string \ + support_openpty \ + support_path_support_time64 \ + support_paths \ +diff --git a/support/file_contents.h b/support/file_contents.h +new file mode 100644 +index 0000000000000000..9b2d750aae8a885a +--- /dev/null ++++ b/support/file_contents.h +@@ -0,0 +1,63 @@ ++/* Functionality for checking file contents. ++ 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 ++ . */ ++ ++#ifndef SUPPORT_FILE_CONTENTS_H ++#define SUPPORT_FILE_CONTENTS_H ++ ++#include ++#include ++ ++__BEGIN_DECLS ++ ++/* Check that an already-open file has exactly the given bytes, ++ starting at the current location in the file. The file position ++ indicator is updated to point after the bytes compared. Return 0 ++ if equal, 1 otherwise or on read error. */ ++int support_compare_file_bytes (FILE *fp, const char *contents, size_t length); ++ ++/* Check that an already-open file has exactly the given string as ++ contents, starting at the current offset. The file position ++ indicator is updated to point after the bytes compared. Return 0 ++ if equal, 1 otherwise or on read error. */ ++int support_compare_file_string (FILE *fp, const char *contents); ++ ++/* Check that a not-currently-open file has exactly the given bytes. ++ Return 0 if equal, 1 otherwise or on read error. */ ++int support_open_and_compare_file_bytes (const char *file, ++ const char *contents, ++ size_t length); ++ ++/* Check that a not-currently-open file has exactly the given string ++ as contents, starting at the current offset. Return 0 if equal, 1 ++ otherwise or on read error. */ ++int support_open_and_compare_file_string (const char *file, ++ const char *contents); ++ ++/* Compare bytes read from an open file with the given string. The ++ file position indicator is updated to point after the bytes ++ compared. */ ++#define TEST_COMPARE_FILE_STRING(FP, CONTENTS) \ ++ TEST_COMPARE (support_compare_file_string (FP, CONTENTS), 0) ++ ++/* Read a file and compare bytes read from it with the given string. */ ++#define TEST_OPEN_AND_COMPARE_FILE_STRING(FILE, CONTENTS) \ ++ TEST_COMPARE (support_open_and_compare_file_string (FILE, CONTENTS), 0) ++ ++__END_DECLS ++ ++#endif /* SUPPORT_FILE_CONTENTS_H */ +diff --git a/support/support_compare_file_bytes.c b/support/support_compare_file_bytes.c +new file mode 100644 +index 0000000000000000..e261e1da8f7b02b2 +--- /dev/null ++++ b/support/support_compare_file_bytes.c +@@ -0,0 +1,42 @@ ++/* Compare bytes from an open file. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++#include ++ ++/* Check that an already-open file has exactly the given bytes, ++ starting at the current offset. */ ++ ++int ++support_compare_file_bytes (FILE *fp, const char *contents, size_t length) ++{ ++ int c; ++ while (length > 0) ++ { ++ c = getc (fp); ++ if (c == EOF || (unsigned char) c != (unsigned char) contents[0]) ++ return 1; ++ contents++; ++ length--; ++ } ++ c = getc (fp); ++ if (c != EOF || ferror (fp)) ++ return 1; ++ return 0; ++} +diff --git a/support/support_compare_file_string.c b/support/support_compare_file_string.c +new file mode 100644 +index 0000000000000000..04513c3af197037d +--- /dev/null ++++ b/support/support_compare_file_string.c +@@ -0,0 +1,28 @@ ++/* Compare string from an open file. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++#include ++ ++int ++support_compare_file_string (FILE *fp, const char *contents) ++{ ++ return support_compare_file_bytes (fp, contents, strlen (contents)); ++} +diff --git a/support/support_open_and_compare_file_bytes.c b/support/support_open_and_compare_file_bytes.c +new file mode 100644 +index 0000000000000000..f804ed8e460d82f0 +--- /dev/null ++++ b/support/support_open_and_compare_file_bytes.c +@@ -0,0 +1,33 @@ ++/* Compare bytes from a file. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++/* Check that a not-currently-open file has exactly the given ++ bytes. */ ++ ++int ++support_open_and_compare_file_bytes (const char *file, const char *contents, ++ size_t length) ++{ ++ FILE *fp = xfopen (file, "r"); ++ int ret = support_compare_file_bytes (fp, contents, length); ++ xfclose (fp); ++ return ret; ++} +diff --git a/support/support_open_and_compare_file_string.c b/support/support_open_and_compare_file_string.c +new file mode 100644 +index 0000000000000000..2b596d4c88b697f2 +--- /dev/null ++++ b/support/support_open_and_compare_file_string.c +@@ -0,0 +1,32 @@ ++/* Compare string from a file. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++#include ++#include ++ ++/* Check that a not-currently-open file has exactly the given string ++ as contents, starting at the current offset. */ ++ ++int ++support_open_and_compare_file_string (const char *file, const char *contents) ++{ ++ return support_open_and_compare_file_bytes (file, contents, ++ strlen (contents)); ++} diff --git a/glibc-RHEL-46736-4.patch b/glibc-RHEL-46736-4.patch new file mode 100644 index 0000000..cb728cb --- /dev/null +++ b/glibc-RHEL-46736-4.patch @@ -0,0 +1,739 @@ +commit ed4bb289cf739f537deb735eaa01be531df084b9 +Author: Joseph Myers +Date: Wed Sep 4 16:32:21 2024 +0000 + + Add more thorough tests of freopen + + freopen is rather minimally tested in libio/tst-freopen and + libio/test-freopen. Add some more thorough tests, covering different + cases for change of mode in particular. The tests are run for both + freopen and freopen64 (given that those functions have two separate + copies of much of the code, so any bug fix directly in the freopen + code would probably need applying in both places). + + Note that there are two parts of the tests disabled because of bugs + discovered through running the tests, with bug numbers given in + comments. I expect to address those separately. The tests also don't + cover changes to cancellation ("c" in mode); I think that will better + be handled through a separate test. Also to handle separately: + testing on stdin / stdout / stderr; documenting lack of support for + streams opened with popen / fmemopen / open_memstream / fopencookie; + maybe also a chroot test without /proc; maybe also more thorough tests + for large file handling on 32-bit systems (freopen64). + + Tested for x86_64. + +Conflicts: + stdio-common/Makefile + (tst-fread already backported) + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index ea8598bbe3a6dfdd..5eddc4bfbf4e7fb9 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -175,6 +175,10 @@ tests := \ + tst-fphex \ + tst-fphex-wide \ + tst-fread \ ++ tst-freopen2 \ ++ tst-freopen3 \ ++ tst-freopen64-2 \ ++ tst-freopen64-3 \ + tst-fseek \ + tst-fwrite \ + tst-getline \ +@@ -246,6 +250,8 @@ tests-special += \ + ifeq (yes,$(build-shared)) + ifneq ($(PERL),no) + tests-special += \ ++ $(objpfx)tst-freopen2-mem.out \ ++ $(objpfx)tst-freopen64-2-mem.out \ + $(objpfx)tst-getline-enomem-mem.out \ + $(objpfx)tst-getline-mem.out \ + $(objpfx)tst-printf-bz18872-mem.out \ +@@ -256,6 +262,10 @@ tests-special += \ + # tests-special + + generated += \ ++ tst-freopen2-mem.out \ ++ tst-freopen2.mtrace \ ++ tst-freopen64-2-mem.out \ ++ tst-freopen64-2.mtrace \ + tst-getline-enomem-mem.out \ + tst-getline-enomem.mtrace \ + tst-getline-mem.out \ +@@ -328,6 +338,12 @@ tst-getline-ENV = \ + tst-getline-enomem-ENV = \ + MALLOC_TRACE=$(objpfx)tst-getline-enomem.mtrace \ + LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-freopen2-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-freopen2.mtrace \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-freopen64-2-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-freopen64-2.mtrace \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so + + $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc + $(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \ +diff --git a/stdio-common/tst-freopen2-main.c b/stdio-common/tst-freopen2-main.c +new file mode 100644 +index 0000000000000000..22b21afebf709563 +--- /dev/null ++++ b/stdio-common/tst-freopen2-main.c +@@ -0,0 +1,526 @@ ++/* Test freopen. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define START_TEST(DESC) \ ++ do \ ++ { \ ++ fds = support_descriptors_list (); \ ++ verbose_printf (DESC); \ ++ } \ ++ while (0) ++ ++#define END_TEST \ ++ do \ ++ { \ ++ support_descriptors_check (fds); \ ++ support_descriptors_free (fds); \ ++ } \ ++ while (0) ++ ++int ++do_test (void) ++{ ++ mtrace (); ++ struct support_descriptors *fds; ++ char *temp_dir = support_create_temp_directory ("tst-freopen2"); ++ char *file1 = xasprintf ("%s/file1", temp_dir); ++ support_write_file_string (file1, "file1"); ++ add_temp_file (file1); ++ char *file2 = xasprintf ("%s/file2", temp_dir); ++ support_write_file_string (file2, "file2"); ++ add_temp_file (file2); ++ char *file3 = xasprintf ("%s/file3", temp_dir); ++ char *file4 = xasprintf ("%s/file4", temp_dir); ++ char *file1a = xasprintf ("%s/file1a", temp_dir); ++ FILE *fp; ++ int ret; ++ wint_t wc; ++ ++ /* Test each pair of old and new modes from r w a. */ ++ ++ START_TEST ("Testing r -> r\n"); ++ fp = xfopen (file1, "r"); ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "file2"); ++ xfclose (fp); ++ END_TEST; ++ ++ START_TEST ("Testing r -> w\n"); ++ fp = xfopen (file1, "r"); ++ fp = FREOPEN (file2, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("File2new", fp); ++ TEST_VERIFY (ret >= 0); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file1, "file1"); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "File2new"); ++ END_TEST; ++ ++ START_TEST ("Testing r -> a\n"); ++ fp = xfopen (file1, "r"); ++ fp = FREOPEN (file2, "a", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("3", fp); ++ TEST_VERIFY (ret >= 0); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "File2new3"); ++ END_TEST; ++ ++ START_TEST ("Testing w -> r\n"); ++ fp = xfopen (file1, "w"); ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "File2new3"); ++ xfclose (fp); ++ END_TEST; ++ ++ START_TEST ("Testing w -> w\n"); ++ fp = xfopen (file1, "w"); ++ fp = FREOPEN (file2, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("next", fp); ++ TEST_VERIFY (ret >= 0); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file1, ""); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "next"); ++ END_TEST; ++ ++ START_TEST ("Testing w -> a\n"); ++ fp = xfopen (file1, "w"); ++ fp = FREOPEN (file2, "a", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("4", fp); ++ TEST_VERIFY (ret >= 0); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "next4"); ++ END_TEST; ++ ++ START_TEST ("Testing a -> r\n"); ++ fp = xfopen (file1, "a"); ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "next4"); ++ xfclose (fp); ++ END_TEST; ++ ++ START_TEST ("Testing a -> w\n"); ++ fp = xfopen (file1, "a"); ++ fp = FREOPEN (file2, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("another", fp); ++ TEST_VERIFY (ret >= 0); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "another"); ++ END_TEST; ++ ++ START_TEST ("Testing a -> a\n"); ++ fp = xfopen (file1, "a"); ++ fp = FREOPEN (file2, "a", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("5", fp); ++ TEST_VERIFY (ret >= 0); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "another5"); ++ END_TEST; ++ ++ /* Test for file originally opened with fopen64. */ ++ START_TEST ("Testing fopen64 a -> a\n"); ++ fp = fopen64 (file1, "a"); ++ TEST_VERIFY_EXIT (fp != NULL); ++ fp = FREOPEN (file2, "a", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("64", fp); ++ TEST_VERIFY (ret >= 0); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "another564"); ++ END_TEST; ++ ++ /* Test calling freopen more than once on the same FILE *. */ ++ ++ START_TEST ("Testing r -> w -> r\n"); ++ fp = xfopen (file1, "r"); ++ fp = FREOPEN (file2, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("freopen-twice", fp); ++ TEST_VERIFY (ret >= 0); ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "freopen-twice"); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "freopen-twice"); ++ END_TEST; ++ ++ START_TEST ("Testing r -> w -> r (exactly one freopen64)\n"); ++ fp = xfopen (file1, "r"); ++ fp = OTHER_FREOPEN (file2, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("freopen-twice64", fp); ++ TEST_VERIFY (ret >= 0); ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "freopen-twice64"); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "freopen-twice64"); ++ END_TEST; ++ ++ /* Test changing to/from b (binary, no-op). */ ++ ++ START_TEST ("Testing rb -> r\n"); ++ fp = xfopen (file1, "rb"); ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "freopen-twice64"); ++ xfclose (fp); ++ END_TEST; ++ ++ START_TEST ("Testing r -> rb\n"); ++ fp = xfopen (file1, "r"); ++ fp = FREOPEN (file2, "rb", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "freopen-twice64"); ++ xfclose (fp); ++ END_TEST; ++ ++ /* Test changing to/from + (read-and-write). */ ++ ++ START_TEST ("Testing r -> w+\n"); ++ fp = xfopen (file1, "r"); ++ fp = FREOPEN (file2, "w+", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("latest", fp); ++ TEST_VERIFY (ret >= 0); ++ ret = fseek (fp, 0, SEEK_SET); ++ TEST_COMPARE (ret, 0); ++ TEST_COMPARE_FILE_STRING (fp, "latest"); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "latest"); ++ END_TEST; ++ ++ START_TEST ("Testing w -> a+\n"); ++ fp = xfopen (file1, "w"); ++ fp = FREOPEN (file2, "a+", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("suffix", fp); ++ TEST_VERIFY (ret >= 0); ++ ret = fseek (fp, 0, SEEK_SET); ++ TEST_COMPARE (ret, 0); ++ TEST_COMPARE_FILE_STRING (fp, "latestsuffix"); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "latestsuffix"); ++ END_TEST; ++ ++ START_TEST ("Testing a -> r+\n"); ++ fp = xfopen (file1, "a"); ++ fp = FREOPEN (file2, "r+", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "latestsuffix"); ++ ret = fseek (fp, 0, SEEK_SET); ++ TEST_COMPARE (ret, 0); ++ ret = fputs ("new", fp); ++ TEST_VERIFY (ret >= 0); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "newestsuffix"); ++ END_TEST; ++ ++ START_TEST ("Testing r+ -> w\n"); ++ fp = xfopen (file1, "r+"); ++ fp = FREOPEN (file2, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("plusto", fp); ++ TEST_VERIFY (ret >= 0); ++ ret = fseek (fp, 0, SEEK_SET); ++ TEST_COMPARE (ret, 0); ++ errno = 0; ++ TEST_COMPARE (fgetc (fp), EOF); ++ TEST_COMPARE (errno, EBADF); ++ clearerr (fp); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "plusto"); ++ END_TEST; ++ ++ START_TEST ("Testing w+ -> a\n"); ++ fp = xfopen (file1, "w+"); ++ fp = FREOPEN (file2, "a", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("more", fp); ++ TEST_VERIFY (ret >= 0); ++ ret = fseek (fp, 0, SEEK_SET); ++ TEST_COMPARE (ret, 0); ++ errno = 0; ++ TEST_COMPARE (fgetc (fp), EOF); ++ TEST_COMPARE (errno, EBADF); ++ clearerr (fp); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "plustomore"); ++ END_TEST; ++ ++ START_TEST ("Testing a+ -> r\n"); ++ fp = xfopen (file1, "a+"); ++ fp = FREOPEN (file2, "rr", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "plustomore"); ++ ret = fputs ("2", fp); ++ TEST_COMPARE (ret, EOF); ++ clearerr (fp); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "plustomore"); ++ END_TEST; ++ ++ /* Test changing to/from e (FD_CLOEXEC). */ ++ ++ START_TEST ("Testing re -> r\n"); ++ fp = xfopen (file1, "re"); ++ ret = fcntl (fileno (fp), F_GETFD); ++ TEST_VERIFY (ret != -1); ++ TEST_COMPARE (ret & FD_CLOEXEC, FD_CLOEXEC); ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fcntl (fileno (fp), F_GETFD); ++ TEST_VERIFY (ret != -1); ++#if 0 /* Fails to clear FD_CLOEXEC (bug 32134). */ ++ TEST_COMPARE (ret & FD_CLOEXEC, 0); ++#endif ++ TEST_COMPARE_FILE_STRING (fp, "plustomore"); ++ xfclose (fp); ++ END_TEST; ++ ++ START_TEST ("Testing r -> re\n"); ++ fp = xfopen (file1, "r"); ++ ret = fcntl (fileno (fp), F_GETFD); ++ TEST_VERIFY (ret != -1); ++ TEST_COMPARE (ret & FD_CLOEXEC, 0); ++ fp = FREOPEN (file2, "re", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fcntl (fileno (fp), F_GETFD); ++ TEST_VERIFY (ret != -1); ++ TEST_COMPARE (ret & FD_CLOEXEC, FD_CLOEXEC); ++ TEST_COMPARE_FILE_STRING (fp, "plustomore"); ++ xfclose (fp); ++ END_TEST; ++ ++ /* Test changing to/from m (mmap) (a no-op as far as testing ++ semantics is concerned). */ ++ ++ START_TEST ("Testing rm -> r\n"); ++ fp = xfopen (file1, "rm"); ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "plustomore"); ++ xfclose (fp); ++ END_TEST; ++ ++ START_TEST ("Testing r -> rm\n"); ++ fp = xfopen (file1, "r"); ++ fp = FREOPEN (file2, "rm", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "plustomore"); ++ xfclose (fp); ++ END_TEST; ++ ++ /* Test changing to/from x (O_EXCL). */ ++ ++ START_TEST ("Testing wx -> w\n"); ++ fp = xfopen (file3, "wx"); ++ add_temp_file (file3); ++ fp = FREOPEN (file2, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ ret = fputs ("wxtow", fp); ++ TEST_VERIFY (ret >= 0); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file2, "wxtow"); ++ END_TEST; ++ ++ START_TEST ("Testing w -> wx (file does not exist)\n"); ++ fp = xfopen (file1, "w"); ++ fp = FREOPEN (file4, "wx", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ add_temp_file (file4); ++ ret = fputs ("wtowx", fp); ++ TEST_VERIFY (ret >= 0); ++ xfclose (fp); ++ TEST_OPEN_AND_COMPARE_FILE_STRING (file4, "wtowx"); ++ END_TEST; ++ ++ /* Test with ,ccs=CHARSET. */ ++ ++ START_TEST ("testing w,ccs=utf-8 -> r\n"); ++ fp = xfopen (file1, "w,ccs=utf-8"); ++ ret = fputws (L"\xc0\xc1", fp); ++ TEST_VERIFY (ret >= 0); ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "wxtow"); ++ xfclose (fp); ++ END_TEST; ++ ++ START_TEST ("testing w,ccs=iso-8859-1 -> r,ccs=utf-8\n"); ++ fp = xfopen (file2, "w,ccs=iso-8859-1"); ++ ret = fputws (L"\xc0\xc1", fp); ++ TEST_VERIFY (ret >= 0); ++#if 0 /* Doesn't work (bug 23675). */ ++ fp = FREOPEN (file1, "r,ccs=utf-8", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++#else /* Works instead. */ ++ xfclose (fp); ++ fp = xfopen (file1, "r,ccs=utf-8"); ++#endif ++ wc = fgetwc (fp); ++ TEST_COMPARE (wc, (wint_t) 0xc0); ++ wc = fgetwc (fp); ++ TEST_COMPARE (wc, (wint_t) 0xc1); ++ wc = fgetwc (fp); ++ TEST_COMPARE (wc, WEOF); ++ xfclose (fp); ++ END_TEST; ++ ++ START_TEST ("testing r,ccs=utf-8 -> r\n"); ++ fp = xfopen (file1, "r,ccs=utf-8"); ++ fp = FREOPEN (file1, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "\u00c0\u00c1"); ++ xfclose (fp); ++ END_TEST; ++ ++ /* Test that errors closing the old file are ignored. */ ++ ++ START_TEST ("testing errors closing old file ignored\n"); ++ fp = xfopen ("/dev/full", "w"); ++ fputc ('x', fp); ++ fp = FREOPEN (file1, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "\u00c0\u00c1"); ++ xfclose (fp); ++ END_TEST; ++ ++ /* Test that error / EOF state from the old file are cleared. */ ++ ++ START_TEST ("testing error state from old file cleared\n"); ++ fp = xfopen ("/dev/full", "w"); ++ fputc ('x', fp); ++ fflush (fp); ++ TEST_VERIFY (ferror (fp)); ++ TEST_VERIFY (!feof (fp)); ++ fp = FREOPEN (file2, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_VERIFY (!ferror (fp)); ++ TEST_VERIFY (!feof (fp)); ++ xfclose (fp); ++ END_TEST; ++ ++ START_TEST ("testing EOF state from old file cleared\n"); ++ fp = xfopen ("/dev/null", "r"); ++ fgetc (fp); ++ TEST_VERIFY (!ferror (fp)); ++ TEST_VERIFY (feof (fp)); ++ fp = FREOPEN (file2, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_VERIFY (!ferror (fp)); ++ TEST_VERIFY (!feof (fp)); ++ xfclose (fp); ++ END_TEST; ++ ++ /* Test freopen with NULL, same mode (should flush content and reset ++ file offset). */ ++ ++ START_TEST ("testing freopen with NULL, same mode\n"); ++ fp = xfopen (file1, "r+"); ++ ret = fputs ("same mode", fp); ++ TEST_VERIFY (ret >= 0); ++ fp = FREOPEN (NULL, "r+", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "same mode"); ++ xfclose (fp); ++ END_TEST; ++ ++ /* Test freopen with NULL, different mode. */ ++ ++ START_TEST ("testing freopen with NULL, different mode\n"); ++ fp = xfopen (file1, "w"); ++ ret = fputs ("different mode", fp); ++ TEST_VERIFY (ret >= 0); ++ fp = FREOPEN (NULL, "r", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "different mode"); ++ xfclose (fp); ++ END_TEST; ++ ++ /* Test freopen with NULL, renamed file. This verifies that ++ reopening succeeds (and resets the file position indicator to ++ start of file) even when the original path could no longer be ++ opened. */ ++ ++ START_TEST ("testing freopen with NULL, renamed file\n"); ++ fp = xfopen (file1, "r+"); ++ ret = fputs ("file has been renamed", fp); ++ TEST_VERIFY (ret >= 0); ++ ret = rename (file1, file1a); ++ TEST_COMPARE (ret, 0); ++ fp = FREOPEN (NULL, "r+", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "file has been renamed"); ++ xfclose (fp); ++ ret = rename (file1a, file1); ++ TEST_COMPARE (ret, 0); ++ END_TEST; ++ ++ /* Test freopen with NULL, deleted file. This verifies that ++ reopening succeeds (and resets the file position indicator to ++ start of file) even when the original path could no longer be ++ opened. */ ++ ++ START_TEST ("testing freopen with NULL, deleted file\n"); ++ fp = xfopen (file1, "r+"); ++ ret = fputs ("file has now been deleted", fp); ++ TEST_VERIFY (ret >= 0); ++ ret = remove (file1); ++ TEST_COMPARE (ret, 0); ++ fp = FREOPEN (NULL, "r+", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ TEST_COMPARE_FILE_STRING (fp, "file has now been deleted"); ++ xfclose (fp); ++ /* Recreate the file so it is present when expected for temporary ++ file deletion. */ ++ support_write_file_string (file1, "file1"); ++ END_TEST; ++ ++ free (temp_dir); ++ free (file1); ++ free (file2); ++ free (file3); ++ free (file4); ++ free (file1a); ++ return 0; ++} ++ ++#include +diff --git a/stdio-common/tst-freopen2.c b/stdio-common/tst-freopen2.c +new file mode 100644 +index 0000000000000000..11ec7a9783b7caa3 +--- /dev/null ++++ b/stdio-common/tst-freopen2.c +@@ -0,0 +1,3 @@ ++#define FREOPEN freopen ++#define OTHER_FREOPEN freopen64 ++#include +diff --git a/stdio-common/tst-freopen3-main.c b/stdio-common/tst-freopen3-main.c +new file mode 100644 +index 0000000000000000..5107e1f98e189e4b +--- /dev/null ++++ b/stdio-common/tst-freopen3-main.c +@@ -0,0 +1,90 @@ ++/* Test freopen failure. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define START_TEST(DESC) \ ++ do \ ++ { \ ++ fds = support_descriptors_list (); \ ++ verbose_printf (DESC); \ ++ } \ ++ while (0) ++ ++#define END_TEST \ ++ do \ ++ { \ ++ support_descriptors_check (fds); \ ++ support_descriptors_free (fds); \ ++ } \ ++ while (0) ++ ++int ++do_test (void) ++{ ++ struct support_descriptors *fds; ++ char *temp_dir = support_create_temp_directory ("tst-freopen3"); ++ char *file1 = xasprintf ("%s/file1", temp_dir); ++ support_write_file_string (file1, "file1"); ++ add_temp_file (file1); ++ char *file2 = xasprintf ("%s/file2", temp_dir); ++ support_write_file_string (file2, "file2"); ++ add_temp_file (file2); ++ char *file_nodir = xasprintf ("%s/nodir/file", temp_dir); ++ FILE *fp; ++ int ret; ++ int fd; ++ ++ START_TEST ("Testing w -> wx (file exists)\n"); ++ fp = xfopen (file1, "w"); ++ fp = FREOPEN (file2, "wx", fp); ++ TEST_VERIFY (fp == NULL); ++ END_TEST; ++ ++ /* Test old file is closed even when opening the new file fails. */ ++ ++ START_TEST ("testing r -> r (opening new file fails)\n"); ++ fp = xfopen (file1, "r"); ++ fd = fileno (fp); ++ fp = FREOPEN (file_nodir, "r", fp); ++ TEST_VERIFY (fp == NULL); ++ errno = 0; ++ ret = fcntl (fd, F_GETFL); ++ TEST_COMPARE (ret, -1); ++ TEST_COMPARE (errno, EBADF); ++ END_TEST; ++ ++ free (temp_dir); ++ free (file1); ++ free (file2); ++ free (file_nodir); ++ return 0; ++} ++ ++#include +diff --git a/stdio-common/tst-freopen3.c b/stdio-common/tst-freopen3.c +new file mode 100644 +index 0000000000000000..5041b6b2332c8af1 +--- /dev/null ++++ b/stdio-common/tst-freopen3.c +@@ -0,0 +1,2 @@ ++#define FREOPEN freopen ++#include +diff --git a/stdio-common/tst-freopen64-2.c b/stdio-common/tst-freopen64-2.c +new file mode 100644 +index 0000000000000000..88fdc64d8c6548f5 +--- /dev/null ++++ b/stdio-common/tst-freopen64-2.c +@@ -0,0 +1,3 @@ ++#define FREOPEN freopen64 ++#define OTHER_FREOPEN freopen ++#include +diff --git a/stdio-common/tst-freopen64-3.c b/stdio-common/tst-freopen64-3.c +new file mode 100644 +index 0000000000000000..b91b6d2c033a1a79 +--- /dev/null ++++ b/stdio-common/tst-freopen64-3.c +@@ -0,0 +1,2 @@ ++#define FREOPEN freopen64 ++#include diff --git a/glibc-RHEL-46736-5.patch b/glibc-RHEL-46736-5.patch new file mode 100644 index 0000000..ca67e62 --- /dev/null +++ b/glibc-RHEL-46736-5.patch @@ -0,0 +1,69 @@ +commit f512634ddef242ef0ff025ddeba64ce51035040f +Author: Joseph Myers +Date: Thu Sep 5 11:15:29 2024 +0000 + + Clear flags2 flags set from mode in freopen (bug 32134) + + As reported in bug 32134, freopen does not clear the flags set in + fp->_flags2 by the "e", "m" or "c" mode characters. Clear these so + that they can be set or not as appropriate from the mode string passed + to freopen. The relevant test for "e" in tst-freopen2-main.c is + enabled accordingly; "c" is expected to be covered in a separately + written test (and while tst-freopen2-main.c does include transitions + to and from "m", that's not really a semantic flag intended to result + in behaving in an observably different way). + + Tested for x86_64. + +diff --git a/libio/freopen.c b/libio/freopen.c +index c947a5aecfde3c80..bed034d89441f200 100644 +--- a/libio/freopen.c ++++ b/libio/freopen.c +@@ -63,6 +63,9 @@ freopen (const char *filename, const char *mode, FILE *fp) + up here. */ + _IO_old_file_close_it (fp); + _IO_JUMPS_FUNC_UPDATE (fp, &_IO_old_file_jumps); ++ fp->_flags2 &= ~(_IO_FLAGS2_MMAP ++ | _IO_FLAGS2_NOTCANCEL ++ | _IO_FLAGS2_CLOEXEC); + result = _IO_old_file_fopen (fp, gfilename, mode); + } + else +@@ -72,6 +75,9 @@ freopen (const char *filename, const char *mode, FILE *fp) + _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps; + if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL) + fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; ++ fp->_flags2 &= ~(_IO_FLAGS2_MMAP ++ | _IO_FLAGS2_NOTCANCEL ++ | _IO_FLAGS2_CLOEXEC); + result = _IO_file_fopen (fp, gfilename, mode, 1); + if (result != NULL) + result = __fopen_maybe_mmap (result); +diff --git a/libio/freopen64.c b/libio/freopen64.c +index fb02c201bd83c401..9a314c65c1d8a5a4 100644 +--- a/libio/freopen64.c ++++ b/libio/freopen64.c +@@ -56,6 +56,9 @@ freopen64 (const char *filename, const char *mode, FILE *fp) + _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps; + if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL) + fp->_wide_data->_wide_vtable = &_IO_wfile_jumps; ++ fp->_flags2 &= ~(_IO_FLAGS2_MMAP ++ | _IO_FLAGS2_NOTCANCEL ++ | _IO_FLAGS2_CLOEXEC); + result = _IO_file_fopen (fp, gfilename, mode, 0); + fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE; + if (result != NULL) +diff --git a/stdio-common/tst-freopen2-main.c b/stdio-common/tst-freopen2-main.c +index 22b21afebf709563..5dad41c76b02e6de 100644 +--- a/stdio-common/tst-freopen2-main.c ++++ b/stdio-common/tst-freopen2-main.c +@@ -308,9 +308,7 @@ do_test (void) + TEST_VERIFY_EXIT (fp != NULL); + ret = fcntl (fileno (fp), F_GETFD); + TEST_VERIFY (ret != -1); +-#if 0 /* Fails to clear FD_CLOEXEC (bug 32134). */ + TEST_COMPARE (ret & FD_CLOEXEC, 0); +-#endif + TEST_COMPARE_FILE_STRING (fp, "plustomore"); + xfclose (fp); + END_TEST; diff --git a/glibc-RHEL-46736-6.patch b/glibc-RHEL-46736-6.patch new file mode 100644 index 0000000..5650c7b --- /dev/null +++ b/glibc-RHEL-46736-6.patch @@ -0,0 +1,119 @@ +commit 9c0d6f7a1046aba111e25e34ec07242853e859dc +Author: Joseph Myers +Date: Thu Sep 5 11:16:59 2024 +0000 + + Fix memory leak on freopen error return (bug 32140) + + As reported in bug 32140, freopen leaks the FILE object when it + returns NULL: there is no valid use of the FILE * pointer (including + passing to freopen again or to fclose) after such an error return, so + the underlying object should be freed. Add code to free it. + + Note 1: while I think it's clear from the relevant standards that the + object should be freed and the FILE * can't be used after the call in + this case (the stream is closed, which ends the lifetime of the FILE), + it's entirely possible that some existing code does in fact try to use + the existing FILE * in some way and could be broken by this change. + (Though the most common case for freopen may be stdin / stdout / + stderr, which _IO_deallocate_file explicitly checks for and does not + deallocate.) + + Note 2: the deallocation is only done in the _IO_IS_FILEBUF case. + Other kinds of streams bypass all the freopen logic handling closing + the file, meaning a call to _IO_deallocate_file would neither be safe + (the FILE might still be linked into the list of all open FILEs) nor + sufficient (other internal memory allocations associated with the file + would not have been freed). I think the validity of freopen for any + other kind of stream will need clarifying with the Austin Group, but + if it is valid in any such case (where "valid" means "not undefined + behavior so required to close the stream" rather than "required to + successfully associate the stream with the new file in cases where + fopen would work"), more significant changes would be needed to ensure + the stream gets fully closed. + + Tested for x86_64. + +diff --git a/libio/freopen.c b/libio/freopen.c +index bed034d89441f200..03f8961a61b12e80 100644 +--- a/libio/freopen.c ++++ b/libio/freopen.c +@@ -114,5 +114,7 @@ freopen (const char *filename, const char *mode, FILE *fp) + + end: + _IO_release_lock (fp); ++ if (result == NULL && (fp->_flags & _IO_IS_FILEBUF) != 0) ++ _IO_deallocate_file (fp); + return result; + } +diff --git a/libio/freopen64.c b/libio/freopen64.c +index 9a314c65c1d8a5a4..abcbd80a5bd92e69 100644 +--- a/libio/freopen64.c ++++ b/libio/freopen64.c +@@ -94,5 +94,7 @@ freopen64 (const char *filename, const char *mode, FILE *fp) + + end: + _IO_release_lock (fp); ++ if (result == NULL && (fp->_flags & _IO_IS_FILEBUF) != 0) ++ _IO_deallocate_file (fp); + return result; + } +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index 5eddc4bfbf4e7fb9..bd3c785537ba0330 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -251,7 +251,9 @@ ifeq (yes,$(build-shared)) + ifneq ($(PERL),no) + tests-special += \ + $(objpfx)tst-freopen2-mem.out \ ++ $(objpfx)tst-freopen3-mem.out \ + $(objpfx)tst-freopen64-2-mem.out \ ++ $(objpfx)tst-freopen64-3-mem.out \ + $(objpfx)tst-getline-enomem-mem.out \ + $(objpfx)tst-getline-mem.out \ + $(objpfx)tst-printf-bz18872-mem.out \ +@@ -264,8 +266,12 @@ tests-special += \ + generated += \ + tst-freopen2-mem.out \ + tst-freopen2.mtrace \ ++ tst-freopen3-mem.out \ ++ tst-freopen3.mtrace \ + tst-freopen64-2-mem.out \ + tst-freopen64-2.mtrace \ ++ tst-freopen64-3-mem.out \ ++ tst-freopen64-3.mtrace \ + tst-getline-enomem-mem.out \ + tst-getline-enomem.mtrace \ + tst-getline-mem.out \ +@@ -344,6 +350,12 @@ tst-freopen2-ENV = \ + tst-freopen64-2-ENV = \ + MALLOC_TRACE=$(objpfx)tst-freopen64-2.mtrace \ + LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-freopen3-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-freopen3.mtrace \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-freopen64-3-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-freopen64-3.mtrace \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so + + $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc + $(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \ +diff --git a/stdio-common/tst-freopen3-main.c b/stdio-common/tst-freopen3-main.c +index 5107e1f98e189e4b..990a6e5921843793 100644 +--- a/stdio-common/tst-freopen3-main.c ++++ b/stdio-common/tst-freopen3-main.c +@@ -18,6 +18,7 @@ + + #include + #include ++#include + #include + #include + +@@ -48,6 +49,7 @@ + int + do_test (void) + { ++ mtrace (); + struct support_descriptors *fds; + char *temp_dir = support_create_temp_directory ("tst-freopen3"); + char *file1 = xasprintf ("%s/file1", temp_dir); diff --git a/glibc-RHEL-46736-7.patch b/glibc-RHEL-46736-7.patch new file mode 100644 index 0000000..e025835 --- /dev/null +++ b/glibc-RHEL-46736-7.patch @@ -0,0 +1,86 @@ +commit e44ca1c085b3bd41266c882ea1cb0fd436231635 +Author: Joseph Myers +Date: Thu Sep 5 20:08:10 2024 +0000 + + Fix freopen handling of ,ccs= (bug 23675) + + As reported in bug 23675 and shown up in the recently added tests of + different cases of freopen (relevant part of the test currently + conditioned under #if 0 to avoid a failure resulting from this bug), + freopen wrongly forces the stream to unoriented even when a mode with + ,ccs= is specified, though such a mode is supposed to result in a + wide-oriented stream. Move the clearing of _mode to before the actual + reopening occurs, so that the main fopen implementation can leave a + wide-oriented stream in the ,ccs= case. + + Tested for x86_64. + +diff --git a/libio/freopen.c b/libio/freopen.c +index 03f8961a61b12e80..d71a4cfffdc35280 100644 +--- a/libio/freopen.c ++++ b/libio/freopen.c +@@ -66,6 +66,7 @@ freopen (const char *filename, const char *mode, FILE *fp) + fp->_flags2 &= ~(_IO_FLAGS2_MMAP + | _IO_FLAGS2_NOTCANCEL + | _IO_FLAGS2_CLOEXEC); ++ fp->_mode = 0; + result = _IO_old_file_fopen (fp, gfilename, mode); + } + else +@@ -78,6 +79,7 @@ freopen (const char *filename, const char *mode, FILE *fp) + fp->_flags2 &= ~(_IO_FLAGS2_MMAP + | _IO_FLAGS2_NOTCANCEL + | _IO_FLAGS2_CLOEXEC); ++ fp->_mode = 0; + result = _IO_file_fopen (fp, gfilename, mode, 1); + if (result != NULL) + result = __fopen_maybe_mmap (result); +@@ -85,9 +87,6 @@ freopen (const char *filename, const char *mode, FILE *fp) + fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE; + if (result != NULL) + { +- /* unbound stream orientation */ +- result->_mode = 0; +- + if (fd != -1 && _IO_fileno (result) != fd) + { + /* At this point we have both file descriptors already allocated, +diff --git a/libio/freopen64.c b/libio/freopen64.c +index abcbd80a5bd92e69..64af2c5f7c80a3e9 100644 +--- a/libio/freopen64.c ++++ b/libio/freopen64.c +@@ -59,15 +59,13 @@ freopen64 (const char *filename, const char *mode, FILE *fp) + fp->_flags2 &= ~(_IO_FLAGS2_MMAP + | _IO_FLAGS2_NOTCANCEL + | _IO_FLAGS2_CLOEXEC); ++ fp->_mode = 0; + result = _IO_file_fopen (fp, gfilename, mode, 0); + fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE; + if (result != NULL) + result = __fopen_maybe_mmap (result); + if (result != NULL) + { +- /* unbound stream orientation */ +- result->_mode = 0; +- + if (fd != -1 && _IO_fileno (result) != fd) + { + /* At this point we have both file descriptors already allocated, +diff --git a/stdio-common/tst-freopen2-main.c b/stdio-common/tst-freopen2-main.c +index 5dad41c76b02e6de..74c3125fca697fe3 100644 +--- a/stdio-common/tst-freopen2-main.c ++++ b/stdio-common/tst-freopen2-main.c +@@ -386,13 +386,8 @@ do_test (void) + fp = xfopen (file2, "w,ccs=iso-8859-1"); + ret = fputws (L"\xc0\xc1", fp); + TEST_VERIFY (ret >= 0); +-#if 0 /* Doesn't work (bug 23675). */ + fp = FREOPEN (file1, "r,ccs=utf-8", fp); + TEST_VERIFY_EXIT (fp != NULL); +-#else /* Works instead. */ +- xfclose (fp); +- fp = xfopen (file1, "r,ccs=utf-8"); +-#endif + wc = fgetwc (fp); + TEST_COMPARE (wc, (wint_t) 0xc0); + wc = fgetwc (fp); diff --git a/glibc-RHEL-46736-8.patch b/glibc-RHEL-46736-8.patch new file mode 100644 index 0000000..c265ed5 --- /dev/null +++ b/glibc-RHEL-46736-8.patch @@ -0,0 +1,33 @@ +commit a2509a8bc955988f01f389a1cf74db3a9da42409 +Author: Joseph Myers +Date: Fri Sep 6 20:38:23 2024 +0000 + + Document limitations on streams passed to freopen + + As recently discussed, document that freopen does not work with + streams opened with functions such as popen, fmemopen, open_memstream + or fopencookie. I've filed + to clarify this issue + in POSIX. + + Tested with "make info" and "make html". + +diff --git a/manual/stdio.texi b/manual/stdio.texi +index 60ab7e7a5d505bb6..a2d9292a787b9fa3 100644 +--- a/manual/stdio.texi ++++ b/manual/stdio.texi +@@ -330,6 +330,14 @@ this ability, so using @code{freopen} is more portable. + When the sources are compiled with @code{_FILE_OFFSET_BITS == 64} on a + 32 bit machine this function is in fact @code{freopen64} since the LFS + interface replaces transparently the old interface. ++ ++@Theglibc{} only supports use of @code{freopen} on streams opened with ++@code{fopen} or @code{fopen64} and on the original values of the ++standard streams @code{stdin}, @code{stdout}, and @code{stderr}; such ++a stream may be reopened multiple times with @code{freopen}. If it is ++called on another kind of stream (opened with functions such as ++@code{popen}, @code{fmemopen}, @code{open_memstream}, and ++@code{fopencookie}), @code{freopen} fails and returns a null pointer. + @end deftypefun + + @deftypefun {FILE *} freopen64 (const char *@var{filename}, const char *@var{opentype}, FILE *@var{stream}) diff --git a/glibc-RHEL-46736-9.patch b/glibc-RHEL-46736-9.patch new file mode 100644 index 0000000..f9316a1 --- /dev/null +++ b/glibc-RHEL-46736-9.patch @@ -0,0 +1,495 @@ +commit e0f3bf10acf4aab27752847828bfecd3fce41190 +Author: Joseph Myers +Date: Fri Sep 20 23:26:31 2024 +0000 + + Add freopen special-case tests: chroot, EFBIG, stdin/stdout/stderr + + Add tests of special cases for freopen that were omitted from the more + general tests of different modes and similar issues. The special + cases in the three tests here are logically unconnected, it was simply + convenient to put these tests in one patch. + + * Test freopen with a NULL path to the new file, in a chroot. Rather + than asserting that this fails (logically, failure in this case is + an implementation detail; it's not required for freopen to rely on + /proc), verify that either it fails (without memory leaks) or that + it succeeds and behaves as expected on success. There is no check + for file descriptor leaks because the machinery for that also + depends on /proc, so can't be used in a chroot. + + * Test that freopen and freopen64 are genuinely different in + configurations with 32-bit off_t by checking for an EFBIG trying to + write past 2GB in a file opened with freopen in such a configuration + but no error with 64-bit off_t or when opening with freopen64. + + * Test freopen of stdin, stdout and stderr. + + Tested for x86_64 and x86. + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index bd3c785537ba0330..c920f55ed2119900 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -177,8 +177,13 @@ tests := \ + tst-fread \ + tst-freopen2 \ + tst-freopen3 \ ++ tst-freopen4 \ ++ tst-freopen5 \ ++ tst-freopen6 \ + tst-freopen64-2 \ + tst-freopen64-3 \ ++ tst-freopen64-4 \ ++ tst-freopen64-6 \ + tst-fseek \ + tst-fwrite \ + tst-getline \ +@@ -252,8 +257,13 @@ ifneq ($(PERL),no) + tests-special += \ + $(objpfx)tst-freopen2-mem.out \ + $(objpfx)tst-freopen3-mem.out \ ++ $(objpfx)tst-freopen4-mem.out \ ++ $(objpfx)tst-freopen5-mem.out \ ++ $(objpfx)tst-freopen6-mem.out \ + $(objpfx)tst-freopen64-2-mem.out \ + $(objpfx)tst-freopen64-3-mem.out \ ++ $(objpfx)tst-freopen64-4-mem.out \ ++ $(objpfx)tst-freopen64-6-mem.out \ + $(objpfx)tst-getline-enomem-mem.out \ + $(objpfx)tst-getline-mem.out \ + $(objpfx)tst-printf-bz18872-mem.out \ +@@ -268,10 +278,20 @@ generated += \ + tst-freopen2.mtrace \ + tst-freopen3-mem.out \ + tst-freopen3.mtrace \ ++ tst-freopen4-mem.out \ ++ tst-freopen4.mtrace \ ++ tst-freopen5-mem.out \ ++ tst-freopen5.mtrace \ ++ tst-freopen6-mem.out \ ++ tst-freopen6.mtrace \ + tst-freopen64-2-mem.out \ + tst-freopen64-2.mtrace \ + tst-freopen64-3-mem.out \ + tst-freopen64-3.mtrace \ ++ tst-freopen64-4-mem.out \ ++ tst-freopen64-4.mtrace \ ++ tst-freopen64-6-mem.out \ ++ tst-freopen64-6.mtrace \ + tst-getline-enomem-mem.out \ + tst-getline-enomem.mtrace \ + tst-getline-mem.out \ +@@ -356,6 +376,21 @@ tst-freopen3-ENV = \ + tst-freopen64-3-ENV = \ + MALLOC_TRACE=$(objpfx)tst-freopen64-3.mtrace \ + LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-freopen4-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-freopen4.mtrace \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-freopen64-4-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-freopen64-4.mtrace \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-freopen5-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-freopen5.mtrace \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-freopen6-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-freopen6.mtrace \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so ++tst-freopen64-6-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-freopen64-6.mtrace \ ++ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so + + $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc + $(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \ +diff --git a/stdio-common/tst-freopen4-main.c b/stdio-common/tst-freopen4-main.c +new file mode 100644 +index 0000000000000000..e169442cf4df2e9d +--- /dev/null ++++ b/stdio-common/tst-freopen4-main.c +@@ -0,0 +1,100 @@ ++/* Test freopen in chroot. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++int ++do_test (void) ++{ ++ mtrace (); ++ char *temp_dir = support_create_temp_directory ("tst-freopen4"); ++ FILE *fp; ++ int ret; ++ ++ /* These chroot tests verify that either reopening a renamed or ++ deleted file works even in the absence of /proc, or that it fails ++ (without memory leaks); thus, for example, such reopening does ++ not crash in the absence of /proc. */ ++ ++ support_become_root (); ++ if (!support_can_chroot ()) ++ return EXIT_UNSUPPORTED; ++ xchroot (temp_dir); ++ ++ /* Test freopen with NULL, renamed file. This verifies that ++ reopening succeeds (and resets the file position indicator to ++ start of file) even when the original path could no longer be ++ opened, or fails without a memory leak. (It is not possible to ++ use to test for file descriptor leaks ++ here, because that also depends on /proc.) */ ++ ++ verbose_printf ("testing freopen with NULL, renamed file\n"); ++ fp = xfopen ("/file1", "w+"); ++ ret = fputs ("file has been renamed", fp); ++ TEST_VERIFY (ret >= 0); ++ ret = rename ("/file1", "/file1a"); ++ TEST_COMPARE (ret, 0); ++ fp = FREOPEN (NULL, "r+", fp); ++ if (fp != NULL) ++ { ++ puts ("freopen of renamed file succeeded"); ++ TEST_COMPARE_FILE_STRING (fp, "file has been renamed"); ++ xfclose (fp); ++ } ++ else ++ puts ("freopen of renamed file failed (OK)"); ++ ret = rename ("/file1a", "/file1"); ++ TEST_COMPARE (ret, 0); ++ ++ /* Test freopen with NULL, deleted file. This verifies that ++ reopening succeeds (and resets the file position indicator to ++ start of file) even when the original path could no longer be ++ opened, or fails without a memory leak. */ ++ ++ verbose_printf ("testing freopen with NULL, deleted file\n"); ++ fp = xfopen ("/file1", "r+"); ++ ret = fputs ("file has now been deleted", fp); ++ TEST_VERIFY (ret >= 0); ++ ret = remove ("/file1"); ++ TEST_COMPARE (ret, 0); ++ fp = FREOPEN (NULL, "r+", fp); ++ if (fp != NULL) ++ { ++ puts ("freopen of deleted file succeeded"); ++ TEST_COMPARE_FILE_STRING (fp, "file has now been deleted"); ++ xfclose (fp); ++ } ++ else ++ puts ("freopen of deleted file failed (OK)"); ++ ++ free (temp_dir); ++ return 0; ++} ++ ++#include +diff --git a/stdio-common/tst-freopen4.c b/stdio-common/tst-freopen4.c +new file mode 100644 +index 0000000000000000..f39ec0d21730879f +--- /dev/null ++++ b/stdio-common/tst-freopen4.c +@@ -0,0 +1,2 @@ ++#define FREOPEN freopen ++#include +diff --git a/stdio-common/tst-freopen5.c b/stdio-common/tst-freopen5.c +new file mode 100644 +index 0000000000000000..f32626bccfe5c10a +--- /dev/null ++++ b/stdio-common/tst-freopen5.c +@@ -0,0 +1,144 @@ ++/* Test freopen and freopen64 with large offsets. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define START_TEST(DESC) \ ++ do \ ++ { \ ++ fds = support_descriptors_list (); \ ++ verbose_printf (DESC); \ ++ } \ ++ while (0) ++ ++#define END_TEST \ ++ do \ ++ { \ ++ support_descriptors_check (fds); \ ++ support_descriptors_free (fds); \ ++ } \ ++ while (0) ++ ++int ++do_test (void) ++{ ++ mtrace (); ++ struct support_descriptors *fds; ++ FILE *fp; ++ int ret; ++ ++ char *temp_dir = support_create_temp_directory ("tst-freopen5"); ++ /* This file is removed at the end of each test rather than left ++ around between tests to avoid problems with subsequent tests ++ reopening it as a large (2GB + 1 byte) file. */ ++ char *file1 = xasprintf ("%s/file1", temp_dir); ++ ++ /* fopen with freopen64: large offsets OK. */ ++ START_TEST ("testing fopen with freopen64\n"); ++ fp = fopen ("/dev/null", "r"); ++ TEST_VERIFY_EXIT (fp != NULL); ++ fp = freopen64 (file1, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ setbuf (fp, NULL); ++ ret = fseeko64 (fp, 1LL << 32, SEEK_SET); ++ TEST_COMPARE (ret, 0); ++ ret = fputc ('x', fp); ++ TEST_COMPARE (ret, 'x'); ++ xfclose (fp); ++ ret = remove (file1); ++ TEST_COMPARE (ret, 0); ++ END_TEST; ++ ++ /* fopen64 with freopen64: large offsets OK. */ ++ START_TEST ("testing fopen64 with freopen64\n"); ++ fp = fopen64 ("/dev/null", "r"); ++ TEST_VERIFY_EXIT (fp != NULL); ++ fp = freopen64 (file1, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ setbuf (fp, NULL); ++ ret = fseeko64 (fp, 1LL << 32, SEEK_SET); ++ TEST_COMPARE (ret, 0); ++ ret = fputc ('x', fp); ++ TEST_COMPARE (ret, 'x'); ++ xfclose (fp); ++ ret = remove (file1); ++ TEST_COMPARE (ret, 0); ++ END_TEST; ++ ++ /* fopen with freopen: large offsets not OK on 32-bit systems. */ ++ START_TEST ("testing fopen with freopen\n"); ++ fp = fopen ("/dev/null", "r"); ++ TEST_VERIFY_EXIT (fp != NULL); ++ fp = freopen (file1, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ setbuf (fp, NULL); ++ ret = fseeko64 (fp, 1LL << 32, SEEK_SET); ++ TEST_COMPARE (ret, 0); ++ errno = 0; ++ ret = fputc ('x', fp); ++ if (sizeof (off_t) == 4) ++ { ++ TEST_COMPARE (ret, EOF); ++ TEST_COMPARE (errno, EFBIG); ++ } ++ else ++ TEST_COMPARE (ret, 'x'); ++ fclose (fp); ++ ret = remove (file1); ++ TEST_COMPARE (ret, 0); ++ END_TEST; ++ ++ /* fopen64 with freopen: large offsets not OK on 32-bit systems. */ ++ START_TEST ("testing fopen64 with freopen\n"); ++ fp = fopen64 ("/dev/null", "r"); ++ TEST_VERIFY_EXIT (fp != NULL); ++ fp = freopen (file1, "w", fp); ++ TEST_VERIFY_EXIT (fp != NULL); ++ setbuf (fp, NULL); ++ ret = fseeko64 (fp, 1LL << 32, SEEK_SET); ++ TEST_COMPARE (ret, 0); ++ errno = 0; ++ ret = fputc ('x', fp); ++ if (sizeof (off_t) == 4) ++ { ++ TEST_COMPARE (ret, EOF); ++ TEST_COMPARE (errno, EFBIG); ++ } ++ else ++ TEST_COMPARE (ret, 'x'); ++ fclose (fp); ++ ret = remove (file1); ++ TEST_COMPARE (ret, 0); ++ END_TEST; ++ ++ free (temp_dir); ++ free (file1); ++ return 0; ++} ++ ++#include +diff --git a/stdio-common/tst-freopen6-main.c b/stdio-common/tst-freopen6-main.c +new file mode 100644 +index 0000000000000000..f493f42fd7486b72 +--- /dev/null ++++ b/stdio-common/tst-freopen6-main.c +@@ -0,0 +1,98 @@ ++/* Test freopen of stdin / stdout / stderr. ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++int ++do_test (void) ++{ ++ mtrace (); ++ char *temp_dir = support_create_temp_directory ("tst-freopen6"); ++ char *file1 = xasprintf ("%s/file1", temp_dir); ++ support_write_file_string (file1, "file1"); ++ add_temp_file (file1); ++ FILE *fp; ++ int ret; ++ ++ verbose_printf ("Testing reopening stdin\n"); ++ fp = FREOPEN (file1, "r", stdin); ++ TEST_VERIFY_EXIT (fp == stdin); ++ ret = getchar (); ++ TEST_COMPARE (ret, 'f'); ++ ret = getchar (); ++ TEST_COMPARE (ret, 'i'); ++ ret = getchar (); ++ TEST_COMPARE (ret, 'l'); ++ ret = getchar (); ++ TEST_COMPARE (ret, 'e'); ++ ret = getchar (); ++ TEST_COMPARE (ret, '1'); ++ ret = getchar (); ++ TEST_COMPARE (ret, EOF); ++ xfclose (fp); ++ ++ verbose_printf ("Testing reopening stderr\n"); ++ fp = FREOPEN (file1, "w+", stderr); ++ TEST_VERIFY_EXIT (fp == stderr); ++ errno = EINVAL; ++ perror ("test"); ++ ret = fseek (fp, 0, SEEK_SET); ++ TEST_COMPARE (ret, 0); ++ TEST_COMPARE_FILE_STRING (fp, "test: Invalid argument\n"); ++ xfclose (fp); ++ ++ verbose_printf ("Testing reopening stdout\n"); ++ /* Defer checks until the old stdout has been restored to make it ++ more likely any errors are written to the old stdout (rather than ++ the temporary file used for the redirected stdout). */ ++ int old_stdout = dup (STDOUT_FILENO); ++ TEST_VERIFY_EXIT (old_stdout != -1); ++ int ret_fseek = 0; ++ int ret_compare = 0; ++ fp = FREOPEN (file1, "w+", stdout); ++ int fp_eq_stdout = fp == stdout; ++ if (fp != NULL) ++ { ++ printf ("reopened\n"); ++ ret_fseek = fseek (fp, 0, SEEK_SET); ++ ret_compare = support_compare_file_string (fp, "reopened\n"); ++ } ++ xfclose (fp); ++ stdout = fdopen (old_stdout, "w"); ++ TEST_VERIFY (fp_eq_stdout); ++ TEST_COMPARE (ret_fseek, 0); ++ TEST_COMPARE (ret_compare, 0); ++ xfclose (stdout); ++ ++ free (temp_dir); ++ free (file1); ++ return 0; ++} ++ ++#include +diff --git a/stdio-common/tst-freopen6.c b/stdio-common/tst-freopen6.c +new file mode 100644 +index 0000000000000000..8fd6957b54fa9bc2 +--- /dev/null ++++ b/stdio-common/tst-freopen6.c +@@ -0,0 +1,2 @@ ++#define FREOPEN freopen ++#include +diff --git a/stdio-common/tst-freopen64-4.c b/stdio-common/tst-freopen64-4.c +new file mode 100644 +index 0000000000000000..1411be2bfa0105c1 +--- /dev/null ++++ b/stdio-common/tst-freopen64-4.c +@@ -0,0 +1,2 @@ ++#define FREOPEN freopen64 ++#include +diff --git a/stdio-common/tst-freopen64-6.c b/stdio-common/tst-freopen64-6.c +new file mode 100644 +index 0000000000000000..3ec509a36c2471f6 +--- /dev/null ++++ b/stdio-common/tst-freopen64-6.c +@@ -0,0 +1,2 @@ ++#define FREOPEN freopen64 ++#include diff --git a/glibc.spec b/glibc.spec index 6dad21e..82e93b8 100644 --- a/glibc.spec +++ b/glibc.spec @@ -157,7 +157,7 @@ end \ Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: 139%{?dist} +Release: 140%{?dist} # In general, GPLv2+ is used by programs, LGPLv2+ is used for # libraries. @@ -917,6 +917,17 @@ Patch678: glibc-RHEL-46733-1.patch Patch679: glibc-RHEL-46733-2.patch Patch680: glibc-RHEL-46733-3.patch Patch681: glibc-RHEL-54413.patch +Patch682: glibc-RHEL-46736-1.patch +Patch683: glibc-RHEL-46736-2.patch +Patch684: glibc-RHEL-46736-3.patch +Patch685: glibc-RHEL-46736-4.patch +Patch686: glibc-RHEL-46736-5.patch +Patch687: glibc-RHEL-46736-6.patch +Patch688: glibc-RHEL-46736-7.patch +Patch689: glibc-RHEL-46736-8.patch +Patch690: glibc-RHEL-46736-9.patch +Patch691: glibc-RHEL-46736-10.patch +Patch692: glibc-RHEL-46736-11.patch ############################################################################## # Continued list of core "glibc" package information: @@ -3076,6 +3087,9 @@ update_gconv_modules_cache () %endif %changelog +* Thu Nov 7 2024 Florian Weimer - 2.34-140 +- Add more tests for freopen (RHEL-46736) + * Thu Nov 7 2024 Florian Weimer - 2.34-139 - Add more tests of getline (RHEL-54413)