Fix memory leak in freopen and improve testing
RPM-Changelog: - Fix memory leak in freopen, mode flag and wide-oriented stream handling (RHEL-115823) - Add comprehensive tests and document limitations (RHEL-115823) Resolves: RHEL-115823
This commit is contained in:
parent
e97a907db2
commit
0cdd6d71bb
261
glibc-RHEL-115823-1.patch
Normal file
261
glibc-RHEL-115823-1.patch
Normal file
@ -0,0 +1,261 @@
|
||||
commit 96d0bf98cafd0b63721f369ca21ec64590551d47
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
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 6b859e85ddb157f4..aee37b9c82e94499 100644
|
||||
--- a/support/Makefile
|
||||
+++ b/support/Makefile
|
||||
@@ -49,6 +49,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 \
|
||||
@@ -66,6 +68,8 @@ libsupport-routines = \
|
||||
support_isolate_in_subprocess \
|
||||
support_mutex_pi_monotonic \
|
||||
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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#ifndef SUPPORT_FILE_CONTENTS_H
|
||||
+#define SUPPORT_FILE_CONTENTS_H
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+__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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+
|
||||
+#include <support/file_contents.h>
|
||||
+
|
||||
+/* 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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <support/file_contents.h>
|
||||
+
|
||||
+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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <support/file_contents.h>
|
||||
+#include <support/xstdio.h>
|
||||
+
|
||||
+/* 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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <string.h>
|
||||
+
|
||||
+#include <support/file_contents.h>
|
||||
+#include <support/xstdio.h>
|
||||
+
|
||||
+/* 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));
|
||||
+}
|
||||
739
glibc-RHEL-115823-2.patch
Normal file
739
glibc-RHEL-115823-2.patch
Normal file
@ -0,0 +1,739 @@
|
||||
commit ed4bb289cf739f537deb735eaa01be531df084b9
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
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
|
||||
(fixup context for newly added tests)
|
||||
|
||||
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
|
||||
index cee076cb7bcff2d2..f949ec37482d8859 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -224,6 +224,10 @@ tests := \
|
||||
tst-fphex \
|
||||
tst-fphex-wide \
|
||||
tst-fread \
|
||||
+ tst-freopen2 \
|
||||
+ tst-freopen3 \
|
||||
+ tst-freopen64-2 \
|
||||
+ tst-freopen64-3 \
|
||||
tst-fseek \
|
||||
tst-fseek-mmap \
|
||||
tst-fwrite \
|
||||
@@ -331,6 +335,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 \
|
||||
@@ -342,6 +348,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 \
|
||||
@@ -461,6 +471,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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <mcheck.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <wchar.h>
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+#include <support/descriptors.h>
|
||||
+#include <support/file_contents.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <support/xstdio.h>
|
||||
+
|
||||
+#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 <support/test-driver.c>
|
||||
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 <tst-freopen2-main.c>
|
||||
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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+#include <support/descriptors.h>
|
||||
+#include <support/file_contents.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <support/xstdio.h>
|
||||
+
|
||||
+#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 <support/test-driver.c>
|
||||
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 <tst-freopen3-main.c>
|
||||
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 <tst-freopen2-main.c>
|
||||
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 <tst-freopen3-main.c>
|
||||
69
glibc-RHEL-115823-3.patch
Normal file
69
glibc-RHEL-115823-3.patch
Normal file
@ -0,0 +1,69 @@
|
||||
commit f512634ddef242ef0ff025ddeba64ce51035040f
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
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 c7e36db7758c8f3b..f6c943ddf82e399c 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 9a6d5ed8016b6ed6..0f3cb16331318425 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;
|
||||
119
glibc-RHEL-115823-4.patch
Normal file
119
glibc-RHEL-115823-4.patch
Normal file
@ -0,0 +1,119 @@
|
||||
commit 9c0d6f7a1046aba111e25e34ec07242853e859dc
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
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 f6c943ddf82e399c..ceeff8f2acb6333f 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 0f3cb16331318425..3a314aca5ce808ca 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 f949ec37482d8859..ea6212b4eacd07d1 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -336,7 +336,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 \
|
||||
@@ -350,8 +352,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 \
|
||||
@@ -477,6 +483,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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
+#include <mcheck.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -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);
|
||||
86
glibc-RHEL-115823-5.patch
Normal file
86
glibc-RHEL-115823-5.patch
Normal file
@ -0,0 +1,86 @@
|
||||
commit e44ca1c085b3bd41266c882ea1cb0fd436231635
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
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 ceeff8f2acb6333f..00f26ad578afc1b1 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 3a314aca5ce808ca..77c0dd3fdf3c3494 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);
|
||||
33
glibc-RHEL-115823-6.patch
Normal file
33
glibc-RHEL-115823-6.patch
Normal file
@ -0,0 +1,33 @@
|
||||
commit a2509a8bc955988f01f389a1cf74db3a9da42409
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
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
|
||||
<https://austingroupbugs.net/view.php?id=1855> to clarify this issue
|
||||
in POSIX.
|
||||
|
||||
Tested with "make info" and "make html".
|
||||
|
||||
diff --git a/manual/stdio.texi b/manual/stdio.texi
|
||||
index de174eafcd5fde0c..7d787735079ea964 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})
|
||||
495
glibc-RHEL-115823-7.patch
Normal file
495
glibc-RHEL-115823-7.patch
Normal file
@ -0,0 +1,495 @@
|
||||
commit e0f3bf10acf4aab27752847828bfecd3fce41190
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
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 ea6212b4eacd07d1..13ad32289e6a9f50 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -226,8 +226,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-fseek-mmap \
|
||||
tst-fwrite \
|
||||
@@ -337,8 +342,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 \
|
||||
@@ -354,10 +364,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 \
|
||||
@@ -489,6 +509,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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <mcheck.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+#include <support/file_contents.h>
|
||||
+#include <support/namespace.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <support/xstdio.h>
|
||||
+#include <support/xunistd.h>
|
||||
+
|
||||
+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 <support/descriptors.h> 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 <support/test-driver.c>
|
||||
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 <tst-freopen4-main.c>
|
||||
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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <mcheck.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+#include <support/descriptors.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <support/xstdio.h>
|
||||
+
|
||||
+#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 <support/test-driver.c>
|
||||
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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <mcheck.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+#include <support/file_contents.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <support/xstdio.h>
|
||||
+
|
||||
+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 <support/test-driver.c>
|
||||
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 <tst-freopen6-main.c>
|
||||
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 <tst-freopen4-main.c>
|
||||
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 <tst-freopen6-main.c>
|
||||
30
glibc-RHEL-115823-8.patch
Normal file
30
glibc-RHEL-115823-8.patch
Normal file
@ -0,0 +1,30 @@
|
||||
commit 6948ee4edf0c57c556f8d5f394d9191216d05780
|
||||
Author: Florian Weimer <fweimer@redhat.com>
|
||||
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
|
||||
216
glibc-RHEL-115823-9.patch
Normal file
216
glibc-RHEL-115823-9.patch
Normal file
@ -0,0 +1,216 @@
|
||||
commit 42c810c2cf3554afbdd60885b7da6bb4e702466f
|
||||
Author: Joseph Myers <josmyers@redhat.com>
|
||||
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 13ad32289e6a9f50..4c39b9d9fb3d029f 100644
|
||||
--- a/stdio-common/Makefile
|
||||
+++ b/stdio-common/Makefile
|
||||
@@ -229,10 +229,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-fseek-mmap \
|
||||
tst-fwrite \
|
||||
@@ -636,3 +638,6 @@ $(objpfx)tst-setvbuf2.out: $(objpfx)tst-setvbuf2-ind
|
||||
|
||||
$(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 <tst-freopen7-main.c>
|
||||
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
|
||||
+ <https://www.gnu.org/licenses/>. */
|
||||
+
|
||||
+#include <errno.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <mcheck.h>
|
||||
+#include <pthread.h>
|
||||
+#include <semaphore.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <wchar.h>
|
||||
+
|
||||
+#include <support/check.h>
|
||||
+#include <support/file_contents.h>
|
||||
+#include <support/support.h>
|
||||
+#include <support/temp_file.h>
|
||||
+#include <support/test-driver.h>
|
||||
+#include <support/xstdio.h>
|
||||
+#include <support/xthread.h>
|
||||
+#include <support/xunistd.h>
|
||||
+
|
||||
+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 <support/test-driver.c>
|
||||
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 <tst-freopen7-main.c>
|
||||
Loading…
Reference in New Issue
Block a user