From 9686d5573bdd39f2c31c27082b8bd98b3cebd77a Mon Sep 17 00:00:00 2001 From: Tim Biermann Date: Sat, 11 Dec 2021 22:59:48 +0100 Subject: [PATCH] glibc-32: included upstream fixes --- glibc-32/.signature | 5 +- glibc-32/Pkgfile | 5 +- glibc-32/glibc-2.34-upstream-fixes.patch | 4387 ++++++++++++++++++++++ 3 files changed, 4393 insertions(+), 4 deletions(-) create mode 100644 glibc-32/glibc-2.34-upstream-fixes.patch diff --git a/glibc-32/.signature b/glibc-32/.signature index 58f95f12..70c87f01 100644 --- a/glibc-32/.signature +++ b/glibc-32/.signature @@ -1,10 +1,11 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqqIvfNfyoGIl3dJWeU+KOTOKkWvyJpUsCaumvqsUo08Gd66SzkGuMdBJ4qYBU1BI/SCmLS1faxl+je8FS/rAIws= -SHA256 (Pkgfile) = 344f3dce94b58f4108dd81e696ed2005138ab6558ddb75131e3943a7602d473b +RWRJc1FUaeVeqrneHjowycLr7W204qXt5Wf3z/w3P42URNoZQg+kIhdH+H6rnVPZcJSAbumo5a5L5RKfobLZiNQr5hAieTyOyg0= +SHA256 (Pkgfile) = 68d47984366f1181f91cfb699012fe591e176a30f4981d2317811874343dbbc9 SHA256 (.footprint) = 28c0be81580495d8789fce4c11a415bd557693f979c5beb40977cbac1607853b SHA256 (glibc-2.34.tar.xz) = 44d26a1fe20b8853a48f470ead01e4279e869ac149b195dda4e44a195d981ab2 SHA256 (linux-5.10.tar.xz) = dcdf99e43e98330d925016985bfbc7b83c66d367b714b2de0cbbfcbf83d8ca43 SHA256 (glibc-c-utf8-locale-1.patch) = c48c306658ede269fb4a43140d41a3f609bffd17a8f661127e3e4dde48b85cd4 SHA256 (glibc-c-utf8-locale-2.patch) = a9d3c0660e6a48bb22dc77afbc7bb47ce79ca0d8c2ee8ebee4228d8d4952214e SHA256 (glibc-python3.patch) = 4a6511436c8abb708f5cb7e9baaf9812f2dc4bb5665a9376c1e270eae4f8b14f +SHA256 (glibc-2.34-upstream-fixes.patch) = 54e965200314f627a3412dd723d31e44a56ae9a156fce066d2a742caa86c0a36 SHA256 (lib32.conf) = 2f174d2bcefe1c29327690514f34d6970fffdd54398320ca23a11b5f1e3c9b2d diff --git a/glibc-32/Pkgfile b/glibc-32/Pkgfile index 2e780f06..489ea204 100644 --- a/glibc-32/Pkgfile +++ b/glibc-32/Pkgfile @@ -4,11 +4,11 @@ name=glibc-32 version=2.34 -release=1 +release=2 source=(https://ftp.gnu.org/gnu/glibc/glibc-$version.tar.xz https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.10.tar.xz glibc-c-utf8-locale-1.patch glibc-c-utf8-locale-2.patch - glibc-python3.patch + glibc-python3.patch glibc-2.34-upstream-fixes.patch lib32.conf) build() { @@ -18,6 +18,7 @@ build() { make INSTALL_HDR_PATH=$PKG/usr headers_install chown root:root $PKG/usr + patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-2.34-upstream-fixes.patch patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-python3.patch patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-c-utf8-locale-1.patch patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-c-utf8-locale-2.patch diff --git a/glibc-32/glibc-2.34-upstream-fixes.patch b/glibc-32/glibc-2.34-upstream-fixes.patch new file mode 100644 index 00000000..02585341 --- /dev/null +++ b/glibc-32/glibc-2.34-upstream-fixes.patch @@ -0,0 +1,4387 @@ +diff --git a/NEWS b/NEWS +index 3c610744c9..698964bb9e 100644 +--- a/NEWS ++++ b/NEWS +@@ -4,6 +4,25 @@ See the end for copying conditions. + + Please send GNU C library bug reports via + using `glibc' in the "product" field. ++ ++Version 2.34.1 ++ ++The following bugs are resolved with this release: ++ ++ [12889] nptl: Fix race between pthread_kill and thread exit ++ [19193] nptl: pthread_kill, pthread_cancel should not fail after exit ++ [28036] Incorrect types for pthread_mutexattr_set/getrobust_np ++ [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl ++ [28310] Do not use affinity mask for sysconf (_SC_NPROCESSORS_CONF) ++ [28340] ld.so crashes while loading a DSO with a read-only dynamic section ++ [28357] deadlock between pthread_create and ELF constructors ++ [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit ++ [28407] pthread_kill assumes that kill and tgkill are equivalent ++ [28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs ++ [28607] Masked signals are delivered on thread exit ++ [28532] powerpc64[le]: CFI for assembly templated syscalls is incorrect ++ [28678] nptl/tst-create1 hangs sporadically ++ + + Version 2.34 + +diff --git a/bits/stdlib-bsearch.h b/bits/stdlib-bsearch.h +index 4132dc6af0..e2fcea6e17 100644 +--- a/bits/stdlib-bsearch.h ++++ b/bits/stdlib-bsearch.h +@@ -29,14 +29,23 @@ bsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size, + while (__l < __u) + { + __idx = (__l + __u) / 2; +- __p = (void *) (((const char *) __base) + (__idx * __size)); ++ __p = (const void *) (((const char *) __base) + (__idx * __size)); + __comparison = (*__compar) (__key, __p); + if (__comparison < 0) + __u = __idx; + else if (__comparison > 0) + __l = __idx + 1; + else +- return (void *) __p; ++ { ++#if __GNUC_PREREQ(4, 6) ++# pragma GCC diagnostic push ++# pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ return (void *) __p; ++#if __GNUC_PREREQ(4, 6) ++# pragma GCC diagnostic pop ++#endif ++ } + } + + return NULL; +diff --git a/elf/Makefile b/elf/Makefile +index d05f410592..118d579c42 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -224,7 +224,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-tls-ie tst-tls-ie-dlmopen argv0test \ + tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \ + tst-tls20 tst-tls21 tst-dlmopen-dlerror tst-dlmopen-gethostbyname \ +- tst-dl-is_dso ++ tst-dl-is_dso tst-ro-dynamic + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -357,7 +357,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \ + tst-tls20mod-bad tst-tls21mod tst-dlmopen-dlerror-mod \ + tst-auxvalmod \ +- tst-dlmopen-gethostbyname-mod \ ++ tst-dlmopen-gethostbyname-mod tst-ro-dynamic-mod \ + + # Most modules build with _ISOMAC defined, but those filtered out + # depend on internal headers. +@@ -399,8 +399,9 @@ endif + modules-execstack-yes = tst-execstack-mod + extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) + +-# filtmod1.so, tst-big-note-lib.so have special rules. +-modules-names-nobuild := filtmod1 tst-big-note-lib ++# filtmod1.so, tst-big-note-lib.so, tst-ro-dynamic-mod.so have special ++# rules. ++modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod + + tests += $(tests-static) + +@@ -1906,3 +1907,10 @@ $(objpfx)tst-getauxval-static.out: $(objpfx)tst-auxvalmod.so + tst-getauxval-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx) + + $(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so ++ ++$(objpfx)tst-ro-dynamic: $(objpfx)tst-ro-dynamic-mod.so ++$(objpfx)tst-ro-dynamic-mod.so: $(objpfx)tst-ro-dynamic-mod.os \ ++ tst-ro-dynamic-mod.map ++ $(LINK.o) -nostdlib -nostartfiles -shared -o $@ \ ++ -Wl,--script=tst-ro-dynamic-mod.map \ ++ $(objpfx)tst-ro-dynamic-mod.os +diff --git a/elf/dl-close.c b/elf/dl-close.c +index f39001cab9..cd7b9c9fe8 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -549,6 +549,9 @@ _dl_close_worker (struct link_map *map, bool force) + size_t tls_free_end; + tls_free_start = tls_free_end = NO_TLS_OFFSET; + ++ /* Protects global and module specitic TLS state. */ ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); ++ + /* We modify the list of loaded objects. */ + __rtld_lock_lock_recursive (GL(dl_load_write_lock)); + +@@ -784,6 +787,9 @@ _dl_close_worker (struct link_map *map, bool force) + GL(dl_tls_static_used) = tls_free_start; + } + ++ /* TLS is cleaned up for the unloaded modules. */ ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); ++ + #ifdef SHARED + /* Auditing checkpoint: we have deleted all objects. */ + if (__glibc_unlikely (do_audit)) +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 650e4edc35..0976977fbd 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1130,6 +1130,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + struct loadcmd loadcmds[l->l_phnum]; + size_t nloadcmds = 0; + bool has_holes = false; ++ bool empty_dynamic = false; + + /* The struct is initialized to zero so this is not necessary: + l->l_ld = 0; +@@ -1142,13 +1143,16 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + segments are mapped in. We record the addresses it says + verbatim, and later correct for the run-time load address. */ + case PT_DYNAMIC: +- if (ph->p_filesz) ++ if (ph->p_filesz == 0) ++ empty_dynamic = true; /* Usually separate debuginfo. */ ++ else + { + /* Debuginfo only files from "objcopy --only-keep-debug" + contain a PT_DYNAMIC segment with p_filesz == 0. Skip + such a segment to avoid a crash later. */ + l->l_ld = (void *) ph->p_vaddr; + l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); ++ l->l_ld_readonly = (ph->p_flags & PF_W) == 0; + } + break; + +@@ -1264,6 +1268,13 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + goto lose; + } + ++ /* This check recognizes most separate debuginfo files. */ ++ if (__glibc_unlikely ((l->l_ld == 0 && type == ET_DYN) || empty_dynamic)) ++ { ++ errstring = N_("object file has no dynamic section"); ++ goto lose; ++ } ++ + /* Length of the sections to be loaded. */ + maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart; + +@@ -1281,18 +1292,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + } + } + +- if (l->l_ld == 0) +- { +- if (__glibc_unlikely (type == ET_DYN)) +- { +- errstring = N_("object file has no dynamic section"); +- goto lose; +- } +- } +- else ++ if (l->l_ld != 0) + l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr); + +- elf_get_dynamic_info (l, NULL); ++ elf_get_dynamic_info (l); + + /* Make sure we are not dlopen'ing an object that has the + DF_1_NOOPEN flag set, or a PIE object. */ +diff --git a/elf/dl-open.c b/elf/dl-open.c +index ec386626f9..bc68e2c376 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -66,6 +66,9 @@ struct dl_open_args + libc_map value in the namespace in case of a dlopen failure. */ + bool libc_already_loaded; + ++ /* Set to true if the end of dl_open_worker_begin was reached. */ ++ bool worker_continue; ++ + /* Original parameters to the program and the current environment. */ + int argc; + char **argv; +@@ -482,7 +485,7 @@ call_dl_init (void *closure) + } + + static void +-dl_open_worker (void *a) ++dl_open_worker_begin (void *a) + { + struct dl_open_args *args = a; + const char *file = args->file; +@@ -774,6 +777,36 @@ dl_open_worker (void *a) + _dl_call_libc_early_init (libc_map, false); + } + ++ args->worker_continue = true; ++} ++ ++static void ++dl_open_worker (void *a) ++{ ++ struct dl_open_args *args = a; ++ ++ args->worker_continue = false; ++ ++ { ++ /* Protects global and module specific TLS state. */ ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); ++ ++ struct dl_exception ex; ++ int err = _dl_catch_exception (&ex, dl_open_worker_begin, args); ++ ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); ++ ++ if (__glibc_unlikely (ex.errstring != NULL)) ++ /* Reraise the error. */ ++ _dl_signal_exception (err, &ex, NULL); ++ } ++ ++ if (!args->worker_continue) ++ return; ++ ++ int mode = args->mode; ++ struct link_map *new = args->map; ++ + /* Run the initializer functions of new objects. Temporarily + disable the exception handler, so that lazy binding failures are + fatal. */ +@@ -886,7 +919,7 @@ no more namespaces available for dlmopen()")); + /* Avoid keeping around a dangling reference to the libc.so link + map in case it has been cached in libc_map. */ + if (!args.libc_already_loaded) +- GL(dl_ns)[nsid].libc_map = NULL; ++ GL(dl_ns)[args.nsid].libc_map = NULL; + + /* Remove the object from memory. It may be in an inconsistent + state if relocation failed, for example. */ +diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c +index d5bd2f31e9..2fb02d7276 100644 +--- a/elf/dl-reloc-static-pie.c ++++ b/elf/dl-reloc-static-pie.c +@@ -40,7 +40,17 @@ _dl_relocate_static_pie (void) + + /* Read our own dynamic section and fill in the info array. */ + main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ()); +- elf_get_dynamic_info (main_map, NULL); ++ ++ const ElfW(Phdr) *ph, *phdr = GL(dl_phdr); ++ size_t phnum = GL(dl_phnum); ++ for (ph = phdr; ph < &phdr[phnum]; ++ph) ++ if (ph->p_type == PT_DYNAMIC) ++ { ++ main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0; ++ break; ++ } ++ ++ elf_get_dynamic_info (main_map); + + # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC + ELF_MACHINE_BEFORE_RTLD_RELOC (main_map->l_info); +diff --git a/elf/dl-support.c b/elf/dl-support.c +index 0155718175..d8c06ba7eb 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -229,6 +229,13 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock) + list of loaded objects while an object is added to or removed from + that list. */ + __rtld_lock_define_initialized_recursive (, _dl_load_write_lock) ++ /* This lock protects global and module specific TLS related data. ++ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation), ++ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are ++ accessed and when TLS related relocations are processed for a ++ module. It was introduced to keep pthread_create accessing TLS ++ state that is being set up. */ ++__rtld_lock_define_initialized_recursive (, _dl_load_tls_lock) + + + #ifdef HAVE_AUX_VECTOR +diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c +index d47bef1340..2c684c2db2 100644 +--- a/elf/dl-sysdep.c ++++ b/elf/dl-sysdep.c +@@ -317,7 +317,7 @@ _dl_show_auxv (void) + [AT_SYSINFO_EHDR - 2] = { "SYSINFO_EHDR: 0x", hex }, + [AT_RANDOM - 2] = { "RANDOM: 0x", hex }, + [AT_HWCAP2 - 2] = { "HWCAP2: 0x", hex }, +- [AT_MINSIGSTKSZ - 2] = { "MINSIGSTKSZ ", dec }, ++ [AT_MINSIGSTKSZ - 2] = { "MINSIGSTKSZ: ", dec }, + [AT_L1I_CACHESIZE - 2] = { "L1I_CACHESIZE: ", dec }, + [AT_L1I_CACHEGEOMETRY - 2] = { "L1I_CACHEGEOMETRY: 0x", hex }, + [AT_L1D_CACHESIZE - 2] = { "L1D_CACHESIZE: ", dec }, +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 423e380f7c..40263cf586 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -532,7 +532,7 @@ _dl_allocate_tls_init (void *result) + size_t maxgen = 0; + + /* Protects global dynamic TLS related state. */ +- __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); + + /* Check if the current dtv is big enough. */ + if (dtv[-1].counter < GL(dl_tls_max_dtv_idx)) +@@ -606,7 +606,7 @@ _dl_allocate_tls_init (void *result) + listp = listp->next; + assert (listp != NULL); + } +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + + /* The DTV version is up-to-date now. */ + dtv[0].counter = maxgen; +@@ -745,7 +745,7 @@ _dl_update_slotinfo (unsigned long int req_modid) + + Here the dtv needs to be updated to new_gen generation count. + +- This code may be called during TLS access when GL(dl_load_lock) ++ This code may be called during TLS access when GL(dl_load_tls_lock) + is not held. In that case the user code has to synchronize with + dlopen and dlclose calls of relevant modules. A module m is + relevant if the generation of m <= new_gen and dlclose of m is +@@ -867,11 +867,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) + if (__glibc_unlikely (the_map->l_tls_offset + != FORCED_DYNAMIC_TLS_OFFSET)) + { +- __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); + if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET)) + { + the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET; +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + } + else if (__glibc_likely (the_map->l_tls_offset + != FORCED_DYNAMIC_TLS_OFFSET)) +@@ -883,7 +883,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) + #else + # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" + #endif +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + + dtv[GET_ADDR_MODULE].pointer.to_free = NULL; + dtv[GET_ADDR_MODULE].pointer.val = p; +@@ -891,7 +891,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) + return (char *) p + GET_ADDR_OFFSET; + } + else +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + } + struct dtv_pointer result = allocate_and_init (the_map); + dtv[GET_ADDR_MODULE].pointer = result; +@@ -962,7 +962,7 @@ _dl_tls_get_addr_soft (struct link_map *l) + return NULL; + + dtv_t *dtv = THREAD_DTV (); +- /* This may be called without holding the GL(dl_load_lock). Reading ++ /* This may be called without holding the GL(dl_load_tls_lock). Reading + arbitrary gen value is fine since this is best effort code. */ + size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); + if (__glibc_unlikely (dtv[0].counter != gen)) +diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h +index d8ec32377d..4aa2058abf 100644 +--- a/elf/get-dynamic-info.h ++++ b/elf/get-dynamic-info.h +@@ -28,7 +28,7 @@ static + auto + #endif + inline void __attribute__ ((unused, always_inline)) +-elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) ++elf_get_dynamic_info (struct link_map *l) + { + #if __ELF_NATIVE_CLASS == 32 + typedef Elf32_Word d_tag_utype; +@@ -69,28 +69,15 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) + info[i] = dyn; + } + +-#define DL_RO_DYN_TEMP_CNT 8 +- +-#ifndef DL_RO_DYN_SECTION + /* Don't adjust .dynamic unnecessarily. */ +- if (l->l_addr != 0) ++ if (l->l_addr != 0 && dl_relocate_ld (l)) + { + ElfW(Addr) l_addr = l->l_addr; +- int cnt = 0; + + # define ADJUST_DYN_INFO(tag) \ + do \ + if (info[tag] != NULL) \ +- { \ +- if (temp) \ +- { \ +- temp[cnt].d_tag = info[tag]->d_tag; \ +- temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr; \ +- info[tag] = temp + cnt++; \ +- } \ +- else \ +- info[tag]->d_un.d_ptr += l_addr; \ +- } \ ++ info[tag]->d_un.d_ptr += l_addr; \ + while (0) + + ADJUST_DYN_INFO (DT_HASH); +@@ -107,9 +94,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) + ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM)); + ADJUST_DYN_INFO (ADDRIDX (DT_GNU_HASH)); + # undef ADJUST_DYN_INFO +- assert (cnt <= DL_RO_DYN_TEMP_CNT); + } +-#endif + if (info[DT_PLTREL] != NULL) + { + #if ELF_MACHINE_NO_RELA +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index 1037e8d0cf..b8893637f8 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -503,7 +503,11 @@ add_dir_1 (const char *line, const char *from_file, int from_line) + entry->path[--i] = '\0'; + + if (i == 0) +- return; ++ { ++ free (entry->path); ++ free (entry); ++ return; ++ } + + char *path = entry->path; + if (opt_chroot != NULL) +diff --git a/elf/rtld.c b/elf/rtld.c +index d733359eaf..d83ac1bdc4 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -322,6 +322,7 @@ struct rtld_global _rtld_global = + #ifdef _LIBC_REENTRANT + ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, + ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, ++ ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, + #endif + ._dl_nns = 1, + ._dl_ns = +@@ -463,6 +464,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) + #ifndef DONT_USE_BOOTSTRAP_MAP + GL(dl_rtld_map).l_addr = info->l.l_addr; + GL(dl_rtld_map).l_ld = info->l.l_ld; ++ GL(dl_rtld_map).l_ld_readonly = info->l.l_ld_readonly; + memcpy (GL(dl_rtld_map).l_info, info->l.l_info, + sizeof GL(dl_rtld_map).l_info); + GL(dl_rtld_map).l_mach = info->l.l_mach; +@@ -546,7 +548,8 @@ _dl_start (void *arg) + + /* Read our own dynamic section and fill in the info array. */ + bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic (); +- elf_get_dynamic_info (&bootstrap_map, NULL); ++ bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION; ++ elf_get_dynamic_info (&bootstrap_map); + + #if NO_TLS_OFFSET != 0 + bootstrap_map.l_tls_offset = NO_TLS_OFFSET; +@@ -1468,6 +1471,7 @@ dl_main (const ElfW(Phdr) *phdr, + /* This tells us where to find the dynamic section, + which tells us everything we need to do. */ + main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr; ++ main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0; + break; + case PT_INTERP: + /* This "interpreter segment" was used by the program loader to +@@ -1613,7 +1617,7 @@ dl_main (const ElfW(Phdr) *phdr, + if (! rtld_is_main) + { + /* Extract the contents of the dynamic section for easy access. */ +- elf_get_dynamic_info (main_map, NULL); ++ elf_get_dynamic_info (main_map); + + /* If the main map is libc.so, update the base namespace to + refer to this map. If libc.so is loaded later, this happens +diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h +index 86c491e49c..f44748bc98 100644 +--- a/elf/setup-vdso.h ++++ b/elf/setup-vdso.h +@@ -33,8 +33,6 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), + 0, LM_ID_BASE); + if (__glibc_likely (l != NULL)) + { +- static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro; +- + l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso) + + GLRO(dl_sysinfo_dso)->e_phoff); + l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum; +@@ -45,6 +43,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), + { + l->l_ld = (void *) ph->p_vaddr; + l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); ++ l->l_ld_readonly = (ph->p_flags & PF_W) == 0; + } + else if (ph->p_type == PT_LOAD) + { +@@ -65,7 +64,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), + l->l_map_end += l->l_addr; + l->l_text_end += l->l_addr; + l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr); +- elf_get_dynamic_info (l, dyn_temp); ++ elf_get_dynamic_info (l); + _dl_setup_hash (l); + l->l_relocated = 1; + +diff --git a/elf/tst-ro-dynamic-mod.c b/elf/tst-ro-dynamic-mod.c +new file mode 100644 +index 0000000000..6d99925964 +--- /dev/null ++++ b/elf/tst-ro-dynamic-mod.c +@@ -0,0 +1,19 @@ ++/* Test case for DSO with readonly dynamic section. ++ 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 ++ . */ ++ ++int foo = -1; +diff --git a/elf/tst-ro-dynamic-mod.map b/elf/tst-ro-dynamic-mod.map +new file mode 100644 +index 0000000000..2fe4a2998c +--- /dev/null ++++ b/elf/tst-ro-dynamic-mod.map +@@ -0,0 +1,16 @@ ++SECTIONS ++{ ++ . = SIZEOF_HEADERS; ++ .dynamic : { *(.dynamic) } :text :dynamic ++ .rodata : { *(.data*) *(.bss*) } :text ++ /DISCARD/ : { ++ *(.note.gnu.property) ++ } ++ .note : { *(.note.*) } :text :note ++} ++PHDRS ++{ ++ text PT_LOAD FLAGS(5) FILEHDR PHDRS; ++ dynamic PT_DYNAMIC FLAGS(4); ++ note PT_NOTE FLAGS(4); ++} +diff --git a/elf/tst-ro-dynamic.c b/elf/tst-ro-dynamic.c +new file mode 100644 +index 0000000000..3a18f8789a +--- /dev/null ++++ b/elf/tst-ro-dynamic.c +@@ -0,0 +1,31 @@ ++/* Test case for DSO with readonly dynamic section. ++ 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 ++ ++extern int foo; ++ ++static int ++do_test (void) ++{ ++ TEST_COMPARE (foo, -1); ++ return 0; ++} ++ ++#include +diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c +index 62bee28769..cc391d8f93 100644 +--- a/iconv/gconv_conf.c ++++ b/iconv/gconv_conf.c +@@ -478,7 +478,7 @@ __gconv_read_conf (void) + __gconv_get_path (); + + for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt) +- gconv_parseconfdir (__gconv_path_elem[cnt].name, ++ gconv_parseconfdir (NULL, __gconv_path_elem[cnt].name, + __gconv_path_elem[cnt].len); + #endif + +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +index a4153e54c6..a586268abc 100644 +--- a/iconv/gconv_parseconfdir.h ++++ b/iconv/gconv_parseconfdir.h +@@ -39,7 +39,6 @@ + /* Name of the file containing the module information in the directories + along the path. */ + static const char gconv_conf_filename[] = "gconv-modules"; +-static const char gconv_conf_dirname[] = "gconv-modules.d"; + + static void add_alias (char *); + static void add_module (char *, const char *, size_t, int); +@@ -110,19 +109,28 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len) + return true; + } + ++/* Prefix DIR (with length DIR_LEN) with PREFIX if the latter is non-NULL and ++ parse configuration in it. */ ++ + static __always_inline bool +-gconv_parseconfdir (const char *dir, size_t dir_len) ++gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) + { +- /* No slash needs to be inserted between dir and gconv_conf_filename; +- dir already ends in a slash. */ +- char *buf = malloc (dir_len + sizeof (gconv_conf_dirname)); ++ /* No slash needs to be inserted between dir and gconv_conf_filename; dir ++ already ends in a slash. The additional 2 is to accommodate the ".d" ++ when looking for configuration files in gconv-modules.d. */ ++ size_t buflen = dir_len + sizeof (gconv_conf_filename) + 2; ++ char *buf = malloc (buflen + (prefix != NULL ? strlen (prefix) : 0)); ++ char *cp = buf; + bool found = false; + + if (buf == NULL) + return false; + +- char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename, +- sizeof (gconv_conf_filename)); ++ if (prefix != NULL) ++ cp = stpcpy (cp, prefix); ++ ++ cp = mempcpy (mempcpy (cp, dir, dir_len), gconv_conf_filename, ++ sizeof (gconv_conf_filename)); + + /* Read the gconv-modules configuration file first. */ + found = read_conf_file (buf, dir, dir_len); +@@ -153,12 +161,11 @@ gconv_parseconfdir (const char *dir, size_t dir_len) + struct stat64 st; + if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) + continue; +- if (ent->d_type == DT_UNKNOWN +- && (lstat64 (conf, &st) == -1 +- || !S_ISREG (st.st_mode))) +- continue; + +- found |= read_conf_file (conf, dir, dir_len); ++ if (ent->d_type != DT_UNKNOWN ++ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode))) ++ found |= read_conf_file (conf, dir, dir_len); ++ + free (conf); + } + } +diff --git a/iconv/iconv_charmap.c b/iconv/iconv_charmap.c +index e2d53fee3c..a8b6b56124 100644 +--- a/iconv/iconv_charmap.c ++++ b/iconv/iconv_charmap.c +@@ -234,6 +234,8 @@ charmap_conversion (const char *from_code, struct charmap_t *from_charmap, + while (++remaining < argc); + + /* All done. */ ++ if (output != stdout) ++ fclose (output); + free_table (cvtbl); + return status; + } +diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c +index 783b2bbdbb..273a71f673 100644 +--- a/iconv/iconvconfig.c ++++ b/iconv/iconvconfig.c +@@ -653,13 +653,21 @@ add_module (char *rp, const char *directory, + static int + handle_dir (const char *dir) + { ++ char *newp = NULL; + size_t dirlen = strlen (dir); + bool found = false; + +- char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "", +- dir, dir[dirlen - 1] != '/' ? "/" : ""); ++ /* End directory path with a '/' if it doesn't already. */ ++ if (dir[dirlen - 1] != '/') ++ { ++ newp = xmalloc (dirlen + 2); ++ memcpy (newp, dir, dirlen); ++ newp[dirlen++] = '/'; ++ newp[dirlen] = '\0'; ++ dir = newp; ++ } + +- found = gconv_parseconfdir (fulldir, strlen (fulldir)); ++ found = gconv_parseconfdir (dir[0] == '/' ? prefix : NULL, dir, dirlen); + + if (!found) + { +@@ -671,7 +679,7 @@ handle_dir (const char *dir) + "configuration files with names ending in .conf."); + } + +- free (fulldir); ++ free (newp); + + return found ? 0 : 1; + } +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index c216f959df..d5507a048c 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -1,4 +1,5 @@ + # Copyright (C) 1997-2021 Free Software Foundation, Inc. ++# Copyright (C) The GNU Toolchain Authors. + # This file is part of the GNU C Library. + + # The GNU C Library is free software; you can redistribute it and/or +@@ -74,7 +75,7 @@ ifeq (yes,$(build-shared)) + tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ + tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ + bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \ +- bug-iconv13 bug-iconv14 ++ bug-iconv13 bug-iconv14 bug-iconv15 + ifeq ($(have-thread-library),yes) + tests += bug-iconv3 + endif +@@ -327,6 +328,8 @@ $(objpfx)bug-iconv12.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) + $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) ++$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \ ++ $(addprefix $(objpfx),$(modules.so)) + + $(objpfx)iconv-test.out: run-iconv-test.sh \ + $(addprefix $(objpfx), $(gconv-modules)) \ +diff --git a/iconvdata/bug-iconv15.c b/iconvdata/bug-iconv15.c +new file mode 100644 +index 0000000000..cc04bd0313 +--- /dev/null ++++ b/iconvdata/bug-iconv15.c +@@ -0,0 +1,60 @@ ++/* Bug 28524: Conversion from ISO-2022-JP-3 with iconv ++ may emit spurious NUL character on state reset. ++ Copyright (C) The GNU Toolchain Authors. ++ 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 ++ ++static int ++do_test (void) ++{ ++ char in[] = "\x1b(I"; ++ char *inbuf = in; ++ size_t inleft = sizeof (in) - 1; ++ char out[1]; ++ char *outbuf = out; ++ size_t outleft = sizeof (out); ++ iconv_t cd; ++ ++ cd = iconv_open ("UTF8", "ISO-2022-JP-3"); ++ TEST_VERIFY_EXIT (cd != (iconv_t) -1); ++ ++ /* First call to iconv should alter internal state. ++ Now, JISX0201_Kana_set is selected and ++ state value != ASCII_set. */ ++ TEST_VERIFY (iconv (cd, &inbuf, &inleft, &outbuf, &outleft) != (size_t) -1); ++ ++ /* No bytes should have been added to ++ the output buffer at this point. */ ++ TEST_VERIFY (outbuf == out); ++ TEST_VERIFY (outleft == sizeof (out)); ++ ++ /* Second call shall emit spurious NUL character in unpatched glibc. */ ++ TEST_VERIFY (iconv (cd, NULL, NULL, &outbuf, &outleft) != (size_t) -1); ++ ++ /* No characters are expected to be produced. */ ++ TEST_VERIFY (outbuf == out); ++ TEST_VERIFY (outleft == sizeof (out)); ++ ++ TEST_VERIFY_EXIT (iconv_close (cd) != -1); ++ ++ return 0; ++} ++ ++#include +diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c +index c8ba88cdc9..5fc0c0f739 100644 +--- a/iconvdata/iso-2022-jp-3.c ++++ b/iconvdata/iso-2022-jp-3.c +@@ -1,5 +1,6 @@ + /* Conversion module for ISO-2022-JP-3. + Copyright (C) 1998-2021 Free Software Foundation, Inc. ++ Copyright (C) The GNU Toolchain Authors. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1998, + and Bruno Haible , 2002. +@@ -81,20 +82,31 @@ enum + the output state to the initial state. This has to be done during the + flushing. */ + #define EMIT_SHIFT_TO_INIT \ +- if (data->__statep->__count != ASCII_set) \ ++ if ((data->__statep->__count & ~7) != ASCII_set) \ + { \ + if (FROM_DIRECTION) \ + { \ +- if (__glibc_likely (outbuf + 4 <= outend)) \ ++ uint32_t ch = data->__statep->__count >> 6; \ ++ \ ++ if (__glibc_unlikely (ch != 0)) \ + { \ +- /* Write out the last character. */ \ +- *((uint32_t *) outbuf) = data->__statep->__count >> 6; \ +- outbuf += sizeof (uint32_t); \ +- data->__statep->__count = ASCII_set; \ ++ if (__glibc_likely (outbuf + 4 <= outend)) \ ++ { \ ++ /* Write out the last character. */ \ ++ put32u (outbuf, ch); \ ++ outbuf += 4; \ ++ data->__statep->__count &= 7; \ ++ data->__statep->__count |= ASCII_set; \ ++ } \ ++ else \ ++ /* We don't have enough room in the output buffer. */ \ ++ status = __GCONV_FULL_OUTPUT; \ + } \ + else \ +- /* We don't have enough room in the output buffer. */ \ +- status = __GCONV_FULL_OUTPUT; \ ++ { \ ++ data->__statep->__count &= 7; \ ++ data->__statep->__count |= ASCII_set; \ ++ } \ + } \ + else \ + { \ +diff --git a/include/link.h b/include/link.h +index 4af16cb596..c46aced9f7 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -205,6 +205,7 @@ struct link_map + unsigned int l_free_initfini:1; /* Nonzero if l_initfini can be + freed, ie. not allocated with + the dummy malloc in ld.so. */ ++ unsigned int l_ld_readonly:1; /* Nonzero if dynamic section is readonly. */ + + /* NODELETE status of the map. Only valid for maps of type + lt_loaded. Lazy binding sets l_nodelete_active directly, +@@ -342,6 +343,8 @@ struct link_map + unsigned long long int l_serial; + }; + ++#include ++ + /* Information used by audit modules. For most link maps, this data + immediate follows the link map in memory. For the dynamic linker, + it is allocated separately. See link_map_audit_state in +diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h +index 7388356a19..c490561581 100644 +--- a/include/sys/sysinfo.h ++++ b/include/sys/sysinfo.h +@@ -9,10 +9,15 @@ + extern int __get_nprocs_conf (void); + libc_hidden_proto (__get_nprocs_conf) + +-/* Return number of available processors. */ ++/* Return number of available processors (not all of them will be ++ available to the caller process). */ + extern int __get_nprocs (void); + libc_hidden_proto (__get_nprocs) + ++/* Return the number of available processors which the process can ++ be scheduled. */ ++extern int __get_nprocs_sched (void) attribute_hidden; ++ + /* Return number of physical pages of memory in the system. */ + extern long int __get_phys_pages (void); + libc_hidden_proto (__get_phys_pages) +diff --git a/io/fcntl.h b/io/fcntl.h +index 8917a73b42..1c96f98f4d 100644 +--- a/io/fcntl.h ++++ b/io/fcntl.h +@@ -187,10 +187,10 @@ extern int fcntl64 (int __fd, int __cmd, ...); + # endif + #else /* __USE_TIME_BITS64 */ + # ifdef __REDIRECT +-extern int __REDIRECT (fcntl, (int __fd, int __request, ...), +- __fcntl_time64) __THROW; +-extern int __REDIRECT (fcntl64, (int __fd, int __request, ...), +- __fcntl_time64) __THROW; ++extern int __REDIRECT_NTH (fcntl, (int __fd, int __request, ...), ++ __fcntl_time64); ++extern int __REDIRECT_NTH (fcntl64, (int __fd, int __request, ...), ++ __fcntl_time64); + # else + extern int __fcntl_time64 (int __fd, int __request, ...) __THROW; + # define fcntl64 __fcntl_time64 +diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c +index d4c187073c..395ec0d894 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/malloc/arena.c b/malloc/arena.c +index 667484630e..f1f0af8648 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -879,7 +879,7 @@ arena_get2 (size_t size, mstate avoid_arena) + narenas_limit = mp_.arena_max; + else if (narenas > mp_.arena_test) + { +- int n = __get_nprocs (); ++ int n = __get_nprocs_sched (); + + if (n >= 1) + narenas_limit = NARENAS_FROM_NCORES (n); +diff --git a/malloc/malloc-debug.c b/malloc/malloc-debug.c +index 9922ef5f25..3d7e6d44fd 100644 +--- a/malloc/malloc-debug.c ++++ b/malloc/malloc-debug.c +@@ -1,5 +1,6 @@ + /* Malloc debug DSO. + Copyright (C) 2021 Free Software Foundation, Inc. ++ Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or +@@ -399,17 +400,17 @@ strong_alias (__debug_calloc, calloc) + size_t + malloc_usable_size (void *mem) + { ++ if (mem == NULL) ++ return 0; ++ + if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)) + return mcheck_usable_size (mem); + if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)) + return malloc_check_get_size (mem); + +- if (mem != NULL) +- { +- mchunkptr p = mem2chunk (mem); +- if (DUMPED_MAIN_ARENA_CHUNK (p)) +- return chunksize (p) - SIZE_SZ; +- } ++ mchunkptr p = mem2chunk (mem); ++ if (DUMPED_MAIN_ARENA_CHUNK (p)) ++ return chunksize (p) - SIZE_SZ; + + return musable (mem); + } +diff --git a/malloc/malloc.c b/malloc/malloc.c +index e065785af7..7882c70f0a 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -1,5 +1,6 @@ + /* Malloc implementation for multiple threads without lock contention. + Copyright (C) 1996-2021 Free Software Foundation, Inc. ++ Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + Contributed by Wolfram Gloger + and Doug Lea , 2001. +@@ -5009,20 +5010,13 @@ __malloc_trim (size_t s) + static size_t + musable (void *mem) + { +- mchunkptr p; +- if (mem != 0) +- { +- size_t result = 0; +- +- p = mem2chunk (mem); ++ mchunkptr p = mem2chunk (mem); + +- if (chunk_is_mmapped (p)) +- result = chunksize (p) - CHUNK_HDR_SZ; +- else if (inuse (p)) +- result = memsize (p); ++ if (chunk_is_mmapped (p)) ++ return chunksize (p) - CHUNK_HDR_SZ; ++ else if (inuse (p)) ++ return memsize (p); + +- return result; +- } + return 0; + } + +@@ -5030,10 +5024,9 @@ musable (void *mem) + size_t + __malloc_usable_size (void *m) + { +- size_t result; +- +- result = musable (m); +- return result; ++ if (m == NULL) ++ return 0; ++ return musable (m); + } + #endif + +diff --git a/malloc/tst-malloc-usable.c b/malloc/tst-malloc-usable.c +index a1074b782a..b0d702be10 100644 +--- a/malloc/tst-malloc-usable.c ++++ b/malloc/tst-malloc-usable.c +@@ -2,6 +2,7 @@ + MALLOC_CHECK_ exported to a positive value. + + Copyright (C) 2012-2021 Free Software Foundation, Inc. ++ Copyright The GNU Toolchain Authors. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or +@@ -21,29 +22,24 @@ + #include + #include + #include ++#include ++#include + + static int + do_test (void) + { + size_t usable_size; + void *p = malloc (7); +- if (!p) +- { +- printf ("memory allocation failed\n"); +- return 1; +- } + ++ TEST_VERIFY_EXIT (p != NULL); + usable_size = malloc_usable_size (p); +- if (usable_size != 7) +- { +- printf ("malloc_usable_size: expected 7 but got %zu\n", usable_size); +- return 1; +- } +- ++ TEST_COMPARE (usable_size, 7); + memset (p, 0, usable_size); + free (p); ++ ++ TEST_COMPARE (malloc_usable_size (NULL), 0); ++ + return 0; + } + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include "support/test-driver.c" +diff --git a/misc/getsysstats.c b/misc/getsysstats.c +index 0eedface6d..57d93601e2 100644 +--- a/misc/getsysstats.c ++++ b/misc/getsysstats.c +@@ -45,6 +45,12 @@ weak_alias (__get_nprocs, get_nprocs) + link_warning (get_nprocs, "warning: get_nprocs will always return 1") + + ++int ++__get_nprocs_sched (void) ++{ ++ return 1; ++} ++ + long int + __get_phys_pages (void) + { +diff --git a/misc/sys/ioctl.h b/misc/sys/ioctl.h +index 6884d9925f..9945c1e918 100644 +--- a/misc/sys/ioctl.h ++++ b/misc/sys/ioctl.h +@@ -42,8 +42,8 @@ __BEGIN_DECLS + extern int ioctl (int __fd, unsigned long int __request, ...) __THROW; + #else + # ifdef __REDIRECT +-extern int __REDIRECT (ioctl, (int __fd, unsigned long int __request, ...), +- __ioctl_time64) __THROW; ++extern int __REDIRECT_NTH (ioctl, (int __fd, unsigned long int __request, ...), ++ __ioctl_time64); + # else + extern int __ioctl_time64 (int __fd, unsigned long int __request, ...) __THROW; + # define ioctl __ioctl_time64 +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index cfe37a3443..50065bc9bd 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + /* Default alignment of stack. */ + #ifndef STACK_ALIGN +@@ -127,6 +128,8 @@ get_cached_stack (size_t *sizep, void **memp) + /* No pending event. */ + result->nextevent = NULL; + ++ result->exiting = false; ++ __libc_lock_init (result->exit_lock); + result->tls_state = (struct tls_internal_t) { 0 }; + + /* Clear the DTV. */ +diff --git a/nptl/descr.h b/nptl/descr.h +index c85778d449..4de84138fb 100644 +--- a/nptl/descr.h ++++ b/nptl/descr.h +@@ -396,6 +396,12 @@ struct pthread + PTHREAD_CANCEL_ASYNCHRONOUS). */ + unsigned char canceltype; + ++ /* Used in __pthread_kill_internal to detected a thread that has ++ exited or is about to exit. exit_lock must only be acquired ++ after blocking signals. */ ++ bool exiting; ++ int exit_lock; /* A low-level lock (for use with __libc_lock_init etc). */ ++ + /* Used on strsignal. */ + struct tls_internal_t tls_state; + +diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c +index cc25ff21f3..9bac6e3b76 100644 +--- a/nptl/pthread_cancel.c ++++ b/nptl/pthread_cancel.c +@@ -62,10 +62,11 @@ __pthread_cancel (pthread_t th) + { + volatile struct pthread *pd = (volatile struct pthread *) th; + +- /* Make sure the descriptor is valid. */ +- if (INVALID_TD_P (pd)) +- /* Not a valid thread handle. */ +- return ESRCH; ++ if (pd->tid == 0) ++ /* The thread has already exited on the kernel side. Its outcome ++ (regular exit, other cancelation) has already been ++ determined. */ ++ return 0; + + static int init_sigcancel = 0; + if (atomic_load_relaxed (&init_sigcancel) == 0) +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index d8ec299cb1..3db0c9fdf4 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #include + +@@ -406,8 +407,6 @@ start_thread (void *arg) + unwind_buf.priv.data.prev = NULL; + unwind_buf.priv.data.cleanup = NULL; + +- __libc_signal_restore_set (&pd->sigmask); +- + /* Allow setxid from now onwards. */ + if (__glibc_unlikely (atomic_exchange_acq (&pd->setxid_futex, 0) == -2)) + futex_wake (&pd->setxid_futex, 1, FUTEX_PRIVATE); +@@ -417,6 +416,8 @@ start_thread (void *arg) + /* Store the new cleanup handler info. */ + THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf); + ++ __libc_signal_restore_set (&pd->sigmask); ++ + LIBC_PROBE (pthread_start, 3, (pthread_t) pd, pd->start_routine, pd->arg); + + /* Run the code the user provided. */ +@@ -485,6 +486,27 @@ start_thread (void *arg) + /* This was the last thread. */ + exit (0); + ++ /* This prevents sending a signal from this thread to itself during ++ its final stages. This must come after the exit call above ++ because atexit handlers must not run with signals blocked. ++ ++ Do not block SIGSETXID. The setxid handshake below expects the ++ signal to be delivered. (SIGSETXID cannot run application code, ++ nor does it use pthread_kill.) Reuse the pd->sigmask space for ++ computing the signal mask, to save stack space. */ ++ __sigfillset (&pd->sigmask); ++ __sigdelset (&pd->sigmask, SIGSETXID); ++ INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &pd->sigmask, NULL, ++ __NSIG_BYTES); ++ ++ /* Tell __pthread_kill_internal that this thread is about to exit. ++ If there is a __pthread_kill_internal in progress, this delays ++ the thread exit until the signal has been queued by the kernel ++ (so that the TID used to send it remains valid). */ ++ __libc_lock_lock (pd->exit_lock); ++ pd->exiting = true; ++ __libc_lock_unlock (pd->exit_lock); ++ + #ifndef __ASSUME_SET_ROBUST_LIST + /* If this thread has any robust mutexes locked, handle them now. */ + # if __PTHREAD_MUTEX_HAVE_PREV +diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c +index f79a2b26fc..35bf1f973e 100644 +--- a/nptl/pthread_kill.c ++++ b/nptl/pthread_kill.c +@@ -16,39 +16,66 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + #include + #include + +-int +-__pthread_kill_internal (pthread_t threadid, int signo) ++/* Sends SIGNO to THREADID. If the thread is about to exit or has ++ already exited on the kernel side, return NO_TID. Otherwise return ++ 0 or an error code. */ ++static int ++__pthread_kill_implementation (pthread_t threadid, int signo, int no_tid) + { +- pid_t tid; + struct pthread *pd = (struct pthread *) threadid; +- + if (pd == THREAD_SELF) +- /* It is a special case to handle raise() implementation after a vfork +- call (which does not update the PD tid field). */ +- tid = INLINE_SYSCALL_CALL (gettid); +- else +- /* Force load of pd->tid into local variable or register. Otherwise +- if a thread exits between ESRCH test and tgkill, we might return +- EINVAL, because pd->tid would be cleared by the kernel. */ +- tid = atomic_forced_read (pd->tid); +- +- int val; +- if (__glibc_likely (tid > 0)) + { +- pid_t pid = __getpid (); +- +- val = INTERNAL_SYSCALL_CALL (tgkill, pid, tid, signo); +- val = (INTERNAL_SYSCALL_ERROR_P (val) +- ? INTERNAL_SYSCALL_ERRNO (val) : 0); ++ /* Use the actual TID from the kernel, so that it refers to the ++ current thread even if called after vfork. There is no ++ signal blocking in this case, so that the signal is delivered ++ immediately, before __pthread_kill_internal returns: a signal ++ sent to the thread itself needs to be delivered ++ synchronously. (It is unclear if Linux guarantees the ++ delivery of all pending signals after unblocking in the code ++ below. POSIX only guarantees delivery of a single signal, ++ which may not be the right one.) */ ++ pid_t tid = INTERNAL_SYSCALL_CALL (gettid); ++ int ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), tid, signo); ++ return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; + } ++ ++ /* Block all signals, as required by pd->exit_lock. */ ++ sigset_t old_mask; ++ __libc_signal_block_all (&old_mask); ++ __libc_lock_lock (pd->exit_lock); ++ ++ int ret; ++ if (pd->exiting) ++ /* The thread is about to exit (or has exited). Sending the ++ signal is either not observable (the target thread has already ++ blocked signals at this point), or it will fail, or it might be ++ delivered to a new, unrelated thread that has reused the TID. ++ So do not actually send the signal. */ ++ ret = no_tid; + else +- val = ESRCH; ++ { ++ ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo); ++ ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; ++ } ++ ++ __libc_lock_unlock (pd->exit_lock); ++ __libc_signal_restore_set (&old_mask); + +- return val; ++ return ret; ++} ++ ++int ++__pthread_kill_internal (pthread_t threadid, int signo) ++{ ++ /* Do not report an error in the no-tid case because the threadid ++ argument is still valid (the thread ID lifetime has not ended), ++ and ESRCH (for example) would be misleading. */ ++ return __pthread_kill_implementation (threadid, signo, 0); + } + + int +@@ -61,6 +88,7 @@ __pthread_kill (pthread_t threadid, int signo) + + return __pthread_kill_internal (threadid, signo); + } ++ + /* Some architectures (for instance arm) might pull raise through libgcc, so + avoid the symbol version if it ends up being used on ld.so. */ + #if !IS_IN(rtld) +@@ -68,6 +96,17 @@ libc_hidden_def (__pthread_kill) + versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34); + + # if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) +-compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0); ++/* Variant which returns ESRCH in the no-TID case, for backwards ++ compatibility. */ ++int ++attribute_compat_text_section ++__pthread_kill_esrch (pthread_t threadid, int signo) ++{ ++ if (__is_internal_signal (signo)) ++ return EINVAL; ++ ++ return __pthread_kill_implementation (threadid, signo, ESRCH); ++} ++compat_symbol (libc, __pthread_kill_esrch, pthread_kill, GLIBC_2_0); + # endif + #endif +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 0000000000..5b0c6a4199 +--- /dev/null ++++ b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf +@@ -0,0 +1 @@ ++hosts: files +diff --git a/posix/Makefile b/posix/Makefile +index 059efb3cd2..09460a28e8 100644 +--- a/posix/Makefile ++++ b/posix/Makefile +@@ -107,7 +107,8 @@ tests := test-errno tstgetopt testfnm runtests runptests \ + tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ + tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \ + bug-regex38 tst-regcomp-truncated tst-spawn-chdir \ +- tst-wordexp-nocmd tst-execveat tst-spawn5 ++ tst-wordexp-nocmd tst-execveat tst-spawn5 \ ++ tst-sched_getaffinity + + # Test for the glob symbol version that was replaced in glibc 2.27. + ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes) +diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h +index f0831386c7..622adeb2b2 100644 +--- a/posix/bits/unistd.h ++++ b/posix/bits/unistd.h +@@ -199,10 +199,9 @@ __NTH (readlinkat (int __fd, const char *__restrict __path, + #endif + + extern char *__getcwd_chk (char *__buf, size_t __size, size_t __buflen) +- __THROW __wur __attr_access ((__write_only__, 1, 2)); ++ __THROW __wur; + extern char *__REDIRECT_NTH (__getcwd_alias, +- (char *__buf, size_t __size), getcwd) +- __wur __attr_access ((__write_only__, 1, 2)); ++ (char *__buf, size_t __size), getcwd) __wur; + extern char *__REDIRECT_NTH (__getcwd_chk_warn, + (char *__buf, size_t __size, size_t __buflen), + __getcwd_chk) +diff --git a/posix/fork.c b/posix/fork.c +index c471f7b15f..021691b9b7 100644 +--- a/posix/fork.c ++++ b/posix/fork.c +@@ -99,6 +99,9 @@ __libc_fork (void) + /* Reset the lock the dynamic loader uses to protect its data. */ + __rtld_lock_initialize (GL(dl_load_lock)); + ++ /* Reset the lock protecting dynamic TLS related data. */ ++ __rtld_lock_initialize (GL(dl_load_tls_lock)); ++ + reclaim_stacks (); + + /* Run the handlers registered for the child. */ +diff --git a/posix/tst-sched_getaffinity.c b/posix/tst-sched_getaffinity.c +new file mode 100644 +index 0000000000..db9d517a96 +--- /dev/null ++++ b/posix/tst-sched_getaffinity.c +@@ -0,0 +1,48 @@ ++/* Tests for sched_getaffinity with large buffers. ++ 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 ++ ++/* NB: this test may fail on system with more than 32k cpus. */ ++ ++static int ++do_test (void) ++{ ++ /* The values are larger than the default cpu_set_t. */ ++ const int bufsize[] = { 1<<11, 1<<12, 1<<13, 1<<14, 1<<15, 1<<16, 1<<17 }; ++ int cpucount[array_length (bufsize)]; ++ ++ for (int i = 0; i < array_length (bufsize); i++) ++ { ++ cpu_set_t *cpuset = CPU_ALLOC (bufsize[i]); ++ TEST_VERIFY (cpuset != NULL); ++ size_t size = CPU_ALLOC_SIZE (bufsize[i]); ++ TEST_COMPARE (sched_getaffinity (0, size, cpuset), 0); ++ cpucount[i] = CPU_COUNT_S (size, cpuset); ++ CPU_FREE (cpuset); ++ } ++ ++ for (int i = 0; i < array_length (cpucount) - 1; i++) ++ TEST_COMPARE (cpucount[i], cpucount[i + 1]); ++ ++ return 0; ++} ++ ++#include +diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c +index ac66738004..a95199af6b 100644 +--- a/posix/tst-spawn5.c ++++ b/posix/tst-spawn5.c +@@ -47,17 +47,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) + { +@@ -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/posix/unistd.h b/posix/unistd.h +index 3dca65732f..8224c5fbc9 100644 +--- a/posix/unistd.h ++++ b/posix/unistd.h +@@ -528,8 +528,7 @@ extern int fchdir (int __fd) __THROW __wur; + an array is allocated with `malloc'; the array is SIZE + bytes long, unless SIZE == 0, in which case it is as + big as necessary. */ +-extern char *getcwd (char *__buf, size_t __size) __THROW __wur +- __attr_access ((__write_only__, 1, 2)); ++extern char *getcwd (char *__buf, size_t __size) __THROW __wur; + + #ifdef __USE_GNU + /* Return a malloc'd string containing the current directory name. +diff --git a/rt/Makefile b/rt/Makefile +index 113cea03a5..910e775995 100644 +--- a/rt/Makefile ++++ b/rt/Makefile +@@ -74,6 +74,7 @@ tests := tst-shm tst-timer tst-timer2 \ + tst-aio7 tst-aio8 tst-aio9 tst-aio10 \ + tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \ + tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \ ++ tst-bz28213 \ + tst-timer3 tst-timer4 tst-timer5 \ + tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \ + tst-shm-cancel \ +diff --git a/rt/tst-bz28213.c b/rt/tst-bz28213.c +new file mode 100644 +index 0000000000..0c096b5a0a +--- /dev/null ++++ b/rt/tst-bz28213.c +@@ -0,0 +1,101 @@ ++/* Bug 28213: test for NULL pointer dereference in mq_notify. ++ Copyright (C) The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static mqd_t m = -1; ++static const char msg[] = "hello"; ++ ++static void ++check_bz28213_cb (union sigval sv) ++{ ++ char buf[sizeof (msg)]; ++ ++ (void) sv; ++ ++ TEST_VERIFY_EXIT ((size_t) mq_receive (m, buf, sizeof (buf), NULL) ++ == sizeof (buf)); ++ TEST_VERIFY_EXIT (memcmp (buf, msg, sizeof (buf)) == 0); ++ ++ exit (0); ++} ++ ++static void ++check_bz28213 (void) ++{ ++ struct sigevent sev; ++ ++ memset (&sev, '\0', sizeof (sev)); ++ sev.sigev_notify = SIGEV_THREAD; ++ sev.sigev_notify_function = check_bz28213_cb; ++ ++ /* Step 1: Register & unregister notifier. ++ Helper thread should receive NOTIFY_REMOVED notification. ++ In a vulnerable version of glibc, NULL pointer dereference follows. */ ++ TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0); ++ TEST_VERIFY_EXIT (mq_notify (m, NULL) == 0); ++ ++ /* Step 2: Once again, register notification. ++ Try to send one message. ++ Test is considered successful, if the callback does exit (0). */ ++ TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0); ++ TEST_VERIFY_EXIT (mq_send (m, msg, sizeof (msg), 1) == 0); ++ ++ /* Wait... */ ++ pause (); ++} ++ ++static int ++do_test (void) ++{ ++ static const char m_name[] = "/bz28213_queue"; ++ struct mq_attr m_attr; ++ ++ memset (&m_attr, '\0', sizeof (m_attr)); ++ m_attr.mq_maxmsg = 1; ++ m_attr.mq_msgsize = sizeof (msg); ++ ++ m = mq_open (m_name, ++ O_RDWR | O_CREAT | O_EXCL, ++ 0600, ++ &m_attr); ++ ++ if (m < 0) ++ { ++ if (errno == ENOSYS) ++ FAIL_UNSUPPORTED ("POSIX message queues are not implemented\n"); ++ FAIL_EXIT1 ("Failed to create POSIX message queue: %m\n"); ++ } ++ ++ TEST_VERIFY_EXIT (mq_unlink (m_name) == 0); ++ ++ check_bz28213 (); ++ ++ return 0; ++} ++ ++#include +diff --git a/scripts/build-many-glibcs.py b/scripts/build-many-glibcs.py +index 5a77af90a6..86537fa800 100755 +--- a/scripts/build-many-glibcs.py ++++ b/scripts/build-many-glibcs.py +@@ -782,7 +782,7 @@ class Context(object): + 'gcc': 'vcs-11', + 'glibc': 'vcs-mainline', + 'gmp': '6.2.1', +- 'linux': '5.13', ++ 'linux': '5.14', + 'mpc': '1.2.1', + 'mpfr': '4.1.0', + 'mig': 'vcs-mainline', +diff --git a/support/Makefile b/support/Makefile +index a462781718..2a0731796f 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 \ +@@ -82,9 +83,10 @@ libsupport-routines = \ + support_test_compare_blob \ + support_test_compare_failure \ + support_test_compare_string \ +- support_write_file_string \ + support_test_main \ + support_test_verify_impl \ ++ support_wait_for_thread_exit \ ++ support_write_file_string \ + temp_file \ + timespec \ + timespec-time64 \ +@@ -264,6 +266,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 0000000000..66a8504105 +--- /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 834dba9097..c219e0d9d1 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -174,6 +174,10 @@ timer_t support_create_timer (uint64_t sec, long int nsec, bool repeat, + /* Disable the timer TIMER. */ + void support_delete_timer (timer_t timer); + ++/* Wait until all threads except the current thread have exited (as ++ far as the kernel is concerned). */ ++void support_wait_for_thread_exit (void); ++ + struct support_stack + { + void *stack; +@@ -193,6 +197,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/support_capture_subprocess.c b/support/support_capture_subprocess.c +index 27bfd19c93..0bacf6dbc2 100644 +--- a/support/support_capture_subprocess.c ++++ b/support/support_capture_subprocess.c +@@ -170,6 +170,7 @@ copy_and_spawn_sgid (char *child_id, gid_t gid) + support_subprogram because we only want the program exit status, not the + contents. */ + ret = 0; ++ infd = outfd = -1; + + char * const args[] = {execname, child_id, NULL}; + +diff --git a/support/support_wait_for_thread_exit.c b/support/support_wait_for_thread_exit.c +new file mode 100644 +index 0000000000..5e3be421a7 +--- /dev/null ++++ b/support/support_wait_for_thread_exit.c +@@ -0,0 +1,75 @@ ++/* Wait until all threads except the current thread has exited. ++ 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 ++ ++void ++support_wait_for_thread_exit (void) ++{ ++#ifdef __linux__ ++ DIR *proc_self_task = opendir ("/proc/self/task"); ++ TEST_VERIFY_EXIT (proc_self_task != NULL); ++ ++ while (true) ++ { ++ errno = 0; ++ struct dirent *e = readdir (proc_self_task); ++ if (e == NULL && errno != 0) ++ FAIL_EXIT1 ("readdir: %m"); ++ if (e == NULL) ++ { ++ /* Only the main thread remains. Testing may continue. */ ++ closedir (proc_self_task); ++ return; ++ } ++ ++ /* In some kernels, "0" entries denote a thread that has just ++ exited. */ ++ if (strcmp (e->d_name, ".") == 0 || strcmp (e->d_name, "..") == 0 ++ || strcmp (e->d_name, "0") == 0) ++ continue; ++ ++ int task_tid = atoi (e->d_name); ++ if (task_tid <= 0) ++ FAIL_EXIT1 ("Invalid /proc/self/task entry: %s", e->d_name); ++ ++ if (task_tid == gettid ()) ++ /* The current thread. Keep scanning for other ++ threads. */ ++ continue; ++ ++ /* task_tid does not refer to this thread here, i.e., there is ++ another running thread. */ ++ ++ /* Small timeout to give the thread a chance to exit. */ ++ usleep (50 * 1000); ++ ++ /* Start scanning the directory from the start. */ ++ rewinddir (proc_self_task); ++ } ++#else ++ /* Use a large timeout because we cannot verify that the thread has ++ exited. */ ++ usleep (5 * 1000 * 1000); ++#endif ++} +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 0000000000..8e29def1ce +--- /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 +diff --git a/sysdeps/generic/dl-relocate-ld.h b/sysdeps/generic/dl-relocate-ld.h +new file mode 100644 +index 0000000000..cfb86c2d6a +--- /dev/null ++++ b/sysdeps/generic/dl-relocate-ld.h +@@ -0,0 +1,25 @@ ++/* Check if dynamic section should be relocated. Generic version. ++ 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 ++ . */ ++ ++#ifndef _DL_RELOCATE_LD_H ++#define _DL_RELOCATE_LD_H ++ ++/* The dynamic section is writable. */ ++#define DL_RO_DYN_SECTION 0 ++ ++#endif /* _DL_RELOCATE_LD_H */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 9c15259236..fcbbf69748 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -69,17 +69,24 @@ __BEGIN_DECLS + `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */ + #define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type) + ++/* Return true if dynamic section in the shared library L should be ++ relocated. */ ++ ++static inline bool ++dl_relocate_ld (const struct link_map *l) ++{ ++ /* Don't relocate dynamic section if it is readonly */ ++ return !(l->l_ld_readonly || DL_RO_DYN_SECTION); ++} ++ + /* All references to the value of l_info[DT_PLTGOT], + l_info[DT_STRTAB], l_info[DT_SYMTAB], l_info[DT_RELA], + l_info[DT_REL], l_info[DT_JMPREL], and l_info[VERSYMIDX (DT_VERSYM)] + have to be accessed via the D_PTR macro. The macro is needed since for + most architectures the entry is already relocated - but for some not + and we need to relocate at access time. */ +-#ifdef DL_RO_DYN_SECTION +-# define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr) +-#else +-# define D_PTR(map, i) (map)->i->d_un.d_ptr +-#endif ++#define D_PTR(map, i) \ ++ ((map)->i->d_un.d_ptr + (dl_relocate_ld (map) ? 0 : (map)->l_addr)) + + /* Result of the lookup functions and how to retrieve the base address. */ + typedef struct link_map *lookup_t; +@@ -372,6 +379,13 @@ struct rtld_global + list of loaded objects while an object is added to or removed + from that list. */ + __rtld_lock_define_recursive (EXTERN, _dl_load_write_lock) ++ /* This lock protects global and module specific TLS related data. ++ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation), ++ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are ++ accessed and when TLS related relocations are processed for a ++ module. It was introduced to keep pthread_create accessing TLS ++ state that is being set up. */ ++ __rtld_lock_define_recursive (EXTERN, _dl_load_tls_lock) + + /* Incremented whenever something may have been added to dl_loaded. */ + EXTERN unsigned long long _dl_load_adds; +@@ -1261,7 +1275,7 @@ extern int _dl_scope_free (void *) attribute_hidden; + + /* Add module to slot information data. If DO_ADD is false, only the + required memory is allocated. Must be called with GL +- (dl_load_lock) acquired. If the function has already been called ++ (dl_load_tls_lock) acquired. If the function has already been called + for the link map L with !do_add, then this function will not raise + an exception, otherwise it is possible that it encounters a memory + allocation failure. */ +diff --git a/sysdeps/mach/getsysstats.c b/sysdeps/mach/getsysstats.c +index 1267f39da2..cc8023f979 100644 +--- a/sysdeps/mach/getsysstats.c ++++ b/sysdeps/mach/getsysstats.c +@@ -62,6 +62,12 @@ __get_nprocs (void) + libc_hidden_def (__get_nprocs) + weak_alias (__get_nprocs, get_nprocs) + ++int ++__get_nprocs_sched (void) ++{ ++ return __get_nprocs (); ++} ++ + /* Return the number of physical pages on the system. */ + long int + __get_phys_pages (void) +diff --git a/sysdeps/mips/dl-relocate-ld.h b/sysdeps/mips/dl-relocate-ld.h +new file mode 100644 +index 0000000000..376ad75dd1 +--- /dev/null ++++ b/sysdeps/mips/dl-relocate-ld.h +@@ -0,0 +1,25 @@ ++/* Check if dynamic section should be relocated. MIPS version. ++ 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 ++ . */ ++ ++#ifndef _DL_RELOCATE_LD_H ++#define _DL_RELOCATE_LD_H ++ ++/* The dynamic section is readonly. */ ++#define DL_RO_DYN_SECTION 1 ++ ++#endif /* _DL_RELOCATE_LD_H */ +diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h +index 4db7c60e38..36fd09a8bd 100644 +--- a/sysdeps/mips/ldsodefs.h ++++ b/sysdeps/mips/ldsodefs.h +@@ -75,10 +75,6 @@ struct La_mips_64_retval; + struct La_mips_64_retval *, \ + const char *); + +-/* The MIPS ABI specifies that the dynamic section has to be read-only. */ +- +-#define DL_RO_DYN_SECTION 1 +- + #include_next + + /* The 64-bit MIPS ELF ABI uses an unusual reloc format. Each +diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h +index f1b7f2bdc6..43146e91c9 100644 +--- a/sysdeps/nptl/pthread.h ++++ b/sysdeps/nptl/pthread.h +@@ -933,7 +933,7 @@ extern int pthread_mutexattr_getrobust (const pthread_mutexattr_t *__attr, + # ifdef __USE_GNU + # ifdef __REDIRECT_NTH + extern int __REDIRECT_NTH (pthread_mutexattr_getrobust_np, +- (pthread_mutex_t *, int *), ++ (pthread_mutexattr_t *, int *), + pthread_mutexattr_getrobust) __nonnull ((1)) + __attribute_deprecated_msg__ ("\ + pthread_mutexattr_getrobust_np is deprecated, use pthread_mutexattr_getrobust"); +@@ -949,7 +949,7 @@ extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr, + # ifdef __USE_GNU + # ifdef __REDIRECT_NTH + extern int __REDIRECT_NTH (pthread_mutexattr_setrobust_np, +- (pthread_mutex_t *, int), ++ (pthread_mutexattr_t *, int), + pthread_mutexattr_setrobust) __nonnull ((1)) + __attribute_deprecated_msg__ ("\ + pthread_mutexattr_setrobust_np is deprecated, use pthread_mutexattr_setrobust"); +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 838a68f022..43dfc6739e 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -2008,6 +2008,7 @@ gaiconf_init (void) + l = l->next; + } + free_prefixlist (labellist); ++ labellist = NULL; + + /* Sort the entries so that the most specific ones are at + the beginning. */ +@@ -2046,6 +2047,7 @@ gaiconf_init (void) + l = l->next; + } + free_prefixlist (precedencelist); ++ precedencelist = NULL; + + /* Sort the entries so that the most specific ones are at + the beginning. */ +diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h +index 589f7c8d18..cfcfa69f91 100644 +--- a/sysdeps/powerpc/powerpc64/sysdep.h ++++ b/sysdeps/powerpc/powerpc64/sysdep.h +@@ -275,12 +275,14 @@ LT_LABELSUFFIX(name,_name_end): ; \ + /* Allocate frame and save register */ + #define NVOLREG_SAVE \ + stdu r1,-SCV_FRAME_SIZE(r1); \ ++ cfi_adjust_cfa_offset(SCV_FRAME_SIZE); \ + std r31,SCV_FRAME_NVOLREG_SAVE(r1); \ +- cfi_adjust_cfa_offset(SCV_FRAME_SIZE); ++ cfi_rel_offset(r31,SCV_FRAME_NVOLREG_SAVE); + + /* Restore register and destroy frame */ + #define NVOLREG_RESTORE \ + ld r31,SCV_FRAME_NVOLREG_SAVE(r1); \ ++ cfi_restore(r31); \ + addi r1,r1,SCV_FRAME_SIZE; \ + cfi_adjust_cfa_offset(-SCV_FRAME_SIZE); + +@@ -331,13 +333,13 @@ LT_LABELSUFFIX(name,_name_end): ; \ + + #define DO_CALL_SCV \ + mflr r9; \ +- std r9,FRAME_LR_SAVE(r1); \ +- cfi_offset(lr,FRAME_LR_SAVE); \ ++ std r9,SCV_FRAME_SIZE+FRAME_LR_SAVE(r1); \ ++ cfi_rel_offset(lr,SCV_FRAME_SIZE+FRAME_LR_SAVE); \ + .machine "push"; \ + .machine "power9"; \ + scv 0; \ + .machine "pop"; \ +- ld r9,FRAME_LR_SAVE(r1); \ ++ ld r9,SCV_FRAME_SIZE+FRAME_LR_SAVE(r1); \ + mtlr r9; \ + cfi_restore(lr); + +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 42f9fc5072..c657101696 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -89,7 +89,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-join8 tst-join9 tst-join10 tst-join11 tst-join12 tst-join13 \ + tst-join14 tst-join15 \ + tst-key1 tst-key2 tst-key3 tst-key4 \ +- tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \ ++ tst-kill1 tst-kill2 tst-kill3 tst-kill5 tst-kill6 \ + tst-locale1 tst-locale2 \ + tst-memstream \ + tst-mutex-errorcheck tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 \ +@@ -118,6 +118,14 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-unload \ + tst-unwind-thread \ + tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \ ++ tst-pthread-exit-signal \ ++ tst-pthread-setuid-loop \ ++ tst-pthread_cancel-exited \ ++ tst-pthread_cancel-select-loop \ ++ tst-pthread-raise-blocked-self \ ++ tst-pthread_kill-exited \ ++ tst-pthread_kill-exiting \ ++ # tests + + tests-time64 := \ + tst-abstime-time64 \ +@@ -145,15 +153,17 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx6 tst-cancelx8 tst-cancelx9 \ + tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 + + ifeq ($(build-shared),yes) +-tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 ++tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 tst-create1 + tests-nolibpthread += tst-fini1 + endif + + modules-names += tst-atfork2mod tst-tls4moda tst-tls4modb \ +- tst-_res1mod1 tst-_res1mod2 tst-fini1mod ++ tst-_res1mod1 tst-_res1mod2 tst-fini1mod \ ++ tst-create1mod + test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names))) + + tst-atfork2mod.so-no-z-defs = yes ++tst-create1mod.so-no-z-defs = yes + + ifeq ($(build-shared),yes) + # Build all the modules even when not actually running test programs. +@@ -272,4 +282,8 @@ LDFLAGS-tst-join7mod.so = -Wl,-soname,tst-join7mod.so + + CFLAGS-tst-unwind-thread.c += -funwind-tables + ++LDFLAGS-tst-create1 = -Wl,-export-dynamic ++$(objpfx)tst-create1: $(shared-thread-library) ++$(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so ++ + endif +diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c +new file mode 100644 +index 0000000000..763ded8d79 +--- /dev/null ++++ b/sysdeps/pthread/tst-create1.c +@@ -0,0 +1,123 @@ ++/* Verify that pthread_create does not deadlock when ctors take locks. ++ 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 ++ ++/* ++Check if ctor and pthread_create deadlocks in ++ ++thread 1: dlopen -> ctor -> lock(user_lock) ++thread 2: lock(user_lock) -> pthread_create ++ ++or in ++ ++thread 1: dlclose -> dtor -> lock(user_lock) ++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; ++ ++void ++ctor (void) ++{ ++ xpthread_barrier_wait (&bar_ctor); ++ dprintf (1, "thread 1: in ctor: started.\n"); ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 1: in ctor: locked user_lock.\n"); ++ 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 ++dtor (void) ++{ ++ xpthread_barrier_wait (&bar_dtor); ++ dprintf (1, "thread 1: in dtor: started.\n"); ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 1: in dtor: locked user_lock.\n"); ++ xpthread_mutex_unlock (&user_lock); ++ dprintf (1, "thread 1: in dtor: unlocked user_lock.\n"); ++ dprintf (1, "thread 1: in dtor: done.\n"); ++} ++ ++static void * ++thread3 (void *a) ++{ ++ dprintf (1, "thread 3: started.\n"); ++ dprintf (1, "thread 3: done.\n"); ++ return 0; ++} ++ ++static void * ++thread2 (void *a) ++{ ++ pthread_t t3; ++ dprintf (1, "thread 2: started.\n"); ++ ++ xpthread_mutex_lock (&user_lock); ++ dprintf (1, "thread 2: locked user_lock.\n"); ++ xpthread_barrier_wait (&bar_ctor); ++ t3 = xpthread_create (0, thread3, 0); ++ 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"); ++ xpthread_barrier_wait (&bar_dtor); ++ t3 = xpthread_create (0, thread3, 0); ++ xpthread_mutex_unlock (&user_lock); ++ dprintf (1, "thread 2: unlocked user_lock.\n"); ++ xpthread_join (t3); ++ ++ dprintf (1, "thread 2: done.\n"); ++ return 0; ++} ++ ++static void ++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); ++ dprintf (1, "thread 1: dlopen done.\n"); ++ xdlclose (p); ++ dprintf (1, "thread 1: dlclose done.\n"); ++ xpthread_join (t2); ++ dprintf (1, "thread 1: done.\n"); ++} ++ ++static int ++do_test (void) ++{ ++ thread1 (); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-create1mod.c b/sysdeps/pthread/tst-create1mod.c +new file mode 100644 +index 0000000000..62c9006961 +--- /dev/null ++++ b/sysdeps/pthread/tst-create1mod.c +@@ -0,0 +1,41 @@ ++/* Verify that pthread_create does not deadlock when ctors take locks. ++ 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 ++ ++/* Require TLS setup for the module. */ ++__thread int tlsvar; ++ ++void ctor (void); ++void dtor (void); ++ ++static void __attribute__ ((constructor)) ++do_init (void) ++{ ++ dprintf (1, "constructor started: %d.\n", tlsvar++); ++ ctor (); ++ dprintf (1, "constructor done: %d.\n", tlsvar++); ++} ++ ++static void __attribute__ ((destructor)) ++do_end (void) ++{ ++ dprintf (1, "destructor started: %d.\n", tlsvar++); ++ dtor (); ++ dprintf (1, "destructor done: %d.\n", tlsvar++); ++} +diff --git a/sysdeps/pthread/tst-kill4.c b/sysdeps/pthread/tst-kill4.c +deleted file mode 100644 +index 9563939792..0000000000 +--- a/sysdeps/pthread/tst-kill4.c ++++ /dev/null +@@ -1,90 +0,0 @@ +-/* Copyright (C) 2003-2021 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper , 2003. +- +- 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 +- +- +-static void * +-tf (void *a) +-{ +- return NULL; +-} +- +- +-int +-do_test (void) +-{ +- pthread_attr_t at; +- if (pthread_attr_init (&at) != 0) +- { +- puts ("attr_create failed"); +- exit (1); +- } +- +- /* Limit thread stack size, because if it is too large, pthread_join +- will free it immediately rather than put it into stack cache. */ +- if (pthread_attr_setstacksize (&at, 2 * 1024 * 1024) != 0) +- { +- puts ("setstacksize failed"); +- exit (1); +- } +- +- pthread_t th; +- if (pthread_create (&th, &at, tf, NULL) != 0) +- { +- puts ("create failed"); +- exit (1); +- } +- +- pthread_attr_destroy (&at); +- +- if (pthread_join (th, NULL) != 0) +- { +- puts ("join failed"); +- exit (1); +- } +- +- /* The following only works because we assume here something about +- the implementation. Namely, that the memory allocated for the +- thread descriptor is not going away, that the TID field is +- cleared and therefore the signal is sent to process 0, and that +- we can savely assume there is no other process with this ID at +- that time. */ +- int e = pthread_kill (th, 0); +- if (e == 0) +- { +- puts ("pthread_kill succeeded"); +- exit (1); +- } +- if (e != ESRCH) +- { +- puts ("pthread_kill didn't return ESRCH"); +- exit (1); +- } +- +- return 0; +-} +- +- +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" +diff --git a/sysdeps/pthread/tst-pthread-exit-signal.c b/sysdeps/pthread/tst-pthread-exit-signal.c +new file mode 100644 +index 0000000000..b4526fe663 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread-exit-signal.c +@@ -0,0 +1,45 @@ ++/* Test that pending signals are not delivered on thread exit (bug 28607). ++ 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 ++ . */ ++ ++/* Due to bug 28607, pthread_kill (or pthread_cancel) restored the ++ signal mask during during thread exit, triggering the delivery of a ++ blocked pending signal (SIGUSR1 in this test). */ ++ ++#include ++#include ++ ++static void * ++threadfunc (void *closure) ++{ ++ sigset_t sigmask; ++ sigfillset (&sigmask); ++ xpthread_sigmask (SIG_SETMASK, &sigmask, NULL); ++ xpthread_kill (pthread_self (), SIGUSR1); ++ pthread_exit (NULL); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ pthread_t thr = xpthread_create (NULL, threadfunc, NULL); ++ xpthread_join (thr); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-pthread-raise-blocked-self.c b/sysdeps/pthread/tst-pthread-raise-blocked-self.c +new file mode 100644 +index 0000000000..128e1a6071 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread-raise-blocked-self.c +@@ -0,0 +1,92 @@ ++/* Test that raise sends signal to current thread even if blocked. ++ 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 ++ ++/* Used to create a dummy thread ID distinct from all other thread ++ IDs. */ ++static void * ++noop (void *ignored) ++{ ++ return NULL; ++} ++ ++static volatile pthread_t signal_thread; ++ ++static void ++signal_handler (int signo) ++{ ++ signal_thread = pthread_self (); ++} ++ ++/* Used to ensure that waiting_thread has launched and can accept ++ signals. */ ++static pthread_barrier_t barrier; ++ ++static void * ++waiting_thread (void *ignored) ++{ ++ xpthread_barrier_wait (&barrier); ++ pause (); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xsignal (SIGUSR1, signal_handler); ++ xpthread_barrier_init (&barrier, NULL, 2); ++ ++ /* Distinct thread ID value to */ ++ pthread_t dummy = xpthread_create (NULL, noop, NULL); ++ signal_thread = dummy; ++ ++ pthread_t helper = xpthread_create (NULL, waiting_thread, NULL); ++ ++ /* Make sure that the thread is running. */ ++ xpthread_barrier_wait (&barrier); ++ ++ /* Block signals on this thread. */ ++ sigset_t set; ++ sigfillset (&set); ++ xpthread_sigmask (SIG_BLOCK, &set, NULL); ++ ++ /* Send the signal to this thread. It must not be delivered. */ ++ raise (SIGUSR1); ++ TEST_VERIFY (signal_thread == dummy); ++ ++ /* Wait a bit to give a chance for signal delivery (increases ++ chances of failure with bug 28407). */ ++ usleep (50 * 1000); ++ ++ /* Unblocking should cause synchronous delivery of the signal. */ ++ xpthread_sigmask (SIG_UNBLOCK, &set, NULL); ++ TEST_VERIFY (signal_thread == pthread_self ()); ++ ++ xpthread_cancel (helper); ++ xpthread_join (helper); ++ xpthread_join (dummy); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-pthread-setuid-loop.c b/sysdeps/pthread/tst-pthread-setuid-loop.c +new file mode 100644 +index 0000000000..fda2a49b7f +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread-setuid-loop.c +@@ -0,0 +1,61 @@ ++/* Test that setuid, pthread_create, thread exit do not deadlock (bug 28361). ++ 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 ++ ++/* How many threads to launch during each iteration. */ ++enum { threads = 4 }; ++ ++/* How many iterations to perform. This value seems to reproduce ++ bug 28361 in a bout one in three runs. */ ++enum { iterations = 5000 }; ++ ++/* Cache of the real user ID used by setuid_thread. */ ++static uid_t uid; ++ ++/* Start routine for the threads. */ ++static void * ++setuid_thread (void *closure) ++{ ++ TEST_COMPARE (setuid (uid), 0); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ /* The setxid machinery is still invoked even if the UID is ++ unchanged. (The kernel might reset other credentials as part of ++ the system call.) */ ++ uid = getuid (); ++ ++ for (int i = 0; i < iterations; ++i) ++ { ++ pthread_t thread_ids[threads]; ++ for (int j = 0; j < threads; ++j) ++ thread_ids[j] = xpthread_create (NULL, setuid_thread, NULL); ++ for (int j = 0; j < threads; ++j) ++ xpthread_join (thread_ids[j]); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-pthread_cancel-exited.c b/sysdeps/pthread/tst-pthread_cancel-exited.c +new file mode 100644 +index 0000000000..811c9bee07 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread_cancel-exited.c +@@ -0,0 +1,45 @@ ++/* Test that pthread_kill succeeds for an exited thread. ++ 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 ++ . */ ++ ++/* This test verifies that pthread_kill returns 0 (and not ESRCH) for ++ a thread that has exited on the kernel side. */ ++ ++#include ++#include ++#include ++ ++static void * ++noop_thread (void *closure) ++{ ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ pthread_t thr = xpthread_create (NULL, noop_thread, NULL); ++ ++ support_wait_for_thread_exit (); ++ ++ xpthread_cancel (thr); ++ xpthread_join (thr); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-pthread_cancel-select-loop.c b/sysdeps/pthread/tst-pthread_cancel-select-loop.c +new file mode 100644 +index 0000000000..a62087589c +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread_cancel-select-loop.c +@@ -0,0 +1,87 @@ ++/* Test that pthread_cancel succeeds during thread exit. ++ 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 ++ . */ ++ ++/* This test tries to trigger an internal race condition in ++ pthread_cancel, where the cancellation signal is sent after the ++ thread has begun the cancellation process. This can result in a ++ spurious ESRCH error. For the original bug 12889, the window is ++ quite small, so the bug was not reproduced in every run. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to true by timeout_thread_function when the test should ++ terminate. */ ++static bool timeout; ++ ++static void * ++timeout_thread_function (void *unused) ++{ ++ usleep (5 * 1000 * 1000); ++ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED); ++ return NULL; ++} ++ ++/* Used for blocking the select function below. */ ++static int pipe_fds[2]; ++ ++static void * ++canceled_thread_function (void *unused) ++{ ++ while (true) ++ { ++ fd_set rfs; ++ fd_set wfs; ++ fd_set efs; ++ FD_ZERO (&rfs); ++ FD_ZERO (&wfs); ++ FD_ZERO (&efs); ++ FD_SET (pipe_fds[0], &rfs); ++ ++ /* If the cancellation request is recognized early, the thread ++ begins exiting while the cancellation signal arrives. */ ++ select (FD_SETSIZE, &rfs, &wfs, &efs, NULL); ++ } ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xpipe (pipe_fds); ++ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL); ++ ++ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED)) ++ { ++ pthread_t thr = xpthread_create (NULL, canceled_thread_function, NULL); ++ xpthread_cancel (thr); ++ TEST_VERIFY (xpthread_join (thr) == PTHREAD_CANCELED); ++ } ++ ++ xpthread_join (thr_timeout); ++ xclose (pipe_fds[0]); ++ xclose (pipe_fds[1]); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-pthread_kill-exited.c b/sysdeps/pthread/tst-pthread_kill-exited.c +new file mode 100644 +index 0000000000..a2fddad526 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread_kill-exited.c +@@ -0,0 +1,63 @@ ++/* Test that pthread_kill succeeds for an exited thread. ++ 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 ++ . */ ++ ++/* This test verifies that the default pthread_kill returns 0 (and not ++ ESRCH) for a thread that has exited on the kernel side. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void * ++noop_thread (void *closure) ++{ ++ return NULL; ++} ++ ++#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC ++extern __typeof (pthread_kill) compat_pthread_kill; ++compat_symbol_reference (libpthread, compat_pthread_kill, pthread_kill, ++ GLIBC_2_0); ++#endif ++ ++static int ++do_test (void) ++{ ++ pthread_t thr = xpthread_create (NULL, noop_thread, NULL); ++ ++ support_wait_for_thread_exit (); ++ ++ /* NB: Always uses the default symbol due to separate compilation. */ ++ xpthread_kill (thr, SIGUSR1); ++ ++#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC ++ /* Old binaries need the non-conforming ESRCH error code. */ ++ TEST_COMPARE (compat_pthread_kill (thr, SIGUSR1), ESRCH); ++#endif ++ ++ xpthread_join (thr); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-pthread_kill-exiting.c b/sysdeps/pthread/tst-pthread_kill-exiting.c +new file mode 100644 +index 0000000000..f803e94f11 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread_kill-exiting.c +@@ -0,0 +1,123 @@ ++/* Test that pthread_kill succeeds during thread exit. ++ 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 ++ . */ ++ ++/* This test verifies that pthread_kill for a thread that is exiting ++ succeeds (with or without actually delivering the signal). */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to true by timeout_thread_function when the test should ++ terminate. */ ++static bool timeout; ++ ++static void * ++timeout_thread_function (void *unused) ++{ ++ usleep (1000 * 1000); ++ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED); ++ return NULL; ++} ++ ++/* Used to synchronize the sending threads with the target thread and ++ main thread. */ ++static pthread_barrier_t barrier_1; ++static pthread_barrier_t barrier_2; ++ ++/* The target thread to which signals are to be sent. */ ++static pthread_t target_thread; ++ ++/* Set by the main thread to true after timeout has been set to ++ true. */ ++static bool exiting; ++ ++static void * ++sender_thread_function (void *unused) ++{ ++ while (true) ++ { ++ /* Wait until target_thread has been initialized. The target ++ thread and main thread participate in this barrier. */ ++ xpthread_barrier_wait (&barrier_1); ++ ++ if (exiting) ++ break; ++ ++ xpthread_kill (target_thread, SIGUSR1); ++ ++ /* Communicate that the signal has been sent. The main thread ++ participates in this barrier. */ ++ xpthread_barrier_wait (&barrier_2); ++ } ++ return NULL; ++} ++ ++static void * ++target_thread_function (void *unused) ++{ ++ target_thread = pthread_self (); ++ xpthread_barrier_wait (&barrier_1); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xsignal (SIGUSR1, SIG_IGN); ++ ++ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL); ++ ++ pthread_t threads[4]; ++ xpthread_barrier_init (&barrier_1, NULL, array_length (threads) + 2); ++ xpthread_barrier_init (&barrier_2, NULL, array_length (threads) + 1); ++ ++ for (int i = 0; i < array_length (threads); ++i) ++ threads[i] = xpthread_create (NULL, sender_thread_function, NULL); ++ ++ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED)) ++ { ++ xpthread_create (NULL, target_thread_function, NULL); ++ ++ /* Wait for the target thread to be set up and signal sending to ++ start. */ ++ xpthread_barrier_wait (&barrier_1); ++ ++ /* Wait for signal sending to complete. */ ++ xpthread_barrier_wait (&barrier_2); ++ ++ xpthread_join (target_thread); ++ } ++ ++ exiting = true; ++ ++ /* Signal the sending threads to exit. */ ++ xpthread_create (NULL, target_thread_function, NULL); ++ xpthread_barrier_wait (&barrier_1); ++ ++ for (int i = 0; i < array_length (threads); ++i) ++ xpthread_join (threads[i]); ++ xpthread_join (thr_timeout); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/riscv/dl-relocate-ld.h b/sysdeps/riscv/dl-relocate-ld.h +new file mode 100644 +index 0000000000..2ab2b8ac6c +--- /dev/null ++++ b/sysdeps/riscv/dl-relocate-ld.h +@@ -0,0 +1,25 @@ ++/* Check if dynamic section should be relocated. RISC-V version. ++ 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 ++ . */ ++ ++#ifndef _DL_RELOCATE_LD_H ++#define _DL_RELOCATE_LD_H ++ ++/* The dynamic section is readonly for ABI compatibility. */ ++#define DL_RO_DYN_SECTION 1 ++ ++#endif /* _DL_RELOCATE_LD_H */ +diff --git a/sysdeps/riscv/ldsodefs.h b/sysdeps/riscv/ldsodefs.h +index 0c696714a7..8947ffe4b5 100644 +--- a/sysdeps/riscv/ldsodefs.h ++++ b/sysdeps/riscv/ldsodefs.h +@@ -38,11 +38,6 @@ struct La_riscv_retval; + struct La_riscv_retval *, \ + const char *); + +-/* Although the RISC-V ABI does not specify that the dynamic section has +- to be read-only, it needs to be kept for ABI compatibility. */ +- +-#define DL_RO_DYN_SECTION 1 +- + #include_next + + #endif +diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c +index c174e27b35..155f0bd99e 100644 +--- a/sysdeps/s390/dl-procinfo.c ++++ b/sysdeps/s390/dl-procinfo.c +@@ -46,13 +46,13 @@ + #if !defined PROCINFO_DECL && defined SHARED + ._dl_s390_cap_flags + #else +-PROCINFO_CLASS const char _dl_s390_cap_flags[21][9] ++PROCINFO_CLASS const char _dl_s390_cap_flags[23][9] + #endif + #ifndef PROCINFO_DECL + = { + "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh", + "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt", +- "vxp2", "nnpa" ++ "vxp2", "nnpa", "pcimio", "sie" + } + #endif + #if !defined SHARED || defined PROCINFO_DECL +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index 2d9c305808..e4e3e334a5 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -21,7 +21,7 @@ + #define _DL_PROCINFO_H 1 + #include + +-#define _DL_HWCAP_COUNT 21 ++#define _DL_HWCAP_COUNT 23 + + #define _DL_PLATFORMS_COUNT 10 + +@@ -63,6 +63,8 @@ enum + HWCAP_S390_DFLT = 1 << 18, + HWCAP_S390_VXRS_PDE2 = 1 << 19, + HWCAP_S390_NNPA = 1 << 20, ++ HWCAP_S390_PCI_MIO = 1 << 21, ++ HWCAP_S390_SIE = 1 << 22, + }; + + #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \ +diff --git a/sysdeps/s390/memmem-arch13.S b/sysdeps/s390/memmem-arch13.S +index c5c8d8c97e..58df8cdb14 100644 +--- a/sysdeps/s390/memmem-arch13.S ++++ b/sysdeps/s390/memmem-arch13.S +@@ -41,7 +41,7 @@ ENTRY(MEMMEM_ARCH13) + # error The arch13 variant of memmem needs the z13 variant of memmem! + # endif + clgfi %r5,9 +- jh MEMMEM_Z13 ++ jgh MEMMEM_Z13 + + aghik %r0,%r5,-1 /* vll needs highest index. */ + bc 4,0(%r14) /* cc==1: return if needle-len == 0. */ +diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S +index c7183e627c..222a6de91a 100644 +--- a/sysdeps/s390/strstr-arch13.S ++++ b/sysdeps/s390/strstr-arch13.S +@@ -49,7 +49,7 @@ ENTRY(STRSTR_ARCH13) + # error The arch13 variant of strstr needs the z13 variant of strstr! + # endif + clgfi %r4,9 +- jh STRSTR_Z13 ++ jgh STRSTR_Z13 + + /* In case of a partial match, the vstrs instruction returns the index + of the partial match in a vector-register. Then we have to +diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +index e9eb707d0a..bedab1abba 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +@@ -126,6 +126,7 @@ + #define __NR_mbind 235 + #define __NR_membarrier 283 + #define __NR_memfd_create 279 ++#define __NR_memfd_secret 447 + #define __NR_migrate_pages 238 + #define __NR_mincore 232 + #define __NR_mkdirat 34 +@@ -187,6 +188,7 @@ + #define __NR_pwritev 70 + #define __NR_pwritev2 287 + #define __NR_quotactl 60 ++#define __NR_quotactl_fd 443 + #define __NR_read 63 + #define __NR_readahead 213 + #define __NR_readlinkat 78 +diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +index bd6b7d4003..91354ed9e2 100644 +--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +@@ -337,6 +337,7 @@ + #define __NR_pwritev2 521 + #define __NR_query_module 347 + #define __NR_quotactl 148 ++#define __NR_quotactl_fd 553 + #define __NR_read 3 + #define __NR_readahead 379 + #define __NR_readlink 58 +diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +index 10650549c1..ff5c7eb36d 100644 +--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +@@ -190,6 +190,7 @@ + #define __NR_pwritev 70 + #define __NR_pwritev2 287 + #define __NR_quotactl 60 ++#define __NR_quotactl_fd 443 + #define __NR_read 63 + #define __NR_readahead 213 + #define __NR_readlinkat 78 +diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +index 85c9b236ce..5772333cee 100644 +--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +@@ -244,6 +244,7 @@ + #define __NR_pwritev 362 + #define __NR_pwritev2 393 + #define __NR_quotactl 131 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 225 + #define __NR_readlink 85 +diff --git a/sysdeps/unix/sysv/linux/bits/mman-linux.h b/sysdeps/unix/sysv/linux/bits/mman-linux.h +index 3b1ae418e0..31451c28d9 100644 +--- a/sysdeps/unix/sysv/linux/bits/mman-linux.h ++++ b/sysdeps/unix/sysv/linux/bits/mman-linux.h +@@ -89,6 +89,10 @@ + # define MADV_KEEPONFORK 19 /* Undo MADV_WIPEONFORK. */ + # define MADV_COLD 20 /* Deactivate these pages. */ + # define MADV_PAGEOUT 21 /* Reclaim these pages. */ ++# define MADV_POPULATE_READ 22 /* Populate (prefault) page tables ++ readable. */ ++# define MADV_POPULATE_WRITE 23 /* Populate (prefault) page tables ++ writable. */ + # define MADV_HWPOISON 100 /* Poison a page for testing. */ + #endif + +diff --git a/sysdeps/unix/sysv/linux/bits/timex.h b/sysdeps/unix/sysv/linux/bits/timex.h +index ee37694e8f..4a5db6deca 100644 +--- a/sysdeps/unix/sysv/linux/bits/timex.h ++++ b/sysdeps/unix/sysv/linux/bits/timex.h +@@ -25,7 +25,7 @@ + + struct timex + { +-# ifdef __USE_TIME_BITS64 ++# if defined __USE_TIME_BITS64 || (__TIMESIZE == 64 && __WORDSIZE == 32) + unsigned int modes; /* mode selector */ + int :32; /* pad */ + long long offset; /* time offset (usec) */ +diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +index 24b0d1f94e..4af6d6202f 100644 +--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +@@ -199,6 +199,7 @@ + #define __NR_pwritev 70 + #define __NR_pwritev2 287 + #define __NR_quotactl 60 ++#define __NR_quotactl_fd 443 + #define __NR_read 63 + #define __NR_readahead 213 + #define __NR_readlinkat 78 +diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c +index 1391e360b8..7fc6521942 100644 +--- a/sysdeps/unix/sysv/linux/getsysstats.c ++++ b/sysdeps/unix/sysv/linux/getsysstats.c +@@ -18,6 +18,8 @@ + . */ + + #include ++#include ++#include + #include + #include + #include +@@ -29,61 +31,170 @@ + #include + #include + +-/* Compute the population count of the entire array. */ +-static int +-__get_nprocs_count (const unsigned long int *array, size_t length) ++int ++__get_nprocs_sched (void) + { +- int count = 0; +- for (size_t i = 0; i < length; ++i) +- if (__builtin_add_overflow (count, __builtin_popcountl (array[i]), +- &count)) +- return INT_MAX; +- return count; ++ enum ++ { ++ max_num_cpus = 32768, ++ cpu_bits_size = CPU_ALLOC_SIZE (32768) ++ }; ++ ++ /* This cannot use malloc because it is used on malloc initialization. */ ++ __cpu_mask cpu_bits[cpu_bits_size / sizeof (__cpu_mask)]; ++ int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, cpu_bits_size, ++ cpu_bits); ++ if (r > 0) ++ return CPU_COUNT_S (cpu_bits_size, (cpu_set_t*) cpu_bits); ++ else if (r == -EINVAL) ++ /* The input buffer is still not enough to store the number of cpus. This ++ is an arbitrary values assuming such systems should be rare and there ++ is no offline cpus. */ ++ return max_num_cpus; ++ /* Some other error. 2 is conservative (not a uniprocessor system, so ++ atomics are needed). */ ++ return 2; ++} ++ ++static char * ++next_line (int fd, char *const buffer, char **cp, char **re, ++ char *const buffer_end) ++{ ++ char *res = *cp; ++ char *nl = memchr (*cp, '\n', *re - *cp); ++ if (nl == NULL) ++ { ++ if (*cp != buffer) ++ { ++ if (*re == buffer_end) ++ { ++ memmove (buffer, *cp, *re - *cp); ++ *re = buffer + (*re - *cp); ++ *cp = buffer; ++ ++ ssize_t n = __read_nocancel (fd, *re, buffer_end - *re); ++ if (n < 0) ++ return NULL; ++ ++ *re += n; ++ ++ nl = memchr (*cp, '\n', *re - *cp); ++ while (nl == NULL && *re == buffer_end) ++ { ++ /* Truncate too long lines. */ ++ *re = buffer + 3 * (buffer_end - buffer) / 4; ++ n = __read_nocancel (fd, *re, buffer_end - *re); ++ if (n < 0) ++ return NULL; ++ ++ nl = memchr (*re, '\n', n); ++ **re = '\n'; ++ *re += n; ++ } ++ } ++ else ++ nl = memchr (*cp, '\n', *re - *cp); ++ ++ res = *cp; ++ } ++ ++ if (nl == NULL) ++ nl = *re - 1; ++ } ++ ++ *cp = nl + 1; ++ assert (*cp <= *re); ++ ++ return res == *re ? NULL : res; + } + +-/* __get_nprocs with a large buffer. */ + static int +-__get_nprocs_large (void) ++get_nproc_stat (char *buffer, size_t buffer_size) + { +- /* This code cannot use scratch_buffer because it is used during +- malloc initialization. */ +- size_t pagesize = GLRO (dl_pagesize); +- unsigned long int *page = __mmap (0, pagesize, PROT_READ | PROT_WRITE, +- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); +- if (page == MAP_FAILED) +- return 2; +- int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, pagesize, page); +- int count; +- if (r > 0) +- count = __get_nprocs_count (page, pagesize / sizeof (unsigned long int)); +- else if (r == -EINVAL) +- /* One page is still not enough to store the bits. A more-or-less +- arbitrary value. This assumes t hat such large systems never +- happen in practice. */ +- count = GLRO (dl_pagesize) * CHAR_BIT; +- else +- count = 2; +- __munmap (page, GLRO (dl_pagesize)); +- return count; ++ char *buffer_end = buffer + buffer_size; ++ char *cp = buffer_end; ++ char *re = buffer_end; ++ ++ /* Default to an SMP system in case we cannot obtain an accurate ++ number. */ ++ int result = 2; ++ ++ const int flags = O_RDONLY | O_CLOEXEC; ++ int fd = __open_nocancel ("/proc/stat", flags); ++ if (fd != -1) ++ { ++ result = 0; ++ ++ char *l; ++ while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL) ++ /* The current format of /proc/stat has all the cpu* entries ++ at the front. We assume here that stays this way. */ ++ if (strncmp (l, "cpu", 3) != 0) ++ break; ++ else if (isdigit (l[3])) ++ ++result; ++ ++ __close_nocancel_nostatus (fd); ++ } ++ ++ return result; + } + + int + __get_nprocs (void) + { +- /* Fast path for most systems. The kernel expects a buffer size +- that is a multiple of 8. */ +- unsigned long int small_buffer[1024 / CHAR_BIT / sizeof (unsigned long int)]; +- int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, +- sizeof (small_buffer), small_buffer); +- if (r > 0) +- return __get_nprocs_count (small_buffer, r / sizeof (unsigned long int)); +- else if (r == -EINVAL) +- /* The kernel requests a larger buffer to store the data. */ +- return __get_nprocs_large (); +- else +- /* Some other error. 2 is conservative (not a uniprocessor +- system, so atomics are needed). */ +- return 2; ++ enum { buffer_size = 1024 }; ++ char buffer[buffer_size]; ++ char *buffer_end = buffer + buffer_size; ++ char *cp = buffer_end; ++ char *re = buffer_end; ++ ++ const int flags = O_RDONLY | O_CLOEXEC; ++ /* This file contains comma-separated ranges. */ ++ int fd = __open_nocancel ("/sys/devices/system/cpu/online", flags); ++ char *l; ++ int result = 0; ++ if (fd != -1) ++ { ++ l = next_line (fd, buffer, &cp, &re, buffer_end); ++ if (l != NULL) ++ do ++ { ++ char *endp; ++ unsigned long int n = strtoul (l, &endp, 10); ++ if (l == endp) ++ { ++ result = 0; ++ break; ++ } ++ ++ unsigned long int m = n; ++ if (*endp == '-') ++ { ++ l = endp + 1; ++ m = strtoul (l, &endp, 10); ++ if (l == endp) ++ { ++ result = 0; ++ break; ++ } ++ } ++ ++ result += m - n + 1; ++ ++ l = endp; ++ if (l < re && *l == ',') ++ ++l; ++ } ++ while (l < re && *l != '\n'); ++ ++ __close_nocancel_nostatus (fd); ++ ++ if (result > 0) ++ return result; ++ } ++ ++ return get_nproc_stat (buffer, buffer_size); + } + libc_hidden_def (__get_nprocs) + weak_alias (__get_nprocs, get_nprocs) +@@ -117,7 +228,9 @@ __get_nprocs_conf (void) + return count; + } + +- return 1; ++ enum { buffer_size = 1024 }; ++ char buffer[buffer_size]; ++ return get_nproc_stat (buffer, buffer_size); + } + libc_hidden_def (__get_nprocs_conf) + weak_alias (__get_nprocs_conf, get_nprocs_conf) +diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +index feb70abc3e..b07fc8549d 100644 +--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +@@ -231,6 +231,7 @@ + #define __NR_pwritev 316 + #define __NR_pwritev2 348 + #define __NR_quotactl 131 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 207 + #define __NR_readlink 85 +diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +index 3b1894a79b..6e4264698b 100644 +--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +@@ -183,6 +183,7 @@ + #define __NR_mbind 274 + #define __NR_membarrier 375 + #define __NR_memfd_create 356 ++#define __NR_memfd_secret 447 + #define __NR_migrate_pages 294 + #define __NR_mincore 218 + #define __NR_mkdir 39 +@@ -266,6 +267,7 @@ + #define __NR_pwritev2 379 + #define __NR_query_module 167 + #define __NR_quotactl 131 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 225 + #define __NR_readdir 89 +diff --git a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h +index fb388a5fa4..1ca706d721 100644 +--- a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h +@@ -218,6 +218,7 @@ + #define __NR_pwritev 1320 + #define __NR_pwritev2 1349 + #define __NR_quotactl 1137 ++#define __NR_quotactl_fd 1467 + #define __NR_read 1026 + #define __NR_readahead 1216 + #define __NR_readlink 1092 +diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +index 7bc8c4af92..2f10f71f90 100644 +--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +@@ -254,6 +254,7 @@ + #define __NR_pwritev2 378 + #define __NR_query_module 167 + #define __NR_quotactl 131 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 240 + #define __NR_readdir 89 +diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +index cf560d3af4..0607a4dfa6 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +@@ -266,6 +266,7 @@ + #define __NR_pwritev2 394 + #define __NR_query_module 167 + #define __NR_quotactl 131 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 225 + #define __NR_readdir 89 +diff --git a/sysdeps/unix/sysv/linux/mips/fxstat.c b/sysdeps/unix/sysv/linux/mips/fxstat.c +index 11511d30b3..4a6016ff12 100644 +--- a/sysdeps/unix/sysv/linux/mips/fxstat.c ++++ b/sysdeps/unix/sysv/linux/mips/fxstat.c +@@ -35,7 +35,9 @@ __fxstat (int vers, int fd, struct stat *buf) + { + struct kernel_stat kbuf; + int r = INTERNAL_SYSCALL_CALL (fstat, fd, &kbuf); +- return r ?: __xstat_conv (vers, &kbuf, buf); ++ if (r == 0) ++ return __xstat_conv (vers, &kbuf, buf); ++ return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r); + } + } + } +diff --git a/sysdeps/unix/sysv/linux/mips/lxstat.c b/sysdeps/unix/sysv/linux/mips/lxstat.c +index 871fb6c6c5..54f990a250 100644 +--- a/sysdeps/unix/sysv/linux/mips/lxstat.c ++++ b/sysdeps/unix/sysv/linux/mips/lxstat.c +@@ -35,7 +35,9 @@ __lxstat (int vers, const char *name, struct stat *buf) + { + struct kernel_stat kbuf; + int r = INTERNAL_SYSCALL_CALL (lstat, name, &kbuf); +- return r ?: __xstat_conv (vers, &kbuf, buf); ++ if (r == 0) ++ return __xstat_conv (vers, &kbuf, buf); ++ return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r); + } + } + } +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +index f346460f48..0055eec0b1 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +@@ -251,6 +251,7 @@ + #define __NR_pwritev2 4362 + #define __NR_query_module 4187 + #define __NR_quotactl 4131 ++#define __NR_quotactl_fd 4443 + #define __NR_read 4003 + #define __NR_readahead 4223 + #define __NR_readdir 4089 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +index 38ed84997a..8e8e9f91cc 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +@@ -232,6 +232,7 @@ + #define __NR_pwritev2 6326 + #define __NR_query_module 6171 + #define __NR_quotactl 6172 ++#define __NR_quotactl_fd 6443 + #define __NR_read 6000 + #define __NR_readahead 6179 + #define __NR_readlink 6087 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +index e6a10c8421..ebd1545f80 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +@@ -219,6 +219,7 @@ + #define __NR_pwritev2 5322 + #define __NR_query_module 5171 + #define __NR_quotactl 5172 ++#define __NR_quotactl_fd 5443 + #define __NR_read 5000 + #define __NR_readahead 5179 + #define __NR_readlink 5087 +diff --git a/sysdeps/unix/sysv/linux/mips/xstat.c b/sysdeps/unix/sysv/linux/mips/xstat.c +index 9d810b6f65..86f4dc31a8 100644 +--- a/sysdeps/unix/sysv/linux/mips/xstat.c ++++ b/sysdeps/unix/sysv/linux/mips/xstat.c +@@ -35,7 +35,9 @@ __xstat (int vers, const char *name, struct stat *buf) + { + struct kernel_stat kbuf; + int r = INTERNAL_SYSCALL_CALL (stat, name, &kbuf); +- return r ?: __xstat_conv (vers, &kbuf, buf); ++ if (r == 0) ++ return __xstat_conv (vers, &kbuf, buf); ++ return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r); + } + } + } +diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c +index 9799dcdaa4..eccae2e4c6 100644 +--- a/sysdeps/unix/sysv/linux/mq_notify.c ++++ b/sysdeps/unix/sysv/linux/mq_notify.c +@@ -131,7 +131,7 @@ helper_thread (void *arg) + to wait until it is done with it. */ + (void) __pthread_barrier_wait (¬ify_barrier); + } +- else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED) ++ else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED && data.attr != NULL) + { + /* The only state we keep is the copy of the thread attributes. */ + __pthread_attr_destroy (data.attr); +diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +index 5314890289..2b530b1f88 100644 +--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +@@ -198,6 +198,7 @@ + #define __NR_pwritev 70 + #define __NR_pwritev2 287 + #define __NR_quotactl 60 ++#define __NR_quotactl_fd 443 + #define __NR_read 63 + #define __NR_readahead 213 + #define __NR_readlinkat 78 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +index b5b0758532..a32984a9c1 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +@@ -260,6 +260,7 @@ + #define __NR_pwritev2 381 + #define __NR_query_module 166 + #define __NR_quotactl 131 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 191 + #define __NR_readdir 89 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +index c77435ca61..b01e464fb9 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +@@ -243,6 +243,7 @@ + #define __NR_pwritev2 381 + #define __NR_query_module 166 + #define __NR_quotactl 131 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 191 + #define __NR_readdir 89 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +index 70854bb9e3..24d0a2c455 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +@@ -179,6 +179,7 @@ + #define __NR_pwritev 70 + #define __NR_pwritev2 287 + #define __NR_quotactl 60 ++#define __NR_quotactl_fd 443 + #define __NR_read 63 + #define __NR_readahead 213 + #define __NR_readlinkat 78 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +index 83b9f31aba..e526c89ae7 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +@@ -187,6 +187,7 @@ + #define __NR_pwritev 70 + #define __NR_pwritev2 287 + #define __NR_quotactl 60 ++#define __NR_quotactl_fd 443 + #define __NR_read 63 + #define __NR_readahead 213 + #define __NR_readlinkat 78 +diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +index e9bd3684db..00e73a3e3b 100644 +--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h ++++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h +@@ -22,6 +22,11 @@ + + /* + * The following must match the kernels asm/elf.h. ++ * Note: The kernel commit 511ad531afd4090625def4d9aba1f5227bd44b8e ++ * "s390/hwcaps: shorten HWCAP defines" has shortened the prefix of the macros ++ * from "HWCAP_S390_" to "HWCAP_". For compatibility reasons, we do not ++ * change the prefix in public glibc header file. ++ * + * Note that these are *not* the same as the STORE FACILITY LIST bits. + */ + #define HWCAP_S390_ESAN3 1 +@@ -48,3 +53,5 @@ + #define HWCAP_S390_DFLT 262144 + #define HWCAP_S390_VXRS_PDE2 524288 + #define HWCAP_S390_NNPA 1048576 ++#define HWCAP_S390_PCI_MIO 2097152 ++#define HWCAP_S390_SIE 4194304 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +index b224c4aad4..d4c7b101b6 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +@@ -251,6 +251,7 @@ + #define __NR_pwritev2 377 + #define __NR_query_module 167 + #define __NR_quotactl 131 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 222 + #define __NR_readdir 89 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +index 59864af125..bd8c78d705 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +@@ -221,6 +221,7 @@ + #define __NR_pwritev2 377 + #define __NR_query_module 167 + #define __NR_quotactl 131 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 222 + #define __NR_readdir 89 +diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +index 23612c9092..3b6ac3d084 100644 +--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +@@ -246,6 +246,7 @@ + #define __NR_pwritev 334 + #define __NR_pwritev2 382 + #define __NR_quotactl 131 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 225 + #define __NR_readdir 89 +diff --git a/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h +index b481b4f9f8..45db6b6ffb 100644 +--- a/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h ++++ b/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h +@@ -28,32 +28,35 @@ + + struct stat + { ++#ifdef __USE_TIME_BITS64 ++# include ++#else + __dev_t st_dev; /* Device. */ +-#if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64 ++# if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64 + unsigned short int __pad1; + __ino_t st_ino; /* File serial number. */ +-#else ++# else + __ino64_t st_ino; /* File serial number. */ +-#endif ++# endif + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ + __uid_t st_uid; /* User ID of the file's owner. */ + __gid_t st_gid; /* Group ID of the file's group.*/ + __dev_t st_rdev; /* Device number, if device. */ + unsigned short int __pad2; +-#ifndef __USE_FILE_OFFSET64 ++# ifndef __USE_FILE_OFFSET64 + __off_t st_size; /* Size of file, in bytes. */ +-#else ++# else + __off64_t st_size; /* Size of file, in bytes. */ +-#endif ++# endif + __blksize_t st_blksize; /* Optimal block size for I/O. */ + +-#ifndef __USE_FILE_OFFSET64 ++# ifndef __USE_FILE_OFFSET64 + __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ +-#else ++# else + __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +-#endif +-#ifdef __USE_XOPEN2K8 ++# endif ++# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the +@@ -63,28 +66,32 @@ struct stat + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +-# define st_atime st_atim.tv_sec /* Backward compatibility. */ +-# define st_mtime st_mtim.tv_sec +-# define st_ctime st_ctim.tv_sec +-#else ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +-#endif ++# endif + unsigned long int __glibc_reserved4; + unsigned long int __glibc_reserved5; ++#endif /* __USE_TIME_BITS64 */ + }; + + #ifdef __USE_LARGEFILE64 + struct stat64 + { ++# ifdef __USE_TIME_BITS64 ++# include ++# else + __dev_t st_dev; /* Device. */ +-# if __WORDSIZE == 64 ++# if __WORDSIZE == 64 + unsigned short int __pad1; +-# endif ++# endif + __ino64_t st_ino; /* File serial number. */ + __mode_t st_mode; /* File mode. */ + __nlink_t st_nlink; /* Link count. */ +@@ -96,7 +103,7 @@ struct stat64 + __blksize_t st_blksize; /* Optimal block size for I/O. */ + + __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +-# ifdef __USE_XOPEN2K8 ++# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the +@@ -106,19 +113,20 @@ struct stat64 + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +-# define st_atime st_atim.tv_sec /* Backward compatibility. */ +-# define st_mtime st_mtim.tv_sec +-# define st_ctime st_ctim.tv_sec +-# else ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +-# endif ++# endif + unsigned long int __glibc_reserved4; + unsigned long int __glibc_reserved5; ++# endif /* __USE_TIME_BITS64 */ + }; + #endif + +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +index 380cddb2d8..35221a707e 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +@@ -252,6 +252,7 @@ + #define __NR_pwritev2 359 + #define __NR_query_module 184 + #define __NR_quotactl 165 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 205 + #define __NR_readdir 204 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +index 2175eeb6ed..5ba2b20509 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +@@ -231,6 +231,7 @@ + #define __NR_pwritev2 359 + #define __NR_query_module 184 + #define __NR_quotactl 165 ++#define __NR_quotactl_fd 443 + #define __NR_read 3 + #define __NR_readahead 205 + #define __NR_readdir 204 +diff --git a/sysdeps/unix/sysv/linux/sys/prctl.h b/sysdeps/unix/sysv/linux/sys/prctl.h +index db88938b3a..f0e0d2f27f 100644 +--- a/sysdeps/unix/sysv/linux/sys/prctl.h ++++ b/sysdeps/unix/sysv/linux/sys/prctl.h +@@ -42,7 +42,7 @@ __BEGIN_DECLS + extern int prctl (int __option, ...) __THROW; + #else + # ifdef __REDIRECT +-extern int __REDIRECT (prctl, (int __option, ...), __prctl_time64) __THROW; ++extern int __REDIRECT_NTH (prctl, (int __option, ...), __prctl_time64); + # else + extern int __prctl_time64 (int __option,d ...) __THROW; + # define ioctl __prctl_time64 +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 89c5895b9b..fd98893b0e 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 5.13. +-kernel 5.13 ++# The list of system calls is current as of Linux 5.14. ++kernel 5.14 + + FAST_atomic_update + FAST_cmpxchg +@@ -247,6 +247,7 @@ madvise + mbind + membarrier + memfd_create ++memfd_secret + memory_ordering + migrate_pages + mincore +@@ -452,6 +453,7 @@ pwritev + pwritev2 + query_module + quotactl ++quotactl_fd + read + readahead + readdir +diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c +index dccb6189c5..f5069d1b8a 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 + { +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index ee5b13ee12..810433c238 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -33,7 +33,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (5, 13) ++ linux_version_glibc = (5, 14) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +index 8e028eb62b..26d6ac68a6 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +@@ -154,6 +154,7 @@ + #define __NR_mbind 237 + #define __NR_membarrier 324 + #define __NR_memfd_create 319 ++#define __NR_memfd_secret 447 + #define __NR_migrate_pages 256 + #define __NR_mincore 27 + #define __NR_mkdir 83 +@@ -224,6 +225,7 @@ + #define __NR_pwritev2 328 + #define __NR_query_module 178 + #define __NR_quotactl 179 ++#define __NR_quotactl_fd 443 + #define __NR_read 0 + #define __NR_readahead 187 + #define __NR_readlink 89 +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +index 004feb53f1..36847783f6 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +@@ -148,6 +148,7 @@ + #define __NR_mbind 1073742061 + #define __NR_membarrier 1073742148 + #define __NR_memfd_create 1073742143 ++#define __NR_memfd_secret 1073742271 + #define __NR_migrate_pages 1073742080 + #define __NR_mincore 1073741851 + #define __NR_mkdir 1073741907 +@@ -216,6 +217,7 @@ + #define __NR_pwritev 1073742359 + #define __NR_pwritev2 1073742371 + #define __NR_quotactl 1073742003 ++#define __NR_quotactl_fd 1073742267 + #define __NR_read 1073741824 + #define __NR_readahead 1073742011 + #define __NR_readlink 1073741913 +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index 9f02624375..abde8438d4 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -325,7 +325,7 @@ L(movsb): + /* Avoid slow backward REP MOVSB. */ + jb L(more_8x_vec_backward) + # if AVOID_SHORT_DISTANCE_REP_MOVSB +- andl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) ++ testl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) + jz 3f + movq %rdi, %rcx + subq %rsi, %rcx +@@ -333,7 +333,7 @@ L(movsb): + # endif + 1: + # if AVOID_SHORT_DISTANCE_REP_MOVSB +- andl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) ++ testl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip) + jz 3f + movq %rsi, %rcx + subq %rdi, %rcx