diff options
author | Juergen Daubert <jue@jue.li> | 2021-12-28 14:25:24 +0100 |
---|---|---|
committer | Juergen Daubert <jue@jue.li> | 2021-12-28 14:25:24 +0100 |
commit | 5233eb446ef5a849dab255897565c60d6b35af07 (patch) | |
tree | 3c295a90a7e1de860799e133fec71b5d63f95722 /glibc-32 | |
parent | a7fd21d07a95d600515f0f758b03c76ac8d3f411 (diff) | |
download | core-5233eb446ef5a849dab255897565c60d6b35af07.tar.gz core-5233eb446ef5a849dab255897565c60d6b35af07.tar.xz |
glibc-32: update to 2.34
Diffstat (limited to 'glibc-32')
-rw-r--r-- | glibc-32/.footprint | 64 | ||||
-rw-r--r-- | glibc-32/.signature | 12 | ||||
-rw-r--r-- | glibc-32/Pkgfile | 12 | ||||
-rw-r--r-- | glibc-32/glibc-2.32-6.patch | 6671 | ||||
-rw-r--r-- | glibc-32/glibc-2.34-1.patch | 4419 |
5 files changed, 4453 insertions, 6725 deletions
diff --git a/glibc-32/.footprint b/glibc-32/.footprint index d90b8baf..92b0e1b6 100644 --- a/glibc-32/.footprint +++ b/glibc-32/.footprint @@ -4,45 +4,28 @@ drwxr-xr-x root/root etc/ld.so.conf.d/ drwxr-xr-x root/root lib/ lrwxrwxrwx root/root lib/ld-linux.so.2 -> /lib32/ld-linux.so.2 drwxr-xr-x root/root lib32/ --rwxr-xr-x root/root lib32/ld-2.32.so -lrwxrwxrwx root/root lib32/ld-linux.so.2 -> ld-2.32.so --rwxr-xr-x root/root lib32/libBrokenLocale-2.32.so -lrwxrwxrwx root/root lib32/libBrokenLocale.so.1 -> libBrokenLocale-2.32.so +-rwxr-xr-x root/root lib32/ld-linux.so.2 +-rwxr-xr-x root/root lib32/libBrokenLocale.so.1 -rwxr-xr-x root/root lib32/libSegFault.so --rwxr-xr-x root/root lib32/libanl-2.32.so -lrwxrwxrwx root/root lib32/libanl.so.1 -> libanl-2.32.so --rwxr-xr-x root/root lib32/libc-2.32.so -lrwxrwxrwx root/root lib32/libc.so.6 -> libc-2.32.so --rwxr-xr-x root/root lib32/libcrypt-2.32.so -lrwxrwxrwx root/root lib32/libcrypt.so.1 -> libcrypt-2.32.so --rwxr-xr-x root/root lib32/libdl-2.32.so -lrwxrwxrwx root/root lib32/libdl.so.2 -> libdl-2.32.so --rwxr-xr-x root/root lib32/libm-2.32.so -lrwxrwxrwx root/root lib32/libm.so.6 -> libm-2.32.so +-rwxr-xr-x root/root lib32/libanl.so.1 +-rwxr-xr-x root/root lib32/libc.so.6 +-rwxr-xr-x root/root lib32/libc_malloc_debug.so.0 +-rwxr-xr-x root/root lib32/libcrypt.so.1 +-rwxr-xr-x root/root lib32/libdl.so.2 +-rwxr-xr-x root/root lib32/libm.so.6 -rwxr-xr-x root/root lib32/libmemusage.so --rwxr-xr-x root/root lib32/libnsl-2.32.so -lrwxrwxrwx root/root lib32/libnsl.so.1 -> libnsl-2.32.so --rwxr-xr-x root/root lib32/libnss_compat-2.32.so -lrwxrwxrwx root/root lib32/libnss_compat.so.2 -> libnss_compat-2.32.so --rwxr-xr-x root/root lib32/libnss_db-2.32.so -lrwxrwxrwx root/root lib32/libnss_db.so.2 -> libnss_db-2.32.so --rwxr-xr-x root/root lib32/libnss_dns-2.32.so -lrwxrwxrwx root/root lib32/libnss_dns.so.2 -> libnss_dns-2.32.so --rwxr-xr-x root/root lib32/libnss_files-2.32.so -lrwxrwxrwx root/root lib32/libnss_files.so.2 -> libnss_files-2.32.so --rwxr-xr-x root/root lib32/libnss_hesiod-2.32.so -lrwxrwxrwx root/root lib32/libnss_hesiod.so.2 -> libnss_hesiod-2.32.so +-rwxr-xr-x root/root lib32/libnsl.so.1 +-rwxr-xr-x root/root lib32/libnss_compat.so.2 +-rwxr-xr-x root/root lib32/libnss_db.so.2 +-rwxr-xr-x root/root lib32/libnss_dns.so.2 +-rwxr-xr-x root/root lib32/libnss_files.so.2 +-rwxr-xr-x root/root lib32/libnss_hesiod.so.2 -rwxr-xr-x root/root lib32/libpcprofile.so --rwxr-xr-x root/root lib32/libpthread-2.32.so -lrwxrwxrwx root/root lib32/libpthread.so.0 -> libpthread-2.32.so --rwxr-xr-x root/root lib32/libresolv-2.32.so -lrwxrwxrwx root/root lib32/libresolv.so.2 -> libresolv-2.32.so --rwxr-xr-x root/root lib32/librt-2.32.so -lrwxrwxrwx root/root lib32/librt.so.1 -> librt-2.32.so --rwxr-xr-x root/root lib32/libthread_db-1.0.so -lrwxrwxrwx root/root lib32/libthread_db.so.1 -> libthread_db-1.0.so --rwxr-xr-x root/root lib32/libutil-2.32.so -lrwxrwxrwx root/root lib32/libutil.so.1 -> libutil-2.32.so +-rwxr-xr-x root/root lib32/libpthread.so.0 +-rwxr-xr-x root/root lib32/libresolv.so.2 +-rwxr-xr-x root/root lib32/librt.so.1 +-rwxr-xr-x root/root lib32/libthread_db.so.1 +-rwxr-xr-x root/root lib32/libutil.so.1 drwxr-xr-x root/root usr/ drwxr-xr-x root/root usr/include/ drwxr-xr-x root/root usr/include/gnu/ @@ -304,6 +287,8 @@ drwxr-xr-x root/root usr/lib32/gconv/ -rwxr-xr-x root/root usr/lib32/gconv/UTF-7.so -rwxr-xr-x root/root usr/lib32/gconv/VISCII.so -rw-r--r-- root/root usr/lib32/gconv/gconv-modules +drwxr-xr-x root/root usr/lib32/gconv/gconv-modules.d/ +-rw-r--r-- root/root usr/lib32/gconv/gconv-modules.d/gconv-modules-extra.conf -rwxr-xr-x root/root usr/lib32/gconv/libCNS.so -rwxr-xr-x root/root usr/lib32/gconv/libGB.so -rwxr-xr-x root/root usr/lib32/gconv/libISOIR165.so @@ -324,26 +309,21 @@ lrwxrwxrwx root/root usr/lib32/libBrokenLocale.so -> ../../lib32/libBrokenLocale lrwxrwxrwx root/root usr/lib32/libanl.so -> ../../lib32/libanl.so.1 -rw-r--r-- root/root usr/lib32/libc.a -rw-r--r-- root/root usr/lib32/libc.so +lrwxrwxrwx root/root usr/lib32/libc_malloc_debug.so -> ../../lib32/libc_malloc_debug.so.0 -rw-r--r-- root/root usr/lib32/libc_nonshared.a -rw-r--r-- root/root usr/lib32/libcrypt.a lrwxrwxrwx root/root usr/lib32/libcrypt.so -> ../../lib32/libcrypt.so.1 -rw-r--r-- root/root usr/lib32/libdl.a -lrwxrwxrwx root/root usr/lib32/libdl.so -> ../../lib32/libdl.so.2 -rw-r--r-- root/root usr/lib32/libg.a -rw-r--r-- root/root usr/lib32/libm.a lrwxrwxrwx root/root usr/lib32/libm.so -> ../../lib32/libm.so.6 -rw-r--r-- root/root usr/lib32/libmcheck.a lrwxrwxrwx root/root usr/lib32/libnss_compat.so -> ../../lib32/libnss_compat.so.2 lrwxrwxrwx root/root usr/lib32/libnss_db.so -> ../../lib32/libnss_db.so.2 -lrwxrwxrwx root/root usr/lib32/libnss_dns.so -> ../../lib32/libnss_dns.so.2 -lrwxrwxrwx root/root usr/lib32/libnss_files.so -> ../../lib32/libnss_files.so.2 lrwxrwxrwx root/root usr/lib32/libnss_hesiod.so -> ../../lib32/libnss_hesiod.so.2 -rw-r--r-- root/root usr/lib32/libpthread.a -lrwxrwxrwx root/root usr/lib32/libpthread.so -> ../../lib32/libpthread.so.0 -rw-r--r-- root/root usr/lib32/libresolv.a lrwxrwxrwx root/root usr/lib32/libresolv.so -> ../../lib32/libresolv.so.2 -rw-r--r-- root/root usr/lib32/librt.a -lrwxrwxrwx root/root usr/lib32/librt.so -> ../../lib32/librt.so.1 lrwxrwxrwx root/root usr/lib32/libthread_db.so -> ../../lib32/libthread_db.so.1 -rw-r--r-- root/root usr/lib32/libutil.a -lrwxrwxrwx root/root usr/lib32/libutil.so -> ../../lib32/libutil.so.1 diff --git a/glibc-32/.signature b/glibc-32/.signature index 017e43a9..1bf25a3a 100644 --- a/glibc-32/.signature +++ b/glibc-32/.signature @@ -1,8 +1,8 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqr36wOeAhPICGi1Hff3GLxSyoYwImwozO3FzfG+efpkBZ+KFTAEpXqJDjp1K5xAbEplpkh8jkVxtELbs/0aaLgE= -SHA256 (Pkgfile) = 0154f2a6a6db64fba487ffc0bd599452d8adf94d962a711c0e29104024eed1fb -SHA256 (.footprint) = 45836a310a6801080a61130aca376091caab990a0c75d9fc039fcb7ad7298642 -SHA256 (glibc-2.32.tar.xz) = 1627ea54f5a1a8467032563393e0901077626dc66f37f10ee6363bb722222836 -SHA256 (linux-5.4.72.tar.xz) = 0e24645bd56fe5b55a7a662895f5562c103d71b54d097281f0c9c71ff22c1172 -SHA256 (glibc-2.32-6.patch) = 70f33f14f62cb2daddd9bbfe0ffdfb3bb01880f7cedbc71cb534e82343d4a3d4 +RWRJc1FUaeVeqpa8Cr4ATxBe5I7WyhDcSv8erM6ralqDcoKb5x56uQ2MlsUZcKgHzQZZvmRg0sDU3pw63eeHEJmXQYsSelUZZA4= +SHA256 (Pkgfile) = 7a91d36f12fcb98b523d0af2898fe75f1e0704e8b83dd32f4415ee1fa8ff143b +SHA256 (.footprint) = 28c0be81580495d8789fce4c11a415bd557693f979c5beb40977cbac1607853b +SHA256 (glibc-2.34.tar.xz) = 44d26a1fe20b8853a48f470ead01e4279e869ac149b195dda4e44a195d981ab2 +SHA256 (linux-5.15.11.tar.xz) = c1178b7e7e12d91292e670191268e3fe9a3563faf899eef43e468577e973a1ce +SHA256 (glibc-2.34-1.patch) = 38455bc201d53743b34335464a10d8ab2bfc456e71c49c116a58397ca48c7e2a SHA256 (lib32.conf) = 2f174d2bcefe1c29327690514f34d6970fffdd54398320ca23a11b5f1e3c9b2d diff --git a/glibc-32/Pkgfile b/glibc-32/Pkgfile index 5fd2a2cc..909dcbeb 100644 --- a/glibc-32/Pkgfile +++ b/glibc-32/Pkgfile @@ -3,21 +3,21 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=glibc-32 -version=2.32 -release=6 +version=2.34 +release=1 source=(https://ftp.gnu.org/gnu/glibc/glibc-$version.tar.xz \ - https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.4.72.tar.xz \ - glibc-$version-6.patch lib32.conf) + https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.15.11.tar.xz \ + glibc-$version-1.patch lib32.conf) build() { # install kernel headers - cd linux-5.4.72 + cd linux-5.15.11 make mrproper make headers_check make INSTALL_HDR_PATH=$PKG/usr headers_install chown root:root $PKG/usr - patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-$version-6.patch + patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-$version-1.patch mkdir $SRC/build cd $SRC/build diff --git a/glibc-32/glibc-2.32-6.patch b/glibc-32/glibc-2.32-6.patch deleted file mode 100644 index 5d4a58d2..00000000 --- a/glibc-32/glibc-2.32-6.patch +++ /dev/null @@ -1,6671 +0,0 @@ -diff --git a/NEWS b/NEWS -index 485b8ddffa..b29826f4f5 100644 ---- a/NEWS -+++ b/NEWS -@@ -5,6 +5,27 @@ See the end for copying conditions. - Please send GNU C library bug reports via <https://sourceware.org/bugzilla/> - using `glibc' in the "product" field. - -+The following bugs are resolved with this release: -+ -+ [20019] NULL pointer dereference in libc.so.6 IFUNC due to uninitialized GOT -+ [26224] iconv hangs when converting some invalid inputs from several IBM -+ character sets (CVE-2020-27618) -+ [26534] libm.so 2.32 SIGILL in pow() due to FMA4 instruction on non-FMA4 -+ system -+ [26555] string: strerrorname_np does not return the documented value -+ [26600] Transaction ID collisions cause slow DNS lookups in getaddrinfo -+ [26636] libc: 32-bit shmctl(IPC_INFO) crashes when shminfo struct is -+ at the end of a memory mapping -+ [26637] libc: semctl SEM_STAT_ANY fails to pass the buffer specified -+ by the caller to the kernel -+ [26639] libc: msgctl IPC_INFO and MSG_INFO return garbage -+ [26853] aarch64: Missing unwind information in statically linked startup code -+ [26932] libc: sh: Multiple floating point functions defined as stubs only -+ [27130] "rep movsb" performance issue -+ [27177] GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on doesn't work -+ [28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs -+ [28607] Masked signals are delivered on thread exit -+ - Version 2.32 - - Major new features: -@@ -185,6 +206,14 @@ Security related changes: - Dytrych of the Cisco Security Assessment and Penetration Team (See - TALOS-2020-1019). - -+ CVE-2020-27618: An infinite loop has been fixed in the iconv program when -+ invoked with input containing redundant shift sequences in the IBM1364, -+ IBM1371, IBM1388, IBM1390, or IBM1399 character sets. -+ -+ CVE-2021-33574: The mq_notify function has a potential use-after-free -+ issue when using a notification type of SIGEV_THREAD and a thread -+ attribute with a non-default affinity mask. -+ - The following bugs are resolved with this release: - - [9809] localedata: ckb_IQ: new Kurdish Sorani locale -diff --git a/Rules b/Rules -index 8b771f6095..beab969fde 100644 ---- a/Rules -+++ b/Rules -@@ -155,6 +155,7 @@ xtests: tests $(xtests-special) - else - tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \ - $(tests-container:%=$(objpfx)%.out) \ -+ $(tests-mcheck:%=$(objpfx)%-mcheck.out) \ - $(tests-special) $(tests-printers-out) - xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special) - endif -@@ -165,7 +166,7 @@ ifeq ($(run-built-tests),no) - tests-expected = - else - tests-expected = $(tests) $(tests-internal) $(tests-printers) \ -- $(tests-container) -+ $(tests-container) $(tests-mcheck:%=%-mcheck) - endif - tests: - $(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \ -@@ -191,6 +192,7 @@ else - binaries-pie-tests = - binaries-pie-notests = - endif -+binaries-mcheck-tests = $(tests-mcheck:%=%-mcheck) - else - binaries-all-notests = - binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs) -@@ -200,6 +202,7 @@ binaries-static-tests = - binaries-static = - binaries-pie-tests = - binaries-pie-notests = -+binaries-mcheck-tests = - endif - - binaries-pie = $(binaries-pie-tests) $(binaries-pie-notests) -@@ -223,6 +226,14 @@ $(addprefix $(objpfx),$(binaries-shared-tests)): %: %.o \ - $(+link-tests) - endif - -+ifneq "$(strip $(binaries-mcheck-tests))" "" -+$(addprefix $(objpfx),$(binaries-mcheck-tests)): %-mcheck: %.o \ -+ $(link-extra-libs-tests) \ -+ $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ -+ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) -+ $(+link-tests) -+endif -+ - ifneq "$(strip $(binaries-pie-tests))" "" - $(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \ - $(link-extra-libs-tests) \ -@@ -253,6 +264,12 @@ $(addprefix $(objpfx),$(binaries-static-tests)): %: %.o \ - $(+link-static-tests) - endif - -+# All mcheck tests will be run with MALLOC_CHECK_=3 -+define mcheck-ENVS -+$(1)-mcheck-ENV = MALLOC_CHECK_=3 -+endef -+$(foreach t,$(tests-mcheck),$(eval $(call mcheck-ENVS,$(t)))) -+ - ifneq "$(strip $(tests) $(tests-internal) $(xtests) $(test-srcs))" "" - # These are the implicit rules for making test outputs - # from the test programs and whatever input files are present. -diff --git a/debug/Makefile b/debug/Makefile -index 3a60d7af7a..0036edd187 100644 ---- a/debug/Makefile -+++ b/debug/Makefile -@@ -51,7 +51,7 @@ routines = backtrace backtracesyms backtracesymsfd noophooks \ - explicit_bzero_chk \ - stack_chk_fail fortify_fail \ - $(static-only-routines) --static-only-routines := warning-nop stack_chk_fail_local -+static-only-routines := stack_chk_fail_local - - # Don't add stack_chk_fail_local.o to libc.a since __stack_chk_fail_local - # is an alias of __stack_chk_fail in stack_chk_fail.o. -diff --git a/debug/warning-nop.c b/debug/warning-nop.c -deleted file mode 100644 -index 4ab7e182b7..0000000000 ---- a/debug/warning-nop.c -+++ /dev/null -@@ -1,70 +0,0 @@ --/* Dummy nop functions to elicit link-time warnings. -- Copyright (C) 2005-2020 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. -- -- In addition to the permissions in the GNU Lesser General Public -- License, the Free Software Foundation gives you unlimited -- permission to link the compiled version of this file with other -- programs, and to distribute those programs without any restriction -- coming from the use of this file. (The GNU Lesser General Public -- License restrictions do apply in other respects; for example, they -- cover modification of the file, and distribution when not linked -- into another program.) -- -- Note that people who make modified versions of this file are not -- obligated to grant this special exception for their modified -- versions; it is their choice whether to do so. The GNU Lesser -- General Public License gives permission to release a modified -- version without this exception; this exception also makes it -- possible to release a modified version which carries forward this -- exception. -- -- The GNU C Library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with the GNU C Library; if not, see -- <https://www.gnu.org/licenses/>. */ -- --#include <sys/cdefs.h> -- --static void --__attribute__ ((used)) --nop (void) --{ --} -- --/* Don't insert any other #include's before this #undef! */ -- --#undef __warndecl --#define __warndecl(name, msg) \ -- extern void name (void) __attribute__ ((alias ("nop"))) attribute_hidden; \ -- link_warning (name, msg) -- --#undef __USE_FORTIFY_LEVEL --#define __USE_FORTIFY_LEVEL 99 -- --/* Following here we need an #include for each public header file -- that uses __warndecl. */ -- --/* Define away to avoid warnings with compilers that do not have these -- builtins. */ --#define __builtin___memcpy_chk(dest, src, len, bos) NULL --#define __builtin___memmove_chk(dest, src, len, bos) NULL --#define __builtin___mempcpy_chk(dest, src, len, bos) NULL --#define __builtin___memset_chk(dest, ch, len, bos) NULL --#define __builtin___stpcpy_chk(dest, src, bos) NULL --#define __builtin___strcat_chk(dest, src, bos) NULL --#define __builtin___strcpy_chk(dest, src, bos) NULL --#define __builtin___strncat_chk(dest, src, len, bos) NULL --#define __builtin___strncpy_chk(dest, src, len, bos) NULL --#define __builtin_object_size(bos, level) 0 -- --#include <string.h> -diff --git a/elf/Makefile b/elf/Makefile -index 0b78721848..3ba7f4ecfc 100644 ---- a/elf/Makefile -+++ b/elf/Makefile -@@ -1381,6 +1381,8 @@ CFLAGS-ifuncmain7pie.c += $(pie-ccflag) - CFLAGS-ifuncmain9pie.c += $(pie-ccflag) - CFLAGS-tst-ifunc-textrel.c += $(pic-ccflag) - -+LDFLAGS-ifuncmain6pie = -Wl,-z,lazy -+ - $(objpfx)ifuncmain1pie: $(objpfx)ifuncmod1.so - $(objpfx)ifuncmain1staticpie: $(objpfx)ifuncdep1pic.o - $(objpfx)ifuncmain1vispie: $(objpfx)ifuncmod1.so -@@ -1630,8 +1632,6 @@ $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \ - - tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \ - LD_HWCAP_MASK=0x1 --tst-env-setuid-tunables-ENV = \ -- GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096 - - $(objpfx)tst-debug1: $(libdl) - $(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so -diff --git a/elf/dl-load.c b/elf/dl-load.c -index e39980fb19..71867e7c1a 100644 ---- a/elf/dl-load.c -+++ b/elf/dl-load.c -@@ -855,10 +855,12 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l, - - /* Process PT_GNU_PROPERTY program header PH in module L after - PT_LOAD segments are mapped. Only one NT_GNU_PROPERTY_TYPE_0 -- note is handled which contains processor specific properties. */ -+ note is handled which contains processor specific properties. -+ FD is -1 for the kernel mapped main executable otherwise it is -+ the fd used for loading module L. */ - - void --_dl_process_pt_gnu_property (struct link_map *l, const ElfW(Phdr) *ph) -+_dl_process_pt_gnu_property (struct link_map *l, int fd, const ElfW(Phdr) *ph) - { - const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr); - const ElfW(Addr) size = ph->p_memsz; -@@ -905,7 +907,7 @@ _dl_process_pt_gnu_property (struct link_map *l, const ElfW(Phdr) *ph) - last_type = type; - - /* Target specific property processing. */ -- if (_dl_process_gnu_property (l, type, datasz, ptr) == 0) -+ if (_dl_process_gnu_property (l, fd, type, datasz, ptr) == 0) - return; - - /* Check the next property item. */ -@@ -1251,21 +1253,6 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, - maplength, has_holes, loader); - if (__glibc_unlikely (errstring != NULL)) - goto call_lose; -- -- /* Process program headers again after load segments are mapped in -- case processing requires accessing those segments. Scan program -- headers backward so that PT_NOTE can be skipped if PT_GNU_PROPERTY -- exits. */ -- for (ph = &phdr[l->l_phnum]; ph != phdr; --ph) -- switch (ph[-1].p_type) -- { -- case PT_NOTE: -- _dl_process_pt_note (l, &ph[-1]); -- break; -- case PT_GNU_PROPERTY: -- _dl_process_pt_gnu_property (l, &ph[-1]); -- break; -- } - } - - if (l->l_ld == 0) -@@ -1377,6 +1364,21 @@ cannot enable executable stack as shared object requires"); - if (l->l_tls_initimage != NULL) - l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr; - -+ /* Process program headers again after load segments are mapped in -+ case processing requires accessing those segments. Scan program -+ headers backward so that PT_NOTE can be skipped if PT_GNU_PROPERTY -+ exits. */ -+ for (ph = &l->l_phdr[l->l_phnum]; ph != l->l_phdr; --ph) -+ switch (ph[-1].p_type) -+ { -+ case PT_NOTE: -+ _dl_process_pt_note (l, fd, &ph[-1]); -+ break; -+ case PT_GNU_PROPERTY: -+ _dl_process_pt_gnu_property (l, fd, &ph[-1]); -+ break; -+ } -+ - /* We are done mapping in the file. We no longer need the descriptor. */ - if (__glibc_unlikely (__close_nocancel (fd) != 0)) - { -diff --git a/elf/dl-open.c b/elf/dl-open.c -index 8769e47051..55b39e1bbe 100644 ---- a/elf/dl-open.c -+++ b/elf/dl-open.c -@@ -887,7 +887,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-tunables.c b/elf/dl-tunables.c -index 26e6e26612..15b29bcb90 100644 ---- a/elf/dl-tunables.c -+++ b/elf/dl-tunables.c -@@ -177,6 +177,7 @@ parse_tunables (char *tunestr, char *valstring) - return; - - char *p = tunestr; -+ size_t off = 0; - - while (true) - { -@@ -190,7 +191,11 @@ parse_tunables (char *tunestr, char *valstring) - /* If we reach the end of the string before getting a valid name-value - pair, bail out. */ - if (p[len] == '\0') -- return; -+ { -+ if (__libc_enable_secure) -+ tunestr[off] = '\0'; -+ return; -+ } - - /* We did not find a valid name-value pair before encountering the - colon. */ -@@ -216,35 +221,28 @@ parse_tunables (char *tunestr, char *valstring) - - if (tunable_is_name (cur->name, name)) - { -- /* If we are in a secure context (AT_SECURE) then ignore the tunable -- unless it is explicitly marked as secure. Tunable values take -- precedence over their envvar aliases. */ -+ /* If we are in a secure context (AT_SECURE) then ignore the -+ tunable unless it is explicitly marked as secure. Tunable -+ values take precedence over their envvar aliases. We write -+ the tunables that are not SXID_ERASE back to TUNESTR, thus -+ dropping all SXID_ERASE tunables and any invalid or -+ unrecognized tunables. */ - if (__libc_enable_secure) - { -- if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE) -+ if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE) - { -- if (p[len] == '\0') -- { -- /* Last tunable in the valstring. Null-terminate and -- return. */ -- *name = '\0'; -- return; -- } -- else -- { -- /* Remove the current tunable from the string. We do -- this by overwriting the string starting from NAME -- (which is where the current tunable begins) with -- the remainder of the string. We then have P point -- to NAME so that we continue in the correct -- position in the valstring. */ -- char *q = &p[len + 1]; -- p = name; -- while (*q != '\0') -- *name++ = *q++; -- name[0] = '\0'; -- len = 0; -- } -+ if (off > 0) -+ tunestr[off++] = ':'; -+ -+ const char *n = cur->name; -+ -+ while (*n != '\0') -+ tunestr[off++] = *n++; -+ -+ tunestr[off++] = '='; -+ -+ for (size_t j = 0; j < len; j++) -+ tunestr[off++] = value[j]; - } - - if (cur->security_level != TUNABLE_SECLEVEL_NONE) -@@ -257,9 +255,7 @@ parse_tunables (char *tunestr, char *valstring) - } - } - -- if (p[len] == '\0') -- return; -- else -+ if (p[len] != '\0') - p += len + 1; - } - } -diff --git a/elf/ifuncmain6pie.c b/elf/ifuncmain6pie.c -index 04faeb86ef..4a01906836 100644 ---- a/elf/ifuncmain6pie.c -+++ b/elf/ifuncmain6pie.c -@@ -9,7 +9,6 @@ - #include "ifunc-sel.h" - - typedef int (*foo_p) (void); --extern foo_p foo_ptr; - - static int - one (void) -@@ -28,20 +27,17 @@ foo_ifunc (void) - } - - extern int foo (void); --extern foo_p get_foo (void); -+extern int call_foo (void); - extern foo_p get_foo_p (void); - --foo_p my_foo_ptr = foo; -+foo_p foo_ptr = foo; - - int - main (void) - { - foo_p p; - -- p = get_foo (); -- if (p != foo) -- abort (); -- if ((*p) () != -30) -+ if (call_foo () != -30) - abort (); - - p = get_foo_p (); -@@ -52,12 +48,8 @@ main (void) - - if (foo_ptr != foo) - abort (); -- if (my_foo_ptr != foo) -- abort (); - if ((*foo_ptr) () != -30) - abort (); -- if ((*my_foo_ptr) () != -30) -- abort (); - if (foo () != -30) - abort (); - -diff --git a/elf/ifuncmod6.c b/elf/ifuncmod6.c -index 2e16c1d06d..2f6d0715e6 100644 ---- a/elf/ifuncmod6.c -+++ b/elf/ifuncmod6.c -@@ -4,7 +4,7 @@ extern int foo (void); - - typedef int (*foo_p) (void); - --foo_p foo_ptr = foo; -+extern foo_p foo_ptr; - - foo_p - get_foo_p (void) -@@ -12,8 +12,8 @@ get_foo_p (void) - return foo_ptr; - } - --foo_p --get_foo (void) -+int -+call_foo (void) - { -- return foo; -+ return foo (); - } -diff --git a/elf/rtld.c b/elf/rtld.c -index 5b882163fa..14a42ed00a 100644 ---- a/elf/rtld.c -+++ b/elf/rtld.c -@@ -1534,10 +1534,10 @@ of this helper program; chances are you did not intend to run this program.\n\ - switch (ph[-1].p_type) - { - case PT_NOTE: -- _dl_process_pt_note (main_map, &ph[-1]); -+ _dl_process_pt_note (main_map, -1, &ph[-1]); - break; - case PT_GNU_PROPERTY: -- _dl_process_pt_gnu_property (main_map, &ph[-1]); -+ _dl_process_pt_gnu_property (main_map, -1, &ph[-1]); - break; - } - -diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c -index 971d5892b1..ca0c8c245c 100644 ---- a/elf/tst-env-setuid-tunables.c -+++ b/elf/tst-env-setuid-tunables.c -@@ -25,35 +25,76 @@ - #include "config.h" - #undef _LIBC - --#define test_parent test_parent_tunables --#define test_child test_child_tunables -- --static int test_child_tunables (void); --static int test_parent_tunables (void); -- --#include "tst-env-setuid.c" -- --#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096" --#define PARENT_VALSTRING_VALUE \ -- "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096" -+#include <errno.h> -+#include <fcntl.h> -+#include <stdlib.h> -+#include <stdint.h> -+#include <stdio.h> -+#include <string.h> -+#include <sys/stat.h> -+#include <sys/wait.h> -+#include <unistd.h> -+#include <intprops.h> -+#include <array_length.h> -+ -+#include <support/check.h> -+#include <support/support.h> -+#include <support/test-driver.h> -+#include <support/capture_subprocess.h> -+ -+const char *teststrings[] = -+{ -+ "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2", -+ "glibc.malloc.perturb=0x800", -+ "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", -+ "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096", -+ "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2", -+ "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096", -+ ":glibc.malloc.garbage=2:glibc.malloc.check=1", -+ "glibc.malloc.check=1:glibc.malloc.check=2", -+ "not_valid.malloc.check=2", -+ "glibc.not_valid.check=2", -+}; -+ -+const char *resultstrings[] = -+{ -+ "glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.perturb=0x800", -+ "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.mmap_threshold=4096", -+ "", -+ "", -+ "", -+ "", -+ "", -+ "", -+}; - - static int --test_child_tunables (void) -+test_child (int off) - { - const char *val = getenv ("GLIBC_TUNABLES"); - - #if HAVE_TUNABLES -- if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0) -+ if (val != NULL && strcmp (val, resultstrings[off]) == 0) - return 0; - - if (val != NULL) -- printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val); -+ printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val); - - return 1; - #else - if (val != NULL) - { -- printf ("GLIBC_TUNABLES not cleared\n"); -+ printf ("[%d] GLIBC_TUNABLES not cleared\n", off); - return 1; - } - return 0; -@@ -61,15 +102,48 @@ test_child_tunables (void) - } - - static int --test_parent_tunables (void) -+do_test (int argc, char **argv) - { -- const char *val = getenv ("GLIBC_TUNABLES"); -+ /* Setgid child process. */ -+ if (argc == 2) -+ { -+ if (getgid () == getegid ()) -+ /* This can happen if the file system is mounted nosuid. */ -+ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n", -+ (intmax_t) getgid ()); - -- if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0) -- return 0; -+ int ret = test_child (atoi (argv[1])); - -- if (val != NULL) -- printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val); -+ if (ret != 0) -+ exit (1); - -- return 1; -+ exit (EXIT_SUCCESS); -+ } -+ else -+ { -+ int ret = 0; -+ -+ /* Spawn tests. */ -+ for (int i = 0; i < array_length (teststrings); i++) -+ { -+ char buf[INT_BUFSIZE_BOUND (int)]; -+ -+ printf ("Spawned test for %s (%d)\n", teststrings[i], i); -+ snprintf (buf, sizeof (buf), "%d\n", i); -+ if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0) -+ exit (1); -+ -+ int status = support_capture_subprogram_self_sgid (buf); -+ -+ /* Bail out early if unsupported. */ -+ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) -+ return EXIT_UNSUPPORTED; -+ -+ ret |= status; -+ } -+ return ret; -+ } - } -+ -+#define TEST_FUNCTION_ARGV do_test -+#include <support/test-driver.c> -diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c -index 41dc79e83a..2dbccdb69e 100644 ---- a/elf/tst-env-setuid.c -+++ b/elf/tst-env-setuid.c -@@ -29,173 +29,12 @@ - #include <sys/wait.h> - #include <unistd.h> - -+#include <support/check.h> - #include <support/support.h> - #include <support/test-driver.h> -+#include <support/capture_subprocess.h> - - static char SETGID_CHILD[] = "setgid-child"; --#define CHILD_STATUS 42 -- --/* Return a GID which is not our current GID, but is present in the -- supplementary group list. */ --static gid_t --choose_gid (void) --{ -- const int count = 64; -- gid_t groups[count]; -- int ret = getgroups (count, groups); -- if (ret < 0) -- { -- printf ("getgroups: %m\n"); -- exit (1); -- } -- gid_t current = getgid (); -- for (int i = 0; i < ret; ++i) -- { -- if (groups[i] != current) -- return groups[i]; -- } -- return 0; --} -- --/* Spawn and execute a program and verify that it returns the CHILD_STATUS. */ --static pid_t --do_execve (char **args) --{ -- pid_t kid = vfork (); -- -- if (kid < 0) -- { -- printf ("vfork: %m\n"); -- return -1; -- } -- -- if (kid == 0) -- { -- /* Child process. */ -- execve (args[0], args, environ); -- _exit (-errno); -- } -- -- if (kid < 0) -- return 1; -- -- int status; -- -- if (waitpid (kid, &status, 0) < 0) -- { -- printf ("waitpid: %m\n"); -- return 1; -- } -- -- if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) -- return EXIT_UNSUPPORTED; -- -- if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS) -- { -- printf ("Unexpected exit status %d from child process\n", -- WEXITSTATUS (status)); -- return 1; -- } -- return 0; --} -- --/* Copies the executable into a restricted directory, so that we can -- safely make it SGID with the TARGET group ID. Then runs the -- executable. */ --static int --run_executable_sgid (gid_t target) --{ -- char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd", -- test_dir, (intmax_t) getpid ()); -- char *execname = xasprintf ("%s/bin", dirname); -- int infd = -1; -- int outfd = -1; -- int ret = 0; -- if (mkdir (dirname, 0700) < 0) -- { -- printf ("mkdir: %m\n"); -- goto err; -- } -- infd = open ("/proc/self/exe", O_RDONLY); -- if (infd < 0) -- { -- printf ("open (/proc/self/exe): %m\n"); -- goto err; -- } -- outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700); -- if (outfd < 0) -- { -- printf ("open (%s): %m\n", execname); -- goto err; -- } -- char buf[4096]; -- for (;;) -- { -- ssize_t rdcount = read (infd, buf, sizeof (buf)); -- if (rdcount < 0) -- { -- printf ("read: %m\n"); -- goto err; -- } -- if (rdcount == 0) -- break; -- char *p = buf; -- char *end = buf + rdcount; -- while (p != end) -- { -- ssize_t wrcount = write (outfd, buf, end - p); -- if (wrcount == 0) -- errno = ENOSPC; -- if (wrcount <= 0) -- { -- printf ("write: %m\n"); -- goto err; -- } -- p += wrcount; -- } -- } -- if (fchown (outfd, getuid (), target) < 0) -- { -- printf ("fchown (%s): %m\n", execname); -- goto err; -- } -- if (fchmod (outfd, 02750) < 0) -- { -- printf ("fchmod (%s): %m\n", execname); -- goto err; -- } -- if (close (outfd) < 0) -- { -- printf ("close (outfd): %m\n"); -- goto err; -- } -- if (close (infd) < 0) -- { -- printf ("close (infd): %m\n"); -- goto err; -- } -- -- char *args[] = {execname, SETGID_CHILD, NULL}; -- -- ret = do_execve (args); -- --err: -- if (outfd >= 0) -- close (outfd); -- if (infd >= 0) -- close (infd); -- if (execname) -- { -- unlink (execname); -- free (execname); -- } -- if (dirname) -- { -- rmdir (dirname); -- free (dirname); -- } -- return ret; --} - - #ifndef test_child - static int -@@ -256,40 +95,32 @@ do_test (int argc, char **argv) - if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0) - { - if (getgid () == getegid ()) -- { -- /* This can happen if the file system is mounted nosuid. */ -- fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n", -- (intmax_t) getgid ()); -- exit (EXIT_UNSUPPORTED); -- } -+ /* This can happen if the file system is mounted nosuid. */ -+ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n", -+ (intmax_t) getgid ()); - - int ret = test_child (); - - if (ret != 0) - exit (1); - -- exit (CHILD_STATUS); -+ exit (EXIT_SUCCESS); - } - else - { - if (test_parent () != 0) - exit (1); - -- /* Try running a setgid program. */ -- gid_t target = choose_gid (); -- if (target == 0) -- { -- fprintf (stderr, -- "Could not find a suitable GID for user %jd, skipping test\n", -- (intmax_t) getuid ()); -- exit (0); -- } -+ int status = support_capture_subprogram_self_sgid (SETGID_CHILD); - -- return run_executable_sgid (target); -- } -+ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) -+ return EXIT_UNSUPPORTED; -+ -+ if (!WIFEXITED (status)) -+ FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status); - -- /* Something went wrong and our argv was corrupted. */ -- _exit (1); -+ return 0; -+ } - } - - #define TEST_FUNCTION_ARGV do_test -diff --git a/iconv/Versions b/iconv/Versions -index 8a5f4cf780..d51af52fa3 100644 ---- a/iconv/Versions -+++ b/iconv/Versions -@@ -6,7 +6,9 @@ libc { - GLIBC_PRIVATE { - # functions shared with iconv program - __gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db; -- __gconv_open; __gconv_create_spec; -+ -+ # functions used elsewhere in glibc -+ __gconv_open; __gconv_create_spec; __gconv_destroy_spec; - - # function used by the gconv modules - __gconv_transliterate; -diff --git a/iconv/gconv_charset.c b/iconv/gconv_charset.c -index 6ccd0773cc..4ba0aa99f5 100644 ---- a/iconv/gconv_charset.c -+++ b/iconv/gconv_charset.c -@@ -216,3 +216,13 @@ out: - return ret; - } - libc_hidden_def (__gconv_create_spec) -+ -+ -+void -+__gconv_destroy_spec (struct gconv_spec *conv_spec) -+{ -+ free (conv_spec->fromcode); -+ free (conv_spec->tocode); -+ return; -+} -+libc_hidden_def (__gconv_destroy_spec) -diff --git a/iconv/gconv_charset.h b/iconv/gconv_charset.h -index b39b09aea1..e9c122cf7e 100644 ---- a/iconv/gconv_charset.h -+++ b/iconv/gconv_charset.h -@@ -48,33 +48,6 @@ - #define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE" - - --/* This function accepts the charset names of the source and destination of the -- conversion and populates *conv_spec with an equivalent conversion -- specification that may later be used by __gconv_open. The charset names -- might contain options in the form of suffixes that alter the conversion, -- e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring -- and truncating any suffix options in fromcode, and processing and truncating -- any suffix options in tocode. Supported suffix options ("TRANSLIT" or -- "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec -- to be set to true. Unrecognized suffix options are silently discarded. If -- the function succeeds, it returns conv_spec back to the caller. It returns -- NULL upon failure. */ --struct gconv_spec * --__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, -- const char *tocode); --libc_hidden_proto (__gconv_create_spec) -- -- --/* This function frees all heap memory allocated by __gconv_create_spec. */ --static void __attribute__ ((unused)) --gconv_destroy_spec (struct gconv_spec *conv_spec) --{ -- free (conv_spec->fromcode); -- free (conv_spec->tocode); -- return; --} -- -- - /* This function copies in-order, characters from the source 's' that are - either alpha-numeric or one in one of these: "_-.,:/" - into the destination - 'wp' while dropping all other characters. In the process, it converts all -diff --git a/iconv/gconv_int.h b/iconv/gconv_int.h -index e86938dae7..f721ce30ff 100644 ---- a/iconv/gconv_int.h -+++ b/iconv/gconv_int.h -@@ -152,6 +152,27 @@ extern int __gconv_open (struct gconv_spec *conv_spec, - __gconv_t *handle, int flags); - libc_hidden_proto (__gconv_open) - -+/* This function accepts the charset names of the source and destination of the -+ conversion and populates *conv_spec with an equivalent conversion -+ specification that may later be used by __gconv_open. The charset names -+ might contain options in the form of suffixes that alter the conversion, -+ e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring -+ and truncating any suffix options in fromcode, and processing and truncating -+ any suffix options in tocode. Supported suffix options ("TRANSLIT" or -+ "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec -+ to be set to true. Unrecognized suffix options are silently discarded. If -+ the function succeeds, it returns conv_spec back to the caller. It returns -+ NULL upon failure. */ -+extern struct gconv_spec * -+__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, -+ const char *tocode); -+libc_hidden_proto (__gconv_create_spec) -+ -+/* This function frees all heap memory allocated by __gconv_create_spec. */ -+extern void -+__gconv_destroy_spec (struct gconv_spec *conv_spec); -+libc_hidden_proto (__gconv_destroy_spec) -+ - /* Free resources associated with transformation descriptor CD. */ - extern int __gconv_close (__gconv_t cd) - attribute_hidden; -diff --git a/iconv/iconv_open.c b/iconv/iconv_open.c -index dd54bc12e0..5b30055c04 100644 ---- a/iconv/iconv_open.c -+++ b/iconv/iconv_open.c -@@ -39,7 +39,7 @@ iconv_open (const char *tocode, const char *fromcode) - - int res = __gconv_open (&conv_spec, &cd, 0); - -- gconv_destroy_spec (&conv_spec); -+ __gconv_destroy_spec (&conv_spec); - - if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK) - { -diff --git a/iconv/iconv_prog.c b/iconv/iconv_prog.c -index b4334faa57..d59979759c 100644 ---- a/iconv/iconv_prog.c -+++ b/iconv/iconv_prog.c -@@ -184,7 +184,7 @@ main (int argc, char *argv[]) - /* Let's see whether we have these coded character sets. */ - res = __gconv_open (&conv_spec, &cd, 0); - -- gconv_destroy_spec (&conv_spec); -+ __gconv_destroy_spec (&conv_spec); - - if (res != __GCONV_OK) - { -diff --git a/iconv/tst-iconv_prog.sh b/iconv/tst-iconv_prog.sh -index 8298136b7f..d8db7b335c 100644 ---- a/iconv/tst-iconv_prog.sh -+++ b/iconv/tst-iconv_prog.sh -@@ -102,12 +102,16 @@ hangarray=( - "\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE" - "\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE" - "\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE" --# These are known hangs that are yet to be fixed: --# "\x00\x0f;-c;IBM1364;UTF-8" --# "\x00\x0f;-c;IBM1371;UTF-8" --# "\x00\x0f;-c;IBM1388;UTF-8" --# "\x00\x0f;-c;IBM1390;UTF-8" --# "\x00\x0f;-c;IBM1399;UTF-8" -+"\x00\x0f;-c;IBM1364;UTF-8" -+"\x0e\x0e;-c;IBM1364;UTF-8" -+"\x00\x0f;-c;IBM1371;UTF-8" -+"\x0e\x0e;-c;IBM1371;UTF-8" -+"\x00\x0f;-c;IBM1388;UTF-8" -+"\x0e\x0e;-c;IBM1388;UTF-8" -+"\x00\x0f;-c;IBM1390;UTF-8" -+"\x0e\x0e;-c;IBM1390;UTF-8" -+"\x00\x0f;-c;IBM1399;UTF-8" -+"\x0e\x0e;-c;IBM1399;UTF-8" - "\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE" - "\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE" - "\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE" -diff --git a/iconvdata/Makefile b/iconvdata/Makefile -index 4ec2741cdc..b67b4feeb4 100644 ---- a/iconvdata/Makefile -+++ b/iconvdata/Makefile -@@ -1,4 +1,5 @@ - # Copyright (C) 1997-2020 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 -@@ -73,7 +74,8 @@ modules.so := $(addsuffix .so, $(modules)) - 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-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \ -+ bug-iconv13 bug-iconv14 bug-iconv15 - ifeq ($(have-thread-library),yes) - tests += bug-iconv3 - endif -@@ -321,6 +323,10 @@ $(objpfx)bug-iconv10.out: $(objpfx)gconv-modules \ - $(addprefix $(objpfx),$(modules.so)) - $(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \ - $(addprefix $(objpfx),$(modules.so)) -+$(objpfx)bug-iconv14.out: $(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 $(objpfx)gconv-modules \ - $(addprefix $(objpfx),$(modules.so)) \ -diff --git a/iconvdata/bug-iconv13.c b/iconvdata/bug-iconv13.c -new file mode 100644 -index 0000000000..87aaff398e ---- /dev/null -+++ b/iconvdata/bug-iconv13.c -@@ -0,0 +1,53 @@ -+/* bug 24973: Test EUC-KR module -+ Copyright (C) 2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <errno.h> -+#include <iconv.h> -+#include <stdio.h> -+#include <support/check.h> -+ -+static int -+do_test (void) -+{ -+ iconv_t cd = iconv_open ("UTF-8//IGNORE", "EUC-KR"); -+ TEST_VERIFY_EXIT (cd != (iconv_t) -1); -+ -+ /* 0xfe (->0x7e : row 94) and 0xc9 (->0x49 : row 41) are user-defined -+ areas, which are not allowed and should be skipped over due to -+ //IGNORE. The trailing 0xfe also is an incomplete sequence, which -+ should be checked first. */ -+ char input[4] = { '\xc9', '\xa1', '\0', '\xfe' }; -+ char *inptr = input; -+ size_t insize = sizeof (input); -+ char output[4]; -+ char *outptr = output; -+ size_t outsize = sizeof (output); -+ -+ /* This used to crash due to buffer overrun. */ -+ TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == (size_t) -1); -+ TEST_VERIFY (errno == EINVAL); -+ /* The conversion should produce one character, the converted null -+ character. */ -+ TEST_VERIFY (sizeof (output) - outsize == 1); -+ -+ TEST_VERIFY_EXIT (iconv_close (cd) != -1); -+ -+ return 0; -+} -+ -+#include <support/test-driver.c> -diff --git a/iconvdata/bug-iconv14.c b/iconvdata/bug-iconv14.c -new file mode 100644 -index 0000000000..902f140fa9 ---- /dev/null -+++ b/iconvdata/bug-iconv14.c -@@ -0,0 +1,127 @@ -+/* Assertion in ISO-2022-JP-3 due to two-character sequence (bug 27256). -+ 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 -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <iconv.h> -+#include <string.h> -+#include <errno.h> -+#include <support/check.h> -+ -+/* Use an escape sequence to return to the initial state. */ -+static void -+with_escape_sequence (void) -+{ -+ iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3"); -+ TEST_VERIFY_EXIT (c != (iconv_t) -1); -+ -+ char in[] = "\e$(O+D\e(B"; -+ char *inbuf = in; -+ size_t inleft = strlen (in); -+ char out[3]; /* Space for one output character. */ -+ char *outbuf; -+ size_t outleft; -+ -+ outbuf = out; -+ outleft = sizeof (out); -+ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1); -+ TEST_COMPARE (errno, E2BIG); -+ TEST_COMPARE (inleft, 3); -+ TEST_COMPARE (inbuf - in, strlen (in) - 3); -+ TEST_COMPARE (outleft, sizeof (out) - 2); -+ TEST_COMPARE (outbuf - out, 2); -+ TEST_COMPARE (out[0] & 0xff, 0xc3); -+ TEST_COMPARE (out[1] & 0xff, 0xa6); -+ -+ /* Return to the initial shift state, producing the pending -+ character. */ -+ outbuf = out; -+ outleft = sizeof (out); -+ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), 0); -+ TEST_COMPARE (inleft, 0); -+ TEST_COMPARE (inbuf - in, strlen (in)); -+ TEST_COMPARE (outleft, sizeof (out) - 2); -+ TEST_COMPARE (outbuf - out, 2); -+ TEST_COMPARE (out[0] & 0xff, 0xcc); -+ TEST_COMPARE (out[1] & 0xff, 0x80); -+ -+ /* Nothing should be flushed the second time. */ -+ outbuf = out; -+ outleft = sizeof (out); -+ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); -+ TEST_COMPARE (outleft, sizeof (out)); -+ TEST_COMPARE (outbuf - out, 0); -+ TEST_COMPARE (out[0] & 0xff, 0xcc); -+ TEST_COMPARE (out[1] & 0xff, 0x80); -+ -+ TEST_COMPARE (iconv_close (c), 0); -+} -+ -+/* Use an explicit flush to return to the initial state. */ -+static void -+with_flush (void) -+{ -+ iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3"); -+ TEST_VERIFY_EXIT (c != (iconv_t) -1); -+ -+ char in[] = "\e$(O+D"; -+ char *inbuf = in; -+ size_t inleft = strlen (in); -+ char out[3]; /* Space for one output character. */ -+ char *outbuf; -+ size_t outleft; -+ -+ outbuf = out; -+ outleft = sizeof (out); -+ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1); -+ TEST_COMPARE (errno, E2BIG); -+ TEST_COMPARE (inleft, 0); -+ TEST_COMPARE (inbuf - in, strlen (in)); -+ TEST_COMPARE (outleft, sizeof (out) - 2); -+ TEST_COMPARE (outbuf - out, 2); -+ TEST_COMPARE (out[0] & 0xff, 0xc3); -+ TEST_COMPARE (out[1] & 0xff, 0xa6); -+ -+ /* Flush the pending character. */ -+ outbuf = out; -+ outleft = sizeof (out); -+ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); -+ TEST_COMPARE (outleft, sizeof (out) - 2); -+ TEST_COMPARE (outbuf - out, 2); -+ TEST_COMPARE (out[0] & 0xff, 0xcc); -+ TEST_COMPARE (out[1] & 0xff, 0x80); -+ -+ /* Nothing should be flushed the second time. */ -+ outbuf = out; -+ outleft = sizeof (out); -+ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); -+ TEST_COMPARE (outleft, sizeof (out)); -+ TEST_COMPARE (outbuf - out, 0); -+ TEST_COMPARE (out[0] & 0xff, 0xcc); -+ TEST_COMPARE (out[1] & 0xff, 0x80); -+ -+ TEST_COMPARE (iconv_close (c), 0); -+} -+ -+static int -+do_test (void) -+{ -+ with_escape_sequence (); -+ with_flush (); -+ return 0; -+} -+ -+#include <support/test-driver.c> -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 -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <stddef.h> -+#include <iconv.h> -+#include <support/check.h> -+ -+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 <support/test-driver.c> -diff --git a/iconvdata/euc-kr.c b/iconvdata/euc-kr.c -index b0d56cf3ee..1045bae926 100644 ---- a/iconvdata/euc-kr.c -+++ b/iconvdata/euc-kr.c -@@ -80,11 +80,7 @@ euckr_from_ucs4 (uint32_t ch, unsigned char *cp) - \ - if (ch <= 0x9f) \ - ++inptr; \ -- /* 0xfe(->0x7e : row 94) and 0xc9(->0x59 : row 41) are \ -- user-defined areas. */ \ -- else if (__builtin_expect (ch == 0xa0, 0) \ -- || __builtin_expect (ch > 0xfe, 0) \ -- || __builtin_expect (ch == 0xc9, 0)) \ -+ else if (__glibc_unlikely (ch == 0xa0)) \ - { \ - /* This is illegal. */ \ - STANDARD_FROM_LOOP_ERR_HANDLER (1); \ -diff --git a/iconvdata/ibm1364.c b/iconvdata/ibm1364.c -index 49e7267ab4..521f0825b7 100644 ---- a/iconvdata/ibm1364.c -+++ b/iconvdata/ibm1364.c -@@ -158,24 +158,14 @@ enum - \ - if (__builtin_expect (ch, 0) == SO) \ - { \ -- /* Shift OUT, change to DBCS converter. */ \ -- if (curcs == db) \ -- { \ -- result = __GCONV_ILLEGAL_INPUT; \ -- break; \ -- } \ -+ /* Shift OUT, change to DBCS converter (redundant escape okay). */ \ - curcs = db; \ - ++inptr; \ - continue; \ - } \ - if (__builtin_expect (ch, 0) == SI) \ - { \ -- /* Shift IN, change to SBCS converter. */ \ -- if (curcs == sb) \ -- { \ -- result = __GCONV_ILLEGAL_INPUT; \ -- break; \ -- } \ -+ /* Shift IN, change to SBCS converter (redundant escape okay). */ \ - curcs = sb; \ - ++inptr; \ - continue; \ -diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c -index 8c3b7e627e..c7b470db61 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-2020 Free Software Foundation, Inc. -+ Copyright (C) The GNU Toolchain Authors. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998, - and Bruno Haible <bruno@clisp.org>, 2002. -@@ -67,10 +68,15 @@ enum - CURRENT_SEL_MASK = 7 << 3 - }; - --/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state -- also contains the last two bytes to be output, shifted by 6 bits, and a -- one-bit indicator whether they must be preceded by the shift sequence, -- in bit 22. */ -+/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the -+ state also contains the last two bytes to be output, shifted by 6 -+ bits, and a one-bit indicator whether they must be preceded by the -+ shift sequence, in bit 22. During ISO-2022-JP-3 to UCS-4 -+ conversion, COUNT may also contain a non-zero pending wide -+ character, shifted by six bits. This happens for certain inputs in -+ JISX0213_1_2004_set and JISX0213_2_set if the second wide character -+ in a combining sequence cannot be written because the buffer is -+ full. */ - - /* Since this is a stateful encoding we have to provide code which resets - the output state to the initial state. This has to be done during the -@@ -80,10 +86,27 @@ enum - { \ - if (FROM_DIRECTION) \ - { \ -- /* It's easy, we don't have to emit anything, we just reset the \ -- state for the input. */ \ -- data->__statep->__count &= 7; \ -- data->__statep->__count |= ASCII_set; \ -+ uint32_t ch = data->__statep->__count >> 6; \ -+ \ -+ if (__glibc_unlikely (ch != 0)) \ -+ { \ -+ 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 \ -+ { \ -+ data->__statep->__count &= 7; \ -+ data->__statep->__count |= ASCII_set; \ -+ } \ - } \ - else \ - { \ -@@ -151,7 +174,21 @@ enum - #define LOOPFCT FROM_LOOP - #define BODY \ - { \ -- uint32_t ch = *inptr; \ -+ uint32_t ch; \ -+ \ -+ /* Output any pending character. */ \ -+ ch = set >> 6; \ -+ if (__glibc_unlikely (ch != 0)) \ -+ { \ -+ put32 (outptr, ch); \ -+ outptr += 4; \ -+ /* Remove the pending character, but preserve state bits. */ \ -+ set &= (1 << 6) - 1; \ -+ continue; \ -+ } \ -+ \ -+ /* Otherwise read the next input byte. */ \ -+ ch = *inptr; \ - \ - /* Recognize escape sequences. */ \ - if (__glibc_unlikely (ch == ESC)) \ -@@ -297,21 +334,25 @@ enum - uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0]; \ - uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1]; \ - \ -+ inptr += 2; \ -+ \ -+ put32 (outptr, u1); \ -+ outptr += 4; \ -+ \ - /* See whether we have room for two characters. */ \ -- if (outptr + 8 <= outend) \ -+ if (outptr + 4 <= outend) \ - { \ -- inptr += 2; \ -- put32 (outptr, u1); \ -- outptr += 4; \ - put32 (outptr, u2); \ - outptr += 4; \ - continue; \ - } \ -- else \ -- { \ -- result = __GCONV_FULL_OUTPUT; \ -- break; \ -- } \ -+ \ -+ /* Otherwise store only the first character now, and \ -+ put the second one into the queue. */ \ -+ set |= u2 << 6; \ -+ /* Tell the caller why we terminate the loop. */ \ -+ result = __GCONV_FULL_OUTPUT; \ -+ break; \ - } \ - \ - inptr += 2; \ -diff --git a/iconvdata/ksc5601.h b/iconvdata/ksc5601.h -index d3eb3a4ff8..f5cdc72797 100644 ---- a/iconvdata/ksc5601.h -+++ b/iconvdata/ksc5601.h -@@ -50,15 +50,15 @@ ksc5601_to_ucs4 (const unsigned char **s, size_t avail, unsigned char offset) - unsigned char ch2; - int idx; - -+ if (avail < 2) -+ return 0; -+ - /* row 94(0x7e) and row 41(0x49) are user-defined area in KS C 5601 */ - - if (ch < offset || (ch - offset) <= 0x20 || (ch - offset) >= 0x7e - || (ch - offset) == 0x49) - return __UNKNOWN_10646_CHAR; - -- if (avail < 2) -- return 0; -- - ch2 = (*s)[1]; - if (ch2 < offset || (ch2 - offset) <= 0x20 || (ch2 - offset) >= 0x7f) - return __UNKNOWN_10646_CHAR; -diff --git a/intl/dcigettext.c b/intl/dcigettext.c -index 2e7c662bc7..bd332e71da 100644 ---- a/intl/dcigettext.c -+++ b/intl/dcigettext.c -@@ -1120,15 +1120,18 @@ _nl_find_msg (struct loaded_l10nfile *domain_file, - - # ifdef _LIBC - -- struct gconv_spec conv_spec -- = { .fromcode = norm_add_slashes (charset, ""), -- .tocode = norm_add_slashes (outcharset, ""), -- /* We always want to use transliteration. */ -- .translit = true, -- .ignore = false -- }; -+ struct gconv_spec conv_spec; -+ -+ __gconv_create_spec (&conv_spec, charset, outcharset); -+ -+ /* We always want to use transliteration. */ -+ conv_spec.translit = true; -+ - int r = __gconv_open (&conv_spec, &convd->conv, - GCONV_AVOID_NOCONV); -+ -+ __gconv_destroy_spec (&conv_spec); -+ - if (__builtin_expect (r != __GCONV_OK, 0)) - { - /* If the output encoding is the same there is -diff --git a/intl/tst-codeset.c b/intl/tst-codeset.c -index fd70432eca..e9f6e5e09f 100644 ---- a/intl/tst-codeset.c -+++ b/intl/tst-codeset.c -@@ -22,13 +22,11 @@ - #include <stdio.h> - #include <stdlib.h> - #include <string.h> -+#include <support/check.h> - - static int - do_test (void) - { -- char *s; -- int result = 0; -- - unsetenv ("LANGUAGE"); - unsetenv ("OUTPUT_CHARSET"); - setlocale (LC_ALL, "de_DE.ISO-8859-1"); -@@ -36,25 +34,21 @@ do_test (void) - bindtextdomain ("codeset", OBJPFX "domaindir"); - - /* Here we expect output in ISO-8859-1. */ -- s = gettext ("cheese"); -- if (strcmp (s, "K\344se")) -- { -- printf ("call 1 returned: %s\n", s); -- result = 1; -- } -+ TEST_COMPARE_STRING (gettext ("cheese"), "K\344se"); - -+ /* Here we expect output in UTF-8. */ - bind_textdomain_codeset ("codeset", "UTF-8"); -+ TEST_COMPARE_STRING (gettext ("cheese"), "K\303\244se"); - -- /* Here we expect output in UTF-8. */ -- s = gettext ("cheese"); -- if (strcmp (s, "K\303\244se")) -- { -- printf ("call 2 returned: %s\n", s); -- result = 1; -- } -- -- return result; -+ /* `a with umlaut' is transliterated to `ae'. */ -+ bind_textdomain_codeset ("codeset", "ASCII//TRANSLIT"); -+ TEST_COMPARE_STRING (gettext ("cheese"), "Kaese"); -+ -+ /* Transliteration also works by default even if not set. */ -+ bind_textdomain_codeset ("codeset", "ASCII"); -+ TEST_COMPARE_STRING (gettext ("cheese"), "Kaese"); -+ -+ return 0; - } - --#define TEST_FUNCTION do_test () --#include "../test-skeleton.c" -+#include <support/test-driver.c> -diff --git a/malloc/Makefile b/malloc/Makefile -index e22cbde22d..5093e8730e 100644 ---- a/malloc/Makefile -+++ b/malloc/Makefile -@@ -62,6 +62,16 @@ endif - tests += $(tests-static) - test-srcs = tst-mtrace - -+# These tests either are run with MALLOC_CHECK_=3 by default or do not work -+# with MALLOC_CHECK_=3 because they expect a specific failure. -+tests-exclude-mcheck = tst-mcheck tst-malloc-usable \ -+ tst-interpose-nothread tst-interpose-static-nothread \ -+ tst-interpose-static-thread tst-malloc-too-large \ -+ tst-mxfast tst-safe-linking -+ -+# Run all tests with MALLOC_CHECK_=3 -+tests-mcheck = $(filter-out $(tests-exclude-mcheck),$(tests)) -+ - routines = malloc morecore mcheck mtrace obstack reallocarray \ - scratch_buffer_grow scratch_buffer_grow_preserve \ - scratch_buffer_set_array_size \ -@@ -100,6 +110,11 @@ $(objpfx)tst-malloc-thread-exit: $(shared-thread-library) - $(objpfx)tst-malloc-thread-fail: $(shared-thread-library) - $(objpfx)tst-malloc-fork-deadlock: $(shared-thread-library) - $(objpfx)tst-malloc-stats-cancellation: $(shared-thread-library) -+$(objpfx)tst-malloc-backtrace-mcheck: $(shared-thread-library) -+$(objpfx)tst-malloc-thread-exit-mcheck: $(shared-thread-library) -+$(objpfx)tst-malloc-thread-fail-mcheck: $(shared-thread-library) -+$(objpfx)tst-malloc-fork-deadlock-mcheck: $(shared-thread-library) -+$(objpfx)tst-malloc-stats-cancellation-mcheck: $(shared-thread-library) - - # Export the __malloc_initialize_hook variable to libc.so. - LDFLAGS-tst-mallocstate = -rdynamic -@@ -239,6 +254,8 @@ $(tests:%=$(objpfx)%.o): CPPFLAGS += -DTEST_NO_MALLOPT - $(objpfx)tst-interpose-nothread: $(objpfx)tst-interpose-aux-nothread.o - $(objpfx)tst-interpose-thread: \ - $(objpfx)tst-interpose-aux-thread.o $(shared-thread-library) -+$(objpfx)tst-interpose-thread-mcheck: \ -+ $(objpfx)tst-interpose-aux-thread.o $(shared-thread-library) - $(objpfx)tst-interpose-static-nothread: $(objpfx)tst-interpose-aux-nothread.o - $(objpfx)tst-interpose-static-thread: \ - $(objpfx)tst-interpose-aux-thread.o $(static-thread-library) -@@ -256,3 +273,6 @@ $(objpfx)tst-dynarray-fail-mem.out: $(objpfx)tst-dynarray-fail.out - $(objpfx)tst-malloc-tcache-leak: $(shared-thread-library) - $(objpfx)tst-malloc_info: $(shared-thread-library) - $(objpfx)tst-mallocfork2: $(shared-thread-library) -+$(objpfx)tst-malloc-tcache-leak-mcheck: $(shared-thread-library) -+$(objpfx)tst-malloc_info-mcheck: $(shared-thread-library) -+$(objpfx)tst-mallocfork2-mcheck: $(shared-thread-library) -diff --git a/manual/tunables.texi b/manual/tunables.texi -index 23ef0d40e7..d72d7a5ec0 100644 ---- a/manual/tunables.texi -+++ b/manual/tunables.texi -@@ -432,7 +432,11 @@ set shared cache size in bytes for use in memory and string routines. - - @deftp Tunable glibc.cpu.x86_non_temporal_threshold - The @code{glibc.cpu.x86_non_temporal_threshold} tunable allows the user --to set threshold in bytes for non temporal store. -+to set threshold in bytes for non temporal store. Non temporal stores -+give a hint to the hardware to move data directly to memory without -+displacing other data from the cache. This tunable is used by some -+platforms to determine when to use non temporal stores in operations -+like memmove and memcpy. - - This tunable is specific to i386 and x86-64. - @end deftp -diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h -index 19d9cc5cfe..38221d0b2a 100644 ---- a/misc/sys/cdefs.h -+++ b/misc/sys/cdefs.h -@@ -124,13 +124,10 @@ - #define __bos0(ptr) __builtin_object_size (ptr, 0) - - #if __GNUC_PREREQ (4,3) --# define __warndecl(name, msg) \ -- extern void name (void) __attribute__((__warning__ (msg))) - # define __warnattr(msg) __attribute__((__warning__ (msg))) - # define __errordecl(name, msg) \ - extern void name (void) __attribute__((__error__ (msg))) - #else --# define __warndecl(name, msg) extern void name (void) - # define __warnattr(msg) - # define __errordecl(name, msg) extern void name (void) - #endif -diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c -index 2cba3da38c..c217cda608 100644 ---- a/nptl/pthread_create.c -+++ b/nptl/pthread_create.c -@@ -416,8 +416,6 @@ START_THREAD_DEFN - 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); -@@ -427,6 +425,8 @@ START_THREAD_DEFN - /* Store the new cleanup handler info. */ - THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf); - -+ __libc_signal_restore_set (&pd->sigmask); -+ - /* We are either in (a) or (b), and in either case we either own - PD already (2) or are about to own PD (1), and so our only - restriction would be that we can't free PD until we know we -diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c -index 88c69d1e9c..381aa721ef 100644 ---- a/nscd/netgroupcache.c -+++ b/nscd/netgroupcache.c -@@ -248,7 +248,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - : NULL); - ndomain = (ndomain ? newbuf + ndomaindiff - : NULL); -- buffer = newbuf; -+ *tofreep = buffer = newbuf; - } - - nhost = memcpy (buffer + bufused, -@@ -319,7 +319,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE) - { - buflen *= 2; -- buffer = xrealloc (buffer, buflen); -+ *tofreep = buffer = xrealloc (buffer, buflen); - } - else if (status == NSS_STATUS_RETURN - || status == NSS_STATUS_NOTFOUND -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/bits/unistd.h b/posix/bits/unistd.h -index 725a83eb0d..7e5bb6fb1e 100644 ---- a/posix/bits/unistd.h -+++ b/posix/bits/unistd.h -@@ -193,10 +193,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/unistd.h b/posix/unistd.h -index 32b8161619..acf9ee7e79 100644 ---- a/posix/unistd.h -+++ b/posix/unistd.h -@@ -517,8 +517,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. -@@ -831,7 +830,7 @@ extern int symlinkat (const char *__from, int __tofd, - /* Like readlink but a relative PATH is interpreted relative to FD. */ - extern ssize_t readlinkat (int __fd, const char *__restrict __path, - char *__restrict __buf, size_t __len) -- __THROW __nonnull ((2, 3)) __wur __attr_access ((__read_only__, 3, 4)); -+ __THROW __nonnull ((2, 3)) __wur __attr_access ((__write_only__, 3, 4)); - #endif - - /* Remove the link NAME. */ -diff --git a/posix/wordexp-test.c b/posix/wordexp-test.c -index ed1b22308e..cb3f989cba 100644 ---- a/posix/wordexp-test.c -+++ b/posix/wordexp-test.c -@@ -183,6 +183,7 @@ struct test_case_struct - { 0, NULL, "$var", 0, 0, { NULL, }, IFS }, - { 0, NULL, "\"\\n\"", 0, 1, { "\\n", }, IFS }, - { 0, NULL, "", 0, 0, { NULL, }, IFS }, -+ { 0, NULL, "${1234567890123456789012}", 0, 0, { NULL, }, IFS }, - - /* Flags not already covered (testit() has special handling for these) */ - { 0, NULL, "one two", WRDE_DOOFFS, 2, { "one", "two", }, IFS }, -diff --git a/posix/wordexp.c b/posix/wordexp.c -index e082d94895..56289503a1 100644 ---- a/posix/wordexp.c -+++ b/posix/wordexp.c -@@ -1399,7 +1399,7 @@ envsubst: - /* Is it a numeric parameter? */ - else if (isdigit (env[0])) - { -- int n = atoi (env); -+ unsigned long n = strtoul (env, NULL, 10); - - if (n >= __libc_argc) - /* Substitute NULL. */ -diff --git a/resolv/Makefile b/resolv/Makefile -index b61c0c3e0c..dbd8f8bf4f 100644 ---- a/resolv/Makefile -+++ b/resolv/Makefile -@@ -61,6 +61,11 @@ tests += \ - tst-resolv-search \ - tst-resolv-trailing \ - -+# This test calls __res_context_send directly, which is not exported -+# from libresolv. -+tests-internal += tst-resolv-txnid-collision -+tests-static += tst-resolv-txnid-collision -+ - # These tests need libdl. - ifeq (yes,$(build-shared)) - tests += \ -@@ -191,6 +196,8 @@ $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-threads: \ - $(libdl) $(objpfx)libresolv.so $(shared-thread-library) -+$(objpfx)tst-resolv-txnid-collision: $(objpfx)libresolv.a \ -+ $(static-thread-library) - $(objpfx)tst-resolv-canonname: \ - $(libdl) $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-trustad: $(objpfx)libresolv.so $(shared-thread-library) -diff --git a/resolv/res_send.c b/resolv/res_send.c -index 7e5fec6646..70e5066031 100644 ---- a/resolv/res_send.c -+++ b/resolv/res_send.c -@@ -1342,15 +1342,6 @@ send_dg(res_state statp, - *terrno = EMSGSIZE; - return close_and_return_error (statp, resplen2); - } -- if ((recvresp1 || hp->id != anhp->id) -- && (recvresp2 || hp2->id != anhp->id)) { -- /* -- * response from old query, ignore it. -- * XXX - potential security hazard could -- * be detected here. -- */ -- goto wait; -- } - - /* Paranoia check. Due to the connected UDP socket, - the kernel has already filtered invalid addresses -@@ -1360,15 +1351,24 @@ send_dg(res_state statp, - - /* Check for the correct header layout and a matching - question. */ -- if ((recvresp1 || !res_queriesmatch(buf, buf + buflen, -- *thisansp, -- *thisansp -- + *thisanssizp)) -- && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2, -- *thisansp, -- *thisansp -- + *thisanssizp))) -- goto wait; -+ int matching_query = 0; /* Default to no matching query. */ -+ if (!recvresp1 -+ && anhp->id == hp->id -+ && res_queriesmatch (buf, buf + buflen, -+ *thisansp, *thisansp + *thisanssizp)) -+ matching_query = 1; -+ if (!recvresp2 -+ && anhp->id == hp2->id -+ && res_queriesmatch (buf2, buf2 + buflen2, -+ *thisansp, *thisansp + *thisanssizp)) -+ matching_query = 2; -+ if (matching_query == 0) -+ /* Spurious UDP packet. Drop it and continue -+ waiting. */ -+ { -+ need_recompute = 1; -+ goto wait; -+ } - - if (anhp->rcode == SERVFAIL || - anhp->rcode == NOTIMP || -@@ -1383,7 +1383,7 @@ send_dg(res_state statp, - /* No data from the first reply. */ - resplen = 0; - /* We are waiting for a possible second reply. */ -- if (hp->id == anhp->id) -+ if (matching_query == 1) - recvresp1 = 1; - else - recvresp2 = 1; -@@ -1414,7 +1414,7 @@ send_dg(res_state statp, - return (1); - } - /* Mark which reply we received. */ -- if (recvresp1 == 0 && hp->id == anhp->id) -+ if (matching_query == 1) - recvresp1 = 1; - else - recvresp2 = 1; -diff --git a/resolv/tst-resolv-txnid-collision.c b/resolv/tst-resolv-txnid-collision.c -new file mode 100644 -index 0000000000..189b76f126 ---- /dev/null -+++ b/resolv/tst-resolv-txnid-collision.c -@@ -0,0 +1,334 @@ -+/* Test parallel queries with transaction ID collisions. -+ Copyright (C) 2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <arpa/nameser.h> -+#include <array_length.h> -+#include <resolv-internal.h> -+#include <resolv_context.h> -+#include <stdbool.h> -+#include <stdio.h> -+#include <string.h> -+#include <support/check.h> -+#include <support/check_nss.h> -+#include <support/resolv_test.h> -+#include <support/support.h> -+#include <support/test-driver.h> -+ -+/* Result of parsing a DNS question name. -+ -+ A question name has the form reorder-N-M-rcode-C.example.net, where -+ N and M are either 0 and 1, corresponding to the reorder member, -+ and C is a number that will be stored in the rcode field. -+ -+ Also see parse_qname below. */ -+struct parsed_qname -+{ -+ /* The DNS response code requested from the first server. The -+ second server always responds with RCODE zero. */ -+ int rcode; -+ -+ /* Indicates whether to perform reordering in the responses from the -+ respective server. */ -+ bool reorder[2]; -+}; -+ -+/* Fills *PARSED based on QNAME. */ -+static void -+parse_qname (struct parsed_qname *parsed, const char *qname) -+{ -+ int reorder0; -+ int reorder1; -+ int rcode; -+ char *suffix; -+ if (sscanf (qname, "reorder-%d-%d.rcode-%d.%ms", -+ &reorder0, &reorder1, &rcode, &suffix) == 4) -+ { -+ if (reorder0 != 0) -+ TEST_COMPARE (reorder0, 1); -+ if (reorder1 != 0) -+ TEST_COMPARE (reorder1, 1); -+ TEST_VERIFY (rcode >= 0 && rcode <= 15); -+ TEST_COMPARE_STRING (suffix, "example.net"); -+ free (suffix); -+ -+ parsed->rcode = rcode; -+ parsed->reorder[0] = reorder0; -+ parsed->reorder[1] = reorder1; -+ } -+ else -+ FAIL_EXIT1 ("unexpected query: %s", qname); -+} -+ -+/* Used to construct a response. The first server responds with an -+ error, the second server succeeds. */ -+static void -+build_response (const struct resolv_response_context *ctx, -+ struct resolv_response_builder *b, -+ const char *qname, uint16_t qclass, uint16_t qtype) -+{ -+ struct parsed_qname parsed; -+ parse_qname (&parsed, qname); -+ -+ switch (ctx->server_index) -+ { -+ case 0: -+ { -+ struct resolv_response_flags flags = { 0 }; -+ if (parsed.rcode == 0) -+ /* Simulate a delegation in case a NODATA (RCODE zero) -+ response is requested. */ -+ flags.clear_ra = true; -+ else -+ flags.rcode = parsed.rcode; -+ -+ resolv_response_init (b, flags); -+ resolv_response_add_question (b, qname, qclass, qtype); -+ } -+ break; -+ -+ case 1: -+ { -+ struct resolv_response_flags flags = { 0, }; -+ resolv_response_init (b, flags); -+ resolv_response_add_question (b, qname, qclass, qtype); -+ -+ resolv_response_section (b, ns_s_an); -+ resolv_response_open_record (b, qname, qclass, qtype, 0); -+ if (qtype == T_A) -+ { -+ char ipv4[4] = { 192, 0, 2, 1 }; -+ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); -+ } -+ else -+ { -+ char ipv6[16] -+ = { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; -+ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); -+ } -+ resolv_response_close_record (b); -+ } -+ break; -+ } -+} -+ -+/* Used to reorder responses. */ -+struct resolv_response_context *previous_query; -+ -+/* Used to keep track of the queries received. */ -+static int previous_server_index = -1; -+static uint16_t previous_qtype; -+ -+/* For each server, buffer the first query and then send both answers -+ to the second query, reordered if requested. */ -+static void -+response (const struct resolv_response_context *ctx, -+ struct resolv_response_builder *b, -+ const char *qname, uint16_t qclass, uint16_t qtype) -+{ -+ TEST_VERIFY (qtype == T_A || qtype == T_AAAA); -+ if (ctx->server_index != 0) -+ TEST_COMPARE (ctx->server_index, 1); -+ -+ struct parsed_qname parsed; -+ parse_qname (&parsed, qname); -+ -+ if (previous_query == NULL) -+ { -+ /* No buffered query. Record this query and do not send a -+ response. */ -+ TEST_COMPARE (previous_qtype, 0); -+ previous_query = resolv_response_context_duplicate (ctx); -+ previous_qtype = qtype; -+ resolv_response_drop (b); -+ previous_server_index = ctx->server_index; -+ -+ if (test_verbose) -+ printf ("info: buffering first query for: %s\n", qname); -+ } -+ else -+ { -+ TEST_VERIFY (previous_query != 0); -+ TEST_COMPARE (ctx->server_index, previous_server_index); -+ TEST_VERIFY (previous_qtype != qtype); /* Not a duplicate. */ -+ -+ /* If reordering, send a response for this query explicitly, and -+ then skip the implicit send. */ -+ if (parsed.reorder[ctx->server_index]) -+ { -+ if (test_verbose) -+ printf ("info: sending reordered second response for: %s\n", -+ qname); -+ build_response (ctx, b, qname, qclass, qtype); -+ resolv_response_send_udp (ctx, b); -+ resolv_response_drop (b); -+ } -+ -+ /* Build a response for the previous query and send it, thus -+ reordering the two responses. */ -+ { -+ if (test_verbose) -+ printf ("info: sending first response for: %s\n", qname); -+ struct resolv_response_builder *btmp -+ = resolv_response_builder_allocate (previous_query->query_buffer, -+ previous_query->query_length); -+ build_response (ctx, btmp, qname, qclass, previous_qtype); -+ resolv_response_send_udp (ctx, btmp); -+ resolv_response_builder_free (btmp); -+ } -+ -+ /* If not reordering, send the reply as usual. */ -+ if (!parsed.reorder[ctx->server_index]) -+ { -+ if (test_verbose) -+ printf ("info: sending non-reordered second response for: %s\n", -+ qname); -+ build_response (ctx, b, qname, qclass, qtype); -+ } -+ -+ /* Unbuffer the response and prepare for the next query. */ -+ resolv_response_context_free (previous_query); -+ previous_query = NULL; -+ previous_qtype = 0; -+ previous_server_index = -1; -+ } -+} -+ -+/* Runs a query for QNAME and checks for the expected reply. See -+ struct parsed_qname for the expected format for QNAME. */ -+static void -+test_qname (const char *qname, int rcode) -+{ -+ struct resolv_context *ctx = __resolv_context_get (); -+ TEST_VERIFY_EXIT (ctx != NULL); -+ -+ unsigned char q1[512]; -+ int q1len = res_mkquery (QUERY, qname, C_IN, T_A, NULL, 0, NULL, -+ q1, sizeof (q1)); -+ TEST_VERIFY_EXIT (q1len > 12); -+ -+ unsigned char q2[512]; -+ int q2len = res_mkquery (QUERY, qname, C_IN, T_AAAA, NULL, 0, NULL, -+ q2, sizeof (q2)); -+ TEST_VERIFY_EXIT (q2len > 12); -+ -+ /* Produce a transaction ID collision. */ -+ memcpy (q2, q1, 2); -+ -+ unsigned char ans1[512]; -+ unsigned char *ans1p = ans1; -+ unsigned char *ans2p = NULL; -+ int nans2p = 0; -+ int resplen2 = 0; -+ int ans2p_malloced = 0; -+ -+ /* Perform a parallel A/AAAA query. */ -+ int resplen1 = __res_context_send (ctx, q1, q1len, q2, q2len, -+ ans1, sizeof (ans1), &ans1p, -+ &ans2p, &nans2p, -+ &resplen2, &ans2p_malloced); -+ -+ TEST_VERIFY (resplen1 > 12); -+ TEST_VERIFY (resplen2 > 12); -+ if (resplen1 <= 12 || resplen2 <= 12) -+ return; -+ -+ if (rcode == 1 || rcode == 3) -+ { -+ /* Format Error and Name Error responses does not trigger -+ switching to the next server. */ -+ TEST_COMPARE (ans1p[3] & 0x0f, rcode); -+ TEST_COMPARE (ans2p[3] & 0x0f, rcode); -+ return; -+ } -+ -+ /* The response should be successful. */ -+ TEST_COMPARE (ans1p[3] & 0x0f, 0); -+ TEST_COMPARE (ans2p[3] & 0x0f, 0); -+ -+ /* Due to bug 19691, the answer may not be in the slot matching the -+ query. Assume that the AAAA response is the longer one. */ -+ unsigned char *a_answer; -+ int a_answer_length; -+ unsigned char *aaaa_answer; -+ int aaaa_answer_length; -+ if (resplen2 > resplen1) -+ { -+ a_answer = ans1p; -+ a_answer_length = resplen1; -+ aaaa_answer = ans2p; -+ aaaa_answer_length = resplen2; -+ } -+ else -+ { -+ a_answer = ans2p; -+ a_answer_length = resplen2; -+ aaaa_answer = ans1p; -+ aaaa_answer_length = resplen1; -+ } -+ -+ { -+ char *expected = xasprintf ("name: %s\n" -+ "address: 192.0.2.1\n", -+ qname); -+ check_dns_packet (qname, a_answer, a_answer_length, expected); -+ free (expected); -+ } -+ { -+ char *expected = xasprintf ("name: %s\n" -+ "address: 2001:db8::1\n", -+ qname); -+ check_dns_packet (qname, aaaa_answer, aaaa_answer_length, expected); -+ free (expected); -+ } -+ -+ if (ans2p_malloced) -+ free (ans2p); -+ -+ __resolv_context_put (ctx); -+} -+ -+static int -+do_test (void) -+{ -+ struct resolv_test *aux = resolv_test_start -+ ((struct resolv_redirect_config) -+ { -+ .response_callback = response, -+ -+ /* The response callback use global state (the previous_* -+ variables), and query processing must therefore be -+ serialized. */ -+ .single_thread_udp = true, -+ }); -+ -+ for (int rcode = 0; rcode <= 5; ++rcode) -+ for (int do_reorder_0 = 0; do_reorder_0 < 2; ++do_reorder_0) -+ for (int do_reorder_1 = 0; do_reorder_1 < 2; ++do_reorder_1) -+ { -+ char *qname = xasprintf ("reorder-%d-%d.rcode-%d.example.net", -+ do_reorder_0, do_reorder_1, rcode); -+ test_qname (qname, rcode); -+ free (qname); -+ } -+ -+ resolv_test_end (aux); -+ -+ return 0; -+} -+ -+#include <support/test-driver.c> -diff --git a/rt/Makefile b/rt/Makefile -index dab5d62a57..93502cfaa7 100644 ---- a/rt/Makefile -+++ b/rt/Makefile -@@ -44,6 +44,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 -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <errno.h> -+#include <sys/types.h> -+#include <sys/stat.h> -+#include <fcntl.h> -+#include <unistd.h> -+#include <mqueue.h> -+#include <signal.h> -+#include <stdlib.h> -+#include <string.h> -+#include <support/check.h> -+ -+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 <support/test-driver.c> -diff --git a/stdio-common/Makefile b/stdio-common/Makefile -index 8475fd1f09..eff0c98d82 100644 ---- a/stdio-common/Makefile -+++ b/stdio-common/Makefile -@@ -69,7 +69,8 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ - tst-printf-bz25691 \ - tst-vfprintf-width-prec-alloc \ - tst-printf-fp-free \ -- tst-printf-fp-leak -+ tst-printf-fp-leak \ -+ test-strerr - - - test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble -diff --git a/stdio-common/errlist.c b/stdio-common/errlist.c -index d15f13a22a..2ecf121674 100644 ---- a/stdio-common/errlist.c -+++ b/stdio-common/errlist.c -@@ -20,9 +20,13 @@ - #include <libintl.h> - #include <array_length.h> - -+#ifndef ERR_MAP -+# define ERR_MAP(n) n -+#endif -+ - const char *const _sys_errlist_internal[] = - { --#define _S(n, str) [n] = str, -+#define _S(n, str) [ERR_MAP(n)] = str, - #include <errlist.h> - #undef _S - }; -@@ -41,20 +45,21 @@ static const union sys_errname_t - { - #define MSGSTRFIELD1(line) str##line - #define MSGSTRFIELD(line) MSGSTRFIELD1(line) --#define _S(n, str) char MSGSTRFIELD(__LINE__)[sizeof(str)]; -+#define _S(n, str) char MSGSTRFIELD(__LINE__)[sizeof(#n)]; - #include <errlist.h> - #undef _S - }; - char str[0]; - } _sys_errname = { { --#define _S(n, s) s, -+#define _S(n, s) #n, - #include <errlist.h> - #undef _S - } }; - - static const unsigned short _sys_errnameidx[] = - { --#define _S(n, s) [n] = offsetof(union sys_errname_t, MSGSTRFIELD(__LINE__)), -+#define _S(n, s) \ -+ [ERR_MAP(n)] = offsetof(union sys_errname_t, MSGSTRFIELD(__LINE__)), - #include <errlist.h> - #undef _S - }; -diff --git a/stdio-common/test-strerr.c b/stdio-common/test-strerr.c -index fded208118..d77b81d507 100644 ---- a/stdio-common/test-strerr.c -+++ b/stdio-common/test-strerr.c -@@ -18,46 +18,672 @@ - - #include <string.h> - #include <errno.h> --#include <array_length.h> - - #include <support/support.h> - #include <support/check.h> - --#define N_(name) name -- --static const char *const errlist[] = -- { --/* This file is auto-generated from errlist.def. */ --#include <errlist.h> -- }; -- --#define MSGSTR_T errname_t --#define MSGSTR errname --#define MSGIDX errnameidx --#include <errlist-name.h> --#undef MSGSTR --#undef MSGIDX -- - static int - do_test (void) - { -- TEST_VERIFY (strerrordesc_np (-1) == NULL); -- TEST_VERIFY (strerrordesc_np (array_length (errlist)) == NULL); -- for (size_t i = 0; i < array_length (errlist); i++) -- { -- if (errlist[i] == NULL) -- continue; -- TEST_COMPARE_STRING (strerrordesc_np (i), errlist[i]); -- } -+ TEST_COMPARE_STRING (strerrordesc_np (0), "Success"); -+ TEST_COMPARE_STRING (strerrorname_np (0), "0"); - -- TEST_VERIFY (strerrorname_np (-1) == NULL); -- TEST_VERIFY (strerrorname_np (array_length (errlist)) == NULL); -- for (size_t i = 0; i < array_length (errlist); i++) -- { -- if (errlist[i] == NULL) -- continue; -- TEST_COMPARE_STRING (strerrorname_np (i), errname.str + errnameidx[i]); -- } -+#ifdef EPERM -+ TEST_COMPARE_STRING (strerrordesc_np (EPERM), "Operation not permitted"); -+ TEST_COMPARE_STRING (strerrorname_np (EPERM), "EPERM"); -+#endif -+#ifdef ENOENT -+ TEST_COMPARE_STRING (strerrordesc_np (ENOENT), -+ "No such file or directory"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOENT), "ENOENT"); -+#endif -+#ifdef ESRCH -+ TEST_COMPARE_STRING (strerrordesc_np (ESRCH), "No such process"); -+ TEST_COMPARE_STRING (strerrorname_np (ESRCH), "ESRCH"); -+#endif -+#ifdef EINTR -+ TEST_COMPARE_STRING (strerrordesc_np (EINTR), "Interrupted system call"); -+ TEST_COMPARE_STRING (strerrorname_np (EINTR), "EINTR"); -+#endif -+#ifdef EIO -+ TEST_COMPARE_STRING (strerrordesc_np (EIO), "Input/output error"); -+ TEST_COMPARE_STRING (strerrorname_np (EIO), "EIO"); -+#endif -+#ifdef ENXIO -+ TEST_COMPARE_STRING (strerrordesc_np (ENXIO), "No such device or address"); -+ TEST_COMPARE_STRING (strerrorname_np (ENXIO), "ENXIO"); -+#endif -+#ifdef E2BIG -+ TEST_COMPARE_STRING (strerrordesc_np (E2BIG), "Argument list too long"); -+ TEST_COMPARE_STRING (strerrorname_np (E2BIG), "E2BIG"); -+#endif -+#ifdef ENOEXEC -+ TEST_COMPARE_STRING (strerrordesc_np (ENOEXEC), "Exec format error"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOEXEC), "ENOEXEC"); -+#endif -+#ifdef EBADF -+ TEST_COMPARE_STRING (strerrordesc_np (EBADF), "Bad file descriptor"); -+ TEST_COMPARE_STRING (strerrorname_np (EBADF), "EBADF"); -+#endif -+#ifdef ECHILD -+ TEST_COMPARE_STRING (strerrordesc_np (ECHILD), "No child processes"); -+ TEST_COMPARE_STRING (strerrorname_np (ECHILD), "ECHILD"); -+#endif -+#ifdef EDEADLK -+ TEST_COMPARE_STRING (strerrordesc_np (EDEADLK), -+ "Resource deadlock avoided"); -+ TEST_COMPARE_STRING (strerrorname_np (EDEADLK), "EDEADLK"); -+#endif -+#ifdef ENOMEM -+ TEST_COMPARE_STRING (strerrordesc_np (ENOMEM), "Cannot allocate memory"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOMEM), "ENOMEM"); -+#endif -+#ifdef EACCES -+ TEST_COMPARE_STRING (strerrordesc_np (EACCES), "Permission denied"); -+ TEST_COMPARE_STRING (strerrorname_np (EACCES), "EACCES"); -+#endif -+#ifdef EFAULT -+ TEST_COMPARE_STRING (strerrordesc_np (EFAULT), "Bad address"); -+ TEST_COMPARE_STRING (strerrorname_np (EFAULT), "EFAULT"); -+#endif -+#ifdef ENOTBLK -+ TEST_COMPARE_STRING (strerrordesc_np (ENOTBLK), "Block device required"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOTBLK), "ENOTBLK"); -+#endif -+#ifdef EBUSY -+ TEST_COMPARE_STRING (strerrordesc_np (EBUSY), "Device or resource busy"); -+ TEST_COMPARE_STRING (strerrorname_np (EBUSY), "EBUSY"); -+#endif -+#ifdef EEXIST -+ TEST_COMPARE_STRING (strerrordesc_np (EEXIST), "File exists"); -+ TEST_COMPARE_STRING (strerrorname_np (EEXIST), "EEXIST"); -+#endif -+#ifdef EXDEV -+ TEST_COMPARE_STRING (strerrordesc_np (EXDEV), "Invalid cross-device link"); -+ TEST_COMPARE_STRING (strerrorname_np (EXDEV), "EXDEV"); -+#endif -+#ifdef ENODEV -+ TEST_COMPARE_STRING (strerrordesc_np (ENODEV), "No such device"); -+ TEST_COMPARE_STRING (strerrorname_np (ENODEV), "ENODEV"); -+#endif -+#ifdef ENOTDIR -+ TEST_COMPARE_STRING (strerrordesc_np (ENOTDIR), "Not a directory"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOTDIR), "ENOTDIR"); -+#endif -+#ifdef EISDIR -+ TEST_COMPARE_STRING (strerrordesc_np (EISDIR), "Is a directory"); -+ TEST_COMPARE_STRING (strerrorname_np (EISDIR), "EISDIR"); -+#endif -+#ifdef EINVAL -+ TEST_COMPARE_STRING (strerrordesc_np (EINVAL), "Invalid argument"); -+ TEST_COMPARE_STRING (strerrorname_np (EINVAL), "EINVAL"); -+#endif -+#ifdef EMFILE -+ TEST_COMPARE_STRING (strerrordesc_np (EMFILE), "Too many open files"); -+ TEST_COMPARE_STRING (strerrorname_np (EMFILE), "EMFILE"); -+#endif -+#ifdef ENFILE -+ TEST_COMPARE_STRING (strerrordesc_np (ENFILE), -+ "Too many open files in system"); -+ TEST_COMPARE_STRING (strerrorname_np (ENFILE), "ENFILE"); -+#endif -+#ifdef ENOTTY -+ TEST_COMPARE_STRING (strerrordesc_np (ENOTTY), -+ "Inappropriate ioctl for device"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOTTY), "ENOTTY"); -+#endif -+#ifdef ETXTBSY -+ TEST_COMPARE_STRING (strerrordesc_np (ETXTBSY), "Text file busy"); -+ TEST_COMPARE_STRING (strerrorname_np (ETXTBSY), "ETXTBSY"); -+#endif -+#ifdef EFBIG -+ TEST_COMPARE_STRING (strerrordesc_np (EFBIG), "File too large"); -+ TEST_COMPARE_STRING (strerrorname_np (EFBIG), "EFBIG"); -+#endif -+#ifdef ENOSPC -+ TEST_COMPARE_STRING (strerrordesc_np (ENOSPC), "No space left on device"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOSPC), "ENOSPC"); -+#endif -+#ifdef ESPIPE -+ TEST_COMPARE_STRING (strerrordesc_np (ESPIPE), "Illegal seek"); -+ TEST_COMPARE_STRING (strerrorname_np (ESPIPE), "ESPIPE"); -+#endif -+#ifdef EROFS -+ TEST_COMPARE_STRING (strerrordesc_np (EROFS), "Read-only file system"); -+ TEST_COMPARE_STRING (strerrorname_np (EROFS), "EROFS"); -+#endif -+#ifdef EMLINK -+ TEST_COMPARE_STRING (strerrordesc_np (EMLINK), "Too many links"); -+ TEST_COMPARE_STRING (strerrorname_np (EMLINK), "EMLINK"); -+#endif -+#ifdef EPIPE -+ TEST_COMPARE_STRING (strerrordesc_np (EPIPE), "Broken pipe"); -+ TEST_COMPARE_STRING (strerrorname_np (EPIPE), "EPIPE"); -+#endif -+#ifdef EDOM -+ TEST_COMPARE_STRING (strerrordesc_np (EDOM), -+ "Numerical argument out of domain"); -+ TEST_COMPARE_STRING (strerrorname_np (EDOM), "EDOM"); -+#endif -+#ifdef ERANGE -+ TEST_COMPARE_STRING (strerrordesc_np (ERANGE), -+ "Numerical result out of range"); -+ TEST_COMPARE_STRING (strerrorname_np (ERANGE), "ERANGE"); -+#endif -+#ifdef EAGAIN -+ TEST_COMPARE_STRING (strerrordesc_np (EAGAIN), -+ "Resource temporarily unavailable"); -+ TEST_COMPARE_STRING (strerrorname_np (EAGAIN), "EAGAIN"); -+#endif -+#ifdef EINPROGRESS -+ TEST_COMPARE_STRING (strerrordesc_np (EINPROGRESS), -+ "Operation now in progress"); -+ TEST_COMPARE_STRING (strerrorname_np (EINPROGRESS), "EINPROGRESS"); -+#endif -+#ifdef EALREADY -+ TEST_COMPARE_STRING (strerrordesc_np (EALREADY), -+ "Operation already in progress"); -+ TEST_COMPARE_STRING (strerrorname_np (EALREADY), "EALREADY"); -+#endif -+#ifdef ENOTSOCK -+ TEST_COMPARE_STRING (strerrordesc_np (ENOTSOCK), -+ "Socket operation on non-socket"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOTSOCK), "ENOTSOCK"); -+#endif -+#ifdef EMSGSIZE -+ TEST_COMPARE_STRING (strerrordesc_np (EMSGSIZE), "Message too long"); -+ TEST_COMPARE_STRING (strerrorname_np (EMSGSIZE), "EMSGSIZE"); -+#endif -+#ifdef EPROTOTYPE -+ TEST_COMPARE_STRING (strerrordesc_np (EPROTOTYPE), -+ "Protocol wrong type for socket"); -+ TEST_COMPARE_STRING (strerrorname_np (EPROTOTYPE), "EPROTOTYPE"); -+#endif -+#ifdef ENOPROTOOPT -+ TEST_COMPARE_STRING (strerrordesc_np (ENOPROTOOPT), -+ "Protocol not available"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOPROTOOPT), "ENOPROTOOPT"); -+#endif -+#ifdef EPROTONOSUPPORT -+ TEST_COMPARE_STRING (strerrordesc_np (EPROTONOSUPPORT), -+ "Protocol not supported"); -+ TEST_COMPARE_STRING (strerrorname_np (EPROTONOSUPPORT), "EPROTONOSUPPORT"); -+#endif -+#ifdef ESOCKTNOSUPPORT -+ TEST_COMPARE_STRING (strerrordesc_np (ESOCKTNOSUPPORT), -+ "Socket type not supported"); -+ TEST_COMPARE_STRING (strerrorname_np (ESOCKTNOSUPPORT), "ESOCKTNOSUPPORT"); -+#endif -+#ifdef EOPNOTSUPP -+ TEST_COMPARE_STRING (strerrordesc_np (EOPNOTSUPP), -+ "Operation not supported"); -+ TEST_COMPARE_STRING (strerrorname_np (EOPNOTSUPP), "EOPNOTSUPP"); -+#endif -+#ifdef EPFNOSUPPORT -+ TEST_COMPARE_STRING (strerrordesc_np (EPFNOSUPPORT), -+ "Protocol family not supported"); -+ TEST_COMPARE_STRING (strerrorname_np (EPFNOSUPPORT), "EPFNOSUPPORT"); -+#endif -+#ifdef EAFNOSUPPORT -+ TEST_COMPARE_STRING (strerrordesc_np (EAFNOSUPPORT), -+ "Address family not supported by protocol"); -+ TEST_COMPARE_STRING (strerrorname_np (EAFNOSUPPORT), "EAFNOSUPPORT"); -+#endif -+#ifdef EADDRINUSE -+ TEST_COMPARE_STRING (strerrordesc_np (EADDRINUSE), -+ "Address already in use"); -+ TEST_COMPARE_STRING (strerrorname_np (EADDRINUSE), "EADDRINUSE"); -+#endif -+#ifdef EADDRNOTAVAIL -+ TEST_COMPARE_STRING (strerrordesc_np (EADDRNOTAVAIL), -+ "Cannot assign requested address"); -+ TEST_COMPARE_STRING (strerrorname_np (EADDRNOTAVAIL), "EADDRNOTAVAIL"); -+#endif -+#ifdef ENETDOWN -+ TEST_COMPARE_STRING (strerrordesc_np (ENETDOWN), "Network is down"); -+ TEST_COMPARE_STRING (strerrorname_np (ENETDOWN), "ENETDOWN"); -+#endif -+#ifdef ENETUNREACH -+ TEST_COMPARE_STRING (strerrordesc_np (ENETUNREACH), -+ "Network is unreachable"); -+ TEST_COMPARE_STRING (strerrorname_np (ENETUNREACH), "ENETUNREACH"); -+#endif -+#ifdef ENETRESET -+ TEST_COMPARE_STRING (strerrordesc_np (ENETRESET), -+ "Network dropped connection on reset"); -+ TEST_COMPARE_STRING (strerrorname_np (ENETRESET), "ENETRESET"); -+#endif -+#ifdef ECONNABORTED -+ TEST_COMPARE_STRING (strerrordesc_np (ECONNABORTED), -+ "Software caused connection abort"); -+ TEST_COMPARE_STRING (strerrorname_np (ECONNABORTED), "ECONNABORTED"); -+#endif -+#ifdef ECONNRESET -+ TEST_COMPARE_STRING (strerrordesc_np (ECONNRESET), -+ "Connection reset by peer"); -+ TEST_COMPARE_STRING (strerrorname_np (ECONNRESET), "ECONNRESET"); -+#endif -+#ifdef ENOBUFS -+ TEST_COMPARE_STRING (strerrordesc_np (ENOBUFS), -+ "No buffer space available"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOBUFS), "ENOBUFS"); -+#endif -+#ifdef EISCONN -+ TEST_COMPARE_STRING (strerrordesc_np (EISCONN), -+ "Transport endpoint is already connected"); -+ TEST_COMPARE_STRING (strerrorname_np (EISCONN), "EISCONN"); -+#endif -+#ifdef ENOTCONN -+ TEST_COMPARE_STRING (strerrordesc_np (ENOTCONN), -+ "Transport endpoint is not connected"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOTCONN), "ENOTCONN"); -+#endif -+#ifdef EDESTADDRREQ -+ TEST_COMPARE_STRING (strerrordesc_np (EDESTADDRREQ), -+ "Destination address required"); -+ TEST_COMPARE_STRING (strerrorname_np (EDESTADDRREQ), "EDESTADDRREQ"); -+#endif -+#ifdef ESHUTDOWN -+ TEST_COMPARE_STRING (strerrordesc_np (ESHUTDOWN), -+ "Cannot send after transport endpoint shutdown"); -+ TEST_COMPARE_STRING (strerrorname_np (ESHUTDOWN), "ESHUTDOWN"); -+#endif -+#ifdef ETOOMANYREFS -+ TEST_COMPARE_STRING (strerrordesc_np (ETOOMANYREFS), -+ "Too many references: cannot splice"); -+ TEST_COMPARE_STRING (strerrorname_np (ETOOMANYREFS), "ETOOMANYREFS"); -+#endif -+#ifdef ETIMEDOUT -+ TEST_COMPARE_STRING (strerrordesc_np (ETIMEDOUT), "Connection timed out"); -+ TEST_COMPARE_STRING (strerrorname_np (ETIMEDOUT), "ETIMEDOUT"); -+#endif -+#ifdef ECONNREFUSED -+ TEST_COMPARE_STRING (strerrordesc_np (ECONNREFUSED), "Connection refused"); -+ TEST_COMPARE_STRING (strerrorname_np (ECONNREFUSED), "ECONNREFUSED"); -+#endif -+#ifdef ELOOP -+ TEST_COMPARE_STRING (strerrordesc_np (ELOOP), -+ "Too many levels of symbolic links"); -+ TEST_COMPARE_STRING (strerrorname_np (ELOOP), "ELOOP"); -+#endif -+#ifdef ENAMETOOLONG -+ TEST_COMPARE_STRING (strerrordesc_np (ENAMETOOLONG), "File name too long"); -+ TEST_COMPARE_STRING (strerrorname_np (ENAMETOOLONG), "ENAMETOOLONG"); -+#endif -+#ifdef EHOSTDOWN -+ TEST_COMPARE_STRING (strerrordesc_np (EHOSTDOWN), "Host is down"); -+ TEST_COMPARE_STRING (strerrorname_np (EHOSTDOWN), "EHOSTDOWN"); -+#endif -+#ifdef EHOSTUNREACH -+ TEST_COMPARE_STRING (strerrordesc_np (EHOSTUNREACH), "No route to host"); -+ TEST_COMPARE_STRING (strerrorname_np (EHOSTUNREACH), "EHOSTUNREACH"); -+#endif -+#ifdef ENOTEMPTY -+ TEST_COMPARE_STRING (strerrordesc_np (ENOTEMPTY), "Directory not empty"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOTEMPTY), "ENOTEMPTY"); -+#endif -+#ifdef EUSERS -+ TEST_COMPARE_STRING (strerrordesc_np (EUSERS), "Too many users"); -+ TEST_COMPARE_STRING (strerrorname_np (EUSERS), "EUSERS"); -+#endif -+#ifdef EDQUOT -+ TEST_COMPARE_STRING (strerrordesc_np (EDQUOT), "Disk quota exceeded"); -+ TEST_COMPARE_STRING (strerrorname_np (EDQUOT), "EDQUOT"); -+#endif -+#ifdef ESTALE -+ TEST_COMPARE_STRING (strerrordesc_np (ESTALE), "Stale file handle"); -+ TEST_COMPARE_STRING (strerrorname_np (ESTALE), "ESTALE"); -+#endif -+#ifdef EREMOTE -+ TEST_COMPARE_STRING (strerrordesc_np (EREMOTE), "Object is remote"); -+ TEST_COMPARE_STRING (strerrorname_np (EREMOTE), "EREMOTE"); -+#endif -+#ifdef ENOLCK -+ TEST_COMPARE_STRING (strerrordesc_np (ENOLCK), "No locks available"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOLCK), "ENOLCK"); -+#endif -+#ifdef ENOSYS -+ TEST_COMPARE_STRING (strerrordesc_np (ENOSYS), "Function not implemented"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOSYS), "ENOSYS"); -+#endif -+#ifdef EILSEQ -+ TEST_COMPARE_STRING (strerrordesc_np (EILSEQ), -+ "Invalid or incomplete multibyte or wide character"); -+ TEST_COMPARE_STRING (strerrorname_np (EILSEQ), "EILSEQ"); -+#endif -+#ifdef EBADMSG -+ TEST_COMPARE_STRING (strerrordesc_np (EBADMSG), "Bad message"); -+ TEST_COMPARE_STRING (strerrorname_np (EBADMSG), "EBADMSG"); -+#endif -+#ifdef EIDRM -+ TEST_COMPARE_STRING (strerrordesc_np (EIDRM), "Identifier removed"); -+ TEST_COMPARE_STRING (strerrorname_np (EIDRM), "EIDRM"); -+#endif -+#ifdef EMULTIHOP -+ TEST_COMPARE_STRING (strerrordesc_np (EMULTIHOP), "Multihop attempted"); -+ TEST_COMPARE_STRING (strerrorname_np (EMULTIHOP), "EMULTIHOP"); -+#endif -+#ifdef ENODATA -+ TEST_COMPARE_STRING (strerrordesc_np (ENODATA), "No data available"); -+ TEST_COMPARE_STRING (strerrorname_np (ENODATA), "ENODATA"); -+#endif -+#ifdef ENOLINK -+ TEST_COMPARE_STRING (strerrordesc_np (ENOLINK), "Link has been severed"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOLINK), "ENOLINK"); -+#endif -+#ifdef ENOMSG -+ TEST_COMPARE_STRING (strerrordesc_np (ENOMSG), -+ "No message of desired type"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOMSG), "ENOMSG"); -+#endif -+#ifdef ENOSR -+ TEST_COMPARE_STRING (strerrordesc_np (ENOSR), "Out of streams resources"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOSR), "ENOSR"); -+#endif -+#ifdef ENOSTR -+ TEST_COMPARE_STRING (strerrordesc_np (ENOSTR), "Device not a stream"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOSTR), "ENOSTR"); -+#endif -+#ifdef EOVERFLOW -+ TEST_COMPARE_STRING (strerrordesc_np (EOVERFLOW), -+ "Value too large for defined data type"); -+ TEST_COMPARE_STRING (strerrorname_np (EOVERFLOW), "EOVERFLOW"); -+#endif -+#ifdef EPROTO -+ TEST_COMPARE_STRING (strerrordesc_np (EPROTO), "Protocol error"); -+ TEST_COMPARE_STRING (strerrorname_np (EPROTO), "EPROTO"); -+#endif -+#ifdef ETIME -+ TEST_COMPARE_STRING (strerrordesc_np (ETIME), "Timer expired"); -+ TEST_COMPARE_STRING (strerrorname_np (ETIME), "ETIME"); -+#endif -+#ifdef ECANCELED -+ TEST_COMPARE_STRING (strerrordesc_np (ECANCELED), "Operation canceled"); -+ TEST_COMPARE_STRING (strerrorname_np (ECANCELED), "ECANCELED"); -+#endif -+#ifdef EOWNERDEAD -+ TEST_COMPARE_STRING (strerrordesc_np (EOWNERDEAD), "Owner died"); -+ TEST_COMPARE_STRING (strerrorname_np (EOWNERDEAD), "EOWNERDEAD"); -+#endif -+#ifdef ENOTRECOVERABLE -+ TEST_COMPARE_STRING (strerrordesc_np (ENOTRECOVERABLE), -+ "State not recoverable"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOTRECOVERABLE), "ENOTRECOVERABLE"); -+#endif -+#ifdef ERESTART -+ TEST_COMPARE_STRING (strerrordesc_np (ERESTART), -+ "Interrupted system call should be restarted"); -+ TEST_COMPARE_STRING (strerrorname_np (ERESTART), "ERESTART"); -+#endif -+#ifdef ECHRNG -+ TEST_COMPARE_STRING (strerrordesc_np (ECHRNG), -+ "Channel number out of range"); -+ TEST_COMPARE_STRING (strerrorname_np (ECHRNG), "ECHRNG"); -+#endif -+#ifdef EL2NSYNC -+ TEST_COMPARE_STRING (strerrordesc_np (EL2NSYNC), -+ "Level 2 not synchronized"); -+ TEST_COMPARE_STRING (strerrorname_np (EL2NSYNC), "EL2NSYNC"); -+#endif -+#ifdef EL3HLT -+ TEST_COMPARE_STRING (strerrordesc_np (EL3HLT), "Level 3 halted"); -+ TEST_COMPARE_STRING (strerrorname_np (EL3HLT), "EL3HLT"); -+#endif -+#ifdef EL3RST -+ TEST_COMPARE_STRING (strerrordesc_np (EL3RST), "Level 3 reset"); -+ TEST_COMPARE_STRING (strerrorname_np (EL3RST), "EL3RST"); -+#endif -+#ifdef ELNRNG -+ TEST_COMPARE_STRING (strerrordesc_np (ELNRNG), "Link number out of range"); -+ TEST_COMPARE_STRING (strerrorname_np (ELNRNG), "ELNRNG"); -+#endif -+#ifdef EUNATCH -+ TEST_COMPARE_STRING (strerrordesc_np (EUNATCH), -+ "Protocol driver not attached"); -+ TEST_COMPARE_STRING (strerrorname_np (EUNATCH), "EUNATCH"); -+#endif -+#ifdef ENOCSI -+ TEST_COMPARE_STRING (strerrordesc_np (ENOCSI), -+ "No CSI structure available"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOCSI), "ENOCSI"); -+#endif -+#ifdef EL2HLT -+ TEST_COMPARE_STRING (strerrordesc_np (EL2HLT), "Level 2 halted"); -+ TEST_COMPARE_STRING (strerrorname_np (EL2HLT), "EL2HLT"); -+#endif -+#ifdef EBADE -+ TEST_COMPARE_STRING (strerrordesc_np (EBADE), "Invalid exchange"); -+ TEST_COMPARE_STRING (strerrorname_np (EBADE), "EBADE"); -+#endif -+#ifdef EBADR -+ TEST_COMPARE_STRING (strerrordesc_np (EBADR), -+ "Invalid request descriptor"); -+ TEST_COMPARE_STRING (strerrorname_np (EBADR), "EBADR"); -+#endif -+#ifdef EXFULL -+ TEST_COMPARE_STRING (strerrordesc_np (EXFULL), "Exchange full"); -+ TEST_COMPARE_STRING (strerrorname_np (EXFULL), "EXFULL"); -+#endif -+#ifdef ENOANO -+ TEST_COMPARE_STRING (strerrordesc_np (ENOANO), "No anode"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOANO), "ENOANO"); -+#endif -+#ifdef EBADRQC -+ TEST_COMPARE_STRING (strerrordesc_np (EBADRQC), "Invalid request code"); -+ TEST_COMPARE_STRING (strerrorname_np (EBADRQC), "EBADRQC"); -+#endif -+#ifdef EBADSLT -+ TEST_COMPARE_STRING (strerrordesc_np (EBADSLT), "Invalid slot"); -+ TEST_COMPARE_STRING (strerrorname_np (EBADSLT), "EBADSLT"); -+#endif -+#ifdef EBFONT -+ TEST_COMPARE_STRING (strerrordesc_np (EBFONT), "Bad font file format"); -+ TEST_COMPARE_STRING (strerrorname_np (EBFONT), "EBFONT"); -+#endif -+#ifdef ENONET -+ TEST_COMPARE_STRING (strerrordesc_np (ENONET), -+ "Machine is not on the network"); -+ TEST_COMPARE_STRING (strerrorname_np (ENONET), "ENONET"); -+#endif -+#ifdef ENOPKG -+ TEST_COMPARE_STRING (strerrordesc_np (ENOPKG), "Package not installed"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOPKG), "ENOPKG"); -+#endif -+#ifdef EADV -+ TEST_COMPARE_STRING (strerrordesc_np (EADV), "Advertise error"); -+ TEST_COMPARE_STRING (strerrorname_np (EADV), "EADV"); -+#endif -+#ifdef ESRMNT -+ TEST_COMPARE_STRING (strerrordesc_np (ESRMNT), "Srmount error"); -+ TEST_COMPARE_STRING (strerrorname_np (ESRMNT), "ESRMNT"); -+#endif -+#ifdef ECOMM -+ TEST_COMPARE_STRING (strerrordesc_np (ECOMM), -+ "Communication error on send"); -+ TEST_COMPARE_STRING (strerrorname_np (ECOMM), "ECOMM"); -+#endif -+#ifdef EDOTDOT -+ TEST_COMPARE_STRING (strerrordesc_np (EDOTDOT), "RFS specific error"); -+ TEST_COMPARE_STRING (strerrorname_np (EDOTDOT), "EDOTDOT"); -+#endif -+#ifdef ENOTUNIQ -+ TEST_COMPARE_STRING (strerrordesc_np (ENOTUNIQ), -+ "Name not unique on network"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOTUNIQ), "ENOTUNIQ"); -+#endif -+#ifdef EBADFD -+ TEST_COMPARE_STRING (strerrordesc_np (EBADFD), -+ "File descriptor in bad state"); -+ TEST_COMPARE_STRING (strerrorname_np (EBADFD), "EBADFD"); -+#endif -+#ifdef EREMCHG -+ TEST_COMPARE_STRING (strerrordesc_np (EREMCHG), "Remote address changed"); -+ TEST_COMPARE_STRING (strerrorname_np (EREMCHG), "EREMCHG"); -+#endif -+#ifdef ELIBACC -+ TEST_COMPARE_STRING (strerrordesc_np (ELIBACC), -+ "Can not access a needed shared library"); -+ TEST_COMPARE_STRING (strerrorname_np (ELIBACC), "ELIBACC"); -+#endif -+#ifdef ELIBBAD -+ TEST_COMPARE_STRING (strerrordesc_np (ELIBBAD), -+ "Accessing a corrupted shared library"); -+ TEST_COMPARE_STRING (strerrorname_np (ELIBBAD), "ELIBBAD"); -+#endif -+#ifdef ELIBSCN -+ TEST_COMPARE_STRING (strerrordesc_np (ELIBSCN), -+ ".lib section in a.out corrupted"); -+ TEST_COMPARE_STRING (strerrorname_np (ELIBSCN), "ELIBSCN"); -+#endif -+#ifdef ELIBMAX -+ TEST_COMPARE_STRING (strerrordesc_np (ELIBMAX), -+ "Attempting to link in too many shared libraries"); -+ TEST_COMPARE_STRING (strerrorname_np (ELIBMAX), "ELIBMAX"); -+#endif -+#ifdef ELIBEXEC -+ TEST_COMPARE_STRING (strerrordesc_np (ELIBEXEC), -+ "Cannot exec a shared library directly"); -+ TEST_COMPARE_STRING (strerrorname_np (ELIBEXEC), "ELIBEXEC"); -+#endif -+#ifdef ESTRPIPE -+ TEST_COMPARE_STRING (strerrordesc_np (ESTRPIPE), "Streams pipe error"); -+ TEST_COMPARE_STRING (strerrorname_np (ESTRPIPE), "ESTRPIPE"); -+#endif -+#ifdef EUCLEAN -+ TEST_COMPARE_STRING (strerrordesc_np (EUCLEAN), -+ "Structure needs cleaning"); -+ TEST_COMPARE_STRING (strerrorname_np (EUCLEAN), "EUCLEAN"); -+#endif -+#ifdef ENOTNAM -+ TEST_COMPARE_STRING (strerrordesc_np (ENOTNAM), -+ "Not a XENIX named type file"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOTNAM), "ENOTNAM"); -+#endif -+#ifdef ENAVAIL -+ TEST_COMPARE_STRING (strerrordesc_np (ENAVAIL), -+ "No XENIX semaphores available"); -+ TEST_COMPARE_STRING (strerrorname_np (ENAVAIL), "ENAVAIL"); -+#endif -+#ifdef EISNAM -+ TEST_COMPARE_STRING (strerrordesc_np (EISNAM), "Is a named type file"); -+ TEST_COMPARE_STRING (strerrorname_np (EISNAM), "EISNAM"); -+#endif -+#ifdef EREMOTEIO -+ TEST_COMPARE_STRING (strerrordesc_np (EREMOTEIO), "Remote I/O error"); -+ TEST_COMPARE_STRING (strerrorname_np (EREMOTEIO), "EREMOTEIO"); -+#endif -+#ifdef ENOMEDIUM -+ TEST_COMPARE_STRING (strerrordesc_np (ENOMEDIUM), "No medium found"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOMEDIUM), "ENOMEDIUM"); -+#endif -+#ifdef EMEDIUMTYPE -+ TEST_COMPARE_STRING (strerrordesc_np (EMEDIUMTYPE), "Wrong medium type"); -+ TEST_COMPARE_STRING (strerrorname_np (EMEDIUMTYPE), "EMEDIUMTYPE"); -+#endif -+#ifdef ENOKEY -+ TEST_COMPARE_STRING (strerrordesc_np (ENOKEY), -+ "Required key not available"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOKEY), "ENOKEY"); -+#endif -+#ifdef EKEYEXPIRED -+ TEST_COMPARE_STRING (strerrordesc_np (EKEYEXPIRED), "Key has expired"); -+ TEST_COMPARE_STRING (strerrorname_np (EKEYEXPIRED), "EKEYEXPIRED"); -+#endif -+#ifdef EKEYREVOKED -+ TEST_COMPARE_STRING (strerrordesc_np (EKEYREVOKED), -+ "Key has been revoked"); -+ TEST_COMPARE_STRING (strerrorname_np (EKEYREVOKED), "EKEYREVOKED"); -+#endif -+#ifdef EKEYREJECTED -+ TEST_COMPARE_STRING (strerrordesc_np (EKEYREJECTED), -+ "Key was rejected by service"); -+ TEST_COMPARE_STRING (strerrorname_np (EKEYREJECTED), "EKEYREJECTED"); -+#endif -+#ifdef ERFKILL -+ TEST_COMPARE_STRING (strerrordesc_np (ERFKILL), -+ "Operation not possible due to RF-kill"); -+ TEST_COMPARE_STRING (strerrorname_np (ERFKILL), "ERFKILL"); -+#endif -+#ifdef EHWPOISON -+ TEST_COMPARE_STRING (strerrordesc_np (EHWPOISON), -+ "Memory page has hardware error"); -+ TEST_COMPARE_STRING (strerrorname_np (EHWPOISON), "EHWPOISON"); -+#endif -+#ifdef EBADRPC -+ TEST_COMPARE_STRING (strerrordesc_np (EBADRPC), "RPC struct is bad"); -+ TEST_COMPARE_STRING (strerrorname_np (EBADRPC), "EBADRPC"); -+#endif -+#ifdef EFTYPE -+ TEST_COMPARE_STRING (strerrordesc_np (EFTYPE), -+ "Inappropriate file type or format"); -+ TEST_COMPARE_STRING (strerrorname_np (EFTYPE), "EFTYPE"); -+#endif -+#ifdef EPROCUNAVAIL -+ TEST_COMPARE_STRING (strerrordesc_np (EPROCUNAVAIL), -+ "RPC bad procedure for program"); -+ TEST_COMPARE_STRING (strerrorname_np (EPROCUNAVAIL), "EPROCUNAVAIL"); -+#endif -+#ifdef EAUTH -+ TEST_COMPARE_STRING (strerrordesc_np (EAUTH), "Authentication error"); -+ TEST_COMPARE_STRING (strerrorname_np (EAUTH), "EAUTH"); -+#endif -+#ifdef EDIED -+ TEST_COMPARE_STRING (strerrordesc_np (EDIED), "Translator died"); -+ TEST_COMPARE_STRING (strerrorname_np (EDIED), "EDIED"); -+#endif -+#ifdef ERPCMISMATCH -+ TEST_COMPARE_STRING (strerrordesc_np (ERPCMISMATCH), "RPC version wrong"); -+ TEST_COMPARE_STRING (strerrorname_np (ERPCMISMATCH), "ERPCMISMATCH"); -+#endif -+#ifdef EGREGIOUS -+ TEST_COMPARE_STRING (strerrordesc_np (EGREGIOUS), -+ "You really blew it this time"); -+ TEST_COMPARE_STRING (strerrorname_np (EGREGIOUS), "EGREGIOUS"); -+#endif -+#ifdef EPROCLIM -+ TEST_COMPARE_STRING (strerrordesc_np (EPROCLIM), "Too many processes"); -+ TEST_COMPARE_STRING (strerrorname_np (EPROCLIM), "EPROCLIM"); -+#endif -+#ifdef EGRATUITOUS -+ TEST_COMPARE_STRING (strerrordesc_np (EGRATUITOUS), "Gratuitous error"); -+ TEST_COMPARE_STRING (strerrorname_np (EGRATUITOUS), "EGRATUITOUS"); -+#endif -+#if defined (ENOTSUP) && ENOTSUP != EOPNOTSUPP -+ TEST_COMPARE_STRING (strerrordesc_np (ENOTSUP), "Not supported"); -+ TEST_COMPARE_STRING (strerrorname_np (ENOTSUP), "ENOTSUP"); -+#endif -+#ifdef EPROGMISMATCH -+ TEST_COMPARE_STRING (strerrordesc_np (EPROGMISMATCH), -+ "RPC program version wrong"); -+ TEST_COMPARE_STRING (strerrorname_np (EPROGMISMATCH), "EPROGMISMATCH"); -+#endif -+#ifdef EBACKGROUND -+ TEST_COMPARE_STRING (strerrordesc_np (EBACKGROUND), -+ "Inappropriate operation for background process"); -+ TEST_COMPARE_STRING (strerrorname_np (EBACKGROUND), "EBACKGROUND"); -+#endif -+#ifdef EIEIO -+ TEST_COMPARE_STRING (strerrordesc_np (EIEIO), "Computer bought the farm"); -+ TEST_COMPARE_STRING (strerrorname_np (EIEIO), "EIEIO"); -+#endif -+#if defined (EWOULDBLOCK) && EWOULDBLOCK != EAGAIN -+ TEST_COMPARE_STRING (strerrordesc_np (EWOULDBLOCK), -+ "Operation would block"); -+ TEST_COMPARE_STRING (strerrorname_np (EWOULDBLOCK), "EWOULDBLOCK"); -+#endif -+#ifdef ENEEDAUTH -+ TEST_COMPARE_STRING (strerrordesc_np (ENEEDAUTH), "Need authenticator"); -+ TEST_COMPARE_STRING (strerrorname_np (ENEEDAUTH), "ENEEDAUTH"); -+#endif -+#ifdef ED -+ TEST_COMPARE_STRING (strerrordesc_np (ED), "?"); -+ TEST_COMPARE_STRING (strerrorname_np (ED), "ED"); -+#endif -+#ifdef EPROGUNAVAIL -+ TEST_COMPARE_STRING (strerrordesc_np (EPROGUNAVAIL), -+ "RPC program not available"); -+ TEST_COMPARE_STRING (strerrorname_np (EPROGUNAVAIL), "EPROGUNAVAIL"); -+#endif - - return 0; - } -diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c -index 95b46dcbeb..3a323547f9 100644 ---- a/stdio-common/vfscanf-internal.c -+++ b/stdio-common/vfscanf-internal.c -@@ -277,7 +277,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, - #endif - { - va_list arg; -- const CHAR_T *f = format; -+ const UCHAR_T *f = (const UCHAR_T *) format; - UCHAR_T fc; /* Current character of the format. */ - WINT_T done = 0; /* Assignments done. */ - size_t read_in = 0; /* Chars read in. */ -@@ -415,10 +415,11 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, - #endif - - #ifndef COMPILE_WSCANF -- if (!isascii ((unsigned char) *f)) -+ if (!isascii (*f)) - { - /* Non-ASCII, may be a multibyte. */ -- int len = __mbrlen (f, strlen (f), &state); -+ int len = __mbrlen ((const char *) f, strlen ((const char *) f), -+ &state); - if (len > 0) - { - do -@@ -426,7 +427,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, - c = inchar (); - if (__glibc_unlikely (c == EOF)) - input_error (); -- else if (c != (unsigned char) *f++) -+ else if (c != *f++) - { - ungetc_not_eof (c, s); - conv_error (); -@@ -484,9 +485,9 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, - char_buffer_rewind (&charbuf); - - /* Check for a positional parameter specification. */ -- if (ISDIGIT ((UCHAR_T) *f)) -+ if (ISDIGIT (*f)) - { -- argpos = read_int ((const UCHAR_T **) &f); -+ argpos = read_int (&f); - if (*f == L_('$')) - ++f; - else -@@ -521,8 +522,8 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, - - /* Find the maximum field width. */ - width = 0; -- if (ISDIGIT ((UCHAR_T) *f)) -- width = read_int ((const UCHAR_T **) &f); -+ if (ISDIGIT (*f)) -+ width = read_int (&f); - got_width: - if (width == 0) - width = -1; -@@ -2522,12 +2523,11 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr, - } - - while ((fc = *f++) != '\0' && fc != ']') -- if (fc == '-' && *f != '\0' && *f != ']' -- && (unsigned char) f[-2] <= (unsigned char) *f) -+ if (fc == '-' && *f != '\0' && *f != ']' && f[-2] <= *f) - { - /* Add all characters from the one before the '-' - up to (but not including) the next format char. */ -- for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc) -+ for (fc = f[-2]; fc < *f; ++fc) - ((char *)charbuf.scratch.data)[fc] = 1; - } - else -diff --git a/stdlib/tst-secure-getenv.c b/stdlib/tst-secure-getenv.c -index 3cfe9a05c3..d4b1139c5e 100644 ---- a/stdlib/tst-secure-getenv.c -+++ b/stdlib/tst-secure-getenv.c -@@ -30,167 +30,12 @@ - #include <sys/wait.h> - #include <unistd.h> - -+#include <support/check.h> - #include <support/support.h> -+#include <support/capture_subprocess.h> - #include <support/test-driver.h> - - static char MAGIC_ARGUMENT[] = "run-actual-test"; --#define MAGIC_STATUS 19 -- --/* Return a GID which is not our current GID, but is present in the -- supplementary group list. */ --static gid_t --choose_gid (void) --{ -- int count = getgroups (0, NULL); -- if (count < 0) -- { -- printf ("getgroups: %m\n"); -- exit (1); -- } -- gid_t *groups; -- groups = xcalloc (count, sizeof (*groups)); -- int ret = getgroups (count, groups); -- if (ret < 0) -- { -- printf ("getgroups: %m\n"); -- exit (1); -- } -- gid_t current = getgid (); -- gid_t not_current = 0; -- for (int i = 0; i < ret; ++i) -- { -- if (groups[i] != current) -- { -- not_current = groups[i]; -- break; -- } -- } -- free (groups); -- return not_current; --} -- -- --/* Copies the executable into a restricted directory, so that we can -- safely make it SGID with the TARGET group ID. Then runs the -- executable. */ --static int --run_executable_sgid (gid_t target) --{ -- char *dirname = xasprintf ("%s/secure-getenv.%jd", -- test_dir, (intmax_t) getpid ()); -- char *execname = xasprintf ("%s/bin", dirname); -- int infd = -1; -- int outfd = -1; -- int ret = -1; -- if (mkdir (dirname, 0700) < 0) -- { -- printf ("mkdir: %m\n"); -- goto err; -- } -- infd = open ("/proc/self/exe", O_RDONLY); -- if (infd < 0) -- { -- printf ("open (/proc/self/exe): %m\n"); -- goto err; -- } -- outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700); -- if (outfd < 0) -- { -- printf ("open (%s): %m\n", execname); -- goto err; -- } -- char buf[4096]; -- for (;;) -- { -- ssize_t rdcount = read (infd, buf, sizeof (buf)); -- if (rdcount < 0) -- { -- printf ("read: %m\n"); -- goto err; -- } -- if (rdcount == 0) -- break; -- char *p = buf; -- char *end = buf + rdcount; -- while (p != end) -- { -- ssize_t wrcount = write (outfd, buf, end - p); -- if (wrcount == 0) -- errno = ENOSPC; -- if (wrcount <= 0) -- { -- printf ("write: %m\n"); -- goto err; -- } -- p += wrcount; -- } -- } -- if (fchown (outfd, getuid (), target) < 0) -- { -- printf ("fchown (%s): %m\n", execname); -- goto err; -- } -- if (fchmod (outfd, 02750) < 0) -- { -- printf ("fchmod (%s): %m\n", execname); -- goto err; -- } -- if (close (outfd) < 0) -- { -- printf ("close (outfd): %m\n"); -- goto err; -- } -- if (close (infd) < 0) -- { -- printf ("close (infd): %m\n"); -- goto err; -- } -- -- int kid = fork (); -- if (kid < 0) -- { -- printf ("fork: %m\n"); -- goto err; -- } -- if (kid == 0) -- { -- /* Child process. */ -- char *args[] = { execname, MAGIC_ARGUMENT, NULL }; -- execve (execname, args, environ); -- printf ("execve (%s): %m\n", execname); -- _exit (1); -- } -- int status; -- if (waitpid (kid, &status, 0) < 0) -- { -- printf ("waitpid: %m\n"); -- goto err; -- } -- if (!WIFEXITED (status) || WEXITSTATUS (status) != MAGIC_STATUS) -- { -- printf ("Unexpected exit status %d from child process\n", -- status); -- goto err; -- } -- ret = 0; -- --err: -- if (outfd >= 0) -- close (outfd); -- if (infd >= 0) -- close (infd); -- if (execname) -- { -- unlink (execname); -- free (execname); -- } -- if (dirname) -- { -- rmdir (dirname); -- free (dirname); -- } -- return ret; --} - - static int - do_test (void) -@@ -212,15 +57,15 @@ do_test (void) - exit (1); - } - -- gid_t target = choose_gid (); -- if (target == 0) -- { -- fprintf (stderr, -- "Could not find a suitable GID for user %jd, skipping test\n", -- (intmax_t) getuid ()); -- exit (0); -- } -- return run_executable_sgid (target); -+ int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT); -+ -+ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) -+ return EXIT_UNSUPPORTED; -+ -+ if (!WIFEXITED (status)) -+ FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status); -+ -+ return 0; - } - - static void -@@ -229,23 +74,15 @@ alternative_main (int argc, char **argv) - if (argc == 2 && strcmp (argv[1], MAGIC_ARGUMENT) == 0) - { - if (getgid () == getegid ()) -- { -- /* This can happen if the file system is mounted nosuid. */ -- fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n", -- (intmax_t) getgid ()); -- exit (MAGIC_STATUS); -- } -+ /* This can happen if the file system is mounted nosuid. */ -+ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n", -+ (intmax_t) getgid ()); - if (getenv ("PATH") == NULL) -- { -- printf ("PATH variable not present\n"); -- exit (3); -- } -+ FAIL_EXIT (3, "PATH variable not present\n"); - if (secure_getenv ("PATH") != NULL) -- { -- printf ("PATH variable not filtered out\n"); -- exit (4); -- } -- exit (MAGIC_STATUS); -+ FAIL_EXIT (4, "PATH variable not filtered out\n"); -+ -+ exit (EXIT_SUCCESS); - } - } - -diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h -index 309d0f39b2..c8d3051af8 100644 ---- a/string/bits/string_fortified.h -+++ b/string/bits/string_fortified.h -@@ -22,11 +22,6 @@ - # error "Never use <bits/string_fortified.h> directly; include <string.h> instead." - #endif - --#if !__GNUC_PREREQ (5,0) --__warndecl (__warn_memset_zero_len, -- "memset used with constant zero length parameter; this could be due to transposed parameters"); --#endif -- - __fortify_function void * - __NTH (memcpy (void *__restrict __dest, const void *__restrict __src, - size_t __len)) -@@ -58,16 +53,6 @@ __NTH (mempcpy (void *__restrict __dest, const void *__restrict __src, - __fortify_function void * - __NTH (memset (void *__dest, int __ch, size_t __len)) - { -- /* GCC-5.0 and newer implements these checks in the compiler, so we don't -- need them here. */ --#if !__GNUC_PREREQ (5,0) -- if (__builtin_constant_p (__len) && __len == 0 -- && (!__builtin_constant_p (__ch) || __ch != 0)) -- { -- __warn_memset_zero_len (); -- return __dest; -- } --#endif - return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest)); - } - -diff --git a/support/Makefile b/support/Makefile -index 93faafddf9..3d3aff5ff9 100644 ---- a/support/Makefile -+++ b/support/Makefile -@@ -35,6 +35,8 @@ libsupport-routines = \ - ignore_stderr \ - next_to_fault \ - oom_error \ -+ resolv_response_context_duplicate \ -+ resolv_response_context_free \ - resolv_test \ - set_fortify_handler \ - support-xfstat \ -@@ -133,6 +135,7 @@ libsupport-routines = \ - xpthread_join \ - xpthread_key_create \ - xpthread_key_delete \ -+ xpthread_kill \ - xpthread_mutex_consistent \ - xpthread_mutex_destroy \ - xpthread_mutex_init \ -diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h -index 9808750f80..421f657678 100644 ---- a/support/capture_subprocess.h -+++ b/support/capture_subprocess.h -@@ -41,6 +41,12 @@ struct support_capture_subprocess support_capture_subprocess - struct support_capture_subprocess support_capture_subprogram - (const char *file, char *const argv[]); - -+/* Copy the running program into a setgid binary and run it with CHILD_ID -+ argument. If execution is successful, return the exit status of the child -+ program, otherwise return a non-zero failure exit code. */ -+int support_capture_subprogram_self_sgid -+ (char *child_id); -+ - /* Deallocate the subprocess data captured by - support_capture_subprocess. */ - void support_capture_subprocess_free (struct support_capture_subprocess *); -diff --git a/support/resolv_response_context_duplicate.c b/support/resolv_response_context_duplicate.c -new file mode 100644 -index 0000000000..f9c5c3462a ---- /dev/null -+++ b/support/resolv_response_context_duplicate.c -@@ -0,0 +1,37 @@ -+/* Duplicate a response context used in DNS resolver tests. -+ Copyright (C) 2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <string.h> -+#include <support/resolv_test.h> -+#include <support/support.h> -+ -+struct resolv_response_context * -+resolv_response_context_duplicate (const struct resolv_response_context *ctx) -+{ -+ struct resolv_response_context *result = xmalloc (sizeof (*result)); -+ memcpy (result, ctx, sizeof (*result)); -+ if (result->client_address != NULL) -+ { -+ result->client_address = xmalloc (result->client_address_length); -+ memcpy (result->client_address, ctx->client_address, -+ result->client_address_length); -+ } -+ result->query_buffer = xmalloc (result->query_length); -+ memcpy (result->query_buffer, ctx->query_buffer, result->query_length); -+ return result; -+} -diff --git a/support/resolv_response_context_free.c b/support/resolv_response_context_free.c -new file mode 100644 -index 0000000000..b88c05ffd4 ---- /dev/null -+++ b/support/resolv_response_context_free.c -@@ -0,0 +1,28 @@ -+/* Free a response context used in DNS resolver tests. -+ Copyright (C) 2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <stdlib.h> -+#include <support/resolv_test.h> -+ -+void -+resolv_response_context_free (struct resolv_response_context *ctx) -+{ -+ free (ctx->query_buffer); -+ free (ctx->client_address); -+ free (ctx); -+} -diff --git a/support/resolv_test.c b/support/resolv_test.c -index 53b7fc41ab..9878a040a3 100644 ---- a/support/resolv_test.c -+++ b/support/resolv_test.c -@@ -181,7 +181,9 @@ resolv_response_init (struct resolv_response_builder *b, - b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit. */ - if (flags.tc) - b->buffer[2] |= 0x02; -- b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */ -+ b->buffer[3] = flags.rcode; -+ if (!flags.clear_ra) -+ b->buffer[3] |= 0x80; - if (flags.ad) - b->buffer[3] |= 0x20; - -@@ -434,9 +436,9 @@ resolv_response_buffer (const struct resolv_response_builder *b) - return result; - } - --static struct resolv_response_builder * --response_builder_allocate -- (const unsigned char *query_buffer, size_t query_length) -+struct resolv_response_builder * -+resolv_response_builder_allocate (const unsigned char *query_buffer, -+ size_t query_length) - { - struct resolv_response_builder *b = xmalloc (sizeof (*b)); - memset (b, 0, offsetof (struct resolv_response_builder, buffer)); -@@ -445,8 +447,8 @@ response_builder_allocate - return b; - } - --static void --response_builder_free (struct resolv_response_builder *b) -+void -+resolv_response_builder_free (struct resolv_response_builder *b) - { - tdestroy (b->compression_offsets, free); - free (b); -@@ -661,13 +663,17 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index) - - struct resolv_response_context ctx = - { -+ .test = obj, -+ .client_address = &peer, -+ .client_address_length = peerlen, - .query_buffer = query, - .query_length = length, - .server_index = server_index, - .tcp = false, - .edns = qinfo.edns, - }; -- struct resolv_response_builder *b = response_builder_allocate (query, length); -+ struct resolv_response_builder *b -+ = resolv_response_builder_allocate (query, length); - obj->config.response_callback - (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); - -@@ -684,7 +690,7 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index) - if (b->offset >= 12) - printf ("info: UDP server %d: sending response:" - " %zu bytes, RCODE %d (for %s/%u/%u)\n", -- server_index, b->offset, b->buffer[3] & 0x0f, -+ ctx.server_index, b->offset, b->buffer[3] & 0x0f, - qinfo.qname, qinfo.qclass, qinfo.qtype); - else - printf ("info: UDP server %d: sending response: %zu bytes" -@@ -694,23 +700,31 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index) - if (b->truncate_bytes > 0) - printf ("info: truncated by %u bytes\n", b->truncate_bytes); - } -- size_t to_send = b->offset; -- if (to_send < b->truncate_bytes) -- to_send = 0; -- else -- to_send -= b->truncate_bytes; -- -- /* Ignore most errors here because the other end may have closed -- the socket. */ -- if (sendto (obj->servers[server_index].socket_udp, -- b->buffer, to_send, 0, -- (struct sockaddr *) &peer, peerlen) < 0) -- TEST_VERIFY_EXIT (errno != EBADF); -+ resolv_response_send_udp (&ctx, b); - } -- response_builder_free (b); -+ resolv_response_builder_free (b); - return true; - } - -+void -+resolv_response_send_udp (const struct resolv_response_context *ctx, -+ struct resolv_response_builder *b) -+{ -+ TEST_VERIFY_EXIT (!ctx->tcp); -+ size_t to_send = b->offset; -+ if (to_send < b->truncate_bytes) -+ to_send = 0; -+ else -+ to_send -= b->truncate_bytes; -+ -+ /* Ignore most errors here because the other end may have closed -+ the socket. */ -+ if (sendto (ctx->test->servers[ctx->server_index].socket_udp, -+ b->buffer, to_send, 0, -+ ctx->client_address, ctx->client_address_length) < 0) -+ TEST_VERIFY_EXIT (errno != EBADF); -+} -+ - /* UDP thread_callback function. Variant for one thread per - server. */ - static void -@@ -897,14 +911,15 @@ server_thread_tcp_client (void *arg) - - struct resolv_response_context ctx = - { -+ .test = closure->obj, - .query_buffer = query_buffer, - .query_length = query_length, - .server_index = closure->server_index, - .tcp = true, - .edns = qinfo.edns, - }; -- struct resolv_response_builder *b = response_builder_allocate -- (query_buffer, query_length); -+ struct resolv_response_builder *b -+ = resolv_response_builder_allocate (query_buffer, query_length); - closure->obj->config.response_callback - (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); - -@@ -936,7 +951,7 @@ server_thread_tcp_client (void *arg) - writev_fully (closure->client_socket, buffers, 2); - } - bool close_flag = b->close; -- response_builder_free (b); -+ resolv_response_builder_free (b); - free (query_buffer); - if (close_flag) - break; -diff --git a/support/resolv_test.h b/support/resolv_test.h -index 67819469a0..31a5c1c3e7 100644 ---- a/support/resolv_test.h -+++ b/support/resolv_test.h -@@ -35,25 +35,36 @@ struct resolv_edns_info - uint16_t payload_size; - }; - -+/* This opaque struct collects information about the resolver testing -+ currently in progress. */ -+struct resolv_test; -+ - /* This struct provides context information when the response callback - specified in struct resolv_redirect_config is invoked. */ - struct resolv_response_context - { -- const unsigned char *query_buffer; -+ struct resolv_test *test; -+ void *client_address; -+ size_t client_address_length; -+ unsigned char *query_buffer; - size_t query_length; - int server_index; - bool tcp; - struct resolv_edns_info edns; - }; - -+/* Produces a deep copy of the context. */ -+struct resolv_response_context * -+ resolv_response_context_duplicate (const struct resolv_response_context *); -+ -+/* Frees the copy. For the context passed to the response function, -+ this happens implicitly. */ -+void resolv_response_context_free (struct resolv_response_context *); -+ - /* This opaque struct is used to construct responses from within the - response callback function. */ - struct resolv_response_builder; - --/* This opaque struct collects information about the resolver testing -- currently in progress. */ --struct resolv_test; -- - enum - { - /* Maximum number of test servers supported by the framework. */ -@@ -137,6 +148,10 @@ struct resolv_response_flags - /* If true, the AD (authenticated data) flag will be set. */ - bool ad; - -+ /* If true, do not set the RA (recursion available) flag in the -+ response. */ -+ bool clear_ra; -+ - /* Initial section count values. Can be used to artificially - increase the counts, for malformed packet testing.*/ - unsigned short qdcount; -@@ -188,6 +203,22 @@ void resolv_response_close (struct resolv_response_builder *); - /* The size of the response packet built so far. */ - size_t resolv_response_length (const struct resolv_response_builder *); - -+/* Allocates a response builder tied to a specific query packet, -+ starting at QUERY_BUFFER, containing QUERY_LENGTH bytes. */ -+struct resolv_response_builder * -+ resolv_response_builder_allocate (const unsigned char *query_buffer, -+ size_t query_length); -+ -+/* Deallocates a response buffer. */ -+void resolv_response_builder_free (struct resolv_response_builder *); -+ -+/* Sends a UDP response using a specific context. This can be used to -+ reorder or duplicate responses, along with -+ resolv_response_context_duplicate and -+ response_builder_allocate. */ -+void resolv_response_send_udp (const struct resolv_response_context *, -+ struct resolv_response_builder *); -+ - __END_DECLS - - #endif /* SUPPORT_RESOLV_TEST_H */ -diff --git a/support/subprocess.h b/support/subprocess.h -index 8b442fd5c0..34ffd02e8e 100644 ---- a/support/subprocess.h -+++ b/support/subprocess.h -@@ -38,6 +38,11 @@ struct support_subprocess support_subprocess - struct support_subprocess support_subprogram - (const char *file, char *const argv[]); - -+/* Invoke program FILE with ARGV arguments by using posix_spawn and wait for it -+ to complete. Return program exit status. */ -+int support_subprogram_wait -+ (const char *file, char *const argv[]); -+ - /* Wait for the subprocess indicated by PROC::PID. Return the status - indicate by waitpid call. */ - int support_process_wait (struct support_subprocess *proc); -diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c -index eeed676e3d..28a37df67f 100644 ---- a/support/support_capture_subprocess.c -+++ b/support/support_capture_subprocess.c -@@ -20,11 +20,14 @@ - #include <support/capture_subprocess.h> - - #include <errno.h> -+#include <fcntl.h> - #include <stdlib.h> - #include <support/check.h> - #include <support/xunistd.h> - #include <support/xsocket.h> - #include <support/xspawn.h> -+#include <support/support.h> -+#include <support/test-driver.h> - - static void - transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) -@@ -36,7 +39,7 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) - if (ret < 0) - { - support_record_failure (); -- printf ("error: reading from subprocess %s: %m", what); -+ printf ("error: reading from subprocess %s: %m\n", what); - pfd->events = 0; - pfd->revents = 0; - } -@@ -102,6 +105,129 @@ support_capture_subprogram (const char *file, char *const argv[]) - return result; - } - -+/* Copies the executable into a restricted directory, so that we can -+ safely make it SGID with the TARGET group ID. Then runs the -+ executable. */ -+static int -+copy_and_spawn_sgid (char *child_id, gid_t gid) -+{ -+ char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd", -+ test_dir, (intmax_t) getpid ()); -+ char *execname = xasprintf ("%s/bin", dirname); -+ int infd = -1; -+ int outfd = -1; -+ int ret = 1, status = 1; -+ -+ TEST_VERIFY (mkdir (dirname, 0700) == 0); -+ if (support_record_failure_is_failed ()) -+ goto err; -+ -+ infd = open ("/proc/self/exe", O_RDONLY); -+ if (infd < 0) -+ FAIL_UNSUPPORTED ("unsupported: Cannot read binary from procfs\n"); -+ -+ outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700); -+ TEST_VERIFY (outfd >= 0); -+ if (support_record_failure_is_failed ()) -+ goto err; -+ -+ char buf[4096]; -+ for (;;) -+ { -+ ssize_t rdcount = read (infd, buf, sizeof (buf)); -+ TEST_VERIFY (rdcount >= 0); -+ if (support_record_failure_is_failed ()) -+ goto err; -+ if (rdcount == 0) -+ break; -+ char *p = buf; -+ char *end = buf + rdcount; -+ while (p != end) -+ { -+ ssize_t wrcount = write (outfd, buf, end - p); -+ if (wrcount == 0) -+ errno = ENOSPC; -+ TEST_VERIFY (wrcount > 0); -+ if (support_record_failure_is_failed ()) -+ goto err; -+ p += wrcount; -+ } -+ } -+ TEST_VERIFY (fchown (outfd, getuid (), gid) == 0); -+ if (support_record_failure_is_failed ()) -+ goto err; -+ TEST_VERIFY (fchmod (outfd, 02750) == 0); -+ if (support_record_failure_is_failed ()) -+ goto err; -+ TEST_VERIFY (close (outfd) == 0); -+ if (support_record_failure_is_failed ()) -+ goto err; -+ TEST_VERIFY (close (infd) == 0); -+ if (support_record_failure_is_failed ()) -+ goto err; -+ -+ /* We have the binary, now spawn the subprocess. Avoid using -+ support_subprogram because we only want the program exit status, not the -+ contents. */ -+ ret = 0; -+ -+ char * const args[] = {execname, child_id, NULL}; -+ -+ status = support_subprogram_wait (args[0], args); -+ -+err: -+ if (outfd >= 0) -+ close (outfd); -+ if (infd >= 0) -+ close (infd); -+ if (execname != NULL) -+ { -+ unlink (execname); -+ free (execname); -+ } -+ if (dirname != NULL) -+ { -+ rmdir (dirname); -+ free (dirname); -+ } -+ -+ if (ret != 0) -+ FAIL_EXIT1("Failed to make sgid executable for test\n"); -+ -+ return status; -+} -+ -+int -+support_capture_subprogram_self_sgid (char *child_id) -+{ -+ gid_t target = 0; -+ const int count = 64; -+ gid_t groups[count]; -+ -+ /* Get a GID which is not our current GID, but is present in the -+ supplementary group list. */ -+ int ret = getgroups (count, groups); -+ if (ret < 0) -+ FAIL_UNSUPPORTED("Could not get group list for user %jd\n", -+ (intmax_t) getuid ()); -+ -+ gid_t current = getgid (); -+ for (int i = 0; i < ret; ++i) -+ { -+ if (groups[i] != current) -+ { -+ target = groups[i]; -+ break; -+ } -+ } -+ -+ if (target == 0) -+ FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n", -+ (intmax_t) getuid ()); -+ -+ return copy_and_spawn_sgid (child_id, target); -+} -+ - void - support_capture_subprocess_free (struct support_capture_subprocess *p) - { -diff --git a/support/support_subprocess.c b/support/support_subprocess.c -index 36e3a77af2..4a25828111 100644 ---- a/support/support_subprocess.c -+++ b/support/support_subprocess.c -@@ -27,7 +27,7 @@ - #include <support/subprocess.h> - - static struct support_subprocess --support_suprocess_init (void) -+support_subprocess_init (void) - { - struct support_subprocess result; - -@@ -48,7 +48,7 @@ support_suprocess_init (void) - struct support_subprocess - support_subprocess (void (*callback) (void *), void *closure) - { -- struct support_subprocess result = support_suprocess_init (); -+ struct support_subprocess result = support_subprocess_init (); - - result.pid = xfork (); - if (result.pid == 0) -@@ -71,7 +71,7 @@ support_subprocess (void (*callback) (void *), void *closure) - struct support_subprocess - support_subprogram (const char *file, char *const argv[]) - { -- struct support_subprocess result = support_suprocess_init (); -+ struct support_subprocess result = support_subprocess_init (); - - posix_spawn_file_actions_t fa; - /* posix_spawn_file_actions_init does not fail. */ -@@ -84,7 +84,7 @@ support_subprogram (const char *file, char *const argv[]) - xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]); - xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]); - -- result.pid = xposix_spawn (file, &fa, NULL, argv, NULL); -+ result.pid = xposix_spawn (file, &fa, NULL, argv, environ); - - xclose (result.stdout_pipe[1]); - xclose (result.stderr_pipe[1]); -@@ -92,6 +92,19 @@ support_subprogram (const char *file, char *const argv[]) - return result; - } - -+int -+support_subprogram_wait (const char *file, char *const argv[]) -+{ -+ posix_spawn_file_actions_t fa; -+ -+ posix_spawn_file_actions_init (&fa); -+ struct support_subprocess res = support_subprocess_init (); -+ -+ res.pid = xposix_spawn (file, &fa, NULL, argv, environ); -+ -+ return support_process_wait (&res); -+} -+ - int - support_process_wait (struct support_subprocess *proc) - { -diff --git a/support/xpthread_kill.c b/support/xpthread_kill.c -new file mode 100644 -index 0000000000..111a75d85e ---- /dev/null -+++ b/support/xpthread_kill.c -@@ -0,0 +1,26 @@ -+/* pthread_kill with error checking. -+ 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 -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <signal.h> -+#include <support/xthread.h> -+ -+void -+xpthread_kill (pthread_t thr, int signo) -+{ -+ xpthread_check_return ("pthread_kill", pthread_kill (thr, signo)); -+} -diff --git a/support/xthread.h b/support/xthread.h -index 05f8d4a7d9..cb1fc30da0 100644 ---- a/support/xthread.h -+++ b/support/xthread.h -@@ -75,6 +75,8 @@ void xpthread_attr_setstacksize (pthread_attr_t *attr, - void xpthread_attr_setguardsize (pthread_attr_t *attr, - size_t guardsize); - -+void xpthread_kill (pthread_t thr, int signo); -+ - /* Set the stack size in ATTR to a small value, but still large enough - to cover most internal glibc stack usage. */ - void support_set_small_thread_stack_size (pthread_attr_t *attr); -diff --git a/sysdeps/aarch64/dl-bti.c b/sysdeps/aarch64/dl-bti.c -index 196e462520..cf7624aaa2 100644 ---- a/sysdeps/aarch64/dl-bti.c -+++ b/sysdeps/aarch64/dl-bti.c -@@ -19,43 +19,76 @@ - #include <errno.h> - #include <libintl.h> - #include <ldsodefs.h> -+#include <sys/mman.h> - --static int --enable_bti (struct link_map *map, const char *program) -+/* See elf/dl-load.h. */ -+#ifndef MAP_COPY -+# define MAP_COPY (MAP_PRIVATE | MAP_DENYWRITE) -+#endif -+ -+/* Enable BTI protection for MAP. */ -+ -+void -+_dl_bti_protect (struct link_map *map, int fd) - { -+ const size_t pagesz = GLRO(dl_pagesize); - const ElfW(Phdr) *phdr; -- unsigned prot; - - for (phdr = map->l_phdr; phdr < &map->l_phdr[map->l_phnum]; ++phdr) - if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X)) - { -- void *start = (void *) (phdr->p_vaddr + map->l_addr); -- size_t len = phdr->p_memsz; -+ size_t vstart = ALIGN_DOWN (phdr->p_vaddr, pagesz); -+ size_t vend = ALIGN_UP (phdr->p_vaddr + phdr->p_filesz, pagesz); -+ off_t off = ALIGN_DOWN (phdr->p_offset, pagesz); -+ void *start = (void *) (vstart + map->l_addr); -+ size_t len = vend - vstart; - -- prot = PROT_EXEC | PROT_BTI; -+ unsigned prot = PROT_EXEC | PROT_BTI; - if (phdr->p_flags & PF_R) - prot |= PROT_READ; - if (phdr->p_flags & PF_W) - prot |= PROT_WRITE; - -- if (__mprotect (start, len, prot) < 0) -- { -- if (program) -- _dl_fatal_printf ("%s: mprotect failed to turn on BTI\n", -- map->l_name); -- else -- _dl_signal_error (errno, map->l_name, "dlopen", -- N_("mprotect failed to turn on BTI")); -- } -+ if (fd == -1) -+ /* Ignore failures for kernel mapped binaries. */ -+ __mprotect (start, len, prot); -+ else -+ map->l_mach.bti_fail = __mmap (start, len, prot, -+ MAP_FIXED|MAP_COPY|MAP_FILE, -+ fd, off) == MAP_FAILED; - } -- return 0; - } - --/* Enable BTI for L if required. */ -+ -+static void -+bti_failed (struct link_map *l, const char *program) -+{ -+ if (program) -+ _dl_fatal_printf ("%s: %s: failed to turn on BTI protection\n", -+ program, l->l_name); -+ else -+ /* Note: the errno value is not available any more. */ -+ _dl_signal_error (0, l->l_name, "dlopen", -+ N_("failed to turn on BTI protection")); -+} -+ -+ -+/* Enable BTI for L and its dependencies. */ - - void - _dl_bti_check (struct link_map *l, const char *program) - { -- if (GLRO(dl_aarch64_cpu_features).bti && l->l_mach.bti) -- enable_bti (l, program); -+ if (!GLRO(dl_aarch64_cpu_features).bti) -+ return; -+ -+ if (l->l_mach.bti_fail) -+ bti_failed (l, program); -+ -+ unsigned int i = l->l_searchlist.r_nlist; -+ while (i-- > 0) -+ { -+ struct link_map *dep = l->l_initfini[i]; -+ if (dep->l_mach.bti_fail) -+ bti_failed (dep, program); -+ } - } -diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h -index 70b9ed3925..fde7cfd9e2 100644 ---- a/sysdeps/aarch64/dl-machine.h -+++ b/sysdeps/aarch64/dl-machine.h -@@ -395,13 +395,6 @@ elf_machine_lazy_rel (struct link_map *map, - /* Check for unexpected PLT reloc type. */ - if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1)) - { -- if (map->l_mach.plt == 0) -- { -- /* Prelinking. */ -- *reloc_addr += l_addr; -- return; -- } -- - if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL)) - { - /* Check the symbol table for variant PCS symbols. */ -@@ -425,7 +418,10 @@ elf_machine_lazy_rel (struct link_map *map, - } - } - -- *reloc_addr = map->l_mach.plt; -+ if (map->l_mach.plt == 0) -+ *reloc_addr += l_addr; -+ else -+ *reloc_addr = map->l_mach.plt; - } - else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1)) - { -diff --git a/sysdeps/aarch64/dl-prop.h b/sysdeps/aarch64/dl-prop.h -index b0785bda83..e926e54984 100644 ---- a/sysdeps/aarch64/dl-prop.h -+++ b/sysdeps/aarch64/dl-prop.h -@@ -19,6 +19,8 @@ - #ifndef _DL_PROP_H - #define _DL_PROP_H - -+extern void _dl_bti_protect (struct link_map *, int) attribute_hidden; -+ - extern void _dl_bti_check (struct link_map *, const char *) - attribute_hidden; - -@@ -35,14 +37,18 @@ _dl_open_check (struct link_map *m) - } - - static inline void __attribute__ ((always_inline)) --_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph) -+_dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph) - { - } - - static inline int --_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz, -- void *data) -+_dl_process_gnu_property (struct link_map *l, int fd, uint32_t type, -+ uint32_t datasz, void *data) - { -+ if (!GLRO(dl_aarch64_cpu_features).bti) -+ /* Skip note processing. */ -+ return 0; -+ - if (type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) - { - /* Stop if the property note is ill-formed. */ -@@ -51,7 +57,7 @@ _dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz, - - unsigned int feature_1 = *(unsigned int *) data; - if (feature_1 & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) -- l->l_mach.bti = true; -+ _dl_bti_protect (l, fd); - - /* Stop if we processed the property note. */ - return 0; -diff --git a/sysdeps/aarch64/linkmap.h b/sysdeps/aarch64/linkmap.h -index 847a03ace2..b3f7663b07 100644 ---- a/sysdeps/aarch64/linkmap.h -+++ b/sysdeps/aarch64/linkmap.h -@@ -22,5 +22,5 @@ struct link_map_machine - { - ElfW(Addr) plt; /* Address of .plt */ - void *tlsdesc_table; /* Address of TLS descriptor hash table. */ -- bool bti; /* Branch Target Identification is enabled. */ -+ bool bti_fail; /* Failed to enable Branch Target Identification. */ - }; -diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c -index 7cf5f033e8..799d60c98c 100644 ---- a/sysdeps/aarch64/multiarch/memcpy.c -+++ b/sysdeps/aarch64/multiarch/memcpy.c -@@ -41,7 +41,8 @@ libc_ifunc (__libc_memcpy, - ? __memcpy_falkor - : (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr) - ? __memcpy_thunderx2 -- : (IS_NEOVERSE_N1 (midr) -+ : (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr) -+ || IS_NEOVERSE_V1 (midr) - ? __memcpy_simd - : __memcpy_generic))))); - -diff --git a/sysdeps/aarch64/multiarch/memcpy_advsimd.S b/sysdeps/aarch64/multiarch/memcpy_advsimd.S -index d4ba747777..48bb6d7ca4 100644 ---- a/sysdeps/aarch64/multiarch/memcpy_advsimd.S -+++ b/sysdeps/aarch64/multiarch/memcpy_advsimd.S -@@ -223,12 +223,13 @@ L(copy_long_backwards): - b.ls L(copy64_from_start) - - L(loop64_backwards): -- stp A_q, B_q, [dstend, -32] -+ str B_q, [dstend, -16] -+ str A_q, [dstend, -32] - ldp A_q, B_q, [srcend, -96] -- stp C_q, D_q, [dstend, -64] -+ str D_q, [dstend, -48] -+ str C_q, [dstend, -64]! - ldp C_q, D_q, [srcend, -128] - sub srcend, srcend, 64 -- sub dstend, dstend, 64 - subs count, count, 64 - b.hi L(loop64_backwards) - -diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c -index ad10aa8ac6..46a4cb3a54 100644 ---- a/sysdeps/aarch64/multiarch/memmove.c -+++ b/sysdeps/aarch64/multiarch/memmove.c -@@ -41,7 +41,8 @@ libc_ifunc (__libc_memmove, - ? __memmove_falkor - : (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr) - ? __memmove_thunderx2 -- : (IS_NEOVERSE_N1 (midr) -+ : (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr) -+ || IS_NEOVERSE_V1 (midr) - ? __memmove_simd - : __memmove_generic))))); - -diff --git a/sysdeps/aarch64/start.S b/sysdeps/aarch64/start.S -index 75393e1c18..1998ea95d4 100644 ---- a/sysdeps/aarch64/start.S -+++ b/sysdeps/aarch64/start.S -@@ -43,11 +43,9 @@ - */ - - .text -- .globl _start -- .type _start,#function --_start: -- BTI_C -+ENTRY(_start) - /* Create an initial frame with 0 LR and FP */ -+ cfi_undefined (x30) - mov x29, #0 - mov x30, #0 - -@@ -101,8 +99,10 @@ _start: - because crt1.o and rcrt1.o share code and the later must avoid the - use of GOT relocations before __libc_start_main is called. */ - __wrap_main: -+ BTI_C - b main - #endif -+END(_start) - - /* Define a symbol for the first piece of initialized data. */ - .data -diff --git a/sysdeps/generic/dl-prop.h b/sysdeps/generic/dl-prop.h -index f1cf576fe3..df27ff8e6a 100644 ---- a/sysdeps/generic/dl-prop.h -+++ b/sysdeps/generic/dl-prop.h -@@ -37,15 +37,15 @@ _dl_open_check (struct link_map *m) - } - - static inline void __attribute__ ((always_inline)) --_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph) -+_dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph) - { - } - - /* Called for each property in the NT_GNU_PROPERTY_TYPE_0 note of L, - processing of the properties continues until this returns 0. */ - static inline int __attribute__ ((always_inline)) --_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz, -- void *data) -+_dl_process_gnu_property (struct link_map *l, int fd, uint32_t type, -+ uint32_t datasz, void *data) - { - return 0; - } -diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h -index ba114ab4b1..62ac40d81b 100644 ---- a/sysdeps/generic/ldsodefs.h -+++ b/sysdeps/generic/ldsodefs.h -@@ -919,8 +919,9 @@ extern void _dl_rtld_di_serinfo (struct link_map *loader, - Dl_serinfo *si, bool counting); - - /* Process PT_GNU_PROPERTY program header PH in module L after -- PT_LOAD segments are mapped. */ --void _dl_process_pt_gnu_property (struct link_map *l, const ElfW(Phdr) *ph); -+ PT_LOAD segments are mapped from file FD. */ -+void _dl_process_pt_gnu_property (struct link_map *l, int fd, -+ const ElfW(Phdr) *ph); - - - /* Search loaded objects' symbol tables for a definition of the symbol -diff --git a/sysdeps/generic/unwind.h b/sysdeps/generic/unwind.h -index b667a5b652..c229603af3 100644 ---- a/sysdeps/generic/unwind.h -+++ b/sysdeps/generic/unwind.h -@@ -75,15 +75,21 @@ typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code, - - struct _Unwind_Exception - { -- _Unwind_Exception_Class exception_class; -- _Unwind_Exception_Cleanup_Fn exception_cleanup; -- _Unwind_Word private_1; -- _Unwind_Word private_2; -- -- /* @@@ The IA-64 ABI says that this structure must be double-word aligned. -- Taking that literally does not make much sense generically. Instead we -- provide the maximum alignment required by any type for the machine. */ --} __attribute__((__aligned__)); -+ union -+ { -+ struct -+ { -+ _Unwind_Exception_Class exception_class; -+ _Unwind_Exception_Cleanup_Fn exception_cleanup; -+ _Unwind_Word private_1; -+ _Unwind_Word private_2; -+ }; -+ -+ /* The IA-64 ABI says that this structure must be double-word aligned. */ -+ _Unwind_Word unwind_exception_align[2] -+ __attribute__ ((__aligned__ (2 * sizeof (_Unwind_Word)))); -+ }; -+}; - - - /* The ACTIONS argument to the personality routine is a bitwise OR of one -diff --git a/sysdeps/gnu/errlist.h b/sysdeps/gnu/errlist.h -index 5d11ed723d..6329e5f393 100644 ---- a/sysdeps/gnu/errlist.h -+++ b/sysdeps/gnu/errlist.h -@@ -1,24 +1,21 @@ --#ifndef ERR_MAP --#define ERR_MAP(value) value --#endif --_S(ERR_MAP(0), N_("Success")) -+_S(0, N_("Success")) - #ifdef EPERM - /* - TRANS Only the owner of the file (or other resource) - TRANS or processes with special privileges can perform the operation. */ --_S(ERR_MAP(EPERM), N_("Operation not permitted")) -+_S(EPERM, N_("Operation not permitted")) - #endif - #ifdef ENOENT - /* - TRANS This is a ``file doesn't exist'' error - TRANS for ordinary files that are referenced in contexts where they are - TRANS expected to already exist. */ --_S(ERR_MAP(ENOENT), N_("No such file or directory")) -+_S(ENOENT, N_("No such file or directory")) - #endif - #ifdef ESRCH - /* - TRANS No process matches the specified process ID. */ --_S(ERR_MAP(ESRCH), N_("No such process")) -+_S(ESRCH, N_("No such process")) - #endif - #ifdef EINTR - /* -@@ -29,12 +26,12 @@ TRANS - TRANS You can choose to have functions resume after a signal that is handled, - TRANS rather than failing with @code{EINTR}; see @ref{Interrupted - TRANS Primitives}. */ --_S(ERR_MAP(EINTR), N_("Interrupted system call")) -+_S(EINTR, N_("Interrupted system call")) - #endif - #ifdef EIO - /* - TRANS Usually used for physical read or write errors. */ --_S(ERR_MAP(EIO), N_("Input/output error")) -+_S(EIO, N_("Input/output error")) - #endif - #ifdef ENXIO - /* -@@ -43,7 +40,7 @@ TRANS represented by a file you specified, and it couldn't find the device. - TRANS This can mean that the device file was installed incorrectly, or that - TRANS the physical device is missing or not correctly attached to the - TRANS computer. */ --_S(ERR_MAP(ENXIO), N_("No such device or address")) -+_S(ENXIO, N_("No such device or address")) - #endif - #ifdef E2BIG - /* -@@ -51,27 +48,27 @@ TRANS Used when the arguments passed to a new program - TRANS being executed with one of the @code{exec} functions (@pxref{Executing a - TRANS File}) occupy too much memory space. This condition never arises on - TRANS @gnuhurdsystems{}. */ --_S(ERR_MAP(E2BIG), N_("Argument list too long")) -+_S(E2BIG, N_("Argument list too long")) - #endif - #ifdef ENOEXEC - /* - TRANS Invalid executable file format. This condition is detected by the - TRANS @code{exec} functions; see @ref{Executing a File}. */ --_S(ERR_MAP(ENOEXEC), N_("Exec format error")) -+_S(ENOEXEC, N_("Exec format error")) - #endif - #ifdef EBADF - /* - TRANS For example, I/O on a descriptor that has been - TRANS closed or reading from a descriptor open only for writing (or vice - TRANS versa). */ --_S(ERR_MAP(EBADF), N_("Bad file descriptor")) -+_S(EBADF, N_("Bad file descriptor")) - #endif - #ifdef ECHILD - /* - TRANS This error happens on operations that are - TRANS supposed to manipulate child processes, when there aren't any processes - TRANS to manipulate. */ --_S(ERR_MAP(ECHILD), N_("No child processes")) -+_S(ECHILD, N_("No child processes")) - #endif - #ifdef EDEADLK - /* -@@ -79,74 +76,74 @@ TRANS Allocating a system resource would have resulted in a - TRANS deadlock situation. The system does not guarantee that it will notice - TRANS all such situations. This error means you got lucky and the system - TRANS noticed; it might just hang. @xref{File Locks}, for an example. */ --_S(ERR_MAP(EDEADLK), N_("Resource deadlock avoided")) -+_S(EDEADLK, N_("Resource deadlock avoided")) - #endif - #ifdef ENOMEM - /* - TRANS The system cannot allocate more virtual memory - TRANS because its capacity is full. */ --_S(ERR_MAP(ENOMEM), N_("Cannot allocate memory")) -+_S(ENOMEM, N_("Cannot allocate memory")) - #endif - #ifdef EACCES - /* - TRANS The file permissions do not allow the attempted operation. */ --_S(ERR_MAP(EACCES), N_("Permission denied")) -+_S(EACCES, N_("Permission denied")) - #endif - #ifdef EFAULT - /* - TRANS An invalid pointer was detected. - TRANS On @gnuhurdsystems{}, this error never happens; you get a signal instead. */ --_S(ERR_MAP(EFAULT), N_("Bad address")) -+_S(EFAULT, N_("Bad address")) - #endif - #ifdef ENOTBLK - /* - TRANS A file that isn't a block special file was given in a situation that - TRANS requires one. For example, trying to mount an ordinary file as a file - TRANS system in Unix gives this error. */ --_S(ERR_MAP(ENOTBLK), N_("Block device required")) -+_S(ENOTBLK, N_("Block device required")) - #endif - #ifdef EBUSY - /* - TRANS A system resource that can't be shared is already in use. - TRANS For example, if you try to delete a file that is the root of a currently - TRANS mounted filesystem, you get this error. */ --_S(ERR_MAP(EBUSY), N_("Device or resource busy")) -+_S(EBUSY, N_("Device or resource busy")) - #endif - #ifdef EEXIST - /* - TRANS An existing file was specified in a context where it only - TRANS makes sense to specify a new file. */ --_S(ERR_MAP(EEXIST), N_("File exists")) -+_S(EEXIST, N_("File exists")) - #endif - #ifdef EXDEV - /* - TRANS An attempt to make an improper link across file systems was detected. - TRANS This happens not only when you use @code{link} (@pxref{Hard Links}) but - TRANS also when you rename a file with @code{rename} (@pxref{Renaming Files}). */ --_S(ERR_MAP(EXDEV), N_("Invalid cross-device link")) -+_S(EXDEV, N_("Invalid cross-device link")) - #endif - #ifdef ENODEV - /* - TRANS The wrong type of device was given to a function that expects a - TRANS particular sort of device. */ --_S(ERR_MAP(ENODEV), N_("No such device")) -+_S(ENODEV, N_("No such device")) - #endif - #ifdef ENOTDIR - /* - TRANS A file that isn't a directory was specified when a directory is required. */ --_S(ERR_MAP(ENOTDIR), N_("Not a directory")) -+_S(ENOTDIR, N_("Not a directory")) - #endif - #ifdef EISDIR - /* - TRANS You cannot open a directory for writing, - TRANS or create or remove hard links to it. */ --_S(ERR_MAP(EISDIR), N_("Is a directory")) -+_S(EISDIR, N_("Is a directory")) - #endif - #ifdef EINVAL - /* - TRANS This is used to indicate various kinds of problems - TRANS with passing the wrong argument to a library function. */ --_S(ERR_MAP(EINVAL), N_("Invalid argument")) -+_S(EINVAL, N_("Invalid argument")) - #endif - #ifdef EMFILE - /* -@@ -157,20 +154,20 @@ TRANS In BSD and GNU, the number of open files is controlled by a resource - TRANS limit that can usually be increased. If you get this error, you might - TRANS want to increase the @code{RLIMIT_NOFILE} limit or make it unlimited; - TRANS @pxref{Limits on Resources}. */ --_S(ERR_MAP(EMFILE), N_("Too many open files")) -+_S(EMFILE, N_("Too many open files")) - #endif - #ifdef ENFILE - /* - TRANS There are too many distinct file openings in the entire system. Note - TRANS that any number of linked channels count as just one file opening; see - TRANS @ref{Linked Channels}. This error never occurs on @gnuhurdsystems{}. */ --_S(ERR_MAP(ENFILE), N_("Too many open files in system")) -+_S(ENFILE, N_("Too many open files in system")) - #endif - #ifdef ENOTTY - /* - TRANS Inappropriate I/O control operation, such as trying to set terminal - TRANS modes on an ordinary file. */ --_S(ERR_MAP(ENOTTY), N_("Inappropriate ioctl for device")) -+_S(ENOTTY, N_("Inappropriate ioctl for device")) - #endif - #ifdef ETXTBSY - /* -@@ -179,35 +176,35 @@ TRANS write to a file that is currently being executed. Often using a - TRANS debugger to run a program is considered having it open for writing and - TRANS will cause this error. (The name stands for ``text file busy''.) This - TRANS is not an error on @gnuhurdsystems{}; the text is copied as necessary. */ --_S(ERR_MAP(ETXTBSY), N_("Text file busy")) -+_S(ETXTBSY, N_("Text file busy")) - #endif - #ifdef EFBIG - /* - TRANS The size of a file would be larger than allowed by the system. */ --_S(ERR_MAP(EFBIG), N_("File too large")) -+_S(EFBIG, N_("File too large")) - #endif - #ifdef ENOSPC - /* - TRANS Write operation on a file failed because the - TRANS disk is full. */ --_S(ERR_MAP(ENOSPC), N_("No space left on device")) -+_S(ENOSPC, N_("No space left on device")) - #endif - #ifdef ESPIPE - /* - TRANS Invalid seek operation (such as on a pipe). */ --_S(ERR_MAP(ESPIPE), N_("Illegal seek")) -+_S(ESPIPE, N_("Illegal seek")) - #endif - #ifdef EROFS - /* - TRANS An attempt was made to modify something on a read-only file system. */ --_S(ERR_MAP(EROFS), N_("Read-only file system")) -+_S(EROFS, N_("Read-only file system")) - #endif - #ifdef EMLINK - /* - TRANS The link count of a single file would become too large. - TRANS @code{rename} can cause this error if the file being renamed already has - TRANS as many links as it can take (@pxref{Renaming Files}). */ --_S(ERR_MAP(EMLINK), N_("Too many links")) -+_S(EMLINK, N_("Too many links")) - #endif - #ifdef EPIPE - /* -@@ -216,19 +213,19 @@ TRANS Every library function that returns this error code also generates a - TRANS @code{SIGPIPE} signal; this signal terminates the program if not handled - TRANS or blocked. Thus, your program will never actually see @code{EPIPE} - TRANS unless it has handled or blocked @code{SIGPIPE}. */ --_S(ERR_MAP(EPIPE), N_("Broken pipe")) -+_S(EPIPE, N_("Broken pipe")) - #endif - #ifdef EDOM - /* - TRANS Used by mathematical functions when an argument value does - TRANS not fall into the domain over which the function is defined. */ --_S(ERR_MAP(EDOM), N_("Numerical argument out of domain")) -+_S(EDOM, N_("Numerical argument out of domain")) - #endif - #ifdef ERANGE - /* - TRANS Used by mathematical functions when the result value is - TRANS not representable because of overflow or underflow. */ --_S(ERR_MAP(ERANGE), N_("Numerical result out of range")) -+_S(ERANGE, N_("Numerical result out of range")) - #endif - #ifdef EAGAIN - /* -@@ -261,7 +258,7 @@ TRANS Such shortages are usually fairly serious and affect the whole system, - TRANS so usually an interactive program should report the error to the user - TRANS and return to its command loop. - TRANS @end itemize */ --_S(ERR_MAP(EAGAIN), N_("Resource temporarily unavailable")) -+_S(EAGAIN, N_("Resource temporarily unavailable")) - #endif - #ifdef EINPROGRESS - /* -@@ -273,47 +270,47 @@ TRANS the operation has begun and will take some time. Attempts to manipulate - TRANS the object before the call completes return @code{EALREADY}. You can - TRANS use the @code{select} function to find out when the pending operation - TRANS has completed; @pxref{Waiting for I/O}. */ --_S(ERR_MAP(EINPROGRESS), N_("Operation now in progress")) -+_S(EINPROGRESS, N_("Operation now in progress")) - #endif - #ifdef EALREADY - /* - TRANS An operation is already in progress on an object that has non-blocking - TRANS mode selected. */ --_S(ERR_MAP(EALREADY), N_("Operation already in progress")) -+_S(EALREADY, N_("Operation already in progress")) - #endif - #ifdef ENOTSOCK - /* - TRANS A file that isn't a socket was specified when a socket is required. */ --_S(ERR_MAP(ENOTSOCK), N_("Socket operation on non-socket")) -+_S(ENOTSOCK, N_("Socket operation on non-socket")) - #endif - #ifdef EMSGSIZE - /* - TRANS The size of a message sent on a socket was larger than the supported - TRANS maximum size. */ --_S(ERR_MAP(EMSGSIZE), N_("Message too long")) -+_S(EMSGSIZE, N_("Message too long")) - #endif - #ifdef EPROTOTYPE - /* - TRANS The socket type does not support the requested communications protocol. */ --_S(ERR_MAP(EPROTOTYPE), N_("Protocol wrong type for socket")) -+_S(EPROTOTYPE, N_("Protocol wrong type for socket")) - #endif - #ifdef ENOPROTOOPT - /* - TRANS You specified a socket option that doesn't make sense for the - TRANS particular protocol being used by the socket. @xref{Socket Options}. */ --_S(ERR_MAP(ENOPROTOOPT), N_("Protocol not available")) -+_S(ENOPROTOOPT, N_("Protocol not available")) - #endif - #ifdef EPROTONOSUPPORT - /* - TRANS The socket domain does not support the requested communications protocol - TRANS (perhaps because the requested protocol is completely invalid). - TRANS @xref{Creating a Socket}. */ --_S(ERR_MAP(EPROTONOSUPPORT), N_("Protocol not supported")) -+_S(EPROTONOSUPPORT, N_("Protocol not supported")) - #endif - #ifdef ESOCKTNOSUPPORT - /* - TRANS The socket type is not supported. */ --_S(ERR_MAP(ESOCKTNOSUPPORT), N_("Socket type not supported")) -+_S(ESOCKTNOSUPPORT, N_("Socket type not supported")) - #endif - #ifdef EOPNOTSUPP - /* -@@ -323,71 +320,71 @@ TRANS implemented for all communications protocols. On @gnuhurdsystems{}, this - TRANS error can happen for many calls when the object does not support the - TRANS particular operation; it is a generic indication that the server knows - TRANS nothing to do for that call. */ --_S(ERR_MAP(EOPNOTSUPP), N_("Operation not supported")) -+_S(EOPNOTSUPP, N_("Operation not supported")) - #endif - #ifdef EPFNOSUPPORT - /* - TRANS The socket communications protocol family you requested is not supported. */ --_S(ERR_MAP(EPFNOSUPPORT), N_("Protocol family not supported")) -+_S(EPFNOSUPPORT, N_("Protocol family not supported")) - #endif - #ifdef EAFNOSUPPORT - /* - TRANS The address family specified for a socket is not supported; it is - TRANS inconsistent with the protocol being used on the socket. @xref{Sockets}. */ --_S(ERR_MAP(EAFNOSUPPORT), N_("Address family not supported by protocol")) -+_S(EAFNOSUPPORT, N_("Address family not supported by protocol")) - #endif - #ifdef EADDRINUSE - /* - TRANS The requested socket address is already in use. @xref{Socket Addresses}. */ --_S(ERR_MAP(EADDRINUSE), N_("Address already in use")) -+_S(EADDRINUSE, N_("Address already in use")) - #endif - #ifdef EADDRNOTAVAIL - /* - TRANS The requested socket address is not available; for example, you tried - TRANS to give a socket a name that doesn't match the local host name. - TRANS @xref{Socket Addresses}. */ --_S(ERR_MAP(EADDRNOTAVAIL), N_("Cannot assign requested address")) -+_S(EADDRNOTAVAIL, N_("Cannot assign requested address")) - #endif - #ifdef ENETDOWN - /* - TRANS A socket operation failed because the network was down. */ --_S(ERR_MAP(ENETDOWN), N_("Network is down")) -+_S(ENETDOWN, N_("Network is down")) - #endif - #ifdef ENETUNREACH - /* - TRANS A socket operation failed because the subnet containing the remote host - TRANS was unreachable. */ --_S(ERR_MAP(ENETUNREACH), N_("Network is unreachable")) -+_S(ENETUNREACH, N_("Network is unreachable")) - #endif - #ifdef ENETRESET - /* - TRANS A network connection was reset because the remote host crashed. */ --_S(ERR_MAP(ENETRESET), N_("Network dropped connection on reset")) -+_S(ENETRESET, N_("Network dropped connection on reset")) - #endif - #ifdef ECONNABORTED - /* - TRANS A network connection was aborted locally. */ --_S(ERR_MAP(ECONNABORTED), N_("Software caused connection abort")) -+_S(ECONNABORTED, N_("Software caused connection abort")) - #endif - #ifdef ECONNRESET - /* - TRANS A network connection was closed for reasons outside the control of the - TRANS local host, such as by the remote machine rebooting or an unrecoverable - TRANS protocol violation. */ --_S(ERR_MAP(ECONNRESET), N_("Connection reset by peer")) -+_S(ECONNRESET, N_("Connection reset by peer")) - #endif - #ifdef ENOBUFS - /* - TRANS The kernel's buffers for I/O operations are all in use. In GNU, this - TRANS error is always synonymous with @code{ENOMEM}; you may get one or the - TRANS other from network operations. */ --_S(ERR_MAP(ENOBUFS), N_("No buffer space available")) -+_S(ENOBUFS, N_("No buffer space available")) - #endif - #ifdef EISCONN - /* - TRANS You tried to connect a socket that is already connected. - TRANS @xref{Connecting}. */ --_S(ERR_MAP(EISCONN), N_("Transport endpoint is already connected")) -+_S(EISCONN, N_("Transport endpoint is already connected")) - #endif - #ifdef ENOTCONN - /* -@@ -395,74 +392,74 @@ TRANS The socket is not connected to anything. You get this error when you - TRANS try to transmit data over a socket, without first specifying a - TRANS destination for the data. For a connectionless socket (for datagram - TRANS protocols, such as UDP), you get @code{EDESTADDRREQ} instead. */ --_S(ERR_MAP(ENOTCONN), N_("Transport endpoint is not connected")) -+_S(ENOTCONN, N_("Transport endpoint is not connected")) - #endif - #ifdef EDESTADDRREQ - /* - TRANS No default destination address was set for the socket. You get this - TRANS error when you try to transmit data over a connectionless socket, - TRANS without first specifying a destination for the data with @code{connect}. */ --_S(ERR_MAP(EDESTADDRREQ), N_("Destination address required")) -+_S(EDESTADDRREQ, N_("Destination address required")) - #endif - #ifdef ESHUTDOWN - /* - TRANS The socket has already been shut down. */ --_S(ERR_MAP(ESHUTDOWN), N_("Cannot send after transport endpoint shutdown")) -+_S(ESHUTDOWN, N_("Cannot send after transport endpoint shutdown")) - #endif - #ifdef ETOOMANYREFS --_S(ERR_MAP(ETOOMANYREFS), N_("Too many references: cannot splice")) -+_S(ETOOMANYREFS, N_("Too many references: cannot splice")) - #endif - #ifdef ETIMEDOUT - /* - TRANS A socket operation with a specified timeout received no response during - TRANS the timeout period. */ --_S(ERR_MAP(ETIMEDOUT), N_("Connection timed out")) -+_S(ETIMEDOUT, N_("Connection timed out")) - #endif - #ifdef ECONNREFUSED - /* - TRANS A remote host refused to allow the network connection (typically because - TRANS it is not running the requested service). */ --_S(ERR_MAP(ECONNREFUSED), N_("Connection refused")) -+_S(ECONNREFUSED, N_("Connection refused")) - #endif - #ifdef ELOOP - /* - TRANS Too many levels of symbolic links were encountered in looking up a file name. - TRANS This often indicates a cycle of symbolic links. */ --_S(ERR_MAP(ELOOP), N_("Too many levels of symbolic links")) -+_S(ELOOP, N_("Too many levels of symbolic links")) - #endif - #ifdef ENAMETOOLONG - /* - TRANS Filename too long (longer than @code{PATH_MAX}; @pxref{Limits for - TRANS Files}) or host name too long (in @code{gethostname} or - TRANS @code{sethostname}; @pxref{Host Identification}). */ --_S(ERR_MAP(ENAMETOOLONG), N_("File name too long")) -+_S(ENAMETOOLONG, N_("File name too long")) - #endif - #ifdef EHOSTDOWN - /* - TRANS The remote host for a requested network connection is down. */ --_S(ERR_MAP(EHOSTDOWN), N_("Host is down")) -+_S(EHOSTDOWN, N_("Host is down")) - #endif - /* - TRANS The remote host for a requested network connection is not reachable. */ - #ifdef EHOSTUNREACH --_S(ERR_MAP(EHOSTUNREACH), N_("No route to host")) -+_S(EHOSTUNREACH, N_("No route to host")) - #endif - #ifdef ENOTEMPTY - /* - TRANS Directory not empty, where an empty directory was expected. Typically, - TRANS this error occurs when you are trying to delete a directory. */ --_S(ERR_MAP(ENOTEMPTY), N_("Directory not empty")) -+_S(ENOTEMPTY, N_("Directory not empty")) - #endif - #ifdef EUSERS - /* - TRANS The file quota system is confused because there are too many users. - TRANS @c This can probably happen in a GNU system when using NFS. */ --_S(ERR_MAP(EUSERS), N_("Too many users")) -+_S(EUSERS, N_("Too many users")) - #endif - #ifdef EDQUOT - /* - TRANS The user's disk quota was exceeded. */ --_S(ERR_MAP(EDQUOT), N_("Disk quota exceeded")) -+_S(EDQUOT, N_("Disk quota exceeded")) - #endif - #ifdef ESTALE - /* -@@ -471,7 +468,7 @@ TRANS file system which is due to file system rearrangements on the server host - TRANS for NFS file systems or corruption in other file systems. - TRANS Repairing this condition usually requires unmounting, possibly repairing - TRANS and remounting the file system. */ --_S(ERR_MAP(ESTALE), N_("Stale file handle")) -+_S(ESTALE, N_("Stale file handle")) - #endif - #ifdef EREMOTE - /* -@@ -479,7 +476,7 @@ TRANS An attempt was made to NFS-mount a remote file system with a file name tha - TRANS already specifies an NFS-mounted file. - TRANS (This is an error on some operating systems, but we expect it to work - TRANS properly on @gnuhurdsystems{}, making this error code impossible.) */ --_S(ERR_MAP(EREMOTE), N_("Object is remote")) -+_S(EREMOTE, N_("Object is remote")) - #endif - #ifdef ENOLCK - /* -@@ -487,7 +484,7 @@ TRANS This is used by the file locking facilities; see - TRANS @ref{File Locks}. This error is never generated by @gnuhurdsystems{}, but - TRANS it can result from an operation to an NFS server running another - TRANS operating system. */ --_S(ERR_MAP(ENOLCK), N_("No locks available")) -+_S(ENOLCK, N_("No locks available")) - #endif - #ifdef ENOSYS - /* -@@ -496,46 +493,46 @@ TRANS not implemented at all, either in the C library itself or in the - TRANS operating system. When you get this error, you can be sure that this - TRANS particular function will always fail with @code{ENOSYS} unless you - TRANS install a new version of the C library or the operating system. */ --_S(ERR_MAP(ENOSYS), N_("Function not implemented")) -+_S(ENOSYS, N_("Function not implemented")) - #endif - #ifdef EILSEQ - /* - TRANS While decoding a multibyte character the function came along an invalid - TRANS or an incomplete sequence of bytes or the given wide character is invalid. */ --_S(ERR_MAP(EILSEQ), N_("Invalid or incomplete multibyte or wide character")) -+_S(EILSEQ, N_("Invalid or incomplete multibyte or wide character")) - #endif - #ifdef EBADMSG --_S(ERR_MAP(EBADMSG), N_("Bad message")) -+_S(EBADMSG, N_("Bad message")) - #endif - #ifdef EIDRM --_S(ERR_MAP(EIDRM), N_("Identifier removed")) -+_S(EIDRM, N_("Identifier removed")) - #endif - #ifdef EMULTIHOP --_S(ERR_MAP(EMULTIHOP), N_("Multihop attempted")) -+_S(EMULTIHOP, N_("Multihop attempted")) - #endif - #ifdef ENODATA --_S(ERR_MAP(ENODATA), N_("No data available")) -+_S(ENODATA, N_("No data available")) - #endif - #ifdef ENOLINK --_S(ERR_MAP(ENOLINK), N_("Link has been severed")) -+_S(ENOLINK, N_("Link has been severed")) - #endif - #ifdef ENOMSG --_S(ERR_MAP(ENOMSG), N_("No message of desired type")) -+_S(ENOMSG, N_("No message of desired type")) - #endif - #ifdef ENOSR --_S(ERR_MAP(ENOSR), N_("Out of streams resources")) -+_S(ENOSR, N_("Out of streams resources")) - #endif - #ifdef ENOSTR --_S(ERR_MAP(ENOSTR), N_("Device not a stream")) -+_S(ENOSTR, N_("Device not a stream")) - #endif - #ifdef EOVERFLOW --_S(ERR_MAP(EOVERFLOW), N_("Value too large for defined data type")) -+_S(EOVERFLOW, N_("Value too large for defined data type")) - #endif - #ifdef EPROTO --_S(ERR_MAP(EPROTO), N_("Protocol error")) -+_S(EPROTO, N_("Protocol error")) - #endif - #ifdef ETIME --_S(ERR_MAP(ETIME), N_("Timer expired")) -+_S(ETIME, N_("Timer expired")) - #endif - #ifdef ECANCELED - /* -@@ -543,148 +540,148 @@ TRANS An asynchronous operation was canceled before it - TRANS completed. @xref{Asynchronous I/O}. When you call @code{aio_cancel}, - TRANS the normal result is for the operations affected to complete with this - TRANS error; @pxref{Cancel AIO Operations}. */ --_S(ERR_MAP(ECANCELED), N_("Operation canceled")) -+_S(ECANCELED, N_("Operation canceled")) - #endif - #ifdef EOWNERDEAD --_S(ERR_MAP(EOWNERDEAD), N_("Owner died")) -+_S(EOWNERDEAD, N_("Owner died")) - #endif - #ifdef ENOTRECOVERABLE --_S(ERR_MAP(ENOTRECOVERABLE), N_("State not recoverable")) -+_S(ENOTRECOVERABLE, N_("State not recoverable")) - #endif - #ifdef ERESTART --_S(ERR_MAP(ERESTART), N_("Interrupted system call should be restarted")) -+_S(ERESTART, N_("Interrupted system call should be restarted")) - #endif - #ifdef ECHRNG --_S(ERR_MAP(ECHRNG), N_("Channel number out of range")) -+_S(ECHRNG, N_("Channel number out of range")) - #endif - #ifdef EL2NSYNC --_S(ERR_MAP(EL2NSYNC), N_("Level 2 not synchronized")) -+_S(EL2NSYNC, N_("Level 2 not synchronized")) - #endif - #ifdef EL3HLT --_S(ERR_MAP(EL3HLT), N_("Level 3 halted")) -+_S(EL3HLT, N_("Level 3 halted")) - #endif - #ifdef EL3RST --_S(ERR_MAP(EL3RST), N_("Level 3 reset")) -+_S(EL3RST, N_("Level 3 reset")) - #endif - #ifdef ELNRNG --_S(ERR_MAP(ELNRNG), N_("Link number out of range")) -+_S(ELNRNG, N_("Link number out of range")) - #endif - #ifdef EUNATCH --_S(ERR_MAP(EUNATCH), N_("Protocol driver not attached")) -+_S(EUNATCH, N_("Protocol driver not attached")) - #endif - #ifdef ENOCSI --_S(ERR_MAP(ENOCSI), N_("No CSI structure available")) -+_S(ENOCSI, N_("No CSI structure available")) - #endif - #ifdef EL2HLT --_S(ERR_MAP(EL2HLT), N_("Level 2 halted")) -+_S(EL2HLT, N_("Level 2 halted")) - #endif - #ifdef EBADE --_S(ERR_MAP(EBADE), N_("Invalid exchange")) -+_S(EBADE, N_("Invalid exchange")) - #endif - #ifdef EBADR --_S(ERR_MAP(EBADR), N_("Invalid request descriptor")) -+_S(EBADR, N_("Invalid request descriptor")) - #endif - #ifdef EXFULL --_S(ERR_MAP(EXFULL), N_("Exchange full")) -+_S(EXFULL, N_("Exchange full")) - #endif - #ifdef ENOANO --_S(ERR_MAP(ENOANO), N_("No anode")) -+_S(ENOANO, N_("No anode")) - #endif - #ifdef EBADRQC --_S(ERR_MAP(EBADRQC), N_("Invalid request code")) -+_S(EBADRQC, N_("Invalid request code")) - #endif - #ifdef EBADSLT --_S(ERR_MAP(EBADSLT), N_("Invalid slot")) -+_S(EBADSLT, N_("Invalid slot")) - #endif - #ifdef EBFONT --_S(ERR_MAP(EBFONT), N_("Bad font file format")) -+_S(EBFONT, N_("Bad font file format")) - #endif - #ifdef ENONET --_S(ERR_MAP(ENONET), N_("Machine is not on the network")) -+_S(ENONET, N_("Machine is not on the network")) - #endif - #ifdef ENOPKG --_S(ERR_MAP(ENOPKG), N_("Package not installed")) -+_S(ENOPKG, N_("Package not installed")) - #endif - #ifdef EADV --_S(ERR_MAP(EADV), N_("Advertise error")) -+_S(EADV, N_("Advertise error")) - #endif - #ifdef ESRMNT --_S(ERR_MAP(ESRMNT), N_("Srmount error")) -+_S(ESRMNT, N_("Srmount error")) - #endif - #ifdef ECOMM --_S(ERR_MAP(ECOMM), N_("Communication error on send")) -+_S(ECOMM, N_("Communication error on send")) - #endif - #ifdef EDOTDOT --_S(ERR_MAP(EDOTDOT), N_("RFS specific error")) -+_S(EDOTDOT, N_("RFS specific error")) - #endif - #ifdef ENOTUNIQ --_S(ERR_MAP(ENOTUNIQ), N_("Name not unique on network")) -+_S(ENOTUNIQ, N_("Name not unique on network")) - #endif - #ifdef EBADFD --_S(ERR_MAP(EBADFD), N_("File descriptor in bad state")) -+_S(EBADFD, N_("File descriptor in bad state")) - #endif - #ifdef EREMCHG --_S(ERR_MAP(EREMCHG), N_("Remote address changed")) -+_S(EREMCHG, N_("Remote address changed")) - #endif - #ifdef ELIBACC --_S(ERR_MAP(ELIBACC), N_("Can not access a needed shared library")) -+_S(ELIBACC, N_("Can not access a needed shared library")) - #endif - #ifdef ELIBBAD --_S(ERR_MAP(ELIBBAD), N_("Accessing a corrupted shared library")) -+_S(ELIBBAD, N_("Accessing a corrupted shared library")) - #endif - #ifdef ELIBSCN --_S(ERR_MAP(ELIBSCN), N_(".lib section in a.out corrupted")) -+_S(ELIBSCN, N_(".lib section in a.out corrupted")) - #endif - #ifdef ELIBMAX --_S(ERR_MAP(ELIBMAX), N_("Attempting to link in too many shared libraries")) -+_S(ELIBMAX, N_("Attempting to link in too many shared libraries")) - #endif - #ifdef ELIBEXEC --_S(ERR_MAP(ELIBEXEC), N_("Cannot exec a shared library directly")) -+_S(ELIBEXEC, N_("Cannot exec a shared library directly")) - #endif - #ifdef ESTRPIPE --_S(ERR_MAP(ESTRPIPE), N_("Streams pipe error")) -+_S(ESTRPIPE, N_("Streams pipe error")) - #endif - #ifdef EUCLEAN --_S(ERR_MAP(EUCLEAN), N_("Structure needs cleaning")) -+_S(EUCLEAN, N_("Structure needs cleaning")) - #endif - #ifdef ENOTNAM --_S(ERR_MAP(ENOTNAM), N_("Not a XENIX named type file")) -+_S(ENOTNAM, N_("Not a XENIX named type file")) - #endif - #ifdef ENAVAIL --_S(ERR_MAP(ENAVAIL), N_("No XENIX semaphores available")) -+_S(ENAVAIL, N_("No XENIX semaphores available")) - #endif - #ifdef EISNAM --_S(ERR_MAP(EISNAM), N_("Is a named type file")) -+_S(EISNAM, N_("Is a named type file")) - #endif - #ifdef EREMOTEIO --_S(ERR_MAP(EREMOTEIO), N_("Remote I/O error")) -+_S(EREMOTEIO, N_("Remote I/O error")) - #endif - #ifdef ENOMEDIUM --_S(ERR_MAP(ENOMEDIUM), N_("No medium found")) -+_S(ENOMEDIUM, N_("No medium found")) - #endif - #ifdef EMEDIUMTYPE --_S(ERR_MAP(EMEDIUMTYPE), N_("Wrong medium type")) -+_S(EMEDIUMTYPE, N_("Wrong medium type")) - #endif - #ifdef ENOKEY --_S(ERR_MAP(ENOKEY), N_("Required key not available")) -+_S(ENOKEY, N_("Required key not available")) - #endif - #ifdef EKEYEXPIRED --_S(ERR_MAP(EKEYEXPIRED), N_("Key has expired")) -+_S(EKEYEXPIRED, N_("Key has expired")) - #endif - #ifdef EKEYREVOKED --_S(ERR_MAP(EKEYREVOKED), N_("Key has been revoked")) -+_S(EKEYREVOKED, N_("Key has been revoked")) - #endif - #ifdef EKEYREJECTED --_S(ERR_MAP(EKEYREJECTED), N_("Key was rejected by service")) -+_S(EKEYREJECTED, N_("Key was rejected by service")) - #endif - #ifdef ERFKILL --_S(ERR_MAP(ERFKILL), N_("Operation not possible due to RF-kill")) -+_S(ERFKILL, N_("Operation not possible due to RF-kill")) - #endif - #ifdef EHWPOISON --_S(ERR_MAP(EHWPOISON), N_("Memory page has hardware error")) -+_S(EHWPOISON, N_("Memory page has hardware error")) - #endif - #ifdef EBADRPC --_S(ERR_MAP(EBADRPC), N_("RPC struct is bad")) -+_S(EBADRPC, N_("RPC struct is bad")) - #endif - #ifdef EFTYPE - /* -@@ -693,40 +690,40 @@ TRANS operation, or a data file had the wrong format. - TRANS - TRANS On some systems @code{chmod} returns this error if you try to set the - TRANS sticky bit on a non-directory file; @pxref{Setting Permissions}. */ --_S(ERR_MAP(EFTYPE), N_("Inappropriate file type or format")) -+_S(EFTYPE, N_("Inappropriate file type or format")) - #endif - #ifdef EPROCUNAVAIL --_S(ERR_MAP(EPROCUNAVAIL), N_("RPC bad procedure for program")) -+_S(EPROCUNAVAIL, N_("RPC bad procedure for program")) - #endif - #ifdef EAUTH --_S(ERR_MAP(EAUTH), N_("Authentication error")) -+_S(EAUTH, N_("Authentication error")) - #endif - #ifdef EDIED - /* - TRANS On @gnuhurdsystems{}, opening a file returns this error when the file is - TRANS translated by a program and the translator program dies while starting - TRANS up, before it has connected to the file. */ --_S(ERR_MAP(EDIED), N_("Translator died")) -+_S(EDIED, N_("Translator died")) - #endif - #ifdef ERPCMISMATCH --_S(ERR_MAP(ERPCMISMATCH), N_("RPC version wrong")) -+_S(ERPCMISMATCH, N_("RPC version wrong")) - #endif - #ifdef EGREGIOUS - /* - TRANS You did @strong{what}? */ --_S(ERR_MAP(EGREGIOUS), N_("You really blew it this time")) -+_S(EGREGIOUS, N_("You really blew it this time")) - #endif - #ifdef EPROCLIM - /* - TRANS This means that the per-user limit on new process would be exceeded by - TRANS an attempted @code{fork}. @xref{Limits on Resources}, for details on - TRANS the @code{RLIMIT_NPROC} limit. */ --_S(ERR_MAP(EPROCLIM), N_("Too many processes")) -+_S(EPROCLIM, N_("Too many processes")) - #endif - #ifdef EGRATUITOUS - /* - TRANS This error code has no purpose. */ --_S(ERR_MAP(EGRATUITOUS), N_("Gratuitous error")) -+_S(EGRATUITOUS, N_("Gratuitous error")) - #endif - #if defined (ENOTSUP) && ENOTSUP != EOPNOTSUPP - /* -@@ -742,10 +739,10 @@ TRANS values. - TRANS - TRANS If the entire function is not available at all in the implementation, - TRANS it returns @code{ENOSYS} instead. */ --_S(ERR_MAP(ENOTSUP), N_("Not supported")) -+_S(ENOTSUP, N_("Not supported")) - #endif - #ifdef EPROGMISMATCH --_S(ERR_MAP(EPROGMISMATCH), N_("RPC program version wrong")) -+_S(EPROGMISMATCH, N_("RPC program version wrong")) - #endif - #ifdef EBACKGROUND - /* -@@ -755,7 +752,7 @@ TRANS foreground process group of the terminal. Users do not usually see this - TRANS error because functions such as @code{read} and @code{write} translate - TRANS it into a @code{SIGTTIN} or @code{SIGTTOU} signal. @xref{Job Control}, - TRANS for information on process groups and these signals. */ --_S(ERR_MAP(EBACKGROUND), N_("Inappropriate operation for background process")) -+_S(EBACKGROUND, N_("Inappropriate operation for background process")) - #endif - #ifdef EIEIO - /* -@@ -773,7 +770,7 @@ TRANS @c "bought the farm" means "died". -jtobey - TRANS @c - TRANS @c Translators, please do not translate this litteraly, translate it into - TRANS @c an idiomatic funny way of saying that the computer died. */ --_S(ERR_MAP(EIEIO), N_("Computer bought the farm")) -+_S(EIEIO, N_("Computer bought the farm")) - #endif - #if defined (EWOULDBLOCK) && EWOULDBLOCK != EAGAIN - /* -@@ -782,18 +779,18 @@ TRANS The values are always the same, on every operating system. - TRANS - TRANS C libraries in many older Unix systems have @code{EWOULDBLOCK} as a - TRANS separate error code. */ --_S(ERR_MAP(EWOULDBLOCK), N_("Operation would block")) -+_S(EWOULDBLOCK, N_("Operation would block")) - #endif - #ifdef ENEEDAUTH --_S(ERR_MAP(ENEEDAUTH), N_("Need authenticator")) -+_S(ENEEDAUTH, N_("Need authenticator")) - #endif - #ifdef ED - /* - TRANS The experienced user will know what is wrong. - TRANS @c This error code is a joke. Its perror text is part of the joke. - TRANS @c Don't change it. */ --_S(ERR_MAP(ED), N_("?")) -+_S(ED, N_("?")) - #endif - #ifdef EPROGUNAVAIL --_S(ERR_MAP(EPROGUNAVAIL), N_("RPC program not available")) -+_S(EPROGUNAVAIL, N_("RPC program not available")) - #endif -diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h -index 0f08079e48..672d8f27ce 100644 ---- a/sysdeps/i386/dl-machine.h -+++ b/sysdeps/i386/dl-machine.h -@@ -338,16 +338,22 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, - { - # ifndef RTLD_BOOTSTRAP - if (sym_map != map -- && sym_map->l_type != lt_executable - && !sym_map->l_relocated) - { - const char *strtab - = (const char *) D_PTR (map, l_info[DT_STRTAB]); -- _dl_error_printf ("\ -+ if (sym_map->l_type == lt_executable) -+ _dl_fatal_printf ("\ -+%s: IFUNC symbol '%s' referenced in '%s' is defined in the executable \ -+and creates an unsatisfiable circular dependency.\n", -+ RTLD_PROGNAME, strtab + refsym->st_name, -+ map->l_name); -+ else -+ _dl_error_printf ("\ - %s: Relink `%s' with `%s' for IFUNC symbol `%s'\n", -- RTLD_PROGNAME, map->l_name, -- sym_map->l_name, -- strtab + refsym->st_name); -+ RTLD_PROGNAME, map->l_name, -+ sym_map->l_name, -+ strtab + refsym->st_name); - } - # endif - value = ((Elf32_Addr (*) (void)) value) (); -diff --git a/sysdeps/powerpc/powerpc64/backtrace.c b/sysdeps/powerpc/powerpc64/backtrace.c -index 8a53a1088f..362a2b713c 100644 ---- a/sysdeps/powerpc/powerpc64/backtrace.c -+++ b/sysdeps/powerpc/powerpc64/backtrace.c -@@ -54,11 +54,22 @@ struct signal_frame_64 { - /* We don't care about the rest, since the IP value is at 'uc' field. */ - }; - -+/* Test if the address match to the inside the trampoline code. -+ Up to and including kernel 5.8, returning from an interrupt or syscall to a -+ signal handler starts execution directly at the handler's entry point, with -+ LR set to address of the sigreturn trampoline (the vDSO symbol). -+ Newer kernels will branch to signal handler from the trampoline instead, so -+ checking the stacktrace against the vDSO entrypoint does not work in such -+ case. -+ The vDSO branches with a 'bctrl' instruction, so checking either the -+ vDSO address itself and the next instruction should cover all kernel -+ versions. */ - static inline bool - is_sigtramp_address (void *nip) - { - #ifdef HAVE_SIGTRAMP_RT64 -- if (nip == GLRO (dl_vdso_sigtramp_rt64)) -+ if (nip == GLRO (dl_vdso_sigtramp_rt64) || -+ nip == GLRO (dl_vdso_sigtramp_rt64) + 4) - return true; - #endif - return false; -diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile -index 920d875420..bf9b7f7223 100644 ---- a/sysdeps/pthread/Makefile -+++ b/sysdeps/pthread/Makefile -@@ -107,6 +107,7 @@ 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 \ - - - # Files which must not be linked with libpthread. -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 -+ <https://www.gnu.org/licenses/>. */ -+ -+/* 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 <support/xthread.h> -+#include <support/xsignal.h> -+ -+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 <support/test-driver.c> -diff --git a/sysdeps/s390/configure b/sysdeps/s390/configure -index fa46e9e351..e7f576338d 100644 ---- a/sysdeps/s390/configure -+++ b/sysdeps/s390/configure -@@ -123,7 +123,9 @@ void testinsn (char *buf) - __asm__ (".machine \"arch13\" \n\t" - ".machinemode \"zarch_nohighgprs\" \n\t" - "lghi %%r0,16 \n\t" -- "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); -+ "mvcrl 0(%0),32(%0) \n\t" -+ "vstrs %%v20,%%v20,%%v20,%%v20,0,2" -+ : : "a" (buf) : "memory", "r0"); - } - EOF - if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c -@@ -271,7 +273,9 @@ else - void testinsn (char *buf) - { - __asm__ ("lghi %%r0,16 \n\t" -- "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); -+ "mvcrl 0(%0),32(%0) \n\t" -+ "vstrs %%v20,%%v20,%%v20,%%v20,0,2" -+ : : "a" (buf) : "memory", "r0"); - } - EOF - if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c -diff --git a/sysdeps/s390/configure.ac b/sysdeps/s390/configure.ac -index 3ed5a8ef87..5c3479e8cf 100644 ---- a/sysdeps/s390/configure.ac -+++ b/sysdeps/s390/configure.ac -@@ -88,7 +88,9 @@ void testinsn (char *buf) - __asm__ (".machine \"arch13\" \n\t" - ".machinemode \"zarch_nohighgprs\" \n\t" - "lghi %%r0,16 \n\t" -- "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); -+ "mvcrl 0(%0),32(%0) \n\t" -+ "vstrs %%v20,%%v20,%%v20,%%v20,0,2" -+ : : "a" (buf) : "memory", "r0"); - } - EOF - dnl test, if assembler supports S390 arch13 instructions -@@ -195,7 +197,9 @@ cat > conftest.c <<\EOF - void testinsn (char *buf) - { - __asm__ ("lghi %%r0,16 \n\t" -- "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0"); -+ "mvcrl 0(%0),32(%0) \n\t" -+ "vstrs %%v20,%%v20,%%v20,%%v20,0,2" -+ : : "a" (buf) : "memory", "r0"); - } - EOF - dnl test, if assembler supports S390 arch13 zarch instructions as default -diff --git a/sysdeps/s390/memmove.c b/sysdeps/s390/memmove.c -index 5fc85e129f..ee59b5de14 100644 ---- a/sysdeps/s390/memmove.c -+++ b/sysdeps/s390/memmove.c -@@ -43,7 +43,7 @@ extern __typeof (__redirect_memmove) MEMMOVE_ARCH13 attribute_hidden; - s390_libc_ifunc_expr (__redirect_memmove, memmove, - ({ - s390_libc_ifunc_expr_stfle_init (); -- (HAVE_MEMMOVE_ARCH13 -+ (HAVE_MEMMOVE_ARCH13 && (hwcap & HWCAP_S390_VXRS_EXT2) - && S390_IS_ARCH13_MIE3 (stfle_bits)) - ? MEMMOVE_ARCH13 - : (HAVE_MEMMOVE_Z13 && (hwcap & HWCAP_S390_VX)) -diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c -index e6195c6e26..17c0cc3952 100644 ---- a/sysdeps/s390/multiarch/ifunc-impl-list.c -+++ b/sysdeps/s390/multiarch/ifunc-impl-list.c -@@ -171,7 +171,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - IFUNC_IMPL (i, name, memmove, - # if HAVE_MEMMOVE_ARCH13 - IFUNC_IMPL_ADD (array, i, memmove, -- S390_IS_ARCH13_MIE3 (stfle_bits), -+ ((dl_hwcap & HWCAP_S390_VXRS_EXT2) -+ && S390_IS_ARCH13_MIE3 (stfle_bits)), - MEMMOVE_ARCH13) - # endif - # if HAVE_MEMMOVE_Z13 -diff --git a/sysdeps/sh/be/sh4/fpu/Implies b/sysdeps/sh/be/sh4/fpu/Implies -new file mode 100644 -index 0000000000..71b28ee1a4 ---- /dev/null -+++ b/sysdeps/sh/be/sh4/fpu/Implies -@@ -0,0 +1 @@ -+sh/sh4/fpu -diff --git a/sysdeps/sh/le/sh4/fpu/Implies b/sysdeps/sh/le/sh4/fpu/Implies -new file mode 100644 -index 0000000000..71b28ee1a4 ---- /dev/null -+++ b/sysdeps/sh/le/sh4/fpu/Implies -@@ -0,0 +1 @@ -+sh/sh4/fpu -diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile -index 9b2a253032..34748ffcd1 100644 ---- a/sysdeps/unix/sysv/linux/Makefile -+++ b/sysdeps/unix/sysv/linux/Makefile -@@ -100,7 +100,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \ - tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \ - test-errno-linux tst-memfd_create tst-mlock2 tst-pkey \ - tst-rlimit-infinity tst-ofdlocks tst-gettid tst-gettid-kill \ -- tst-tgkill -+ tst-tgkill tst-sysvsem-linux tst-sysvmsg-linux tst-sysvshm-linux - tests-internal += tst-ofdlocks-compat tst-sigcontext-get_pc - - CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables -diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h -index fc688450ee..00a4d0c8e7 100644 ---- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h -+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h -@@ -54,6 +54,10 @@ - && MIDR_PARTNUM(midr) == 0x000) - #define IS_NEOVERSE_N1(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \ - && MIDR_PARTNUM(midr) == 0xd0c) -+#define IS_NEOVERSE_N2(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \ -+ && MIDR_PARTNUM(midr) == 0xd49) -+#define IS_NEOVERSE_V1(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \ -+ && MIDR_PARTNUM(midr) == 0xd40) - - #define IS_EMAG(midr) (MIDR_IMPLEMENTOR(midr) == 'P' \ - && MIDR_PARTNUM(midr) == 0x000) -diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c -index 61bbb03b64..2bb98172c8 100644 ---- a/sysdeps/unix/sysv/linux/mq_notify.c -+++ b/sysdeps/unix/sysv/linux/mq_notify.c -@@ -132,9 +132,12 @@ 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) -- /* The only state we keep is the copy of the thread attributes. */ -- free (data.attr); -+ 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); -+ free (data.attr); -+ } - } - return NULL; - } -@@ -255,8 +258,14 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification) - if (data.attr == NULL) - return -1; - -- memcpy (data.attr, notification->sigev_notify_attributes, -- sizeof (pthread_attr_t)); -+ int ret = __pthread_attr_copy (data.attr, -+ notification->sigev_notify_attributes); -+ if (ret != 0) -+ { -+ free (data.attr); -+ __set_errno (ret); -+ return -1; -+ } - } - - /* Construct the new request. */ -@@ -269,8 +278,11 @@ mq_notify (mqd_t mqdes, const struct sigevent *notification) - int retval = INLINE_SYSCALL (mq_notify, 2, mqdes, &se); - - /* If it failed, free the allocated memory. */ -- if (__glibc_unlikely (retval != 0)) -- free (data.attr); -+ if (retval != 0 && data.attr != NULL) -+ { -+ pthread_attr_destroy (data.attr); -+ free (data.attr); -+ } - - return retval; - } -diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c -index 0776472d5e..a1f24ab242 100644 ---- a/sysdeps/unix/sysv/linux/msgctl.c -+++ b/sysdeps/unix/sysv/linux/msgctl.c -@@ -90,8 +90,15 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) - struct kernel_msqid64_ds ksemid, *arg = NULL; - if (buf != NULL) - { -- msqid64_to_kmsqid64 (buf, &ksemid); -- arg = &ksemid; -+ /* This is a Linux extension where kernel returns a 'struct msginfo' -+ instead. */ -+ if (cmd == IPC_INFO || cmd == MSG_INFO) -+ arg = (struct kernel_msqid64_ds *) buf; -+ else -+ { -+ msqid64_to_kmsqid64 (buf, &ksemid); -+ arg = &ksemid; -+ } - } - # ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T - if (cmd == IPC_SET) -@@ -169,8 +176,15 @@ __msgctl (int msqid, int cmd, struct msqid_ds *buf) - struct __msqid64_ds msqid64, *buf64 = NULL; - if (buf != NULL) - { -- msqid_to_msqid64 (&msqid64, buf); -- buf64 = &msqid64; -+ /* This is a Linux extension where kernel returns a 'struct msginfo' -+ instead. */ -+ if (cmd == IPC_INFO || cmd == MSG_INFO) -+ buf64 = (struct __msqid64_ds *) buf; -+ else -+ { -+ msqid_to_msqid64 (&msqid64, buf); -+ buf64 = &msqid64; -+ } - } - - int ret = __msgctl64 (msqid, cmd, buf64); -diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c -index f131a26fc7..1cdabde8f2 100644 ---- a/sysdeps/unix/sysv/linux/semctl.c -+++ b/sysdeps/unix/sysv/linux/semctl.c -@@ -102,6 +102,7 @@ semun64_to_ksemun64 (int cmd, union semun64 semun64, - r.array = semun64.array; - break; - case SEM_STAT: -+ case SEM_STAT_ANY: - case IPC_STAT: - case IPC_SET: - r.buf = buf; -@@ -150,6 +151,7 @@ __semctl64 (int semid, int semnum, int cmd, ...) - case IPC_STAT: /* arg.buf */ - case IPC_SET: - case SEM_STAT: -+ case SEM_STAT_ANY: - case IPC_INFO: /* arg.__buf */ - case SEM_INFO: - va_start (ap, cmd); -@@ -238,6 +240,7 @@ semun_to_semun64 (int cmd, union semun semun, struct __semid64_ds *semid64) - r.array = semun.array; - break; - case SEM_STAT: -+ case SEM_STAT_ANY: - case IPC_STAT: - case IPC_SET: - r.buf = semid64; -@@ -267,6 +270,7 @@ __semctl (int semid, int semnum, int cmd, ...) - case IPC_STAT: /* arg.buf */ - case IPC_SET: - case SEM_STAT: -+ case SEM_STAT_ANY: - case IPC_INFO: /* arg.__buf */ - case SEM_INFO: - va_start (ap, cmd); -@@ -321,6 +325,7 @@ __semctl_mode16 (int semid, int semnum, int cmd, ...) - case IPC_STAT: /* arg.buf */ - case IPC_SET: - case SEM_STAT: -+ case SEM_STAT_ANY: - case IPC_INFO: /* arg.__buf */ - case SEM_INFO: - va_start (ap, cmd); -@@ -354,6 +359,7 @@ __old_semctl (int semid, int semnum, int cmd, ...) - case IPC_STAT: /* arg.buf */ - case IPC_SET: - case SEM_STAT: -+ case SEM_STAT_ANY: - case IPC_INFO: /* arg.__buf */ - case SEM_INFO: - va_start (ap, cmd); -diff --git a/sysdeps/unix/sysv/linux/sh/be/sh4/fpu/Implies b/sysdeps/unix/sysv/linux/sh/be/sh4/fpu/Implies -new file mode 100644 -index 0000000000..7eeaf15a5a ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/sh/be/sh4/fpu/Implies -@@ -0,0 +1 @@ -+unix/sysv/linux/sh/sh4/fpu -diff --git a/sysdeps/unix/sysv/linux/sh/le/sh4/fpu/Implies b/sysdeps/unix/sysv/linux/sh/le/sh4/fpu/Implies -new file mode 100644 -index 0000000000..7eeaf15a5a ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/sh/le/sh4/fpu/Implies -@@ -0,0 +1 @@ -+unix/sysv/linux/sh/sh4/fpu -diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c -index 76d88441f1..1d19a798b1 100644 ---- a/sysdeps/unix/sysv/linux/shmctl.c -+++ b/sysdeps/unix/sysv/linux/shmctl.c -@@ -90,8 +90,15 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) - struct kernel_shmid64_ds kshmid, *arg = NULL; - if (buf != NULL) - { -- shmid64_to_kshmid64 (buf, &kshmid); -- arg = &kshmid; -+ /* This is a Linux extension where kernel expects either a -+ 'struct shminfo' (IPC_INFO) or 'struct shm_info' (SHM_INFO). */ -+ if (cmd == IPC_INFO || cmd == SHM_INFO) -+ arg = (struct kernel_shmid64_ds *) buf; -+ else -+ { -+ shmid64_to_kshmid64 (buf, &kshmid); -+ arg = &kshmid; -+ } - } - # ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T - if (cmd == IPC_SET) -@@ -107,7 +114,6 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) - - switch (cmd) - { -- case IPC_INFO: - case IPC_STAT: - case SHM_STAT: - case SHM_STAT_ANY: -@@ -168,8 +174,15 @@ __shmctl (int shmid, int cmd, struct shmid_ds *buf) - struct __shmid64_ds shmid64, *buf64 = NULL; - if (buf != NULL) - { -- shmid_to_shmid64 (&shmid64, buf); -- buf64 = &shmid64; -+ /* This is a Linux extension where kernel expects either a -+ 'struct shminfo' (IPC_INFO) or 'struct shm_info' (SHM_INFO). */ -+ if (cmd == IPC_INFO || cmd == SHM_INFO) -+ buf64 = (struct __shmid64_ds *) buf; -+ else -+ { -+ shmid_to_shmid64 (&shmid64, buf); -+ buf64 = &shmid64; -+ } - } - - int ret = __shmctl64 (shmid, cmd, buf64); -@@ -178,7 +191,6 @@ __shmctl (int shmid, int cmd, struct shmid_ds *buf) - - switch (cmd) - { -- case IPC_INFO: - case IPC_STAT: - case SHM_STAT: - case SHM_STAT_ANY: -diff --git a/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c b/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c -new file mode 100644 -index 0000000000..630f4f792c ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/tst-sysvmsg-linux.c -@@ -0,0 +1,177 @@ -+/* Basic tests for Linux SYSV message queue extensions. -+ Copyright (C) 2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <sys/ipc.h> -+#include <sys/msg.h> -+#include <errno.h> -+#include <stdlib.h> -+#include <stdbool.h> -+#include <stdio.h> -+ -+#include <support/check.h> -+#include <support/temp_file.h> -+ -+#define MSGQ_MODE 0644 -+ -+/* These are for the temporary file we generate. */ -+static char *name; -+static int msqid; -+ -+static void -+remove_msq (void) -+{ -+ /* Enforce message queue removal in case of early test failure. -+ Ignore error since the msg may already have being removed. */ -+ msgctl (msqid, IPC_RMID, NULL); -+} -+ -+static void -+do_prepare (int argc, char *argv[]) -+{ -+ TEST_VERIFY_EXIT (create_temp_file ("tst-sysvmsg.", &name) != -1); -+} -+ -+#define PREPARE do_prepare -+ -+struct test_msginfo -+{ -+ int msgmax; -+ int msgmnb; -+ int msgmni; -+}; -+ -+/* It tries to obtain some system-wide SysV messsage queue information from -+ /proc to check against IPC_INFO/MSG_INFO. The /proc only returns the -+ tunables value of MSGMAX, MSGMNB, and MSGMNI. -+ -+ The kernel also returns constant value for MSGSSZ, MSGSEG and also MSGMAP, -+ MSGPOOL, and MSGTQL (for IPC_INFO). The issue to check them is they might -+ change over kernel releases. */ -+ -+static int -+read_proc_file (const char *file) -+{ -+ FILE *f = fopen (file, "r"); -+ if (f == NULL) -+ FAIL_UNSUPPORTED ("/proc is not mounted or %s is not available", file); -+ -+ int v; -+ int r = fscanf (f, "%d", & v); -+ TEST_VERIFY_EXIT (r == 1); -+ -+ fclose (f); -+ return v; -+} -+ -+ -+/* Check if the message queue with IDX (index into the kernel's internal -+ array) matches the one with KEY. The CMD is either MSG_STAT or -+ MSG_STAT_ANY. */ -+ -+static bool -+check_msginfo (int idx, key_t key, int cmd) -+{ -+ struct msqid_ds msginfo; -+ int mid = msgctl (idx, cmd, &msginfo); -+ /* Ignore unused array slot returned by the kernel or information from -+ unknown message queue. */ -+ if ((mid == -1 && errno == EINVAL) || mid != msqid) -+ return false; -+ -+ if (mid == -1) -+ FAIL_EXIT1 ("msgctl with %s failed: %m", -+ cmd == MSG_STAT ? "MSG_STAT" : "MSG_STAT_ANY"); -+ -+ TEST_COMPARE (msginfo.msg_perm.__key, key); -+ TEST_COMPARE (msginfo.msg_perm.mode, MSGQ_MODE); -+ TEST_COMPARE (msginfo.msg_qnum, 0); -+ -+ return true; -+} -+ -+static int -+do_test (void) -+{ -+ atexit (remove_msq); -+ -+ key_t key = ftok (name, 'G'); -+ if (key == -1) -+ FAIL_EXIT1 ("ftok failed: %m"); -+ -+ msqid = msgget (key, MSGQ_MODE | IPC_CREAT); -+ if (msqid == -1) -+ FAIL_EXIT1 ("msgget failed: %m"); -+ -+ struct test_msginfo tipcinfo; -+ tipcinfo.msgmax = read_proc_file ("/proc/sys/kernel/msgmax"); -+ tipcinfo.msgmnb = read_proc_file ("/proc/sys/kernel/msgmnb"); -+ tipcinfo.msgmni = read_proc_file ("/proc/sys/kernel/msgmni"); -+ -+ int msqidx; -+ -+ { -+ struct msginfo ipcinfo; -+ msqidx = msgctl (msqid, IPC_INFO, (struct msqid_ds *) &ipcinfo); -+ if (msqidx == -1) -+ FAIL_EXIT1 ("msgctl with IPC_INFO failed: %m"); -+ -+ TEST_COMPARE (ipcinfo.msgmax, tipcinfo.msgmax); -+ TEST_COMPARE (ipcinfo.msgmnb, tipcinfo.msgmnb); -+ TEST_COMPARE (ipcinfo.msgmni, tipcinfo.msgmni); -+ } -+ -+ /* Same as before but with MSG_INFO. */ -+ { -+ struct msginfo ipcinfo; -+ msqidx = msgctl (msqid, MSG_INFO, (struct msqid_ds *) &ipcinfo); -+ if (msqidx == -1) -+ FAIL_EXIT1 ("msgctl with IPC_INFO failed: %m"); -+ -+ TEST_COMPARE (ipcinfo.msgmax, tipcinfo.msgmax); -+ TEST_COMPARE (ipcinfo.msgmnb, tipcinfo.msgmnb); -+ TEST_COMPARE (ipcinfo.msgmni, tipcinfo.msgmni); -+ } -+ -+ /* We check if the created message queue shows in global list. */ -+ bool found = false; -+ for (int i = 0; i <= msqidx; i++) -+ { -+ /* We can't tell apart if MSG_STAT_ANY is not supported (kernel older -+ than 4.17) or if the index used is invalid. So it just check if the -+ value returned from a valid call matches the created message -+ queue. */ -+ check_msginfo (i, key, MSG_STAT_ANY); -+ -+ if (check_msginfo (i, key, MSG_STAT)) -+ { -+ found = true; -+ break; -+ } -+ } -+ -+ if (!found) -+ FAIL_EXIT1 ("msgctl with MSG_STAT/MSG_STAT_ANY could not find the " -+ "created message queue"); -+ -+ if (msgctl (msqid, IPC_RMID, NULL) == -1) -+ FAIL_EXIT1 ("msgctl failed"); -+ -+ return 0; -+} -+ -+#include <support/test-driver.c> -diff --git a/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c b/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c -new file mode 100644 -index 0000000000..45f19e2d37 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/tst-sysvsem-linux.c -@@ -0,0 +1,184 @@ -+/* Basic tests for Linux SYSV semaphore extensions. -+ Copyright (C) 2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <sys/ipc.h> -+#include <sys/sem.h> -+#include <errno.h> -+#include <stdlib.h> -+#include <stdbool.h> -+#include <stdio.h> -+ -+#include <support/check.h> -+#include <support/temp_file.h> -+ -+/* These are for the temporary file we generate. */ -+static char *name; -+static int semid; -+ -+static void -+remove_sem (void) -+{ -+ /* Enforce message queue removal in case of early test failure. -+ Ignore error since the sem may already have being removed. */ -+ semctl (semid, 0, IPC_RMID, 0); -+} -+ -+static void -+do_prepare (int argc, char *argv[]) -+{ -+ TEST_VERIFY_EXIT (create_temp_file ("tst-sysvsem.", &name) != -1); -+} -+ -+#define PREPARE do_prepare -+ -+#define SEM_MODE 0644 -+ -+union semun -+{ -+ int val; -+ struct semid_ds *buf; -+ unsigned short *array; -+ struct seminfo *__buf; -+}; -+ -+struct test_seminfo -+{ -+ int semmsl; -+ int semmns; -+ int semopm; -+ int semmni; -+}; -+ -+/* It tries to obtain some system-wide SysV semaphore information from /proc -+ to check against IPC_INFO/SEM_INFO. The /proc only returns the tunables -+ value of SEMMSL, SEMMNS, SEMOPM, and SEMMNI. -+ -+ The kernel also returns constant value for SEMVMX, SEMMNU, SEMMAP, SEMUME, -+ and also SEMUSZ and SEMAEM (for IPC_INFO). The issue to check them is they -+ might change over kernel releases. */ -+ -+static void -+read_sem_stat (struct test_seminfo *tseminfo) -+{ -+ FILE *f = fopen ("/proc/sys/kernel/sem", "r"); -+ if (f == NULL) -+ FAIL_UNSUPPORTED ("/proc is not mounted or /proc/sys/kernel/sem is not " -+ "available"); -+ -+ int r = fscanf (f, "%d %d %d %d", -+ &tseminfo->semmsl, &tseminfo->semmns, &tseminfo->semopm, -+ &tseminfo->semmni); -+ TEST_VERIFY_EXIT (r == 4); -+ -+ fclose (f); -+} -+ -+ -+/* Check if the semaphore with IDX (index into the kernel's internal array) -+ matches the one with KEY. The CMD is either SEM_STAT or SEM_STAT_ANY. */ -+ -+static bool -+check_seminfo (int idx, key_t key, int cmd) -+{ -+ struct semid_ds seminfo; -+ int sid = semctl (idx, 0, cmd, (union semun) { .buf = &seminfo }); -+ /* Ignore unused array slot returned by the kernel or information from -+ unknown semaphores. */ -+ if ((sid == -1 && errno == EINVAL) || sid != semid) -+ return false; -+ -+ if (sid == -1) -+ FAIL_EXIT1 ("semctl with SEM_STAT failed (errno=%d)", errno); -+ -+ TEST_COMPARE (seminfo.sem_perm.__key, key); -+ TEST_COMPARE (seminfo.sem_perm.mode, SEM_MODE); -+ TEST_COMPARE (seminfo.sem_nsems, 1); -+ -+ return true; -+} -+ -+static int -+do_test (void) -+{ -+ atexit (remove_sem); -+ -+ key_t key = ftok (name, 'G'); -+ if (key == -1) -+ FAIL_EXIT1 ("ftok failed: %m"); -+ -+ semid = semget (key, 1, IPC_CREAT | IPC_EXCL | SEM_MODE); -+ if (semid == -1) -+ FAIL_EXIT1 ("semget failed: %m"); -+ -+ struct test_seminfo tipcinfo; -+ read_sem_stat (&tipcinfo); -+ -+ int semidx; -+ -+ { -+ struct seminfo ipcinfo; -+ semidx = semctl (semid, 0, IPC_INFO, (union semun) { .__buf = &ipcinfo }); -+ if (semidx == -1) -+ FAIL_EXIT1 ("semctl with IPC_INFO failed: %m"); -+ -+ TEST_COMPARE (ipcinfo.semmsl, tipcinfo.semmsl); -+ TEST_COMPARE (ipcinfo.semmns, tipcinfo.semmns); -+ TEST_COMPARE (ipcinfo.semopm, tipcinfo.semopm); -+ TEST_COMPARE (ipcinfo.semmni, tipcinfo.semmni); -+ } -+ -+ /* Same as before but with SEM_INFO. */ -+ { -+ struct seminfo ipcinfo; -+ semidx = semctl (semid, 0, SEM_INFO, (union semun) { .__buf = &ipcinfo }); -+ if (semidx == -1) -+ FAIL_EXIT1 ("semctl with IPC_INFO failed: %m"); -+ -+ TEST_COMPARE (ipcinfo.semmsl, tipcinfo.semmsl); -+ TEST_COMPARE (ipcinfo.semmns, tipcinfo.semmns); -+ TEST_COMPARE (ipcinfo.semopm, tipcinfo.semopm); -+ TEST_COMPARE (ipcinfo.semmni, tipcinfo.semmni); -+ } -+ -+ /* We check if the created semaphore shows in the system-wide status. */ -+ bool found = false; -+ for (int i = 0; i <= semidx; i++) -+ { -+ /* We can't tell apart if SEM_STAT_ANY is not supported (kernel older -+ than 4.17) or if the index used is invalid. So it just check if -+ value returned from a valid call matches the created semaphore. */ -+ check_seminfo (i, key, SEM_STAT_ANY); -+ -+ if (check_seminfo (i, key, SEM_STAT)) -+ { -+ found = true; -+ break; -+ } -+ } -+ -+ if (!found) -+ FAIL_EXIT1 ("semctl with SEM_STAT/SEM_STAT_ANY could not find the " -+ "created semaphore"); -+ -+ if (semctl (semid, 0, IPC_RMID, 0) == -1) -+ FAIL_EXIT1 ("semctl failed: %m"); -+ -+ return 0; -+} -+ -+#include <support/test-driver.c> -diff --git a/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c b/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c -new file mode 100644 -index 0000000000..bb154592a6 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/tst-sysvshm-linux.c -@@ -0,0 +1,188 @@ -+/* Basic tests for Linux SYSV shared memory extensions. -+ Copyright (C) 2020 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ <https://www.gnu.org/licenses/>. */ -+ -+#include <sys/ipc.h> -+#include <sys/shm.h> -+#include <errno.h> -+#include <stdlib.h> -+#include <stdbool.h> -+#include <stdio.h> -+#include <unistd.h> -+#include <inttypes.h> -+#include <limits.h> -+ -+#include <support/check.h> -+#include <support/temp_file.h> -+ -+#define SHM_MODE 0644 -+ -+/* These are for the temporary file we generate. */ -+static char *name; -+static int shmid; -+static long int pgsz; -+ -+static void -+remove_shm (void) -+{ -+ /* Enforce message queue removal in case of early test failure. -+ Ignore error since the shm may already have being removed. */ -+ shmctl (shmid, IPC_RMID, NULL); -+} -+ -+static void -+do_prepare (int argc, char *argv[]) -+{ -+ TEST_VERIFY_EXIT (create_temp_file ("tst-sysvshm.", &name) != -1); -+} -+ -+#define PREPARE do_prepare -+ -+struct test_shminfo -+{ -+ __syscall_ulong_t shmall; -+ __syscall_ulong_t shmmax; -+ __syscall_ulong_t shmmni; -+}; -+ -+/* It tries to obtain some system-wide SysV shared memory information from -+ /proc to check against IPC_INFO/SHM_INFO. The /proc only returns the -+ tunables value of SHMALL, SHMMAX, and SHMMNI. */ -+ -+static uint64_t -+read_proc_file (const char *file) -+{ -+ FILE *f = fopen (file, "r"); -+ if (f == NULL) -+ FAIL_UNSUPPORTED ("/proc is not mounted or %s is not available", file); -+ -+ /* Handle 32-bit binaries running on 64-bit kernels. */ -+ uint64_t v; -+ int r = fscanf (f, "%" SCNu64, &v); -+ TEST_VERIFY_EXIT (r == 1); -+ -+ fclose (f); -+ return v; -+} -+ -+ -+/* Check if the message queue with IDX (index into the kernel's internal -+ array) matches the one with KEY. The CMD is either SHM_STAT or -+ SHM_STAT_ANY. */ -+ -+static bool -+check_shminfo (int idx, key_t key, int cmd) -+{ -+ struct shmid_ds shminfo; -+ int sid = shmctl (idx, cmd, &shminfo); -+ /* Ignore unused array slot returned by the kernel or information from -+ unknown message queue. */ -+ if ((sid == -1 && errno == EINVAL) || sid != shmid) -+ return false; -+ -+ if (sid == -1) -+ FAIL_EXIT1 ("shmctl with %s failed: %m", -+ cmd == SHM_STAT ? "SHM_STAT" : "SHM_STAT_ANY"); -+ -+ TEST_COMPARE (shminfo.shm_perm.__key, key); -+ TEST_COMPARE (shminfo.shm_perm.mode, SHM_MODE); -+ TEST_COMPARE (shminfo.shm_segsz, pgsz); -+ -+ return true; -+} -+ -+static int -+do_test (void) -+{ -+ atexit (remove_shm); -+ -+ pgsz = sysconf (_SC_PAGESIZE); -+ if (pgsz == -1) -+ FAIL_EXIT1 ("sysconf (_SC_PAGESIZE) failed: %m"); -+ -+ key_t key = ftok (name, 'G'); -+ if (key == -1) -+ FAIL_EXIT1 ("ftok failed: %m"); -+ -+ shmid = shmget (key, pgsz, IPC_CREAT | IPC_EXCL | SHM_MODE); -+ if (shmid == -1) -+ FAIL_EXIT1 ("shmget failed: %m"); -+ -+ /* It does not check shmmax because kernel clamp its value to INT_MAX for: -+ -+ 1. Compat symbols with IPC_64, i.e, 32-bit binaries running on 64-bit -+ kernels. -+ -+ 2. Default symbol without IPC_64 (defined as IPC_OLD within Linux) and -+ glibc always use IPC_64 for 32-bit ABIs (to support 64-bit time_t). -+ It means that 32-bit binaries running on 32-bit kernels will not see -+ shmmax being clamped. -+ -+ And finding out whether the compat symbol is used would require checking -+ the underlying kernel against the current ABI. The shmall and shmmni -+ already provided enough coverage. */ -+ -+ struct test_shminfo tipcinfo; -+ tipcinfo.shmall = read_proc_file ("/proc/sys/kernel/shmall"); -+ tipcinfo.shmmni = read_proc_file ("/proc/sys/kernel/shmmni"); -+ -+ int shmidx; -+ -+ /* Note: SHM_INFO does not return a shminfo, but rather a 'struct shm_info'. -+ It is tricky to verify its values since the syscall returns system wide -+ resources consumed by shared memory. The shmctl implementation handles -+ SHM_INFO as IPC_INFO, so the IPC_INFO test should validate SHM_INFO as -+ well. */ -+ -+ { -+ struct shminfo ipcinfo; -+ shmidx = shmctl (shmid, IPC_INFO, (struct shmid_ds *) &ipcinfo); -+ if (shmidx == -1) -+ FAIL_EXIT1 ("shmctl with IPC_INFO failed: %m"); -+ -+ TEST_COMPARE (ipcinfo.shmall, tipcinfo.shmall); -+ TEST_COMPARE (ipcinfo.shmmni, tipcinfo.shmmni); -+ } -+ -+ /* We check if the created shared memory shows in the global list. */ -+ bool found = false; -+ for (int i = 0; i <= shmidx; i++) -+ { -+ /* We can't tell apart if SHM_STAT_ANY is not supported (kernel older -+ than 4.17) or if the index used is invalid. So it just check if -+ value returned from a valid call matches the created message -+ queue. */ -+ check_shminfo (i, key, SHM_STAT_ANY); -+ -+ if (check_shminfo (i, key, SHM_STAT)) -+ { -+ found = true; -+ break; -+ } -+ } -+ -+ if (!found) -+ FAIL_EXIT1 ("shmctl with SHM_STAT/SHM_STAT_ANY could not find the " -+ "created shared memory"); -+ -+ if (shmctl (shmid, IPC_RMID, NULL) == -1) -+ FAIL_EXIT1 ("shmctl failed"); -+ -+ return 0; -+} -+ -+#include <support/test-driver.c> -diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile -index a6736aef25..9736a13e7b 100644 ---- a/sysdeps/x86/Makefile -+++ b/sysdeps/x86/Makefile -@@ -12,6 +12,12 @@ endif - ifeq ($(subdir),setjmp) - gen-as-const-headers += jmp_buf-ssp.sym - sysdep_routines += __longjmp_cancel -+ifneq ($(enable-cet),no) -+ifneq ($(have-tunables),no) -+tests += tst-setjmp-cet -+tst-setjmp-cet-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on -+endif -+endif - endif - - ifeq ($(subdir),string) -diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c -index 217c21c34f..3fb4a028d8 100644 ---- a/sysdeps/x86/cacheinfo.c -+++ b/sysdeps/x86/cacheinfo.c -@@ -808,7 +808,7 @@ init_cacheinfo (void) - threads = 1 << ((ecx >> 12) & 0x0f); - } - -- if (threads == 0) -+ if (threads == 0 || cpu_features->basic.family >= 0x17) - { - /* If APIC ID width is not available, use logical - processor count. */ -@@ -823,8 +823,22 @@ init_cacheinfo (void) - if (threads > 0) - shared /= threads; - -- /* Account for exclusive L2 and L3 caches. */ -- shared += core; -+ /* Get shared cache per ccx for Zen architectures. */ -+ if (cpu_features->basic.family >= 0x17) -+ { -+ unsigned int eax; -+ -+ /* Get number of threads share the L3 cache in CCX. */ -+ __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); -+ -+ unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; -+ shared *= threads_per_ccx; -+ } -+ else -+ { -+ /* Account for exclusive L2 and L3 caches. */ -+ shared += core; -+ } - } - } - -@@ -854,14 +868,20 @@ init_cacheinfo (void) - __x86_shared_cache_size = shared; - } - -- /* The large memcpy micro benchmark in glibc shows that 6 times of -- shared cache size is the approximate value above which non-temporal -- store becomes faster on a 8-core processor. This is the 3/4 of the -- total shared cache size. */ -+ /* The default setting for the non_temporal threshold is 3/4 of one -+ thread's share of the chip's cache. For most Intel and AMD processors -+ with an initial release date between 2017 and 2020, a thread's typical -+ share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4 -+ threshold leaves 125 KBytes to 500 KBytes of the thread's data -+ in cache after a maximum temporal copy, which will maintain -+ in cache a reasonable portion of the thread's stack and other -+ active data. If the threshold is set higher than one thread's -+ share of the cache, it has a substantial risk of negatively -+ impacting the performance of other threads running on the chip. */ - __x86_shared_non_temporal_threshold - = (cpu_features->non_temporal_threshold != 0 - ? cpu_features->non_temporal_threshold -- : __x86_shared_cache_size * threads * 3 / 4); -+ : __x86_shared_cache_size * 3 / 4); - - /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ - unsigned int minimum_rep_movsb_threshold; -diff --git a/sysdeps/x86/dl-cet.c b/sysdeps/x86/dl-cet.c -index 03572f7af6..3cc54a8d53 100644 ---- a/sysdeps/x86/dl-cet.c -+++ b/sysdeps/x86/dl-cet.c -@@ -47,7 +47,10 @@ dl_cet_check (struct link_map *m, const char *program) - /* No legacy object check if both IBT and SHSTK are always on. */ - if (enable_ibt_type == cet_always_on - && enable_shstk_type == cet_always_on) -- return; -+ { -+ THREAD_SETMEM (THREAD_SELF, header.feature_1, GL(dl_x86_feature_1)); -+ return; -+ } - - /* Check if IBT is enabled by kernel. */ - bool ibt_enabled -diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h -index 89911e19e2..4eb3b85a7b 100644 ---- a/sysdeps/x86/dl-prop.h -+++ b/sysdeps/x86/dl-prop.h -@@ -145,15 +145,15 @@ _dl_process_cet_property_note (struct link_map *l, - } - - static inline void __attribute__ ((unused)) --_dl_process_pt_note (struct link_map *l, const ElfW(Phdr) *ph) -+_dl_process_pt_note (struct link_map *l, int fd, const ElfW(Phdr) *ph) - { - const ElfW(Nhdr) *note = (const void *) (ph->p_vaddr + l->l_addr); - _dl_process_cet_property_note (l, note, ph->p_memsz, ph->p_align); - } - - static inline int __attribute__ ((always_inline)) --_dl_process_gnu_property (struct link_map *l, uint32_t type, uint32_t datasz, -- void *data) -+_dl_process_gnu_property (struct link_map *l, int fd, uint32_t type, -+ uint32_t datasz, void *data) - { - return 0; - } -diff --git a/sysdeps/x86/tst-setjmp-cet.c b/sysdeps/x86/tst-setjmp-cet.c -new file mode 100644 -index 0000000000..42c795d2a8 ---- /dev/null -+++ b/sysdeps/x86/tst-setjmp-cet.c -@@ -0,0 +1 @@ -+#include <setjmp/tst-setjmp.c> -diff --git a/sysdeps/x86_64/configure b/sysdeps/x86_64/configure -old mode 100644 -new mode 100755 -index 84f82c2406..fc1840e23f ---- a/sysdeps/x86_64/configure -+++ b/sysdeps/x86_64/configure -@@ -107,39 +107,6 @@ if test x"$build_mathvec" = xnotset; then - build_mathvec=yes - fi - --if test "$static_pie" = yes; then -- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker static PIE support" >&5 --$as_echo_n "checking for linker static PIE support... " >&6; } --if ${libc_cv_ld_static_pie+:} false; then : -- $as_echo_n "(cached) " >&6 --else -- cat > conftest.s <<\EOF -- .text -- .global _start -- .weak foo --_start: -- leaq foo(%rip), %rax --EOF -- libc_cv_pie_option="-Wl,-pie" -- if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&5' -- { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 -- (eval $ac_try) 2>&5 -- ac_status=$? -- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 -- test $ac_status = 0; }; }; then -- libc_cv_ld_static_pie=yes -- else -- libc_cv_ld_static_pie=no -- fi --rm -f conftest* --fi --{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ld_static_pie" >&5 --$as_echo "$libc_cv_ld_static_pie" >&6; } -- if test "$libc_cv_ld_static_pie" != yes; then -- as_fn_error $? "linker support for static PIE needed" "$LINENO" 5 -- fi --fi -- - $as_echo "#define PI_STATIC_AND_HIDDEN 1" >>confdefs.h - - -diff --git a/sysdeps/x86_64/configure.ac b/sysdeps/x86_64/configure.ac -index cdaba0c075..611a7d9ba3 100644 ---- a/sysdeps/x86_64/configure.ac -+++ b/sysdeps/x86_64/configure.ac -@@ -53,31 +53,6 @@ if test x"$build_mathvec" = xnotset; then - build_mathvec=yes - fi - --dnl Check if linker supports static PIE with the fix for --dnl --dnl https://sourceware.org/bugzilla/show_bug.cgi?id=21782 --dnl --if test "$static_pie" = yes; then -- AC_CACHE_CHECK(for linker static PIE support, libc_cv_ld_static_pie, [dnl --cat > conftest.s <<\EOF -- .text -- .global _start -- .weak foo --_start: -- leaq foo(%rip), %rax --EOF -- libc_cv_pie_option="-Wl,-pie" -- if AC_TRY_COMMAND(${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp $libc_cv_pie_option -o conftest conftest.s 1>&AS_MESSAGE_LOG_FD); then -- libc_cv_ld_static_pie=yes -- else -- libc_cv_ld_static_pie=no -- fi --rm -f conftest*]) -- if test "$libc_cv_ld_static_pie" != yes; then -- AC_MSG_ERROR([linker support for static PIE needed]) -- fi --fi -- - dnl It is always possible to access static and hidden symbols in an - dnl position independent way. - AC_DEFINE(PI_STATIC_AND_HIDDEN) -diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h -index ca73d8fef9..363a749cb2 100644 ---- a/sysdeps/x86_64/dl-machine.h -+++ b/sysdeps/x86_64/dl-machine.h -@@ -315,16 +315,22 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc, - { - # ifndef RTLD_BOOTSTRAP - if (sym_map != map -- && sym_map->l_type != lt_executable - && !sym_map->l_relocated) - { - const char *strtab - = (const char *) D_PTR (map, l_info[DT_STRTAB]); -- _dl_error_printf ("\ -+ if (sym_map->l_type == lt_executable) -+ _dl_fatal_printf ("\ -+%s: IFUNC symbol '%s' referenced in '%s' is defined in the executable \ -+and creates an unsatisfiable circular dependency.\n", -+ RTLD_PROGNAME, strtab + refsym->st_name, -+ map->l_name); -+ else -+ _dl_error_printf ("\ - %s: Relink `%s' with `%s' for IFUNC symbol `%s'\n", -- RTLD_PROGNAME, map->l_name, -- sym_map->l_name, -- strtab + refsym->st_name); -+ RTLD_PROGNAME, map->l_name, -+ sym_map->l_name, -+ strtab + refsym->st_name); - } - # endif - value = ((ElfW(Addr) (*) (void)) value) (); -diff --git a/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h b/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h -index 7659758972..e5fd5ac9cb 100644 ---- a/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h -+++ b/sysdeps/x86_64/fpu/multiarch/ifunc-fma4.h -@@ -32,7 +32,7 @@ IFUNC_SELECTOR (void) - && CPU_FEATURE_USABLE_P (cpu_features, AVX2)) - return OPTIMIZE (fma); - -- if (CPU_FEATURE_USABLE_P (cpu_features, FMA)) -+ if (CPU_FEATURE_USABLE_P (cpu_features, FMA4)) - return OPTIMIZE (fma4); - - return OPTIMIZE (sse2); -diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S -index bd5dc1a3f3..092f364bb6 100644 ---- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S -+++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S -@@ -56,6 +56,13 @@ - # endif - #endif - -+/* Avoid short distance rep movsb only with non-SSE vector. */ -+#ifndef AVOID_SHORT_DISTANCE_REP_MOVSB -+# define AVOID_SHORT_DISTANCE_REP_MOVSB (VEC_SIZE > 16) -+#else -+# define AVOID_SHORT_DISTANCE_REP_MOVSB 0 -+#endif -+ - #ifndef PREFETCH - # define PREFETCH(addr) prefetcht0 addr - #endif -@@ -243,7 +250,21 @@ L(movsb): - cmpq %r9, %rdi - /* Avoid slow backward REP MOVSB. */ - jb L(more_8x_vec_backward) -+# if AVOID_SHORT_DISTANCE_REP_MOVSB -+ movq %rdi, %rcx -+ subq %rsi, %rcx -+ jmp 2f -+# endif - 1: -+# if AVOID_SHORT_DISTANCE_REP_MOVSB -+ movq %rsi, %rcx -+ subq %rdi, %rcx -+2: -+/* Avoid "rep movsb" if RCX, the distance between source and destination, -+ is N*4GB + [1..63] with N >= 0. */ -+ cmpl $63, %ecx -+ jbe L(more_2x_vec) /* Avoid "rep movsb" if ECX <= 63. */ -+# endif - mov %RDX_LP, %RCX_LP - rep movsb - L(nop): -diff --git a/sysvipc/test-sysvsem.c b/sysvipc/test-sysvsem.c -index 01dbff343a..b7284e0b48 100644 ---- a/sysvipc/test-sysvsem.c -+++ b/sysvipc/test-sysvsem.c -@@ -20,6 +20,7 @@ - #include <stdlib.h> - #include <errno.h> - #include <string.h> -+#include <stdbool.h> - #include <sys/types.h> - #include <sys/ipc.h> - #include <sys/sem.h> -diff --git a/version.h b/version.h -index 83cd196798..e6ca7a8857 100644 ---- a/version.h -+++ b/version.h -@@ -1,4 +1,4 @@ - /* This file just defines the current version number of libc. */ - --#define RELEASE "release" -+#define RELEASE "stable" - #define VERSION "2.32" -diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure ---- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:02:32.741186019 +1000 -+++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:03:05.314302356 +1000 -@@ -4,10 +4,10 @@ - test -n "$libc_cv_slibdir" || - case "$prefix" in - /usr | /usr/) -- libc_cv_slibdir='/lib64' -- libc_cv_rtlddir='/lib64' -+ libc_cv_slibdir='/lib' -+ libc_cv_rtlddir='/lib' - if test "$libdir" = '${exec_prefix}/lib'; then -- libdir='${exec_prefix}/lib64'; -+ libdir='${exec_prefix}/lib'; - # Locale data can be shared between 32-bit and 64-bit libraries. - libc_cv_complocaledir='${exec_prefix}/lib/locale' - fi -diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h ---- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:02:32.742186053 +1000 -+++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:03:05.314302356 +1000 -@@ -18,9 +18,9 @@ - #include <sysdeps/generic/ldconfig.h> - - #define SYSDEP_KNOWN_INTERPRETER_NAMES \ -- { "/lib/ld-linux.so.2", FLAG_ELF_LIBC6 }, \ -+ { "/lib32/ld-linux.so.2", FLAG_ELF_LIBC6 }, \ - { "/libx32/ld-linux-x32.so.2", FLAG_ELF_LIBC6 }, \ -- { "/lib64/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 }, -+ { "/lib/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 }, - #define SYSDEP_KNOWN_LIBRARY_NAMES \ - { "libc.so.6", FLAG_ELF_LIBC6 }, \ - { "libm.so.6", FLAG_ELF_LIBC6 }, diff --git a/glibc-32/glibc-2.34-1.patch b/glibc-32/glibc-2.34-1.patch new file mode 100644 index 00000000..19452841 --- /dev/null +++ b/glibc-32/glibc-2.34-1.patch @@ -0,0 +1,4419 @@ +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 <https://sourceware.org/bugzilla/> + 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 ++ <https://www.gnu.org/licenses/>. */ ++ ++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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++#include <support/test-driver.h> ++ ++extern int foo; ++ ++static int ++do_test (void) ++{ ++ TEST_COMPARE (foo, -1); ++ return 0; ++} ++ ++#include <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <stddef.h> ++#include <iconv.h> ++#include <support/check.h> ++ ++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 <support/test-driver.c> +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 <drepper@cygnus.com>, 1998, + and Bruno Haible <bruno@clisp.org>, 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 <dl-relocate-ld.h> ++ + /* 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 <support/check.h> + #include <support/descriptors.h> + #include <support/xunistd.h> ++#include <support/support.h> + + #include <array_length.h> + + #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 <wg@malloc.de> + and Doug Lea <dl@cs.oswego.edu>, 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 <malloc.h> + #include <string.h> + #include <stdio.h> ++#include <support/support.h> ++#include <support/check.h> + + 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 <futex-internal.h> + #include <kernel-features.h> + #include <nptl-stack.h> ++#include <libc-lock.h> + + /* 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 <sys/single_threaded.h> + #include <version.h> + #include <clone_internal.h> ++#include <futex-internal.h> + + #include <shlib-compat.h> + +@@ -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 + <https://www.gnu.org/licenses/>. */ + ++#include <libc-lock.h> + #include <unistd.h> + #include <pthreadP.h> + #include <shlib-compat.h> + +-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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <array_length.h> ++#include <sched.h> ++#include <support/check.h> ++ ++/* 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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <errno.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <fcntl.h> ++#include <unistd.h> ++#include <mqueue.h> ++#include <signal.h> ++#include <stdlib.h> ++#include <string.h> ++#include <support/check.h> ++ ++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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <errno.h> ++#include <fcntl.h> ++#include <support/support.h> ++#include <support/check.h> ++#include <support/xunistd.h> ++#include <stdlib.h> ++#include <sys/resource.h> ++ ++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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <dirent.h> ++#include <errno.h> ++#include <string.h> ++#include <support/check.h> ++#include <support/support.h> ++#include <unistd.h> ++ ++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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <errno.h> ++#include <dirent.h> ++#include <fcntl.h> ++#include <limits.h> ++#include <support/check.h> ++#include <support/support.h> ++#include <support/xunistd.h> ++#include <sys/resource.h> ++#include <stdlib.h> ++ ++#ifndef PATH_MAX ++# define PATH_MAX 1024 ++#endif ++ ++#include <stdio.h> ++ ++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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#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 <ldsodefs.h> + + /* 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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <stdio.h> ++#include <support/xdlfcn.h> ++#include <support/xthread.h> ++ ++/* ++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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <stdio.h> ++ ++/* 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 <drepper@redhat.com>, 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 +- <https://www.gnu.org/licenses/>. */ +- +-#include <errno.h> +-#include <pthread.h> +-#include <signal.h> +-#include <stdio.h> +-#include <stdlib.h> +-#include <unistd.h> +- +- +-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 ++ <https://www.gnu.org/licenses/>. */ ++ ++/* 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 <support/xthread.h> ++#include <support/xsignal.h> ++ ++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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <signal.h> ++#include <support/check.h> ++#include <support/xsignal.h> ++#include <support/xthread.h> ++#include <pthread.h> ++#include <unistd.h> ++ ++/* 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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++#include <support/xthread.h> ++#include <unistd.h> ++ ++/* 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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++/* This test verifies that pthread_kill returns 0 (and not ESRCH) for ++ a thread that has exited on the kernel side. */ ++ ++#include <stddef.h> ++#include <support/support.h> ++#include <support/xthread.h> ++ ++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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++/* 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 <stdbool.h> ++#include <stddef.h> ++#include <support/check.h> ++#include <support/xthread.h> ++#include <support/xunistd.h> ++#include <sys/select.h> ++#include <unistd.h> ++ ++/* 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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++/* This test verifies that the default pthread_kill returns 0 (and not ++ ESRCH) for a thread that has exited on the kernel side. */ ++ ++#include <errno.h> ++#include <pthread.h> ++#include <shlib-compat.h> ++#include <signal.h> ++#include <stddef.h> ++#include <support/check.h> ++#include <support/support.h> ++#include <support/xthread.h> ++ ++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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++/* This test verifies that pthread_kill for a thread that is exiting ++ succeeds (with or without actually delivering the signal). */ ++ ++#include <array_length.h> ++#include <stdbool.h> ++#include <stddef.h> ++#include <support/xsignal.h> ++#include <support/xthread.h> ++#include <unistd.h> ++ ++/* 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 <support/test-driver.c> +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 ++ <https://www.gnu.org/licenses/>. */ ++ ++#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 <ldsodefs.h> + + #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 <ldsodefs.h> + +-#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 @@ + <https://www.gnu.org/licenses/>. */ + + #include <array_length.h> ++#include <assert.h> ++#include <ctype.h> + #include <dirent.h> + #include <errno.h> + #include <ldsodefs.h> +@@ -29,61 +31,170 @@ + #include <sys/sysinfo.h> + #include <sysdep.h> + +-/* 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 <bits/struct_stat_time64_helper.h> ++#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 <bits/struct_stat_time64_helper.h> ++# 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 <sys/mman.h>\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 +diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure +--- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:02:32.741186019 +1000 ++++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:03:05.314302356 +1000 +@@ -4,10 +4,10 @@ + test -n "$libc_cv_slibdir" || + case "$prefix" in + /usr | /usr/) +- libc_cv_slibdir='/lib64' +- libc_cv_rtlddir='/lib64' ++ libc_cv_slibdir='/lib' ++ libc_cv_rtlddir='/lib' + if test "$libdir" = '${exec_prefix}/lib'; then +- libdir='${exec_prefix}/lib64'; ++ libdir='${exec_prefix}/lib'; + # Locale data can be shared between 32-bit and 64-bit libraries. + libc_cv_complocaledir='${exec_prefix}/lib/locale' + fi +diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h +--- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:02:32.742186053 +1000 ++++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:03:05.314302356 +1000 +@@ -18,9 +18,9 @@ + #include <sysdeps/generic/ldconfig.h> + + #define SYSDEP_KNOWN_INTERPRETER_NAMES \ +- { "/lib/ld-linux.so.2", FLAG_ELF_LIBC6 }, \ ++ { "/lib32/ld-linux.so.2", FLAG_ELF_LIBC6 }, \ + { "/libx32/ld-linux-x32.so.2", FLAG_ELF_LIBC6 }, \ +- { "/lib64/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 }, ++ { "/lib/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 }, + #define SYSDEP_KNOWN_LIBRARY_NAMES \ + { "libc.so.6", FLAG_ELF_LIBC6 }, \ + { "libm.so.6", FLAG_ELF_LIBC6 }, |