From c66918bc6053415d346a3b7f94553a73ba1df236 Mon Sep 17 00:00:00 2001 From: liqingqing_1229 Date: Tue, 21 Dec 2021 10:00:35 +0800 Subject: [PATCH] fix glibc upstream bug BZ#28260 and nss/tst-nss-files-hosts-long and nptl/tst-create1 --- ...tst-nss-files-hosts-long-with-local-.patch | 37 ++ ..._dev_null_range-io-tst-closefrom-mis.patch | 212 ++++++++++ glibc.spec | 11 +- ...one-more-barrier-to-nptl-tst-create1.patch | 67 ++++ support-Add-support_open_dev_null_range.patch | 363 ++++++++++++++++++ 5 files changed, 689 insertions(+), 1 deletion(-) create mode 100644 Fix-failing-nss-tst-nss-files-hosts-long-with-local-.patch create mode 100644 Use-support_open_dev_null_range-io-tst-closefrom-mis.patch create mode 100644 nptl-Add-one-more-barrier-to-nptl-tst-create1.patch create mode 100644 support-Add-support_open_dev_null_range.patch diff --git a/Fix-failing-nss-tst-nss-files-hosts-long-with-local-.patch b/Fix-failing-nss-tst-nss-files-hosts-long-with-local-.patch new file mode 100644 index 0000000..f9cb581 --- /dev/null +++ b/Fix-failing-nss-tst-nss-files-hosts-long-with-local-.patch @@ -0,0 +1,37 @@ +From ae925404a10bf0ea63d6e8d41e3821f68b4d776c Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 3 Sep 2021 00:28:14 +0200 +Subject: [PATCH] Fix failing nss/tst-nss-files-hosts-long with local resolver + +When a local resolver like unbound is listening on the IPv4 loopback +address 127.0.0.1, the nss/tst-nss-files-hosts-long test fails. This is +due to: +- the default resolver in the absence of resolv.conf being 127.0.0.1 +- the default DNS NSS database configuration in the absence of + nsswitch.conf being 'hosts: dns [!UNAVAIL=return] file' + +This causes the requests for 'test4' and 'test6' to first be sent to the +local resolver, which responds with NXDOMAIN in the likely case those +records do no exist. In turn that causes the access to /etc/hosts to be +skipped, which is the purpose of that test. + +Fix that by providing a simple nsswitch.conf file forcing access to +/etc/hosts for that test. I have tested that the only changed result in +the testsuite is that test. + +(cherry picked from commit 2738480a4b0866723fb8c633f36bdd34a8767581) +--- + nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf | 1 + + 1 file changed, 1 insertion(+) + create mode 100644 nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf + +diff --git a/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf +new file mode 100644 +index 0000000..5b0c6a4 +--- /dev/null ++++ b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf +@@ -0,0 +1 @@ ++hosts: files +-- +1.8.3.1 + diff --git a/Use-support_open_dev_null_range-io-tst-closefrom-mis.patch b/Use-support_open_dev_null_range-io-tst-closefrom-mis.patch new file mode 100644 index 0000000..bd7da16 --- /dev/null +++ b/Use-support_open_dev_null_range-io-tst-closefrom-mis.patch @@ -0,0 +1,212 @@ +From 772e33411bc730f832f415f93eb3e7c67e4d5488 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Tue, 24 Aug 2021 16:15:50 -0300 +Subject: [PATCH] Use support_open_dev_null_range io/tst-closefrom, + misc/tst-close_range, and posix/tst-spawn5 (BZ #28260) + +It ensures a continuous range of file descriptor and avoid hitting +the RLIMIT_NOFILE. + +Checked on x86_64-linux-gnu. + +(cherry picked from commit 6b20880b22d1d0fce7e9f506baa6fe2d5c7fcfdc) +--- + io/tst-closefrom.c | 21 ++++++--------------- + posix/tst-spawn5.c | 13 +------------ + sysdeps/unix/sysv/linux/tst-close_range.c | 31 ++++++++++--------------------- + 3 files changed, 17 insertions(+), 48 deletions(-) + +diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c +index d4c1870..395ec0d 100644 +--- a/io/tst-closefrom.c ++++ b/io/tst-closefrom.c +@@ -24,31 +24,22 @@ + #include + #include + #include ++#include + + #include + + #define NFDS 100 + + static int +-open_multiple_temp_files (void) +-{ +- /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = xopen ("/dev/null", O_RDONLY, 0600); +- for (int i = 1; i <= NFDS; i++) +- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), lowfd + i); +- return lowfd; +-} +- +-static int + closefrom_test (void) + { + struct support_descriptors *descrs = support_descriptors_list (); + +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + +- const int maximum_fd = lowfd + NFDS; ++ const int maximum_fd = lowfd + NFDS - 1; + const int half_fd = lowfd + NFDS / 2; +- const int gap = maximum_fd / 4; ++ const int gap = lowfd + NFDS / 4; + + /* Close half of the descriptors and check result. */ + closefrom (half_fd); +@@ -58,7 +49,7 @@ closefrom_test (void) + TEST_COMPARE (fcntl (i, F_GETFL), -1); + TEST_COMPARE (errno, EBADF); + } +- for (int i = 0; i < half_fd; i++) ++ for (int i = lowfd; i < half_fd; i++) + TEST_VERIFY (fcntl (i, F_GETFL) > -1); + + /* Create some gaps, close up to a threshold, and check result. */ +@@ -74,7 +65,7 @@ closefrom_test (void) + TEST_COMPARE (fcntl (i, F_GETFL), -1); + TEST_COMPARE (errno, EBADF); + } +- for (int i = 0; i < gap; i++) ++ for (int i = lowfd; i < gap; i++) + TEST_VERIFY (fcntl (i, F_GETFL) > -1); + + /* Close the remmaining but the last one. */ +diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c +index ac66738..a95199a 100644 +--- a/posix/tst-spawn5.c ++++ b/posix/tst-spawn5.c +@@ -48,17 +48,6 @@ static int initial_argv_count; + #define NFDS 100 + + static int +-open_multiple_temp_files (void) +-{ +- /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = xopen ("/dev/null", O_RDONLY, 0600); +- for (int i = 1; i <= NFDS; i++) +- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), +- lowfd + i); +- return lowfd; +-} +- +-static int + parse_fd (const char *str) + { + char *endptr; +@@ -185,7 +174,7 @@ spawn_closefrom_test (posix_spawn_file_actions_t *fa, int lowfd, int highfd, + static void + do_test_closefrom (void) + { +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + const int half_fd = lowfd + NFDS / 2; + + /* Close half of the descriptors and check result. */ +diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c +index dccb618..f5069d1 100644 +--- a/sysdeps/unix/sysv/linux/tst-close_range.c ++++ b/sysdeps/unix/sysv/linux/tst-close_range.c +@@ -36,23 +36,12 @@ + + #define NFDS 100 + +-static int +-open_multiple_temp_files (void) +-{ +- /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = xopen ("/dev/null", O_RDONLY, 0600); +- for (int i = 1; i <= NFDS; i++) +- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), +- lowfd + i); +- return lowfd; +-} +- + static void + close_range_test_max_upper_limit (void) + { + struct support_descriptors *descrs = support_descriptors_list (); + +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + + { + int r = close_range (lowfd, ~0U, 0); +@@ -68,7 +57,7 @@ close_range_test_max_upper_limit (void) + static void + close_range_test_common (int lowfd, unsigned int flags) + { +- const int maximum_fd = lowfd + NFDS; ++ const int maximum_fd = lowfd + NFDS - 1; + const int half_fd = lowfd + NFDS / 2; + const int gap_1 = maximum_fd - 8; + +@@ -121,7 +110,7 @@ close_range_test (void) + struct support_descriptors *descrs = support_descriptors_list (); + + /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + + close_range_test_common (lowfd, 0); + +@@ -146,7 +135,7 @@ close_range_test_subprocess (void) + struct support_descriptors *descrs = support_descriptors_list (); + + /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + + struct support_stack stack = support_stack_alloc (4096); + +@@ -184,7 +173,7 @@ close_range_unshare_test (void) + struct support_descriptors *descrs1 = support_descriptors_list (); + + /* Check if the temporary file descriptor has no no gaps. */ +- int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + + struct support_descriptors *descrs2 = support_descriptors_list (); + +@@ -200,7 +189,7 @@ close_range_unshare_test (void) + + support_stack_free (&stack); + +- for (int i = 0; i < NFDS; i++) ++ for (int i = lowfd; i < lowfd + NFDS; i++) + TEST_VERIFY (fcntl (i, F_GETFL) > -1); + + support_descriptors_check (descrs2); +@@ -226,9 +215,9 @@ static void + close_range_cloexec_test (void) + { + /* Check if the temporary file descriptor has no no gaps. */ +- const int lowfd = open_multiple_temp_files (); ++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600); + +- const int maximum_fd = lowfd + NFDS; ++ const int maximum_fd = lowfd + NFDS - 1; + const int half_fd = lowfd + NFDS / 2; + const int gap_1 = maximum_fd - 8; + +@@ -251,13 +240,13 @@ close_range_cloexec_test (void) + /* Create some gaps, close up to a threshold, and check result. */ + static int gap_close[] = { 57, 78, 81, 82, 84, 90 }; + for (int i = 0; i < array_length (gap_close); i++) +- xclose (gap_close[i]); ++ xclose (lowfd + gap_close[i]); + + TEST_COMPARE (close_range (half_fd + 1, gap_1, CLOSE_RANGE_CLOEXEC), 0); + for (int i = half_fd + 1; i < gap_1; i++) + { + int flags = fcntl (i, F_GETFD); +- if (is_in_array (gap_close, array_length (gap_close), i)) ++ if (is_in_array (gap_close, array_length (gap_close), i - lowfd)) + TEST_COMPARE (flags, -1); + else + { +-- +1.8.3.1 + diff --git a/glibc.spec b/glibc.spec index ad8575a..ee69464 100644 --- a/glibc.spec +++ b/glibc.spec @@ -65,7 +65,7 @@ ############################################################################## Name: glibc Version: 2.34 -Release: 33 +Release: 34 Summary: The GNU libc libraries License: %{all_license} URL: http://www.gnu.org/software/glibc/ @@ -138,6 +138,10 @@ Patch51: linux-Simplify-get_nprocs.patch Patch52: misc-Add-__get_nprocs_sched.patch Patch53: linux-Revert-the-use-of-sched_getaffinity-on-get_npr.patch Patch54: pthread-tst-cancel28-Fix-barrier-re-init-race-condit.patch +Patch55: support-Add-support_open_dev_null_range.patch +Patch56: Use-support_open_dev_null_range-io-tst-closefrom-mis.patch +Patch57: Fix-failing-nss-tst-nss-files-hosts-long-with-local-.patch +Patch58: nptl-Add-one-more-barrier-to-nptl-tst-create1.patch Patch9000: turn-default-value-of-x86_rep_stosb_threshold_form_2K_to_1M.patch Patch9001: delete-no-hard-link-to-avoid-all_language-package-to.patch @@ -1334,6 +1338,11 @@ fi %endif %changelog +* Tue Dec 21 2021 Qingqing Li - 2.34-34 +- tst: fix failing nss/tst-nss-files-hosts-long with local resolver + use support_open_dev_null_range io/tst-closefrom, mise/tst-close_range, and posix/tst-spawn5(BZ#28260) + nptl: add one more barrier to nptl/tst-create1 + * Wed Dec 15 2021 Qingqing Li - 2.34-33 - pthread/tst-cancel28: Fix barrier re-init race condition diff --git a/nptl-Add-one-more-barrier-to-nptl-tst-create1.patch b/nptl-Add-one-more-barrier-to-nptl-tst-create1.patch new file mode 100644 index 0000000..e18a8bc --- /dev/null +++ b/nptl-Add-one-more-barrier-to-nptl-tst-create1.patch @@ -0,0 +1,67 @@ +From 5cc338565479a620244c2f8ff35956629c4dbf81 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 10 Dec 2021 05:14:24 +0100 +Subject: [PATCH] nptl: Add one more barrier to nptl/tst-create1 + +Without the bar_ctor_finish barrier, it was possible that thread2 +re-locked user_lock before ctor had a chance to lock it. ctor then +blocked in its locking operation, xdlopen from the main thread +did not return, and thread2 was stuck waiting in bar_dtor: + +thread 1: started. +thread 2: started. +thread 2: locked user_lock. +constructor started: 0. +thread 1: in ctor: started. +thread 3: started. +thread 3: done. +thread 2: unlocked user_lock. +thread 2: locked user_lock. + +Fixes the test in commit 83b5323261bb72313bffcf37476c1b8f0847c736 +("elf: Avoid deadlock between pthread_create and ctors [BZ #28357]"). + +Reviewed-by: Szabolcs Nagy +--- + sysdeps/pthread/tst-create1.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c +index 932586c..763ded8 100644 +--- a/sysdeps/pthread/tst-create1.c ++++ b/sysdeps/pthread/tst-create1.c +@@ -33,6 +33,7 @@ thread 2: lock(user_lock) -> pthread_create + */ + + static pthread_barrier_t bar_ctor; ++static pthread_barrier_t bar_ctor_finish; + static pthread_barrier_t bar_dtor; + static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER; + +@@ -46,6 +47,7 @@ ctor (void) + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 1: in ctor: unlocked user_lock.\n"); + dprintf (1, "thread 1: in ctor: done.\n"); ++ xpthread_barrier_wait (&bar_ctor_finish); + } + + void +@@ -81,6 +83,7 @@ thread2 (void *a) + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 2: unlocked user_lock.\n"); + xpthread_join (t3); ++ xpthread_barrier_wait (&bar_ctor_finish); + + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 2: locked user_lock.\n"); +@@ -99,6 +102,7 @@ thread1 (void) + { + dprintf (1, "thread 1: started.\n"); + xpthread_barrier_init (&bar_ctor, NULL, 2); ++ xpthread_barrier_init (&bar_ctor_finish, NULL, 2); + xpthread_barrier_init (&bar_dtor, NULL, 2); + pthread_t t2 = xpthread_create (0, thread2, 0); + void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL); +-- +1.8.3.1 + diff --git a/support-Add-support_open_dev_null_range.patch b/support-Add-support_open_dev_null_range.patch new file mode 100644 index 0000000..0b78f8c --- /dev/null +++ b/support-Add-support_open_dev_null_range.patch @@ -0,0 +1,363 @@ +From e814f4b04ee413a7bb3dfa43e74c8fb4abf58359 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Tue, 24 Aug 2021 16:12:24 -0300 +Subject: [PATCH] support: Add support_open_dev_null_range + +It returns a range of file descriptor referring to the '/dev/null' +pathname. The function takes care of restarting the open range +if a file descriptor is found within the specified range and +also increases RLIMIT_NOFILE if required. + +Checked on x86_64-linux-gnu. +--- + support/Makefile | 2 + + support/support-open-dev-null-range.c | 134 ++++++++++++++++++++++++++ + support/support.h | 8 ++ + support/tst-support-open-dev-null-range.c | 155 ++++++++++++++++++++++++++++++ + 4 files changed, 299 insertions(+) + create mode 100644 support/support-open-dev-null-range.c + create mode 100644 support/tst-support-open-dev-null-range.c + +diff --git a/support/Makefile b/support/Makefile +index a462781..6332e7b 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -66,6 +66,7 @@ libsupport-routines = \ + support_path_support_time64 \ + support_process_state \ + support_ptrace \ ++ support-open-dev-null-range \ + support_openpty \ + support_paths \ + support_quote_blob \ +@@ -264,6 +265,7 @@ tests = \ + tst-support_capture_subprocess \ + tst-support_descriptors \ + tst-support_format_dns_packet \ ++ tst-support-open-dev-null-range \ + tst-support-process_state \ + tst-support_quote_blob \ + tst-support_quote_string \ +diff --git a/support/support-open-dev-null-range.c b/support/support-open-dev-null-range.c +new file mode 100644 +index 0000000..80d9dba +--- /dev/null ++++ b/support/support-open-dev-null-range.c +@@ -0,0 +1,134 @@ ++/* Return a range of open file descriptors. ++ Copyright (C) 2021 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 ++ ++static void ++increase_nofile (void) ++{ ++ struct rlimit rl; ++ if (getrlimit (RLIMIT_NOFILE, &rl) == -1) ++ FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m"); ++ ++ rl.rlim_cur += 128; ++ ++ if (setrlimit (RLIMIT_NOFILE, &rl) == 1) ++ FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m"); ++} ++ ++static int ++open_dev_null (int flags, mode_t mode) ++{ ++ int fd = open64 ("/dev/null", flags, mode); ++ if (fd > 0) ++ return fd; ++ ++ if (fd < 0 && errno != EMFILE) ++ FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode); ++ ++ increase_nofile (); ++ ++ return xopen ("/dev/null", flags, mode); ++} ++ ++struct range ++{ ++ int lowfd; ++ size_t len; ++}; ++ ++struct range_list ++{ ++ size_t total; ++ size_t used; ++ struct range *ranges; ++}; ++ ++static void ++range_init (struct range_list *r) ++{ ++ r->total = 8; ++ r->used = 0; ++ r->ranges = xmalloc (r->total * sizeof (struct range)); ++} ++ ++static void ++range_add (struct range_list *r, int lowfd, size_t len) ++{ ++ if (r->used == r->total) ++ { ++ r->total *= 2; ++ r->ranges = xrealloc (r->ranges, r->total * sizeof (struct range)); ++ } ++ r->ranges[r->used].lowfd = lowfd; ++ r->ranges[r->used].len = len; ++ r->used++; ++} ++ ++static void ++range_close (struct range_list *r) ++{ ++ for (size_t i = 0; i < r->used; i++) ++ { ++ int minfd = r->ranges[i].lowfd; ++ int maxfd = r->ranges[i].lowfd + r->ranges[i].len; ++ for (int fd = minfd; fd < maxfd; fd++) ++ xclose (fd); ++ } ++ free (r->ranges); ++} ++ ++int ++support_open_dev_null_range (int num, int flags, mode_t mode) ++{ ++ /* We keep track of the ranges that hit an already opened descriptor, so ++ we close them after we get a working range. */ ++ struct range_list rl; ++ range_init (&rl); ++ ++ int lowfd = open_dev_null (flags, mode); ++ int prevfd = lowfd; ++ while (true) ++ { ++ int i = 1; ++ for (; i < num; i++) ++ { ++ int fd = open_dev_null (flags, mode); ++ if (fd != lowfd + i) ++ { ++ range_add (&rl, lowfd, prevfd - lowfd + 1); ++ ++ prevfd = lowfd = fd; ++ break; ++ } ++ prevfd = fd; ++ } ++ if (i == num) ++ break; ++ } ++ ++ range_close (&rl); ++ ++ return lowfd; ++} +diff --git a/support/support.h b/support/support.h +index 834dba9..e6911e1 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -193,6 +193,14 @@ struct support_stack support_stack_alloc (size_t size); + /* Deallocate the STACK. */ + void support_stack_free (struct support_stack *stack); + ++ ++/* Create a range of NUM opened '/dev/null' file descriptors using FLAGS and ++ MODE. The function takes care of restarting the open range if a file ++ descriptor is found within the specified range and also increases ++ RLIMIT_NOFILE if required. ++ The returned value is the lowest file descriptor number. */ ++int support_open_dev_null_range (int num, int flags, mode_t mode); ++ + __END_DECLS + + #endif /* SUPPORT_H */ +diff --git a/support/tst-support-open-dev-null-range.c b/support/tst-support-open-dev-null-range.c +new file mode 100644 +index 0000000..8e29def +--- /dev/null ++++ b/support/tst-support-open-dev-null-range.c +@@ -0,0 +1,155 @@ ++/* Tests for support_open_dev_null_range. ++ Copyright (C) 2021 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 ++ ++#ifndef PATH_MAX ++# define PATH_MAX 1024 ++#endif ++ ++#include ++ ++static void ++check_path (int fd) ++{ ++ char *proc_fd_path = xasprintf ("/proc/self/fd/%d", fd); ++ char file_path[PATH_MAX]; ++ ssize_t file_path_length ++ = readlink (proc_fd_path, file_path, sizeof (file_path)); ++ free (proc_fd_path); ++ if (file_path_length < 0) ++ FAIL_EXIT1 ("readlink (%s, %p, %zu)", proc_fd_path, file_path, ++ sizeof (file_path)); ++ file_path[file_path_length] = '\0'; ++ TEST_COMPARE_STRING (file_path, "/dev/null"); ++} ++ ++static int ++number_of_opened_files (void) ++{ ++ DIR *fds = opendir ("/proc/self/fd"); ++ if (fds == NULL) ++ FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m"); ++ ++ int r = 0; ++ while (true) ++ { ++ errno = 0; ++ struct dirent64 *e = readdir64 (fds); ++ if (e == NULL) ++ { ++ if (errno != 0) ++ FAIL_EXIT1 ("readdir: %m"); ++ break; ++ } ++ ++ if (e->d_name[0] == '.') ++ continue; ++ ++ char *endptr; ++ long int fd = strtol (e->d_name, &endptr, 10); ++ if (*endptr != '\0' || fd < 0 || fd > INT_MAX) ++ FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s", ++ e->d_name); ++ ++ /* Skip the descriptor which is used to enumerate the ++ descriptors. */ ++ if (fd == dirfd (fds)) ++ continue; ++ ++ r = r + 1; ++ } ++ ++ closedir (fds); ++ ++ return r; ++} ++ ++static int ++do_test (void) ++{ ++ const int nfds1 = 8; ++ int lowfd = support_open_dev_null_range (nfds1, O_RDONLY, 0600); ++ for (int i = 0; i < nfds1; i++) ++ { ++ TEST_VERIFY (fcntl (lowfd + i, F_GETFL) > -1); ++ check_path (lowfd + i); ++ } ++ ++ /* create some gaps. */ ++ xclose (lowfd + 1); ++ xclose (lowfd + 5); ++ xclose (lowfd + 6); ++ ++ const int nfds2 = 16; ++ int lowfd2 = support_open_dev_null_range (nfds2, O_RDONLY, 0600); ++ for (int i = 0; i < nfds2; i++) ++ { ++ TEST_VERIFY (fcntl (lowfd2 + i, F_GETFL) > -1); ++ check_path (lowfd2 + i); ++ } ++ ++ /* Decrease the maximum number of files. */ ++ { ++ struct rlimit rl; ++ if (getrlimit (RLIMIT_NOFILE, &rl) == -1) ++ FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m"); ++ ++ rl.rlim_cur = number_of_opened_files (); ++ ++ if (setrlimit (RLIMIT_NOFILE, &rl) == 1) ++ FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m"); ++ } ++ ++ const int nfds3 = 16; ++ int lowfd3 = support_open_dev_null_range (nfds3, O_RDONLY, 0600); ++ for (int i = 0; i < nfds3; i++) ++ { ++ TEST_VERIFY (fcntl (lowfd3 + i, F_GETFL) > -1); ++ check_path (lowfd3 + i); ++ } ++ ++ /* create a lot of gaps to trigger the range extension. */ ++ xclose (lowfd3 + 1); ++ xclose (lowfd3 + 3); ++ xclose (lowfd3 + 5); ++ xclose (lowfd3 + 7); ++ xclose (lowfd3 + 9); ++ xclose (lowfd3 + 11); ++ xclose (lowfd3 + 13); ++ ++ const int nfds4 = 16; ++ int lowfd4 = support_open_dev_null_range (nfds4, O_RDONLY, 0600); ++ for (int i = 0; i < nfds4; i++) ++ { ++ TEST_VERIFY (fcntl (lowfd4 + i, F_GETFL) > -1); ++ check_path (lowfd4 + i); ++ } ++ ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + -- Gitee