From 4955bedbfef4d48e70f707a99c351aedb7e37462 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Thu, 30 Jan 2025 10:24:09 +0100 Subject: [PATCH] glibc: remove not needed patches --- glibc/glibc-2.36-10.patch | 16192 ----------------- glibc/linux-headers-cp-insteadof-rsync.patch | 14 - 2 files changed, 16206 deletions(-) delete mode 100644 glibc/glibc-2.36-10.patch delete mode 100644 glibc/linux-headers-cp-insteadof-rsync.patch diff --git a/glibc/glibc-2.36-10.patch b/glibc/glibc-2.36-10.patch deleted file mode 100644 index b2baf2c..0000000 --- a/glibc/glibc-2.36-10.patch +++ /dev/null @@ -1,16192 +0,0 @@ -diff --git a/Makeconfig b/Makeconfig -index ba70321af1..9dd058e04b 100644 ---- a/Makeconfig -+++ b/Makeconfig -@@ -43,6 +43,22 @@ else - $(error objdir must be defined by the build-directory Makefile) - endif - -+# Did we request 'make -s' run? "yes" or "no". -+# Starting from make-4.4 MAKEFLAGS now contains long -+# options like '--shuffle'. To detect presence of 's' -+# we pick first word with short options. Long options -+# are guaranteed to come after whitespace. We use '-' -+# prefix to always have a word before long options -+# even if no short options were passed. -+# Typical MAKEFLAGS values to watch for: -+# "rs --shuffle=42" (silent) -+# " --shuffle" (not silent) -+ifeq ($(findstring s, $(firstword -$(MAKEFLAGS))),) -+silent-make := no -+else -+silent-make := yes -+endif -+ - # Root of the sysdeps tree. - sysdep_dir := $(..)sysdeps - export sysdep_dir := $(sysdep_dir) -@@ -868,7 +884,7 @@ endif - # Use 64 bit time_t support for installed programs - installed-modules = nonlib nscd lddlibc4 ldconfig locale_programs \ - iconvprogs libnss_files libnss_compat libnss_db libnss_hesiod \ -- libutil libpcprofile libSegFault -+ libutil libpcprofile libSegFault libnsl - +extra-time-flags = $(if $(filter $(installed-modules),\ - $(in-module)),-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64) - -@@ -917,7 +933,7 @@ endif - # umpteen zillion filenames along with it (we use `...' instead) - # but we don't want this echoing done when the user has said - # he doesn't want to see commands echoed by using -s. --ifneq "$(findstring s,$(MAKEFLAGS))" "" # if -s -+ifeq ($(silent-make),yes) # if -s - +cmdecho := echo >/dev/null - else # not -s - +cmdecho := echo -diff --git a/Makerules b/Makerules -index d1e139d03c..09c0cf8357 100644 ---- a/Makerules -+++ b/Makerules -@@ -794,7 +794,7 @@ endif - # Maximize efficiency by minimizing the number of rules. - .SUFFIXES: # Clear the suffix list. We don't use suffix rules. - # Don't define any builtin rules. --MAKEFLAGS := $(MAKEFLAGS)r -+MAKEFLAGS := $(MAKEFLAGS) -r - - # Generic rule for making directories. - %/: -@@ -811,7 +811,7 @@ MAKEFLAGS := $(MAKEFLAGS)r - .PRECIOUS: $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c)) - - # Use the verbose option of ar and tar when not running silently. --ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s -+ifeq ($(silent-make),no) # if not -s - verbose := v - else # -s - verbose := -diff --git a/NEWS b/NEWS -index f61e521fc8..0f0ebce3f0 100644 ---- a/NEWS -+++ b/NEWS -@@ -5,6 +5,94 @@ See the end for copying conditions. - Please send GNU C library bug reports via - using `glibc' in the "product" field. - -+Version 2.36.1 -+ -+Major new features: -+ -+* The getent tool now supports the --no-addrconfig option. The output of -+ getent with --no-addrconfig may contain addresses of families not -+ configured on the current host i.e. as-if you had not passed -+ AI_ADDRCONFIG to getaddrinfo calls. -+ -+Security related changes: -+ -+ CVE-2022-39046: When the syslog function is passed a crafted input -+ string larger than 1024 bytes, it reads uninitialized memory from the -+ heap and prints it to the target log file, potentially revealing a -+ portion of the contents of the heap. -+ -+ CVE-2023-4527: If the system is configured in no-aaaa mode via -+ /etc/resolv.conf, getaddrinfo is called for the AF_UNSPEC address -+ family, and a DNS response is received over TCP that is larger than -+ 2048 bytes, getaddrinfo may potentially disclose stack contents via -+ the returned address data, or crash. -+ -+ CVE-2023-4806: When an NSS plugin only implements the -+ _gethostbyname2_r and _getcanonname_r callbacks, getaddrinfo could use -+ memory that was freed during buffer resizing, potentially causing a -+ crash or read or write to arbitrary memory. -+ -+ CVE-2023-5156: The fix for CVE-2023-4806 introduced a memory leak when -+ an application calls getaddrinfo for AF_INET6 with AI_CANONNAME, -+ AI_ALL and AI_V4MAPPED flags set. -+ -+ CVE-2023-4911: If a tunable of the form NAME=NAME=VAL is passed in the -+ environment of a setuid program and NAME is valid, it may result in a -+ buffer overflow, which could be exploited to achieve escalated -+ privileges. This flaw was introduced in glibc 2.34. -+ -+The following bugs are resolved with this release: -+ -+ [12154] Do not fail DNS resolution for CNAMEs which are not host names -+ [20975] Deferred cancellation triggers in __check_pf and looses lock leading to deadlock -+ [24816] Fix tst-nss-files-hosts-long on single-stack hosts -+ [27576] gmon: improve mcount overflow handling -+ [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning -+ [29039] Corrupt DTV after reuse of a TLS module ID following dlclose with unused TLS -+ [29444] gmon: Fix allocated buffer overflow (bug 29444) -+ [29864] libc: __libc_start_main() should obtain program headers -+ address (_dl_phdr) from the auxv, not the ELF header. -+ [29305] Conserve NSS buffer space during DNS packet parsing -+ [29402] nscd: nscd: No such file or directory -+ [29415] nscd: Fix netlink cache invalidation if epoll is used -+ [28937] New DSO dependency sorter does not put new map first if in a cycle -+ [29446] _dlopen now ignores dl_caller argument in static mode -+ [29485] Linux: Terminate subprocess on late failure in tst-pidfd -+ [29490] alpha: New __brk_call implementation is broken -+ [29463] math/test-float128-y1 fails on x86_64 -+ [29488] test-ibm128-llround fails on ppc64el when built with gcc-12 and -O2 -+ or higher -+ [29528] elf: Call __libc_early_init for reused namespaces -+ [29537] libc: [2.34 regression]: Alignment issue on m68k when using -+ [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are -+ [29576] build: librtld.os: in function `_dl_start_profile': -+ (.text+0x9444): undefined reference to `strcpy' -+ [29583] Use 64-bit interfaces in gconv_parseconfdir -+ [29600] Do not completely clear reused namespace in dlmopen -+ [29607] nscd repeatably crashes calling __strlen_avx2 when hosts cache is -+ enabled -+ [29638] libc: stdlib: arc4random fallback is never used -+ [29657] libc: Incorrect struct stat for 64-bit time on linux/generic -+ platforms -+ [29730] broken y2038 support in fstatat on MIPS N64 -+ [29771] Restore IPC_64 support in sysvipc *ctl functions -+ [29776] elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10 -+ [29951] time: Set daylight to 1 for matching DST/offset change -+ [30053] time: strftime %s returns -1 after 2038 on 32 bits systems -+ [30101] gmon: fix memory corruption issues -+ [30151] gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling -+ [30163] posix: Fix system blocks SIGCHLD erroneously -+ [30305] x86_64: Fix asm constraints in feraiseexcept -+ [30477] libc: [RISCV]: time64 does not work on riscv32 -+ [30515] _dl_find_object incorrectly returns 1 during early startup -+ [30745] Slight bug in cache info codes for x86 -+ [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with -+ -D_FILE_OFFSET_BITS=64 -+ [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) -+ [30843] potential use-after-free in getcanonname (CVE-2023-4806) -+ [31184] FAIL: elf/tst-tlsgap -+ [31185] Incorrect thread point access in _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic -+ - Version 2.36 - - Major new features: -diff --git a/bits/socket.h b/bits/socket.h -index 2b99dea33b..aac8c49b00 100644 ---- a/bits/socket.h -+++ b/bits/socket.h -@@ -245,6 +245,12 @@ struct cmsghdr - + CMSG_ALIGN (sizeof (struct cmsghdr))) - #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) - -+/* Given a length, return the additional padding necessary such that -+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ -+#define __CMSG_PADDING(len) ((sizeof (size_t) \ -+ - ((len) & (sizeof (size_t) - 1))) \ -+ & (sizeof (size_t) - 1)) -+ - extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, - struct cmsghdr *__cmsg) __THROW; - #ifdef __USE_EXTERN_INLINES -@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, - _EXTERN_INLINE struct cmsghdr * - __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) - { -+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and -+ __mhdr->msg_controllen because the user is required to obtain the first -+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs -+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet -+ trust the value of __cmsg->cmsg_len and therefore do not use it in any -+ pointer arithmetic until we check its value. */ -+ -+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; -+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; -+ -+ size_t __size_needed = sizeof (struct cmsghdr) -+ + __CMSG_PADDING (__cmsg->cmsg_len); -+ -+ /* The current header is malformed, too small to be a full header. */ - if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) -- /* The kernel header does this so there may be a reason. */ - return (struct cmsghdr *) 0; - -+ /* There isn't enough space between __cmsg and the end of the buffer to -+ hold the current cmsg *and* the next one. */ -+ if (((size_t) -+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) -+ < __size_needed) -+ || ((size_t) -+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr -+ - __size_needed) -+ < __cmsg->cmsg_len)) -+ -+ return (struct cmsghdr *) 0; -+ -+ /* Now, we trust cmsg_len and can use it to find the next header. */ - __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg - + CMSG_ALIGN (__cmsg->cmsg_len)); -- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control -- + __mhdr->msg_controllen) -- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) -- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) -- /* No more entries. */ -- return (struct cmsghdr *) 0; - return __cmsg; - } - #endif /* Use `extern inline'. */ -diff --git a/bits/wordsize.h b/bits/wordsize.h -index 14edae3a11..53013a9275 100644 ---- a/bits/wordsize.h -+++ b/bits/wordsize.h -@@ -21,7 +21,9 @@ - #define __WORDSIZE32_PTRDIFF_LONG - - /* Set to 1 in order to force time types to be 32 bits instead of 64 bits in -- struct lastlog and struct utmp{,x} on 64-bit ports. This may be done in -+ struct lastlog and struct utmp{,x}. This may be done in - order to make 64-bit ports compatible with 32-bit ports. Set to 0 for -- 64-bit ports where the time types are 64-bits or for any 32-bit ports. */ -+ 64-bit ports where the time types are 64-bits and new 32-bit ports -+ where time_t is 64 bits, and there is no companion architecture with -+ 32-bit time_t. */ - #define __WORDSIZE_TIME64_COMPAT32 -diff --git a/csu/libc-start.c b/csu/libc-start.c -index 543560f36c..bfeee6d851 100644 ---- a/csu/libc-start.c -+++ b/csu/libc-start.c -@@ -262,28 +262,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), - } - # endif - _dl_aux_init (auxvec); -- if (GL(dl_phdr) == NULL) - # endif -- { -- /* Starting from binutils-2.23, the linker will define the -- magic symbol __ehdr_start to point to our own ELF header -- if it is visible in a segment that also includes the phdrs. -- So we can set up _dl_phdr and _dl_phnum even without any -- information from auxv. */ -- -- extern const ElfW(Ehdr) __ehdr_start --# if BUILD_PIE_DEFAULT -- __attribute__ ((visibility ("hidden"))); --# else -- __attribute__ ((weak, visibility ("hidden"))); -- if (&__ehdr_start != NULL) --# endif -- { -- assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr)); -- GL(dl_phdr) = (const void *) &__ehdr_start + __ehdr_start.e_phoff; -- GL(dl_phnum) = __ehdr_start.e_phnum; -- } -- } - - __tunables_init (__environ); - -diff --git a/csu/libc-tls.c b/csu/libc-tls.c -index 0a216c5502..7fdf7cd7a8 100644 ---- a/csu/libc-tls.c -+++ b/csu/libc-tls.c -@@ -118,19 +118,18 @@ __libc_setup_tls (void) - __tls_pre_init_tp (); - - /* Look through the TLS segment if there is any. */ -- if (_dl_phdr != NULL) -- for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) -- if (phdr->p_type == PT_TLS) -- { -- /* Remember the values we need. */ -- memsz = phdr->p_memsz; -- filesz = phdr->p_filesz; -- initimage = (void *) phdr->p_vaddr + main_map->l_addr; -- align = phdr->p_align; -- if (phdr->p_align > max_align) -- max_align = phdr->p_align; -- break; -- } -+ for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) -+ if (phdr->p_type == PT_TLS) -+ { -+ /* Remember the values we need. */ -+ memsz = phdr->p_memsz; -+ filesz = phdr->p_filesz; -+ initimage = (void *) phdr->p_vaddr + main_map->l_addr; -+ align = phdr->p_align; -+ if (phdr->p_align > max_align) -+ max_align = phdr->p_align; -+ break; -+ } - - /* Calculate the size of the static TLS surplus, with 0 auditors. */ - _dl_tls_static_surplus_init (0); -diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c -index 2696dde4b1..9b07b4e132 100644 ---- a/dlfcn/dlopen.c -+++ b/dlfcn/dlopen.c -@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1); - void * - __dlopen (const char *file, int mode, void *dl_caller) - { -- return dlopen_implementation (file, mode, RETURN_ADDRESS (0)); -+ return dlopen_implementation (file, mode, dl_caller); - } - - void * -diff --git a/elf/Makefile b/elf/Makefile -index fd77d0c7c8..cea9c1b29d 100644 ---- a/elf/Makefile -+++ b/elf/Makefile -@@ -53,6 +53,7 @@ routines = \ - # profiled libraries. - dl-routines = \ - dl-call-libc-early-init \ -+ dl-call_fini \ - dl-close \ - dl-debug \ - dl-debug-symbols \ -@@ -176,6 +177,7 @@ CFLAGS-.op += $(call elide-stack-protector,.op,$(elide-routines.os)) - CFLAGS-.os += $(call elide-stack-protector,.os,$(all-rtld-routines)) - - # Add the requested compiler flags to the early startup code. -+CFLAGS-dl-misc.os += $(rtld-early-cflags) - CFLAGS-dl-printf.os += $(rtld-early-cflags) - CFLAGS-dl-setup_hash.os += $(rtld-early-cflags) - CFLAGS-dl-sysdep.os += $(rtld-early-cflags) -@@ -374,6 +376,8 @@ tests += \ - tst-align \ - tst-align2 \ - tst-align3 \ -+ tst-audit-tlsdesc \ -+ tst-audit-tlsdesc-dlopen \ - tst-audit1 \ - tst-audit2 \ - tst-audit8 \ -@@ -408,6 +412,7 @@ tests += \ - tst-dlmopen4 \ - tst-dlmopen-dlerror \ - tst-dlmopen-gethostbyname \ -+ tst-dlmopen-twice \ - tst-dlopenfail \ - tst-dlopenfail-2 \ - tst-dlopenrpath \ -@@ -631,6 +636,7 @@ ifeq ($(run-built-tests),yes) - tests-special += \ - $(objpfx)noload-mem.out \ - $(objpfx)tst-ldconfig-X.out \ -+ $(objpfx)tst-ldconfig-p.out \ - $(objpfx)tst-leaks1-mem.out \ - $(objpfx)tst-rtld-help.out \ - # tests-special -@@ -765,6 +771,8 @@ modules-names += \ - tst-alignmod3 \ - tst-array2dep \ - tst-array5dep \ -+ tst-audit-tlsdesc-mod1 \ -+ tst-audit-tlsdesc-mod2 \ - tst-audit11mod1 \ - tst-audit11mod2 \ - tst-audit12mod1 \ -@@ -798,6 +806,7 @@ modules-names += \ - tst-auditmanymod7 \ - tst-auditmanymod8 \ - tst-auditmanymod9 \ -+ tst-auditmod-tlsdesc \ - tst-auditmod1 \ - tst-auditmod9a \ - tst-auditmod9b \ -@@ -834,6 +843,8 @@ modules-names += \ - tst-dlmopen1mod \ - tst-dlmopen-dlerror-mod \ - tst-dlmopen-gethostbyname-mod \ -+ tst-dlmopen-twice-mod1 \ -+ tst-dlmopen-twice-mod2 \ - tst-dlopenfaillinkmod \ - tst-dlopenfailmod1 \ - tst-dlopenfailmod2 \ -@@ -990,23 +1001,8 @@ modules-names += tst-gnu2-tls1mod - $(objpfx)tst-gnu2-tls1: $(objpfx)tst-gnu2-tls1mod.so - tst-gnu2-tls1mod.so-no-z-defs = yes - CFLAGS-tst-gnu2-tls1mod.c += -mtls-dialect=gnu2 -+endif # $(have-mtls-dialect-gnu2) - --tests += tst-audit-tlsdesc tst-audit-tlsdesc-dlopen --modules-names += tst-audit-tlsdesc-mod1 tst-audit-tlsdesc-mod2 tst-auditmod-tlsdesc --$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ -- $(objpfx)tst-audit-tlsdesc-mod2.so \ -- $(shared-thread-library) --CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2 --CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2 --$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) --$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \ -- $(objpfx)tst-audit-tlsdesc-mod2.so --$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so --$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so --tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so --$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so --tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so --endif - ifeq (yes,$(have-protected-data)) - modules-names += tst-protected1moda tst-protected1modb - tests += tst-protected1a tst-protected1b -@@ -2410,6 +2406,11 @@ $(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig - '$(run-program-env)' > $@; \ - $(evaluate-test) - -+$(objpfx)tst-ldconfig-p.out : tst-ldconfig-p.sh $(objpfx)ldconfig -+ $(SHELL) $< '$(common-objpfx)' '$(test-wrapper-env)' \ -+ '$(run-program-env)' > $@; \ -+ $(evaluate-test) -+ - # Test static linking of all the libraries we can possibly link - # together. Note that in some configurations this may be less than the - # complete list of libraries we build but we try to maxmimize this list. -@@ -2967,3 +2968,25 @@ $(objpfx)tst-tls-allocation-failure-static-patched.out: \ - grep -q '^Fatal glibc error: Cannot allocate TLS block$$' $@ \ - && grep -q '^status: 127$$' $@; \ - $(evaluate-test) -+ -+$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ -+ $(objpfx)tst-audit-tlsdesc-mod2.so \ -+ $(shared-thread-library) -+ifeq (yes,$(have-mtls-dialect-gnu2)) -+# The test is valid for all TLS types, but we want to exercise GNU2 -+# TLS if possible. -+CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2 -+CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2 -+endif -+$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) -+$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \ -+ $(objpfx)tst-audit-tlsdesc-mod2.so -+$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so -+$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so -+tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so -+$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so -+tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so -+ -+$(objpfx)tst-dlmopen-twice.out: \ -+ $(objpfx)tst-dlmopen-twice-mod1.so \ -+ $(objpfx)tst-dlmopen-twice-mod2.so -diff --git a/elf/dl-cache.c b/elf/dl-cache.c -index 8bbf110d02..b97c17b3a9 100644 ---- a/elf/dl-cache.c -+++ b/elf/dl-cache.c -@@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name) - we are accessing. Therefore we must make the copy of the - mapping data without using malloc. */ - char *temp; -- temp = alloca (strlen (best) + 1); -- strcpy (temp, best); -+ size_t best_len = strlen (best) + 1; -+ temp = alloca (best_len); -+ memcpy (temp, best, best_len); - return __strdup (temp); - } - -diff --git a/elf/dl-call_fini.c b/elf/dl-call_fini.c -new file mode 100644 -index 0000000000..9e7ba10fa2 ---- /dev/null -+++ b/elf/dl-call_fini.c -@@ -0,0 +1,50 @@ -+/* Invoke DT_FINI and DT_FINI_ARRAY callbacks. -+ Copyright (C) 1996-2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+ -+void -+_dl_call_fini (void *closure_map) -+{ -+ struct link_map *map = closure_map; -+ -+ /* When debugging print a message first. */ -+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS)) -+ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", map->l_name, map->l_ns); -+ -+ /* Make sure nothing happens if we are called twice. */ -+ map->l_init_called = 0; -+ -+ ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY]; -+ if (fini_array != NULL) -+ { -+ ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr -+ + fini_array->d_un.d_ptr); -+ size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val -+ / sizeof (ElfW(Addr))); -+ -+ while (sz-- > 0) -+ ((fini_t) array[sz]) (); -+ } -+ -+ /* Next try the old-style destructor. */ -+ ElfW(Dyn) *fini = map->l_info[DT_FINI]; -+ if (fini != NULL) -+ DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr)); -+} -diff --git a/elf/dl-close.c b/elf/dl-close.c -index bcd6e206e9..14deca2e2b 100644 ---- a/elf/dl-close.c -+++ b/elf/dl-close.c -@@ -36,11 +36,6 @@ - - #include - -- --/* Type of the constructor functions. */ --typedef void (*fini_t) (void); -- -- - /* Special l_idx value used to indicate which objects remain loaded. */ - #define IDX_STILL_USED -1 - -@@ -110,31 +105,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, - return false; - } - --/* Invoke dstructors for CLOSURE (a struct link_map *). Called with -- exception handling temporarily disabled, to make errors fatal. */ --static void --call_destructors (void *closure) --{ -- struct link_map *map = closure; -- -- if (map->l_info[DT_FINI_ARRAY] != NULL) -- { -- ElfW(Addr) *array = -- (ElfW(Addr) *) (map->l_addr -- + map->l_info[DT_FINI_ARRAY]->d_un.d_ptr); -- unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val -- / sizeof (ElfW(Addr))); -- -- while (sz-- > 0) -- ((fini_t) array[sz]) (); -- } -- -- /* Next try the old-style destructor. */ -- if (map->l_info[DT_FINI] != NULL) -- DL_CALL_DT_FINI (map, ((void *) map->l_addr -- + map->l_info[DT_FINI]->d_un.d_ptr)); --} -- - void - _dl_close_worker (struct link_map *map, bool force) - { -@@ -280,17 +250,7 @@ _dl_close_worker (struct link_map *map, bool force) - half-cooked objects. Temporarily disable exception - handling, so that errors are fatal. */ - if (imap->l_init_called) -- { -- /* When debugging print a message first. */ -- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, -- 0)) -- _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", -- imap->l_name, nsid); -- -- if (imap->l_info[DT_FINI_ARRAY] != NULL -- || imap->l_info[DT_FINI] != NULL) -- _dl_catch_exception (NULL, call_destructors, imap); -- } -+ _dl_catch_exception (NULL, _dl_call_fini, imap); - - #ifdef SHARED - /* Auditing checkpoint: we remove an object. */ -diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c -index 4d5831b6f4..2e5b456c11 100644 ---- a/elf/dl-find_object.c -+++ b/elf/dl-find_object.c -@@ -46,7 +46,7 @@ _dl_find_object_slow (void *pc, struct dl_find_object *result) - struct dl_find_object_internal internal; - _dl_find_object_from_map (l, &internal); - _dl_find_object_to_external (&internal, result); -- return 1; -+ return 0; - } - - /* Object not found. */ -diff --git a/elf/dl-fini.c b/elf/dl-fini.c -index 030b1fcbcd..50ff94db16 100644 ---- a/elf/dl-fini.c -+++ b/elf/dl-fini.c -@@ -21,11 +21,6 @@ - #include - #include - -- --/* Type of the constructor functions. */ --typedef void (*fini_t) (void); -- -- - void - _dl_fini (void) - { -@@ -116,38 +111,7 @@ _dl_fini (void) - - if (l->l_init_called) - { -- /* Make sure nothing happens if we are called twice. */ -- l->l_init_called = 0; -- -- /* Is there a destructor function? */ -- if (l->l_info[DT_FINI_ARRAY] != NULL -- || (ELF_INITFINI && l->l_info[DT_FINI] != NULL)) -- { -- /* When debugging print a message first. */ -- if (__builtin_expect (GLRO(dl_debug_mask) -- & DL_DEBUG_IMPCALLS, 0)) -- _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", -- DSO_FILENAME (l->l_name), -- ns); -- -- /* First see whether an array is given. */ -- if (l->l_info[DT_FINI_ARRAY] != NULL) -- { -- ElfW(Addr) *array = -- (ElfW(Addr) *) (l->l_addr -- + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); -- unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val -- / sizeof (ElfW(Addr))); -- while (i-- > 0) -- ((fini_t) array[i]) (); -- } -- -- /* Next try the old-style destructor. */ -- if (ELF_INITFINI && l->l_info[DT_FINI] != NULL) -- DL_CALL_DT_FINI -- (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr); -- } -- -+ _dl_call_fini (l); - #ifdef SHARED - /* Auditing checkpoint: another object closed. */ - _dl_audit_objclose (l); -diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c -index 6f161f6ad5..92eb53790e 100644 ---- a/elf/dl-hwcaps.c -+++ b/elf/dl-hwcaps.c -@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, - /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix - and a "/" suffix once stored in the result. */ - hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1; -- size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) -+ size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) - + hwcaps_counts.total_length); - - /* Count the number of bits set in the masked value. */ -@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, - assert (m == cnt); - - /* Determine the total size of all strings together. */ -+ size_t total; - if (cnt == 1) -- total += temp[0].len + 1; -+ total = temp[0].len + 1; - else - { -- total += temp[0].len + temp[cnt - 1].len + 2; -+ total = temp[0].len + temp[cnt - 1].len + 2; - if (cnt > 2) - { - total <<= 1; -@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, - /* This is the overall result, including both glibc-hwcaps - subdirectories and the legacy hwcaps subdirectories using the - power set construction. */ -+ total += hwcaps_sz; - struct r_strlenpair *overall_result - = malloc (*sz * sizeof (*result) + total); - if (overall_result == NULL) -diff --git a/elf/dl-init.c b/elf/dl-init.c -index deefeb099a..fca8e3a05e 100644 ---- a/elf/dl-init.c -+++ b/elf/dl-init.c -@@ -25,10 +25,14 @@ - static void - call_init (struct link_map *l, int argc, char **argv, char **env) - { -+ /* Do not run constructors for proxy objects. */ -+ if (l != l->l_real) -+ return; -+ - /* If the object has not been relocated, this is a bug. The - function pointers are invalid in this case. (Executables do not -- need relocation, and neither do proxy objects.) */ -- assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable); -+ need relocation.) */ -+ assert (l->l_relocated || l->l_type == lt_executable); - - if (l->l_init_called) - /* This object is all done. */ -diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c -index 4c86dc694e..67fb2e31e2 100644 ---- a/elf/dl-lookup.c -+++ b/elf/dl-lookup.c -@@ -854,6 +854,23 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, - if (__glibc_unlikely (current_value.m->l_used == 0)) - current_value.m->l_used = 1; - -+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)) -+ { -+ const char *reference_name = undef_map->l_name; -+ -+ _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'", -+ DSO_FILENAME (reference_name), -+ undef_map->l_ns, -+ DSO_FILENAME (current_value.m->l_name), -+ current_value.m->l_ns, -+ protected ? "protected" : "normal", undef_name); -+ if (version) -+ _dl_debug_printf_c (" [%s]\n", version->name); -+ else -+ _dl_debug_printf_c ("\n"); -+ } -+ -+ - *ref = current_value.s; - return LOOKUP_VALUE (current_value.m); - } -diff --git a/elf/dl-open.c b/elf/dl-open.c -index a23e65926b..e7db5e9642 100644 ---- a/elf/dl-open.c -+++ b/elf/dl-open.c -@@ -850,6 +850,7 @@ no more namespaces available for dlmopen()")); - ++GL(dl_nns); - } - -+ GL(dl_ns)[nsid].libc_map = NULL; - _dl_debug_update (nsid)->r_state = RT_CONSISTENT; - } - /* Never allow loading a DSO in a namespace which is empty. Such -diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c -index 96638d7ed1..3e2a6a584e 100644 ---- a/elf/dl-sort-maps.c -+++ b/elf/dl-sort-maps.c -@@ -27,12 +27,12 @@ - If FOR_FINI is true, this is called for finishing an object. */ - static void - _dl_sort_maps_original (struct link_map **maps, unsigned int nmaps, -- unsigned int skip, bool for_fini) -+ bool force_first, bool for_fini) - { - /* Allows caller to do the common optimization of skipping the first map, - usually the main binary. */ -- maps += skip; -- nmaps -= skip; -+ maps += force_first; -+ nmaps -= force_first; - - /* A list of one element need not be sorted. */ - if (nmaps <= 1) -@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map, - - static void - _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, -- unsigned int skip __attribute__ ((unused)), bool for_fini) -+ bool force_first, bool for_fini) - { -+ struct link_map *first_map = maps[0]; - for (int i = nmaps - 1; i >= 0; i--) - maps[i]->l_visited = 0; - -@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, - Adjusting the order so that maps[0] is last traversed naturally avoids - this problem. - -- Further, the old "optimization" of skipping the main object at maps[0] -- from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general -- no longer valid, since traversing along object dependency-links -- may "find" the main object even when it is not included in the initial -- order (e.g. a dlopen()'ed shared object can have circular dependencies -- linked back to itself). In such a case, traversing N-1 objects will -- create a N-object result, and raise problems. -- - To summarize, just passing in the full list, and iterating from back - to front makes things much more straightforward. */ - -@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, - } - - memcpy (maps, rpo, sizeof (struct link_map *) * nmaps); -+ -+ /* Skipping the first object at maps[0] is not valid in general, -+ since traversing along object dependency-links may "find" that -+ first object even when it is not included in the initial order -+ (e.g., a dlopen'ed shared object can have circular dependencies -+ linked back to itself). In such a case, traversing N-1 objects -+ will create a N-object result, and raise problems. Instead, -+ force the object back into first place after sorting. This naive -+ approach may introduce further dependency ordering violations -+ compared to rotating the cycle until the first map is again in -+ the first position, but as there is a cycle, at least one -+ violation is already present. */ -+ if (force_first && maps[0] != first_map) -+ { -+ int i; -+ for (i = 0; maps[i] != first_map; ++i) -+ ; -+ assert (i < nmaps); -+ memmove (&maps[1], maps, i * sizeof (maps[0])); -+ maps[0] = first_map; -+ } - } - - void -@@ -286,7 +300,7 @@ _dl_sort_maps_init (void) - - void - _dl_sort_maps (struct link_map **maps, unsigned int nmaps, -- unsigned int skip, bool for_fini) -+ bool force_first, bool for_fini) - { - /* It can be tempting to use a static function pointer to store and call - the current selected sorting algorithm routine, but experimentation -@@ -296,9 +310,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, - input cases. A simple if-case with direct function calls appears to - be the fastest. */ - if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original)) -- _dl_sort_maps_original (maps, nmaps, skip, for_fini); -+ _dl_sort_maps_original (maps, nmaps, force_first, for_fini); - else -- _dl_sort_maps_dfs (maps, nmaps, skip, for_fini); -+ _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini); - } - - #endif /* HAVE_TUNABLES. */ -diff --git a/elf/dl-support.c b/elf/dl-support.c -index 4af0b5b2ce..f45b630ba5 100644 ---- a/elf/dl-support.c -+++ b/elf/dl-support.c -@@ -255,6 +255,25 @@ _dl_aux_init (ElfW(auxv_t) *av) - for (int i = 0; i < array_length (auxv_values); ++i) - auxv_values[i] = 0; - _dl_parse_auxv (av, auxv_values); -+ -+ _dl_phdr = (void*) auxv_values[AT_PHDR]; -+ _dl_phnum = auxv_values[AT_PHNUM]; -+ -+ if (_dl_phdr == NULL) -+ { -+ /* Starting from binutils-2.23, the linker will define the -+ magic symbol __ehdr_start to point to our own ELF header -+ if it is visible in a segment that also includes the phdrs. -+ So we can set up _dl_phdr and _dl_phnum even without any -+ information from auxv. */ -+ -+ extern const ElfW(Ehdr) __ehdr_start attribute_hidden; -+ assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr)); -+ _dl_phdr = (const void *) &__ehdr_start + __ehdr_start.e_phoff; -+ _dl_phnum = __ehdr_start.e_phnum; -+ } -+ -+ assert (_dl_phdr != NULL); - } - #endif - -@@ -323,20 +342,19 @@ _dl_non_dynamic_init (void) - if (_dl_platform != NULL) - _dl_platformlen = strlen (_dl_platform); - -- if (_dl_phdr != NULL) -- for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph) -- switch (ph->p_type) -- { -- /* Check if the stack is nonexecutable. */ -- case PT_GNU_STACK: -- _dl_stack_flags = ph->p_flags; -- break; -- -- case PT_GNU_RELRO: -- _dl_main_map.l_relro_addr = ph->p_vaddr; -- _dl_main_map.l_relro_size = ph->p_memsz; -- break; -- } -+ for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph) -+ switch (ph->p_type) -+ { -+ /* Check if the stack is nonexecutable. */ -+ case PT_GNU_STACK: -+ _dl_stack_flags = ph->p_flags; -+ break; -+ -+ case PT_GNU_RELRO: -+ _dl_main_map.l_relro_addr = ph->p_vaddr; -+ _dl_main_map.l_relro_size = ph->p_memsz; -+ break; -+ } - - call_function_static_weak (_dl_find_object_init); - -diff --git a/elf/dl-tls.c b/elf/dl-tls.c -index 093cdddb7e..bf0ff0d9e8 100644 ---- a/elf/dl-tls.c -+++ b/elf/dl-tls.c -@@ -160,6 +160,7 @@ _dl_assign_tls_modid (struct link_map *l) - { - /* Mark the entry as used, so any dependency see it. */ - atomic_store_relaxed (&runp->slotinfo[result - disp].map, l); -+ atomic_store_relaxed (&runp->slotinfo[result - disp].gen, 0); - break; - } - -diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c -index 8e7ee9df10..76cf8b9da3 100644 ---- a/elf/dl-tunables.c -+++ b/elf/dl-tunables.c -@@ -187,11 +187,7 @@ 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') -- { -- if (__libc_enable_secure) -- tunestr[off] = '\0'; -- return; -- } -+ break; - - /* We did not find a valid name-value pair before encountering the - colon. */ -@@ -251,9 +247,16 @@ parse_tunables (char *tunestr, char *valstring) - } - } - -- if (p[len] != '\0') -- p += len + 1; -+ /* We reached the end while processing the tunable string. */ -+ if (p[len] == '\0') -+ break; -+ -+ p += len + 1; - } -+ -+ /* Terminate tunestr before we leave. */ -+ if (__libc_enable_secure) -+ tunestr[off] = '\0'; - } - #endif - -diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list -index e6a56b3070..9fa3b484cf 100644 ---- a/elf/dl-tunables.list -+++ b/elf/dl-tunables.list -@@ -169,4 +169,17 @@ glibc { - default: 2 - } - } -+ -+ gmon { -+ minarcs { -+ type: INT_32 -+ minval: 50 -+ default: 50 -+ } -+ maxarcs { -+ type: INT_32 -+ minval: 50 -+ default: 1048576 -+ } -+ } - } -diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def -index 5f7f18ef27..4bf9052db1 100644 ---- a/elf/dso-sort-tests-1.def -+++ b/elf/dso-sort-tests-1.def -@@ -64,3 +64,10 @@ output: b>a>{}b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c - output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[a1;a->a2;a2->a;b->b1;c->a1;c=>a1 -+output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());}l_faked) - /* The library was not found. */ - _dl_printf ("\t%s => not found\n", l->l_libname->name); -+ else if (strcmp (l->l_libname->name, l->l_name) == 0) -+ /* Print vDSO like libraries without duplicate name. Some -+ consumers depend of this format. */ -+ _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name, -+ (int) sizeof l->l_map_start * 2, -+ (size_t) l->l_map_start); - else - _dl_printf ("\t%s => %s (0x%0*Zx)\n", - DSO_FILENAME (l->l_libname->name), -diff --git a/elf/tst-auditmod28.c b/elf/tst-auditmod28.c -index db7ba95abe..9e0a122c38 100644 ---- a/elf/tst-auditmod28.c -+++ b/elf/tst-auditmod28.c -@@ -71,6 +71,17 @@ la_version (unsigned int current) - TEST_VERIFY (dladdr1 (&_exit, &info, &extra_info, RTLD_DL_LINKMAP) != 0); - TEST_VERIFY (extra_info == handle); - -+ /* Check _dl_find_object. */ -+ struct dl_find_object dlfo; -+ TEST_COMPARE (_dl_find_object (__builtin_return_address (0), &dlfo), 0); -+ /* "ld.so" is seen with --enable-hardcoded-path-in-tests. */ -+ if (strcmp (basename (dlfo.dlfo_link_map->l_name), "ld.so") != 0) -+ TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LD_SO); -+ TEST_COMPARE (_dl_find_object (dlsym (handle, "environ"), &dlfo), 0); -+ TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LIBC_SO); -+ TEST_COMPARE (_dl_find_object ((void *) 1, &dlfo), -1); -+ TEST_COMPARE (_dl_find_object ((void *) -1, &dlfo), -1); -+ - /* Verify that dlmopen creates a new namespace. */ - void *dlmopen_handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); - TEST_VERIFY (dlmopen_handle != handle); -diff --git a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c -new file mode 100644 -index 0000000000..0eaf04948c ---- /dev/null -+++ b/elf/tst-dlmopen-twice-mod1.c -@@ -0,0 +1,37 @@ -+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+ -+static void __attribute__ ((constructor)) -+init (void) -+{ -+ puts ("info: tst-dlmopen-twice-mod1.so loaded"); -+ fflush (stdout); -+} -+ -+static void __attribute__ ((destructor)) -+fini (void) -+{ -+ puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded"); -+ fflush (stdout); -+} -+ -+/* Large allocation. The second module does not have this, so it -+ should load libc at a different address. */ -+char large_allocate[16 * 1024 * 1024]; -diff --git a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c -new file mode 100644 -index 0000000000..40c6c01f96 ---- /dev/null -+++ b/elf/tst-dlmopen-twice-mod2.c -@@ -0,0 +1,50 @@ -+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+ -+static void __attribute__ ((constructor)) -+init (void) -+{ -+ puts ("info: tst-dlmopen-twice-mod2.so loaded"); -+ fflush (stdout); -+} -+ -+static void __attribute__ ((destructor)) -+fini (void) -+{ -+ puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded"); -+ fflush (stdout); -+} -+ -+int -+run_check (void) -+{ -+ puts ("info: about to call isalpha"); -+ fflush (stdout); -+ -+ volatile char ch = 'a'; -+ if (!isalpha (ch)) -+ { -+ puts ("error: isalpha ('a') is not true"); -+ fflush (stdout); -+ return 1; -+ } -+ return 0; -+} -diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c -new file mode 100644 -index 0000000000..70c71fe19c ---- /dev/null -+++ b/elf/tst-dlmopen-twice.c -@@ -0,0 +1,54 @@ -+/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+ -+/* Run the test multiple times, to check finding a new namespace while -+ another namespace is already in use. This used to trigger bug 29600. */ -+static void -+recurse (int depth) -+{ -+ if (depth == 0) -+ return; -+ -+ printf ("info: running at depth %d\n", depth); -+ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", -+ RTLD_NOW); -+ xdlclose (handle); -+ handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW); -+ int (*run_check) (void) = xdlsym (handle, "run_check"); -+ TEST_COMPARE (run_check (), 0); -+ recurse (depth - 1); -+ xdlclose (handle); -+} -+ -+static int -+do_test (void) -+{ -+ /* First run the test without nesting. */ -+ recurse (1); -+ -+ /* Then with nesting. The constant needs to be less than the -+ internal DL_NNS namespace constant. */ -+ recurse (10); -+ return 0; -+} -+ -+#include -diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c -index 88182b7b25..5e9e4c5756 100644 ---- a/elf/tst-env-setuid-tunables.c -+++ b/elf/tst-env-setuid-tunables.c -@@ -52,6 +52,8 @@ const char *teststrings[] = - "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.mmap_threshold=glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.check=2", - "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", -@@ -70,6 +72,8 @@ const char *resultstrings[] = - "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", - "glibc.malloc.mmap_threshold=4096", - "glibc.malloc.mmap_threshold=4096", -+ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", -+ "", - "", - "", - "", -@@ -84,11 +88,18 @@ test_child (int off) - const char *val = getenv ("GLIBC_TUNABLES"); - - #if HAVE_TUNABLES -+ printf (" [%d] GLIBC_TUNABLES is %s\n", off, val); -+ fflush (stdout); - if (val != NULL && strcmp (val, resultstrings[off]) == 0) - return 0; - - if (val != NULL) -- printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val); -+ printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n", -+ off, val, resultstrings[off]); -+ else -+ printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off); -+ -+ fflush (stdout); - - return 1; - #else -@@ -117,21 +128,26 @@ do_test (int argc, char **argv) - if (ret != 0) - exit (1); - -- exit (EXIT_SUCCESS); -+ /* Special return code to make sure that the child executed all the way -+ through. */ -+ exit (42); - } - 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); -+ printf ("[%d] Spawned test for %s\n", i, teststrings[i]); - snprintf (buf, sizeof (buf), "%d\n", i); -+ fflush (stdout); - if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0) -- exit (1); -+ { -+ printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i); -+ support_record_failure (); -+ continue; -+ } - - int status = support_capture_subprogram_self_sgid (buf); - -@@ -139,9 +155,14 @@ do_test (int argc, char **argv) - if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) - return EXIT_UNSUPPORTED; - -- ret |= status; -+ if (WEXITSTATUS (status) != 42) -+ { -+ printf (" [%d] child failed with status %d\n", i, -+ WEXITSTATUS (status)); -+ support_record_failure (); -+ } - } -- return ret; -+ return 0; - } - } - -diff --git a/elf/tst-ldconfig-p.sh b/elf/tst-ldconfig-p.sh -new file mode 100644 -index 0000000000..ec937bf4ec ---- /dev/null -+++ b/elf/tst-ldconfig-p.sh -@@ -0,0 +1,77 @@ -+#!/bin/sh -+# Test that ldconfig -p prints something useful. -+# Copyright (C) 2023 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 -+# . -+ -+# Check that the newly built ldconfig -p can dump the system -+# /etc/ld.so.cache file. This should always work even if the ABIs are -+# not compatible, except in a cross-endian build (that presumably -+# involves emulation when running ldconfig). -+ -+common_objpfx=$1 -+test_wrapper_env=$2 -+run_program_env=$3 -+ -+if ! test -r /etc/ld.so.cache; then -+ echo "warning: /etc/ld.so.cache does not exist, test skipped" -+ exit 77 -+fi -+ -+testout="${common_objpfx}elf/tst-ldconfig-p.out" -+# Truncate file. -+: > "$testout" -+ -+${test_wrapper_env} \ -+${run_program_env} \ -+${common_objpfx}elf/ldconfig -p \ -+ $testroot/lib >>"$testout" 2>>"$testout" -+status=$? -+echo "info: ldconfig exit status: $status" >>"$testout" -+ -+errors=0 -+case $status in -+ (0) -+ if head -n 1 "$testout" | \ -+ grep -q "libs found in cache \`/etc/ld.so.cache'\$" ; then -+ echo "info: initial string found" >>"$testout" -+ else -+ echo "error: initial string not found" >>"$testout" -+ errors=1 -+ fi -+ if grep -q "^ libc\.so\..* => " "$testout"; then -+ echo "info: libc.so.* string found" >>"$testout" -+ else -+ echo "error: libc.so.* string not found" >>"$testout" -+ errors=1 -+ fi -+ ;; -+ (1) -+ if head -n 1 "$testout" | \ -+ grep -q ": Cache file has wrong endianness\.$" ; then -+ echo "info: cache file has wrong endianess" >> "$testout" -+ else -+ echo "error: unexpected ldconfig error message" >> "$testout" -+ errors=1 -+ fi -+ ;; -+ (*) -+ echo "error: unexpected exit status" >> "$testout" -+ errors=1 -+ ;; -+esac -+ -+exit $errors -diff --git a/gmon/Makefile b/gmon/Makefile -index 552b7d7751..fbe2b0ba5c 100644 ---- a/gmon/Makefile -+++ b/gmon/Makefile -@@ -1,4 +1,5 @@ --# Copyright (C) 1995-2022 Free Software Foundation, Inc. -+# Copyright (C) 1995-2023 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 -@@ -25,7 +26,7 @@ include ../Makeconfig - headers := sys/gmon.h sys/gmon_out.h sys/profil.h - routines := gmon mcount profil sprofil prof-freq - --tests = tst-sprofil tst-gmon -+tests = tst-sprofil tst-gmon tst-mcleanup - ifeq ($(build-profile),yes) - tests += tst-profile-static - tests-static += tst-profile-static -@@ -56,6 +57,14 @@ ifeq ($(run-built-tests),yes) - tests-special += $(objpfx)tst-gmon-gprof.out - endif - -+CFLAGS-tst-mcleanup.c := -fno-omit-frame-pointer -pg -+tst-mcleanup-no-pie = yes -+CRT-tst-mcleanup := $(csu-objpfx)g$(start-installed-name) -+tst-mcleanup-ENV := GMON_OUT_PREFIX=$(objpfx)tst-mcleanup.data -+ifeq ($(run-built-tests),yes) -+tests-special += $(objpfx)tst-mcleanup.out -+endif -+ - CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg - CRT-tst-gmon-static := $(csu-objpfx)g$(static-start-installed-name) - tst-gmon-static-no-pie = yes -@@ -103,6 +112,18 @@ $(objpfx)tst-gmon.out: clean-tst-gmon-data - clean-tst-gmon-data: - rm -f $(objpfx)tst-gmon.data.* - -+$(objpfx)tst-mcount-overflow.o: clean-tst-mcount-overflow-data -+clean-tst-mcount-overflow-data: -+ rm -f $(objpfx)tst-mcount-overflow.data.* -+ -+$(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)tst-mcount-overflow.out -+ $(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \ -+ $(evaluate-test) -+ -+$(objpfx)tst-mcleanup.out: clean-tst-mcleanup-data -+clean-tst-mcleanup-data: -+ rm -f $(objpfx)tst-mcleanup.data.* -+ - $(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out - $(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \ - $(evaluate-test) -diff --git a/gmon/gmon.c b/gmon/gmon.c -index dee64803ad..97be1f72ca 100644 ---- a/gmon/gmon.c -+++ b/gmon/gmon.c -@@ -97,11 +97,8 @@ __moncontrol (int mode) - { - struct gmonparam *p = &_gmonparam; - -- /* Don't change the state if we ran into an error. */ -- if (p->state == GMON_PROF_ERROR) -- return; -- -- if (mode) -+ /* Treat start request as stop if error or gmon not initialized. */ -+ if (mode && p->state != GMON_PROF_ERROR && p->tos != NULL) - { - /* start */ - __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale); -@@ -111,7 +108,9 @@ __moncontrol (int mode) - { - /* stop */ - __profil(NULL, 0, 0, 0); -- p->state = GMON_PROF_OFF; -+ /* Don't change the state if we ran into an error. */ -+ if (p->state != GMON_PROF_ERROR) -+ p->state = GMON_PROF_OFF; - } - } - libc_hidden_def (__moncontrol) -@@ -124,6 +123,19 @@ __monstartup (u_long lowpc, u_long highpc) - int o; - char *cp; - struct gmonparam *p = &_gmonparam; -+ long int minarcs, maxarcs; -+ -+ /* No tunables, we use hardcoded defaults */ -+ minarcs = MINARCS; -+ maxarcs = MAXARCS; -+ -+ /* -+ * If we are incorrectly called twice in a row (without an -+ * intervening call to _mcleanup), ignore the second call to -+ * prevent leaking memory. -+ */ -+ if (p->tos != NULL) -+ return; - - /* - * round lowpc and highpc to multiples of the density we're using -@@ -132,6 +144,8 @@ __monstartup (u_long lowpc, u_long highpc) - p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); - p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); - p->textsize = p->highpc - p->lowpc; -+ /* This looks like a typo, but it's here to align the p->froms -+ section. */ - p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms)); - p->hashfraction = HASHFRACTION; - p->log_hashfraction = -1; -@@ -142,12 +156,12 @@ __monstartup (u_long lowpc, u_long highpc) - instead of integer division. Precompute shift amount. */ - p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1; - } -- p->fromssize = p->textsize / HASHFRACTION; -+ p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms)); - p->tolimit = p->textsize * ARCDENSITY / 100; -- if (p->tolimit < MINARCS) -- p->tolimit = MINARCS; -- else if (p->tolimit > MAXARCS) -- p->tolimit = MAXARCS; -+ if (p->tolimit < minarcs) -+ p->tolimit = minarcs; -+ else if (p->tolimit > maxarcs) -+ p->tolimit = maxarcs; - p->tossize = p->tolimit * sizeof(struct tostruct); - - cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1); -@@ -440,9 +454,14 @@ _mcleanup (void) - { - __moncontrol (0); - -- if (_gmonparam.state != GMON_PROF_ERROR) -+ if (_gmonparam.state != GMON_PROF_ERROR && _gmonparam.tos != NULL) - write_gmon (); - - /* free the memory. */ - free (_gmonparam.tos); -+ -+ /* reset buffer to initial state for safety */ -+ memset(&_gmonparam, 0, sizeof _gmonparam); -+ /* somewhat confusingly, ON=0, OFF=3 */ -+ _gmonparam.state = GMON_PROF_OFF; - } -diff --git a/gmon/mcount.c b/gmon/mcount.c -index 9d4a1a50fa..f7180fdb83 100644 ---- a/gmon/mcount.c -+++ b/gmon/mcount.c -@@ -41,6 +41,10 @@ static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; - - #include - -+#include -+#include -+#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1) -+ - /* - * mcount is called on entry to each function compiled with the profiling - * switch set. _mcount(), which is declared in a machine-dependent way -@@ -170,6 +174,7 @@ done: - return; - overflow: - p->state = GMON_PROF_ERROR; -+ ERR("mcount: call graph buffer size limit exceeded, gmon.out will not be generated\n"); - return; - } - -diff --git a/gmon/sys/gmon.h b/gmon/sys/gmon.h -index b4cc3b043a..af0582a371 100644 ---- a/gmon/sys/gmon.h -+++ b/gmon/sys/gmon.h -@@ -111,6 +111,8 @@ extern struct __bb *__bb_head; - * Always allocate at least this many tostructs. This - * hides the inadequacy of the ARCDENSITY heuristic, at least - * for small programs. -+ * -+ * Value can be overridden at runtime by glibc.gmon.minarcs tunable. - */ - #define MINARCS 50 - -@@ -124,8 +126,8 @@ extern struct __bb *__bb_head; - * Used to be max representable value of ARCINDEX minus 2, but now - * that ARCINDEX is a long, that's too large; we don't really want - * to allow a 48 gigabyte table. -- * The old value of 1<<16 wasn't high enough in practice for large C++ -- * programs; will 1<<20 be adequate for long? FIXME -+ * -+ * Value can be overridden at runtime by glibc.gmon.maxarcs tunable. - */ - #define MAXARCS (1 << 20) - -diff --git a/gmon/tst-mcleanup.c b/gmon/tst-mcleanup.c -new file mode 100644 -index 0000000000..b259653ec8 ---- /dev/null -+++ b/gmon/tst-mcleanup.c -@@ -0,0 +1,31 @@ -+/* Test program for repeated invocation of _mcleanup -+ 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 -+ 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 -+ . */ -+ -+/* Intentionally calls _mcleanup() twice: once manually, it will be -+ called again as an atexit handler. This is incorrect use of the API, -+ but the point of the test is to make sure we don't crash when the -+ API is misused in this way. */ -+ -+#include -+ -+int -+main (void) -+{ -+ _mcleanup(); -+ return 0; -+} -diff --git a/gmon/tst-mcount-overflow-check.sh b/gmon/tst-mcount-overflow-check.sh -new file mode 100644 -index 0000000000..27eb5538fd ---- /dev/null -+++ b/gmon/tst-mcount-overflow-check.sh -@@ -0,0 +1,45 @@ -+#!/bin/sh -+# Test expected messages generated when mcount overflows -+# Copyright (C) 2017-2023 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 -+# 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 -+# . -+ -+LC_ALL=C -+export LC_ALL -+set -e -+exec 2>&1 -+ -+program="$1" -+ -+check_msg() { -+ if ! grep -q "$1" "$program.out"; then -+ echo "FAIL: expected message not in output: $1" -+ exit 1 -+ fi -+} -+ -+check_msg 'monstartup: maxarcs < minarcs, setting maxarcs = minarcs' -+check_msg 'mcount: call graph buffer size limit exceeded, gmon.out will not be generated' -+ -+for data_file in $1.data.*; do -+ if [ -f "$data_file" ]; then -+ echo "FAIL: expected no data files, but found $data_file" -+ exit 1 -+ fi -+done -+ -+echo PASS -diff --git a/gmon/tst-mcount-overflow.c b/gmon/tst-mcount-overflow.c -new file mode 100644 -index 0000000000..06cc93ef87 ---- /dev/null -+++ b/gmon/tst-mcount-overflow.c -@@ -0,0 +1,72 @@ -+/* Test program to trigger mcount overflow in profiling collection. -+ Copyright (C) 2017-2023 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 -+ . */ -+ -+/* Program with sufficiently complex, yet pointless, call graph -+ that it will trigger an mcount overflow, when you set the -+ minarcs/maxarcs tunables to very low values. */ -+ -+#define PREVENT_TAIL_CALL asm volatile ("") -+ -+/* Calls REP(n) macro 16 times, for n=0..15. -+ * You need to define REP(n) before using this. -+ */ -+#define REPS \ -+ REP(0) REP(1) REP(2) REP(3) REP(4) REP(5) REP(6) REP(7) \ -+ REP(8) REP(9) REP(10) REP(11) REP(12) REP(13) REP(14) REP(15) -+ -+/* Defines 16 leaf functions named f1_0 to f1_15 */ -+#define REP(n) \ -+ __attribute__ ((noinline, noclone, weak)) void f1_##n (void) {}; -+REPS -+#undef REP -+ -+/* Calls all 16 leaf functions f1_* in succession */ -+__attribute__ ((noinline, noclone, weak)) void -+f2 (void) -+{ -+# define REP(n) f1_##n(); -+ REPS -+# undef REP -+ PREVENT_TAIL_CALL; -+} -+ -+/* Defines 16 functions named f2_0 to f2_15, which all just call f2 */ -+#define REP(n) \ -+ __attribute__ ((noinline, noclone, weak)) void \ -+ f2_##n (void) { f2(); PREVENT_TAIL_CALL; }; -+REPS -+#undef REP -+ -+__attribute__ ((noinline, noclone, weak)) void -+f3 (int count) -+{ -+ for (int i = 0; i < count; ++i) -+ { -+ /* Calls f1_0(), f2_0(), f1_1(), f2_1(), f3_0(), etc */ -+# define REP(n) f1_##n(); f2_##n(); -+ REPS -+# undef REP -+ } -+} -+ -+int -+main (void) -+{ -+ f3 (1000); -+ return 0; -+} -diff --git a/gshadow/Makefile b/gshadow/Makefile -index eff303f538..5b3fa7e387 100644 ---- a/gshadow/Makefile -+++ b/gshadow/Makefile -@@ -26,7 +26,7 @@ headers = gshadow.h - routines = getsgent getsgnam sgetsgent fgetsgent putsgent \ - getsgent_r getsgnam_r sgetsgent_r fgetsgent_r - --tests = tst-gshadow tst-putsgent tst-fgetsgent_r -+tests = tst-gshadow tst-putsgent tst-fgetsgent_r tst-sgetsgent - - CFLAGS-getsgent_r.c += -fexceptions - CFLAGS-getsgent.c += -fexceptions -diff --git a/gshadow/sgetsgent_r.c b/gshadow/sgetsgent_r.c -index 28c826c9b5..a767a643d4 100644 ---- a/gshadow/sgetsgent_r.c -+++ b/gshadow/sgetsgent_r.c -@@ -61,7 +61,10 @@ __sgetsgent_r (const char *string, struct sgrp *resbuf, char *buffer, - buffer[buflen - 1] = '\0'; - sp = strncpy (buffer, string, buflen); - if (buffer[buflen - 1] != '\0') -- return ERANGE; -+ { -+ __set_errno (ERANGE); -+ return ERANGE; -+ } - } - else - sp = (char *) string; -diff --git a/gshadow/tst-sgetsgent.c b/gshadow/tst-sgetsgent.c -new file mode 100644 -index 0000000000..0370c10fd0 ---- /dev/null -+++ b/gshadow/tst-sgetsgent.c -@@ -0,0 +1,69 @@ -+/* Test large input for sgetsgent (bug 30151). -+ Copyright (C) 2023 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int -+do_test (void) -+{ -+ /* Create a shadow group with 1000 members. */ -+ struct xmemstream mem; -+ xopen_memstream (&mem); -+ const char *passwd = "k+zD0nucwfxAo3sw1NXUj6K5vt5M16+X0TVGdE1uFvq5R8V7efJ"; -+ fprintf (mem.out, "group-name:%s::m0", passwd); -+ for (int i = 1; i < 1000; ++i) -+ fprintf (mem.out, ",m%d", i); -+ xfclose_memstream (&mem); -+ -+ /* Call sgetsgent. */ -+ char *input = mem.buffer; -+ struct sgrp *e = sgetsgent (input); -+ TEST_VERIFY_EXIT (e != NULL); -+ TEST_COMPARE_STRING (e->sg_namp, "group-name"); -+ TEST_COMPARE_STRING (e->sg_passwd, passwd); -+ /* No administrators. */ -+ TEST_COMPARE_STRING (e->sg_adm[0], NULL); -+ /* Check the members list. */ -+ for (int i = 0; i < 1000; ++i) -+ { -+ char *member = xasprintf ("m%d", i); -+ TEST_COMPARE_STRING (e->sg_mem[i], member); -+ free (member); -+ } -+ TEST_COMPARE_STRING (e->sg_mem[1000], NULL); -+ -+ /* Check that putsgent brings back the input string. */ -+ xopen_memstream (&mem); -+ TEST_COMPARE (putsgent (e, mem.out), 0); -+ xfclose_memstream (&mem); -+ /* Compare without the trailing '\n' that putsgent added. */ -+ TEST_COMPARE (mem.buffer[mem.length - 1], '\n'); -+ mem.buffer[mem.length - 1] = '\0'; -+ TEST_COMPARE_STRING (mem.buffer, input); -+ -+ free (mem.buffer); -+ free (input); -+ return 0; -+} -+ -+#include -diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h -index debb96b322..b72933b526 100644 ---- a/iconv/gconv_parseconfdir.h -+++ b/iconv/gconv_parseconfdir.h -@@ -29,14 +29,14 @@ - # define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr) - # define asprintf __asprintf - # define opendir __opendir --# define readdir __readdir -+# define readdir64 __readdir64 - # define closedir __closedir - # define mempcpy __mempcpy --# define struct_stat struct __stat64_t64 --# define lstat __lstat64_time64 -+# define struct_stat64 struct __stat64_t64 -+# define lstat64 __lstat64_time64 - # define feof_unlocked __feof_unlocked - #else --# define struct_stat struct stat -+# define struct_stat64 struct stat64 - #endif - - /* Name of the file containing the module information in the directories -@@ -148,8 +148,8 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) - DIR *confdir = opendir (buf); - if (confdir != NULL) - { -- struct dirent *ent; -- while ((ent = readdir (confdir)) != NULL) -+ struct dirent64 *ent; -+ while ((ent = readdir64 (confdir)) != NULL) - { - if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN) - continue; -@@ -161,12 +161,12 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) - && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) - { - char *conf; -- struct_stat st; -+ struct_stat64 st; - if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) - continue; - - if (ent->d_type != DT_UNKNOWN -- || (lstat (conf, &st) != -1 && S_ISREG (st.st_mode))) -+ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode))) - found |= read_conf_file (conf, dir, dir_len); - - free (conf); -diff --git a/iconvdata/Makefile b/iconvdata/Makefile -index f4c089ed5d..d01b3fcab6 100644 ---- a/iconvdata/Makefile -+++ b/iconvdata/Makefile -@@ -75,7 +75,8 @@ 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-iconv15 -+ bug-iconv13 bug-iconv14 bug-iconv15 \ -+ tst-iconv-iso-2022-cn-ext - ifeq ($(have-thread-library),yes) - tests += bug-iconv3 - endif -@@ -330,6 +331,8 @@ $(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)tst-iconv-iso-2022-cn-ext.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/iso-2022-cn-ext.c b/iconvdata/iso-2022-cn-ext.c -index e09f358cad..2cc478a8c6 100644 ---- a/iconvdata/iso-2022-cn-ext.c -+++ b/iconvdata/iso-2022-cn-ext.c -@@ -574,6 +574,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); - { \ - const char *escseq; \ - \ -+ if (outptr + 4 > outend) \ -+ { \ -+ result = __GCONV_FULL_OUTPUT; \ -+ break; \ -+ } \ -+ \ - assert (used == CNS11643_2_set); /* XXX */ \ - escseq = "*H"; \ - *outptr++ = ESC; \ -@@ -587,6 +593,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); - { \ - const char *escseq; \ - \ -+ if (outptr + 4 > outend) \ -+ { \ -+ result = __GCONV_FULL_OUTPUT; \ -+ break; \ -+ } \ -+ \ - assert ((used >> 5) >= 3 && (used >> 5) <= 7); \ - escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2; \ - *outptr++ = ESC; \ -diff --git a/iconvdata/tst-iconv-iso-2022-cn-ext.c b/iconvdata/tst-iconv-iso-2022-cn-ext.c -new file mode 100644 -index 0000000000..96a8765fd5 ---- /dev/null -+++ b/iconvdata/tst-iconv-iso-2022-cn-ext.c -@@ -0,0 +1,128 @@ -+/* Verify ISO-2022-CN-EXT does not write out of the bounds. -+ Copyright (C) 2024 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* The test sets up a two memory page buffer with the second page marked -+ PROT_NONE to trigger a fault if the conversion writes beyond the exact -+ expected amount. Then we carry out various conversions and precisely -+ place the start of the output buffer in order to trigger a SIGSEGV if the -+ process writes anywhere between 1 and page sized bytes more (only one -+ PROT_NONE page is setup as a canary) than expected. These tests exercise -+ all three of the cases in ISO-2022-CN-EXT where the converter must switch -+ character sets and may run out of buffer space while doing the -+ operation. */ -+ -+static int -+do_test (void) -+{ -+ iconv_t cd = iconv_open ("ISO-2022-CN-EXT", "UTF-8"); -+ TEST_VERIFY_EXIT (cd != (iconv_t) -1); -+ -+ char *ntf; -+ size_t ntfsize; -+ char *outbufbase; -+ { -+ int pgz = getpagesize (); -+ TEST_VERIFY_EXIT (pgz > 0); -+ ntfsize = 2 * pgz; -+ -+ ntf = xmmap (NULL, ntfsize, PROT_READ | PROT_WRITE, MAP_PRIVATE -+ | MAP_ANONYMOUS, -1); -+ xmprotect (ntf + pgz, pgz, PROT_NONE); -+ -+ outbufbase = ntf + pgz; -+ } -+ -+ /* Check if SOdesignation escape sequence does not trigger an OOB write. */ -+ { -+ char inbuf[] = "\xe4\xba\xa4\xe6\x8d\xa2"; -+ -+ for (int i = 0; i < 9; i++) -+ { -+ char *inp = inbuf; -+ size_t inleft = sizeof (inbuf) - 1; -+ -+ char *outp = outbufbase - i; -+ size_t outleft = i; -+ -+ TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft) -+ == (size_t) -1); -+ TEST_COMPARE (errno, E2BIG); -+ -+ TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0); -+ } -+ } -+ -+ /* Same as before for SS2designation. */ -+ { -+ char inbuf[] = "ã´½ \xe3\xb4\xbd"; -+ -+ for (int i = 0; i < 14; i++) -+ { -+ char *inp = inbuf; -+ size_t inleft = sizeof (inbuf) - 1; -+ -+ char *outp = outbufbase - i; -+ size_t outleft = i; -+ -+ TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft) -+ == (size_t) -1); -+ TEST_COMPARE (errno, E2BIG); -+ -+ TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0); -+ } -+ } -+ -+ /* Same as before for SS3designation. */ -+ { -+ char inbuf[] = "劄 \xe5\x8a\x84"; -+ -+ for (int i = 0; i < 14; i++) -+ { -+ char *inp = inbuf; -+ size_t inleft = sizeof (inbuf) - 1; -+ -+ char *outp = outbufbase - i; -+ size_t outleft = i; -+ -+ TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft) -+ == (size_t) -1); -+ TEST_COMPARE (errno, E2BIG); -+ -+ TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0); -+ } -+ } -+ -+ TEST_VERIFY_EXIT (iconv_close (cd) != -1); -+ -+ xmunmap (ntf, ntfsize); -+ -+ return 0; -+} -+ -+#include -diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h -index 53f1dbc7c3..c27e7886b7 100644 ---- a/include/arpa/nameser.h -+++ b/include/arpa/nameser.h -@@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW; - int __ns_name_unpack (const unsigned char *, const unsigned char *, - const unsigned char *, unsigned char *, size_t) __THROW; - -+/* Like ns_samename, but for uncompressed binary names. Return true -+ if the two arguments compare are equal as case-insensitive domain -+ names. */ -+_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *) -+ attribute_hidden; -+ - #define ns_msg_getflag(handle, flag) \ - (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift) - -@@ -89,5 +95,105 @@ libc_hidden_proto (__ns_name_unpack) - extern __typeof (ns_samename) __libc_ns_samename; - libc_hidden_proto (__libc_ns_samename) - -+/* Packet parser helper functions. */ -+ -+/* Verify that P points to an uncompressed domain name in wire format. -+ On success, return the length of the encoded name, including the -+ terminating null byte. On failure, return -1 and set errno. EOM -+ must point one past the last byte in the packet. */ -+int __ns_name_length_uncompressed (const unsigned char *p, -+ const unsigned char *eom) attribute_hidden; -+ -+/* Iterator over the resource records in a DNS packet. */ -+struct ns_rr_cursor -+{ -+ /* These members are not changed after initialization. */ -+ const unsigned char *begin; /* First byte of packet. */ -+ const unsigned char *end; /* One past the last byte of the packet. */ -+ const unsigned char *first_rr; /* First resource record (or packet end). */ -+ -+ /* Advanced towards the end while reading the packet. */ -+ const unsigned char *current; -+}; -+ -+/* Returns the RCODE field from the DNS header. */ -+static inline int -+ns_rr_cursor_rcode (const struct ns_rr_cursor *c) -+{ -+ return c->begin[3] & 0x0f; /* Lower 4 bits at offset 3. */ -+} -+ -+/* Returns the length of the answer section according to the DNS header. */ -+static inline int -+ns_rr_cursor_ancount (const struct ns_rr_cursor *c) -+{ -+ return c->begin[6] * 256 + c->begin[7]; /* 16 bits at offset 6. */ -+} -+ -+/* Returns the length of the authority (name server) section according -+ to the DNS header. */ -+static inline int -+ns_rr_cursor_nscount (const struct ns_rr_cursor *c) -+{ -+ return c->begin[8] * 256 + c->begin[9]; /* 16 bits at offset 8. */ -+} -+ -+/* Returns the length of the additional data section according to the -+ DNS header. */ -+static inline int -+ns_rr_cursor_adcount (const struct ns_rr_cursor *c) -+{ -+ return c->begin[10] * 256 + c->begin[11]; /* 16 bits at offset 10. */ -+} -+ -+/* Returns a pointer to the uncompressed question name in wire -+ format. */ -+static inline const unsigned char * -+ns_rr_cursor_qname (const struct ns_rr_cursor *c) -+{ -+ return c->begin + 12; /* QNAME starts right after the header. */ -+} -+ -+/* Returns the question type of the first and only question. */ -+static inline const int -+ns_rr_cursor_qtype (const struct ns_rr_cursor *c) -+{ -+ /* 16 bits 4 bytes back from the first RR header start. */ -+ return c->first_rr[-4] * 256 + c->first_rr[-3]; -+} -+ -+/* Returns the clss of the first and only question (usally C_IN). */ -+static inline const int -+ns_rr_cursor_qclass (const struct ns_rr_cursor *c) -+{ -+ /* 16 bits 2 bytes back from the first RR header start. */ -+ return c->first_rr[-2] * 256 + c->first_rr[-1]; -+} -+ -+/* Initializes *C to cover the packet [BUF, BUF+LEN). Returns false -+ if LEN is less than sizeof (*HD), if the packet does not contain a -+ full (uncompressed) question, or if the question count is not 1. */ -+_Bool __ns_rr_cursor_init (struct ns_rr_cursor *c, -+ const unsigned char *buf, size_t len) -+ attribute_hidden; -+ -+/* Like ns_rr, but the record owner name is not decoded into text format. */ -+struct ns_rr_wire -+{ -+ unsigned char rname[NS_MAXCDNAME]; /* Owner name of the record. */ -+ uint16_t rtype; /* Resource record type (T_*). */ -+ uint16_t rclass; /* Resource record class (C_*). */ -+ uint32_t ttl; /* Time-to-live field. */ -+ const unsigned char *rdata; /* Start of resource record data. */ -+ uint16_t rdlength; /* Length of the data at rdata, in bytes. */ -+}; -+ -+/* Attempts to parse the record at C into *RR. On success, return -+ true, and C is advanced past the record, and RR->rdata points to -+ the record data. On failure, errno is set to EMSGSIZE, and false -+ is returned. */ -+_Bool __ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr) -+ attribute_hidden; -+ - # endif /* !_ISOMAC */ - #endif -diff --git a/include/bits/wchar2-decl.h b/include/bits/wchar2-decl.h -new file mode 100644 -index 0000000000..00b1b93342 ---- /dev/null -+++ b/include/bits/wchar2-decl.h -@@ -0,0 +1 @@ -+#include -diff --git a/include/link.h b/include/link.h -index 0ac82d7c77..87966e8397 100644 ---- a/include/link.h -+++ b/include/link.h -@@ -278,6 +278,10 @@ struct link_map - /* List of object in order of the init and fini calls. */ - struct link_map **l_initfini; - -+ /* Linked list of objects in reverse ELF constructor execution -+ order. Head of list is stored in _dl_init_called_list. */ -+ struct link_map *l_init_called_next; -+ - /* List of the dependencies introduced through symbol binding. */ - struct link_map_reldeps - { -diff --git a/include/resolv.h b/include/resolv.h -index 3590b6f496..4dbbac3800 100644 ---- a/include/resolv.h -+++ b/include/resolv.h -@@ -70,5 +70,8 @@ libc_hidden_proto (__libc_res_nameinquery) - extern __typeof (__res_queriesmatch) __libc_res_queriesmatch; - libc_hidden_proto (__libc_res_queriesmatch) - -+/* Variant of res_hnok which operates on binary (but uncompressed) names. */ -+bool __res_binary_hnok (const unsigned char *dn) attribute_hidden; -+ - # endif /* _RESOLV_H_ && !_ISOMAC */ - #endif -diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h -index c490561581..65742b1036 100644 ---- a/include/sys/sysinfo.h -+++ b/include/sys/sysinfo.h -@@ -14,10 +14,6 @@ libc_hidden_proto (__get_nprocs_conf) - 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/Makefile b/io/Makefile -index b1710407d0..b896484320 100644 ---- a/io/Makefile -+++ b/io/Makefile -@@ -59,6 +59,7 @@ routines := \ - ftw64-time64 \ - closefrom close_range - -+ - others := pwd - test-srcs := ftwtest ftwtest-time64 - tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ -@@ -80,7 +81,9 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ - tst-utimensat \ - tst-closefrom \ - tst-close_range \ -- tst-ftw-bz28126 -+ tst-ftw-bz28126 \ -+ tst-fcntl-lock \ -+ tst-fcntl-lock-lfs - - tests-time64 := \ - tst-fcntl-time64 \ -diff --git a/io/tst-fcntl-lock-lfs.c b/io/tst-fcntl-lock-lfs.c -new file mode 100644 -index 0000000000..f2a909fb02 ---- /dev/null -+++ b/io/tst-fcntl-lock-lfs.c -@@ -0,0 +1,2 @@ -+#define _FILE_OFFSET_BITS 64 -+#include -diff --git a/io/tst-fcntl-lock.c b/io/tst-fcntl-lock.c -new file mode 100644 -index 0000000000..357c4b7b56 ---- /dev/null -+++ b/io/tst-fcntl-lock.c -@@ -0,0 +1,97 @@ -+/* Test for advisory record locking. -+ Copyright (C) 2023 Free Software Foundation, Inc. -+ -+ This program is free software; you can redistribute it and/or -+ modify it under the terms of the GNU General Public License -+ as published by the Free Software Foundation; either version 2 -+ of the License, or (at your option) any later version. -+ -+ This program 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 General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, see . -+*/ -+ -+#include -+#include -+#include -+ -+/* This is essentially the POSIX lockf. */ -+ -+static int -+fcntl_lockf (int fd, int cmd, off_t len) -+{ -+ struct flock fl = { -+ .l_type = F_WRLCK, -+ .l_whence = SEEK_CUR, -+ .l_len = len -+ }; -+ -+ switch (cmd) -+ { -+ case F_TEST: -+ fl.l_type = F_RDLCK; -+ if (fcntl (fd, F_GETLK, &fl) < 0) -+ return -1; -+ if (fl.l_type == F_UNLCK || fl.l_pid == getpid ()) -+ return 0; -+ errno = EACCES; -+ return -1; -+ -+ case F_ULOCK: -+ fl.l_type = F_UNLCK; -+ return fcntl (fd, F_SETLK, &fl); -+ -+ case F_LOCK: -+ return fcntl (fd, F_SETLKW, &fl); -+ -+ case F_TLOCK: -+ return fcntl (fd, F_SETLK, &fl); -+ } -+ -+ errno = EINVAL; -+ return -1; -+} -+ -+static int -+fcntl64_lockf (int fd, int cmd, off64_t len64) -+ { -+ struct flock64 fl64 = { -+ .l_type = F_WRLCK, -+ .l_whence = SEEK_CUR, -+ .l_len = len64 -+ }; -+ -+ switch (cmd) -+ { -+ case F_TEST: -+ fl64.l_type = F_RDLCK; -+ if (fcntl64 (fd, F_GETLK64, &fl64) < 0) -+ return -1; -+ if (fl64.l_type == F_UNLCK || fl64.l_pid == getpid ()) -+ return 0; -+ errno = EACCES; -+ return -1; -+ -+ case F_ULOCK: -+ fl64.l_type = F_UNLCK; -+ return fcntl64 (fd, F_SETLK64, &fl64); -+ -+ case F_LOCK: -+ return fcntl64 (fd, F_SETLKW64, &fl64); -+ -+ case F_TLOCK: -+ return fcntl64 (fd, F_SETLK64, &fl64); -+ } -+ -+ errno = EINVAL; -+ return -1; -+} -+ -+#define TST_LOCKFD "tst-fcntl-lock." -+#define LOCKF fcntl_lockf -+#define LOCKF64 fcntl64_lockf -+#include "tst-lockf.c" -diff --git a/io/tst-lockf.c b/io/tst-lockf.c -index be92f33fd1..5e41dc19df 100644 ---- a/io/tst-lockf.c -+++ b/io/tst-lockf.c -@@ -24,13 +24,23 @@ - #include - #include - -+#ifndef TST_LOCKFD -+# define TST_LOCKFD "tst-lockfd." -+#endif -+#ifndef LOCKF -+# define LOCKF lockf -+#endif -+#ifndef LOCKF64 -+# define LOCKF64 lockf64 -+#endif -+ - static char *temp_filename; - static int temp_fd; - - static void - do_prepare (int argc, char **argv) - { -- temp_fd = create_temp_file ("tst-lockfd.", &temp_filename); -+ temp_fd = create_temp_file (TST_LOCKFD, &temp_filename); - TEST_VERIFY_EXIT (temp_fd != -1); - } - #define PREPARE do_prepare -@@ -40,22 +50,22 @@ do_test_child_lockf (void *closure) - { - /* Check if parent has [0, 1024) locked. */ - TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0); -- TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), -1); -+ TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), -1); - TEST_COMPARE (errno, EAGAIN); -- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1); -+ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1); - TEST_COMPARE (errno, EACCES); - /* Also Check if parent has last 1024 bytes locked. */ - TEST_COMPARE (lseek (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024); -- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1); -+ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1); - - /* And try to lock [1024, 2048). */ - TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024); -- TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0); -+ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0); - - /* Check if non-LFS interface cap access to 32-bif off_t. */ - TEST_COMPARE (lseek64 (temp_fd, (off64_t)INT32_MAX, SEEK_SET), - (off64_t)INT32_MAX); -- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0); - } - - static void -@@ -63,32 +73,32 @@ do_test_child_lockf64 (void *closure) - { - /* Check if parent has [0, 1024) locked. */ - TEST_COMPARE (lseek64 (temp_fd, 0, SEEK_SET), 0); -- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1); - TEST_COMPARE (errno, EAGAIN); -- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); - TEST_COMPARE (errno, EACCES); - /* Also Check if parent has last 1024 bytes locked. */ - TEST_COMPARE (lseek64 (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024); -- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); - - /* And try to lock [1024, 2048). */ - TEST_COMPARE (lseek64 (temp_fd, 1024, SEEK_SET), 1024); -- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); - - /* And also [INT32_MAX, INT32_MAX+1024). */ - { - off64_t off = (off64_t)INT32_MAX; - TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); -- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); - } - - /* Check if [INT32_MAX+1024, INT64_MAX) is locked. */ - { - off64_t off = (off64_t)INT32_MAX+1024; - TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); -- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1); - TEST_COMPARE (errno, EAGAIN); -- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); - TEST_COMPARE (errno, EACCES); - } - } -@@ -97,38 +107,38 @@ static int - do_test (void) - { - /* Basic tests to check if a lock can be obtained and checked. */ -- TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0); -- TEST_COMPARE (lockf (temp_fd, F_LOCK, INT32_MAX), 0); -- TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), 0); -- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), 0); -+ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0); -+ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, INT32_MAX), 0); -+ TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), 0); -+ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), 0); - TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024); -- TEST_COMPARE (lockf (temp_fd, F_ULOCK, 1024), 0); -+ TEST_COMPARE (LOCKF (temp_fd, F_ULOCK, 1024), 0); - /* Parent process should have ([0, 1024), [2048, INT32_MAX)) ranges locked. */ - - { - struct support_capture_subprocess result; - result = support_capture_subprocess (do_test_child_lockf, NULL); -- support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none); -+ support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none); - } - - if (sizeof (off_t) != sizeof (off64_t)) - { - /* Check if previously locked regions with LFS symbol. */ - TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0); -- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); -- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), 0); -- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), 0); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0); - /* Lock region [INT32_MAX+1024, INT64_MAX). */ - off64_t off = (off64_t)INT32_MAX + 1024; - TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); -- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); -+ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); - /* Parent process should have ([0, 1024), [2048, INT32_MAX), - [INT32_MAX+1024, INT64_MAX)) ranges locked. */ - - { - struct support_capture_subprocess result; - result = support_capture_subprocess (do_test_child_lockf64, NULL); -- support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none); -+ support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none); - } - } - -diff --git a/locale/weight.h b/locale/weight.h -index 8be2d220f8..4a4d5aa6b2 100644 ---- a/locale/weight.h -+++ b/locale/weight.h -@@ -27,7 +27,14 @@ findidx (const int32_t *table, - const unsigned char *extra, - const unsigned char **cpp, size_t len) - { -+ /* With GCC 8 when compiling with -Os the compiler warns that -+ seq1.back_us and seq2.back_us might be used uninitialized. -+ This uninitialized use is impossible for the same reason -+ as described in comments in locale/weightwc.h. */ -+ DIAG_PUSH_NEEDS_COMMENT; -+ DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized"); - int32_t i = table[*(*cpp)++]; -+ DIAG_POP_NEEDS_COMMENT; - const unsigned char *cp; - const unsigned char *usrc; - -diff --git a/login/Makefile b/login/Makefile -index 62440499bc..0b6b962c06 100644 ---- a/login/Makefile -+++ b/login/Makefile -@@ -44,7 +44,9 @@ subdir-dirs = programs - vpath %.c programs - - tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \ -- tst-pututxline-lockfail tst-pututxline-cache -+ tst-pututxline-lockfail tst-pututxline-cache tst-utmp-size tst-utmp-size-64 -+ -+CFLAGS-tst-utmp-size-64.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 - - # Empty compatibility library for old binaries. - extra-libs := libutil -diff --git a/login/tst-utmp-size-64.c b/login/tst-utmp-size-64.c -new file mode 100644 -index 0000000000..7a581a4c12 ---- /dev/null -+++ b/login/tst-utmp-size-64.c -@@ -0,0 +1,2 @@ -+/* The on-disk layout must not change in time64 mode. */ -+#include "tst-utmp-size.c" -diff --git a/login/tst-utmp-size.c b/login/tst-utmp-size.c -new file mode 100644 -index 0000000000..1b7f7ff042 ---- /dev/null -+++ b/login/tst-utmp-size.c -@@ -0,0 +1,33 @@ -+/* Check expected sizes of struct utmp, struct utmpx, struct lastlog. -+ Copyright (C) 2024 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+ -+static int -+do_test (void) -+{ -+ _Static_assert (sizeof (struct utmp) == UTMP_SIZE, "struct utmp size"); -+ _Static_assert (sizeof (struct utmpx) == UTMP_SIZE, "struct utmpx size"); -+ _Static_assert (sizeof (struct lastlog) == LASTLOG_SIZE, -+ "struct lastlog size"); -+ return 0; -+} -+ -+#include -diff --git a/malloc/arena.c b/malloc/arena.c -index 0a684a720d..a1ee7928d3 100644 ---- a/malloc/arena.c -+++ b/malloc/arena.c -@@ -937,7 +937,7 @@ arena_get2 (size_t size, mstate avoid_arena) - narenas_limit = mp_.arena_max; - else if (narenas > mp_.arena_test) - { -- int n = __get_nprocs_sched (); -+ int n = __get_nprocs (); - - if (n >= 1) - narenas_limit = NARENAS_FROM_NCORES (n); -diff --git a/manual/tunables.texi b/manual/tunables.texi -index 83cdcdac6d..ab5145ce0c 100644 ---- a/manual/tunables.texi -+++ b/manual/tunables.texi -@@ -502,7 +502,7 @@ This tunable is specific to powerpc, powerpc64 and powerpc64le. - @deftp Tunable glibc.cpu.name - The @code{glibc.cpu.name=xxx} tunable allows the user to tell @theglibc{} to - assume that the CPU is @code{xxx} where xxx may have one of these values: --@code{generic}, @code{falkor}, @code{thunderxt88}, @code{thunderx2t99}, -+@code{generic}, @code{thunderxt88}, @code{thunderx2t99}, - @code{thunderx2t99p1}, @code{ares}, @code{emag}, @code{kunpeng}, - @code{a64fx}. - -diff --git a/misc/Makefile b/misc/Makefile -index ba8232a0e9..66e9ded8f9 100644 ---- a/misc/Makefile -+++ b/misc/Makefile -@@ -115,7 +115,10 @@ tests-special += $(objpfx)tst-error1-mem.out \ - $(objpfx)tst-allocate_once-mem.out - endif - --tests-container := tst-syslog -+tests-container := \ -+ tst-syslog \ -+ tst-syslog-long-progname \ -+ # tests-container - - CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables - CFLAGS-tsearch.c += $(uses-callbacks) -@@ -175,6 +178,9 @@ $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out - $(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \ - $(evaluate-test) - -+tst-syslog-long-progname-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \ -+ LD_PRELOAD=libc_malloc_debug.so.0 -+ - $(objpfx)tst-select: $(librt) - $(objpfx)tst-select-time64: $(librt) - $(objpfx)tst-pselect: $(librt) -diff --git a/misc/bits/syslog.h b/misc/bits/syslog.h -index fd30dd3114..916d2b6f12 100644 ---- a/misc/bits/syslog.h -+++ b/misc/bits/syslog.h -@@ -24,6 +24,20 @@ - extern void __syslog_chk (int __pri, int __flag, const char *__fmt, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); - -+#ifdef __USE_MISC -+extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt, -+ __gnuc_va_list __ap) -+ __attribute__ ((__format__ (__printf__, 3, 0))); -+#endif -+ -+#include -+#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 -+# include -+#endif -+ -+/* The following functions must be used only after applying all asm -+ redirections, e.g. long double asm redirections. */ -+ - #ifdef __va_arg_pack - __fortify_function void - syslog (int __pri, const char *__fmt, ...) -@@ -37,10 +51,6 @@ syslog (int __pri, const char *__fmt, ...) - - - #ifdef __USE_MISC --extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt, -- __gnuc_va_list __ap) -- __attribute__ ((__format__ (__printf__, 3, 0))); -- - __fortify_function void - vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap) - { -diff --git a/misc/getsysstats.c b/misc/getsysstats.c -index e56aff0f37..660f64eb80 100644 ---- a/misc/getsysstats.c -+++ b/misc/getsysstats.c -@@ -44,12 +44,6 @@ 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/cdefs.h b/misc/sys/cdefs.h -index f525f67547..294e633335 100644 ---- a/misc/sys/cdefs.h -+++ b/misc/sys/cdefs.h -@@ -152,6 +152,7 @@ - # define __glibc_objsize(__o) __bos (__o) - #endif - -+#if __USE_FORTIFY_LEVEL > 0 - /* Compile time conditions to choose between the regular, _chk and _chk_warn - variants. These conditions should get evaluated to constant and optimized - away. */ -@@ -187,7 +188,7 @@ - ? __ ## f ## _alias (__VA_ARGS__) \ - : (__glibc_unsafe_len (__l, __s, __osz) \ - ? __ ## f ## _chk_warn (__VA_ARGS__, __osz) \ -- : __ ## f ## _chk (__VA_ARGS__, __osz))) \ -+ : __ ## f ## _chk (__VA_ARGS__, __osz))) - - /* Fortify function f, where object size argument passed to f is the number of - elements and not total size. */ -@@ -197,7 +198,8 @@ - ? __ ## f ## _alias (__VA_ARGS__) \ - : (__glibc_unsafe_len (__l, __s, __osz) \ - ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s)) \ -- : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) \ -+ : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) -+#endif - - #if __GNUC_PREREQ (4,3) - # define __warnattr(msg) __attribute__((__warning__ (msg))) -diff --git a/misc/sys/syslog.h b/misc/sys/syslog.h -index d933fea104..3888153ed2 100644 ---- a/misc/sys/syslog.h -+++ b/misc/sys/syslog.h -@@ -205,11 +205,11 @@ extern void vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap) - /* Define some macros helping to catch buffer overflows. */ - #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function - # include --#endif -- --#include --#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 --# include -+#else -+# include -+# if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 -+# include -+# endif - #endif - - __END_DECLS -diff --git a/misc/syslog.c b/misc/syslog.c -index 554089bfc4..9336036666 100644 ---- a/misc/syslog.c -+++ b/misc/syslog.c -@@ -41,6 +41,7 @@ static char sccsid[] = "@(#)syslog.c 8.4 (Berkeley) 3/18/94"; - #include - #include - #include -+#include - - static int LogType = SOCK_DGRAM; /* type of socket connection */ - static int LogFile = -1; /* fd for log */ -@@ -122,8 +123,9 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, - { - /* Try to use a static buffer as an optimization. */ - char bufs[1024]; -- char *buf = NULL; -- size_t bufsize = 0; -+ char *buf = bufs; -+ size_t bufsize; -+ - int msgoff; - int saved_errno = errno; - -@@ -167,7 +169,7 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, - _nl_C_locobj_ptr); - - #define SYSLOG_HEADER(__pri, __timestamp, __msgoff, pid) \ -- "<%d>%s %n%s%s%.0d%s: ", \ -+ "<%d>%s%n%s%s%.0d%s: ", \ - __pri, __timestamp, __msgoff, \ - LogTag == NULL ? __progname : LogTag, \ - "[" + (pid == 0), pid, "]" + (pid == 0) -@@ -175,53 +177,95 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, - #define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff) \ - "<%d>: %n", __pri, __msgoff - -- int l; -+ int l, vl; - if (has_ts) - l = __snprintf (bufs, sizeof bufs, - SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); - else - l = __snprintf (bufs, sizeof bufs, - SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); -- if (0 <= l && l < sizeof bufs) -+ if (l < 0) -+ goto out; -+ -+ char *pos; -+ size_t len; -+ -+ if (l < sizeof bufs) - { -- va_list apc; -- va_copy (apc, ap); -+ /* At this point, there is still a chance that we can print the -+ remaining part of the log into bufs and use that. */ -+ pos = bufs + l; -+ len = sizeof (bufs) - l; -+ } -+ else -+ { -+ buf = NULL; -+ /* We already know that bufs is too small to use for this log message. -+ The next vsnprintf into bufs is used only to calculate the total -+ required buffer length. We will discard bufs contents and allocate -+ an appropriately sized buffer later instead. */ -+ pos = bufs; -+ len = sizeof (bufs); -+ } - -- /* Restore errno for %m format. */ -- __set_errno (saved_errno); -+ { -+ va_list apc; -+ va_copy (apc, ap); - -- int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc, -- mode_flags); -- if (0 <= vl && vl < sizeof bufs - l) -- { -- buf = bufs; -- bufsize = l + vl; -- } -+ /* Restore errno for %m format. */ -+ __set_errno (saved_errno); - -- va_end (apc); -- } -+ vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags); -+ va_end (apc); -+ -+ if (vl < 0 || vl >= INT_MAX - l) -+ goto out; -+ -+ if (vl >= len) -+ buf = NULL; -+ -+ bufsize = l + vl; -+ } - - if (buf == NULL) - { -- buf = malloc (l * sizeof (char)); -+ buf = malloc ((bufsize + 1) * sizeof (char)); - if (buf != NULL) - { - /* Tell the cancellation handler to free this buffer. */ - clarg.buf = buf; - -+ int cl; - if (has_ts) -- __snprintf (bufs, sizeof bufs, -- SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); -+ cl = __snprintf (buf, l + 1, -+ SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); - else -- __snprintf (bufs, sizeof bufs, -- SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); -+ cl = __snprintf (buf, l + 1, -+ SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); -+ if (cl != l) -+ goto out; -+ -+ va_list apc; -+ va_copy (apc, ap); -+ cl = __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, -+ mode_flags); -+ va_end (apc); -+ -+ if (cl != vl) -+ goto out; - } - else - { -+ int bl; - /* Nothing much to do but emit an error message. */ -- bufsize = __snprintf (bufs, sizeof bufs, -- "out of memory[%d]", __getpid ()); -+ bl = __snprintf (bufs, sizeof bufs, -+ "out of memory[%d]", __getpid ()); -+ if (bl < 0 || bl >= sizeof bufs) -+ goto out; -+ -+ bufsize = bl; - buf = bufs; -+ msgoff = 0; - } - } - -diff --git a/misc/tst-syslog-long-progname.c b/misc/tst-syslog-long-progname.c -new file mode 100644 -index 0000000000..88f37a8a00 ---- /dev/null -+++ b/misc/tst-syslog-long-progname.c -@@ -0,0 +1,39 @@ -+/* Test heap buffer overflow in syslog with long __progname (CVE-2023-6246) -+ Copyright (C) 2023 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+ -+extern char * __progname; -+ -+static int -+do_test (void) -+{ -+ char long_progname[2048]; -+ -+ memset (long_progname, 'X', sizeof (long_progname) - 1); -+ long_progname[sizeof (long_progname) - 1] = '\0'; -+ -+ __progname = long_progname; -+ -+ syslog (LOG_INFO, "Hello, World!"); -+ -+ return 0; -+} -+ -+#include -diff --git a/misc/tst-syslog-long-progname.root/postclean.req b/misc/tst-syslog-long-progname.root/postclean.req -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/misc/tst-syslog.c b/misc/tst-syslog.c -index e550d15796..3560b518a2 100644 ---- a/misc/tst-syslog.c -+++ b/misc/tst-syslog.c -@@ -68,21 +68,19 @@ static const int priorities[] = - LOG_DEBUG - }; - --enum -- { -- ident_length = 64, -- msg_length = 64 -- }; -+#define IDENT_LENGTH 64 -+#define MSG_LENGTH 1024 - - #define SYSLOG_MSG_BASE "syslog_message" - #define OPENLOG_IDENT "openlog_ident" -+static char large_message[MSG_LENGTH]; - - struct msg_t - { - int priority; - int facility; -- char ident[ident_length]; -- char msg[msg_length]; -+ char ident[IDENT_LENGTH]; -+ char msg[MSG_LENGTH]; - pid_t pid; - }; - -@@ -147,6 +145,37 @@ check_syslog_message (const struct msg_t *msg, int msgnum, int options, - return true; - } - -+static void -+send_syslog_large (int options) -+{ -+ int facility = LOG_USER; -+ int priority = LOG_INFO; -+ -+ syslog (facility | priority, "%s %d %d", large_message, facility, -+ priority); -+} -+ -+static void -+send_vsyslog_large (int options) -+{ -+ int facility = LOG_USER; -+ int priority = LOG_INFO; -+ -+ call_vsyslog (facility | priority, "%s %d %d", large_message, facility, -+ priority); -+} -+ -+static bool -+check_syslog_message_large (const struct msg_t *msg, int msgnum, int options, -+ pid_t pid) -+{ -+ TEST_COMPARE (msg->facility, LOG_USER); -+ TEST_COMPARE (msg->priority, LOG_INFO); -+ TEST_COMPARE_STRING (msg->msg, large_message); -+ -+ return false; -+} -+ - static void - send_openlog (int options) - { -@@ -179,6 +208,17 @@ send_openlog (int options) - closelog (); - } - -+static void -+send_openlog_large (int options) -+{ -+ /* Define a non-default IDENT and a not default facility. */ -+ openlog (OPENLOG_IDENT, options, LOG_LOCAL0); -+ -+ syslog (LOG_INFO, "%s %d %d", large_message, LOG_LOCAL0, LOG_INFO); -+ -+ closelog (); -+} -+ - static bool - check_openlog_message (const struct msg_t *msg, int msgnum, - int options, pid_t pid) -@@ -189,7 +229,7 @@ check_openlog_message (const struct msg_t *msg, int msgnum, - int expected_priority = priorities[msgnum % array_length (priorities)]; - TEST_COMPARE (msg->priority, expected_priority); - -- char expected_ident[ident_length]; -+ char expected_ident[IDENT_LENGTH]; - snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:", - OPENLOG_IDENT, - options & LOG_PID ? "[" : "", -@@ -211,17 +251,43 @@ check_openlog_message (const struct msg_t *msg, int msgnum, - return true; - } - -+static bool -+check_openlog_message_large (const struct msg_t *msg, int msgnum, -+ int options, pid_t pid) -+{ -+ char expected_ident[IDENT_LENGTH]; -+ snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:", -+ OPENLOG_IDENT, -+ options & LOG_PID ? "[" : "", -+ options & LOG_PID ? pid : 0, -+ options & LOG_PID ? "]" : ""); -+ -+ TEST_COMPARE_STRING (msg->ident, expected_ident); -+ TEST_COMPARE_STRING (msg->msg, large_message); -+ TEST_COMPARE (msg->priority, LOG_INFO); -+ TEST_COMPARE (msg->facility, LOG_LOCAL0); -+ -+ return false; -+} -+ - static struct msg_t - parse_syslog_msg (const char *msg) - { - struct msg_t r = { .pid = -1 }; - int number; -+ int wsb, wsa; -+ -+#define STRINPUT(size) XSTRINPUT(size) -+#define XSTRINPUT(size) "%" # size "s" - - /* The message in the form: -- <179>Apr 8 14:51:19 tst-syslog: syslog message 176 3 */ -- int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d %32s %64s %*d %*d", -- &number, r.ident, r.msg); -+ <179>Apr 8 14:51:19 tst-syslog: message 176 3 */ -+ int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d%n %n" STRINPUT(IDENT_LENGTH) -+ " " STRINPUT(MSG_LENGTH) " %*d %*d", -+ &number, &wsb, &wsa, r.ident, r.msg); - TEST_COMPARE (n, 3); -+ /* It should only one space between timestamp and message. */ -+ TEST_COMPARE (wsa - wsb, 1); - - r.facility = number & LOG_FACMASK; - r.priority = number & LOG_PRIMASK; -@@ -246,7 +312,7 @@ parse_syslog_console (const char *msg) - - /* The message in the form: - openlog_ident: syslog_message 128 0 */ -- int n = sscanf (msg, "%32s %64s %d %d", -+ int n = sscanf (msg, STRINPUT(IDENT_LENGTH) " " STRINPUT(MSG_LENGTH) " %d %d", - r.ident, r.msg, &facility, &priority); - TEST_COMPARE (n, 4); - -@@ -281,7 +347,7 @@ check_syslog_udp (void (*syslog_send)(int), int options, - int msgnum = 0; - while (1) - { -- char buf[512]; -+ char buf[2048]; - size_t l = xrecvfrom (server_udp, buf, sizeof (buf), 0, - (struct sockaddr *) &addr, &addrlen); - buf[l] = '\0'; -@@ -325,7 +391,7 @@ check_syslog_tcp (void (*syslog_send)(int), int options, - - int client_tcp = xaccept (server_tcp, NULL, NULL); - -- char buf[512], *rb = buf; -+ char buf[2048], *rb = buf; - size_t rbl = sizeof (buf); - size_t prl = 0; /* Track the size of the partial record. */ - int msgnum = 0; -@@ -393,20 +459,34 @@ check_syslog_console_read (FILE *fp) - } - - static void --check_syslog_console (void) -+check_syslog_console_read_large (FILE *fp) -+{ -+ char buf[2048]; -+ TEST_VERIFY (fgets (buf, sizeof (buf), fp) != NULL); -+ struct msg_t msg = parse_syslog_console (buf); -+ -+ TEST_COMPARE_STRING (msg.ident, OPENLOG_IDENT ":"); -+ TEST_COMPARE_STRING (msg.msg, large_message); -+ TEST_COMPARE (msg.priority, LOG_INFO); -+ TEST_COMPARE (msg.facility, LOG_LOCAL0); -+} -+ -+static void -+check_syslog_console (void (*syslog_send)(int), -+ void (*syslog_check)(FILE *fp)) - { - xmkfifo (_PATH_CONSOLE, 0666); - - pid_t sender_pid = xfork (); - if (sender_pid == 0) - { -- send_openlog (LOG_CONS); -+ syslog_send (LOG_CONS); - _exit (0); - } - - { - FILE *fp = xfopen (_PATH_CONSOLE, "r+"); -- check_syslog_console_read (fp); -+ syslog_check (fp); - xfclose (fp); - } - -@@ -425,16 +505,28 @@ send_openlog_callback (void *clousure) - } - - static void --check_syslog_perror (void) -+send_openlog_callback_large (void *clousure) -+{ -+ int options = *(int *) clousure; -+ send_openlog_large (options); -+} -+ -+static void -+check_syslog_perror (bool large) - { - struct support_capture_subprocess result; -- result = support_capture_subprocess (send_openlog_callback, -+ result = support_capture_subprocess (large -+ ? send_openlog_callback_large -+ : send_openlog_callback, - &(int){LOG_PERROR}); - - FILE *mfp = fmemopen (result.err.buffer, result.err.length, "r"); - if (mfp == NULL) - FAIL_EXIT1 ("fmemopen: %m"); -- check_syslog_console_read (mfp); -+ if (large) -+ check_syslog_console_read_large (mfp); -+ else -+ check_syslog_console_read (mfp); - xfclose (mfp); - - support_capture_subprocess_check (&result, "tst-openlog-child", 0, -@@ -462,10 +554,31 @@ do_test (void) - check_syslog_tcp (send_openlog, LOG_PID, check_openlog_message); - - /* Check the LOG_CONS option. */ -- check_syslog_console (); -+ check_syslog_console (send_openlog, check_syslog_console_read); - - /* Check the LOG_PERROR option. */ -- check_syslog_perror (); -+ check_syslog_perror (false); -+ -+ /* Similar tests as before, but with a large message to trigger the -+ syslog path that uses dynamically allocated memory. */ -+ memset (large_message, 'a', sizeof large_message - 1); -+ large_message[sizeof large_message - 1] = '\0'; -+ -+ check_syslog_udp (send_syslog_large, 0, check_syslog_message_large); -+ check_syslog_tcp (send_syslog_large, 0, check_syslog_message_large); -+ -+ check_syslog_udp (send_vsyslog_large, 0, check_syslog_message_large); -+ check_syslog_tcp (send_vsyslog_large, 0, check_syslog_message_large); -+ -+ check_syslog_udp (send_openlog_large, 0, check_openlog_message_large); -+ check_syslog_tcp (send_openlog_large, 0, check_openlog_message_large); -+ -+ check_syslog_udp (send_openlog_large, LOG_PID, check_openlog_message_large); -+ check_syslog_tcp (send_openlog_large, LOG_PID, check_openlog_message_large); -+ -+ check_syslog_console (send_openlog_large, check_syslog_console_read_large); -+ -+ check_syslog_perror (true); - - return 0; - } -diff --git a/nis/nis_call.c b/nis/nis_call.c -index 90187e30b1..5b9dd50151 100644 ---- a/nis/nis_call.c -+++ b/nis/nis_call.c -@@ -574,7 +574,7 @@ static struct nis_server_cache - unsigned int size; - unsigned int server_used; - unsigned int current_ep; -- __time64_t expires; -+ time_t expires; - char name[]; - } *nis_server_cache[16]; - static time_t nis_cold_start_mtime; -@@ -583,7 +583,7 @@ __libc_lock_define_initialized (static, nis_server_cache_lock) - static directory_obj * - nis_server_cache_search (const_nis_name name, int search_parent, - unsigned int *server_used, unsigned int *current_ep, -- struct __timespec64 *now) -+ struct timespec *now) - { - directory_obj *ret = NULL; - int i; -@@ -641,7 +641,7 @@ nis_server_cache_search (const_nis_name name, int search_parent, - static void - nis_server_cache_add (const_nis_name name, int search_parent, - directory_obj *dir, unsigned int server_used, -- unsigned int current_ep, struct __timespec64 *now) -+ unsigned int current_ep, struct timespec *now) - { - struct nis_server_cache **loc; - struct nis_server_cache *new; -@@ -707,7 +707,7 @@ __nisfind_server (const_nis_name name, int search_parent, - nis_error result = NIS_SUCCESS; - nis_error status; - directory_obj *obj; -- struct __timespec64 ts; -+ struct timespec ts; - unsigned int server_used = ~0; - unsigned int current_ep = ~0; - -@@ -717,7 +717,7 @@ __nisfind_server (const_nis_name name, int search_parent, - if (*dir != NULL) - return NIS_SUCCESS; - -- __clock_gettime64 (CLOCK_REALTIME, &ts); -+ clock_gettime (CLOCK_REALTIME, &ts); - - if ((flags & NO_CACHE) == 0) - *dir = nis_server_cache_search (name, search_parent, &server_used, -diff --git a/nptl/descr.h b/nptl/descr.h -index 5cacb286f3..ff634dac33 100644 ---- a/nptl/descr.h -+++ b/nptl/descr.h -@@ -34,7 +34,6 @@ - #include - #include - #include --#include - #include - - #ifndef TCB_ALIGNMENT -@@ -402,14 +401,25 @@ struct pthread - /* Used on strsignal. */ - struct tls_internal_t tls_state; - -- /* rseq area registered with the kernel. */ -- struct rseq rseq_area; -- -- /* This member must be last. */ -- char end_padding[]; -- -+ /* rseq area registered with the kernel. Use a custom definition -+ here to isolate from kernel struct rseq changes. The -+ implementation of sched_getcpu needs acccess to the cpu_id field; -+ the other fields are unused and not included here. */ -+ union -+ { -+ struct -+ { -+ uint32_t cpu_id_start; -+ uint32_t cpu_id; -+ }; -+ char pad[32]; /* Original rseq area size. */ -+ } rseq_area __attribute__ ((aligned (32))); -+ -+ /* Amount of end padding, if any, in this structure. -+ This definition relies on rseq_area being last. */ - #define PTHREAD_STRUCT_END_PADDING \ -- (sizeof (struct pthread) - offsetof (struct pthread, end_padding)) -+ (sizeof (struct pthread) - offsetof (struct pthread, rseq_area) \ -+ + sizeof ((struct pthread) {}.rseq_area)) - } __attribute ((aligned (TCB_ALIGNMENT))); - - static inline bool -diff --git a/nscd/aicache.c b/nscd/aicache.c -index 51e793199f..e0baed170b 100644 ---- a/nscd/aicache.c -+++ b/nscd/aicache.c -@@ -110,11 +110,10 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, - "gethostbyname4_r"); - if (fct4 != NULL) - { -- struct gaih_addrtuple atmem; - struct gaih_addrtuple *at; - while (1) - { -- at = &atmem; -+ at = NULL; - rc6 = 0; - herrno = 0; - status[1] = DL_CALL_FCT (fct4, (key, &at, -@@ -137,7 +136,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, - goto next_nip; - - /* We found the data. Count the addresses and the size. */ -- for (const struct gaih_addrtuple *at2 = at = &atmem; at2 != NULL; -+ for (const struct gaih_addrtuple *at2 = at; at2 != NULL; - at2 = at2->next) - { - ++naddrs; -diff --git a/nscd/connections.c b/nscd/connections.c -index 61d1674eb4..531d2e83df 100644 ---- a/nscd/connections.c -+++ b/nscd/connections.c -@@ -2284,7 +2284,8 @@ main_loop_epoll (int efd) - sizeof (buf))) != -1) - ; - -- __bump_nl_timestamp (); -+ dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP] -+ = __bump_nl_timestamp (); - } - # endif - else -diff --git a/nscd/netgroupcache.c b/nscd/netgroupcache.c -index 85977521a6..adc34ba6b4 100644 ---- a/nscd/netgroupcache.c -+++ b/nscd/netgroupcache.c -@@ -23,6 +23,7 @@ - #include - #include - #include -+#include - - #include "../inet/netgroup.h" - #include "nscd.h" -@@ -65,6 +66,16 @@ struct dataset - char strdata[0]; - }; - -+/* Send a notfound response to FD. Always returns -1 to indicate an -+ ephemeral error. */ -+static time_t -+send_notfound (int fd) -+{ -+ if (fd != -1) -+ TEMP_FAILURE_RETRY (send (fd, ¬found, sizeof (notfound), MSG_NOSIGNAL)); -+ return -1; -+} -+ - /* Sends a notfound message and prepares a notfound dataset to write to the - cache. Returns true if there was enough memory to allocate the dataset and - returns the dataset in DATASETP, total bytes to write in TOTALP and the -@@ -83,8 +94,7 @@ do_notfound (struct database_dyn *db, int fd, request_header *req, - total = sizeof (notfound); - timeout = time (NULL) + db->negtimeout; - -- if (fd != -1) -- TEMP_FAILURE_RETRY (send (fd, ¬found, total, MSG_NOSIGNAL)); -+ send_notfound (fd); - - dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len, 1); - /* If we cannot permanently store the result, so be it. */ -@@ -109,11 +119,78 @@ do_notfound (struct database_dyn *db, int fd, request_header *req, - return cacheable; - } - -+struct addgetnetgrentX_scratch -+{ -+ /* This is the result that the caller should use. It can be NULL, -+ point into buffer, or it can be in the cache. */ -+ struct dataset *dataset; -+ -+ struct scratch_buffer buffer; -+ -+ /* Used internally in addgetnetgrentX as a staging area. */ -+ struct scratch_buffer tmp; -+ -+ /* Number of bytes in buffer that are actually used. */ -+ size_t buffer_used; -+}; -+ -+static void -+addgetnetgrentX_scratch_init (struct addgetnetgrentX_scratch *scratch) -+{ -+ scratch->dataset = NULL; -+ scratch_buffer_init (&scratch->buffer); -+ scratch_buffer_init (&scratch->tmp); -+ -+ /* Reserve space for the header. */ -+ scratch->buffer_used = sizeof (struct dataset); -+ static_assert (sizeof (struct dataset) < sizeof (scratch->tmp.__space), -+ "initial buffer space"); -+ memset (scratch->tmp.data, 0, sizeof (struct dataset)); -+} -+ -+static void -+addgetnetgrentX_scratch_free (struct addgetnetgrentX_scratch *scratch) -+{ -+ scratch_buffer_free (&scratch->buffer); -+ scratch_buffer_free (&scratch->tmp); -+} -+ -+/* Copy LENGTH bytes from S into SCRATCH. Returns NULL if SCRATCH -+ could not be resized, otherwise a pointer to the copy. */ -+static char * -+addgetnetgrentX_append_n (struct addgetnetgrentX_scratch *scratch, -+ const char *s, size_t length) -+{ -+ while (true) -+ { -+ size_t remaining = scratch->buffer.length - scratch->buffer_used; -+ if (remaining >= length) -+ break; -+ if (!scratch_buffer_grow_preserve (&scratch->buffer)) -+ return NULL; -+ } -+ char *copy = scratch->buffer.data + scratch->buffer_used; -+ memcpy (copy, s, length); -+ scratch->buffer_used += length; -+ return copy; -+} -+ -+/* Copy S into SCRATCH, including its null terminator. Returns false -+ if SCRATCH could not be resized. */ -+static bool -+addgetnetgrentX_append (struct addgetnetgrentX_scratch *scratch, const char *s) -+{ -+ if (s == NULL) -+ s = ""; -+ return addgetnetgrentX_append_n (scratch, s, strlen (s) + 1) != NULL; -+} -+ -+/* Caller must initialize and free *SCRATCH. If the return value is -+ negative, this function has sent a notfound response. */ - static time_t - addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - const char *key, uid_t uid, struct hashentry *he, -- struct datahead *dh, struct dataset **resultp, -- void **tofreep) -+ struct datahead *dh, struct addgetnetgrentX_scratch *scratch) - { - if (__glibc_unlikely (debug_level > 0)) - { -@@ -132,14 +209,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - - char *key_copy = NULL; - struct __netgrent data; -- size_t buflen = MAX (1024, sizeof (*dataset) + req->key_len); -- size_t buffilled = sizeof (*dataset); -- char *buffer = NULL; - size_t nentries = 0; - size_t group_len = strlen (key) + 1; - struct name_list *first_needed - = alloca (sizeof (struct name_list) + group_len); -- *tofreep = NULL; - - if (netgroup_database == NULL - && !__nss_database_get (nss_database_netgroup, &netgroup_database)) -@@ -147,12 +220,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - /* No such service. */ - cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout, - &key_copy); -- goto writeout; -+ goto maybe_cache_add; - } - - memset (&data, '\0', sizeof (data)); -- buffer = xmalloc (buflen); -- *tofreep = buffer; - first_needed->next = first_needed; - memcpy (first_needed->name, key, group_len); - data.needed_groups = first_needed; -@@ -195,8 +266,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - while (1) - { - int e; -- status = getfct.f (&data, buffer + buffilled, -- buflen - buffilled - req->key_len, &e); -+ status = getfct.f (&data, scratch->tmp.data, -+ scratch->tmp.length, &e); - if (status == NSS_STATUS_SUCCESS) - { - if (data.type == triple_val) -@@ -204,68 +275,10 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - const char *nhost = data.val.triple.host; - const char *nuser = data.val.triple.user; - const char *ndomain = data.val.triple.domain; -- -- size_t hostlen = strlen (nhost ?: "") + 1; -- size_t userlen = strlen (nuser ?: "") + 1; -- size_t domainlen = strlen (ndomain ?: "") + 1; -- -- if (nhost == NULL || nuser == NULL || ndomain == NULL -- || nhost > nuser || nuser > ndomain) -- { -- const char *last = nhost; -- if (last == NULL -- || (nuser != NULL && nuser > last)) -- last = nuser; -- if (last == NULL -- || (ndomain != NULL && ndomain > last)) -- last = ndomain; -- -- size_t bufused -- = (last == NULL -- ? buffilled -- : last + strlen (last) + 1 - buffer); -- -- /* We have to make temporary copies. */ -- size_t needed = hostlen + userlen + domainlen; -- -- if (buflen - req->key_len - bufused < needed) -- { -- buflen += MAX (buflen, 2 * needed); -- /* Save offset in the old buffer. We don't -- bother with the NULL check here since -- we'll do that later anyway. */ -- size_t nhostdiff = nhost - buffer; -- size_t nuserdiff = nuser - buffer; -- size_t ndomaindiff = ndomain - buffer; -- -- char *newbuf = xrealloc (buffer, buflen); -- /* Fix up the triplet pointers into the new -- buffer. */ -- nhost = (nhost ? newbuf + nhostdiff -- : NULL); -- nuser = (nuser ? newbuf + nuserdiff -- : NULL); -- ndomain = (ndomain ? newbuf + ndomaindiff -- : NULL); -- *tofreep = buffer = newbuf; -- } -- -- nhost = memcpy (buffer + bufused, -- nhost ?: "", hostlen); -- nuser = memcpy ((char *) nhost + hostlen, -- nuser ?: "", userlen); -- ndomain = memcpy ((char *) nuser + userlen, -- ndomain ?: "", domainlen); -- } -- -- char *wp = buffer + buffilled; -- wp = memmove (wp, nhost ?: "", hostlen); -- wp += hostlen; -- wp = memmove (wp, nuser ?: "", userlen); -- wp += userlen; -- wp = memmove (wp, ndomain ?: "", domainlen); -- wp += domainlen; -- buffilled = wp - buffer; -+ if (!(addgetnetgrentX_append (scratch, nhost) -+ && addgetnetgrentX_append (scratch, nuser) -+ && addgetnetgrentX_append (scratch, ndomain))) -+ return send_notfound (fd); - ++nentries; - } - else -@@ -317,8 +330,8 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - } - else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE) - { -- buflen *= 2; -- *tofreep = buffer = xrealloc (buffer, buflen); -+ if (!scratch_buffer_grow (&scratch->tmp)) -+ return send_notfound (fd); - } - else if (status == NSS_STATUS_RETURN - || status == NSS_STATUS_NOTFOUND -@@ -348,13 +361,20 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - { - cacheable = do_notfound (db, fd, req, key, &dataset, &total, &timeout, - &key_copy); -- goto writeout; -+ goto maybe_cache_add; - } - -- total = buffilled; -+ /* Capture the result size without the key appended. */ -+ total = scratch->buffer_used; -+ -+ /* Make a copy of the key. The scratch buffer must not move after -+ this point. */ -+ key_copy = addgetnetgrentX_append_n (scratch, key, req->key_len); -+ if (key_copy == NULL) -+ return send_notfound (fd); - - /* Fill in the dataset. */ -- dataset = (struct dataset *) buffer; -+ dataset = scratch->buffer.data; - timeout = datahead_init_pos (&dataset->head, total + req->key_len, - total - offsetof (struct dataset, resp), - he == NULL ? 0 : dh->nreloads + 1, -@@ -363,11 +383,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - dataset->resp.version = NSCD_VERSION; - dataset->resp.found = 1; - dataset->resp.nresults = nentries; -- dataset->resp.result_len = buffilled - sizeof (*dataset); -- -- assert (buflen - buffilled >= req->key_len); -- key_copy = memcpy (buffer + buffilled, key, req->key_len); -- buffilled += req->key_len; -+ dataset->resp.result_len = total - sizeof (*dataset); - - /* Now we can determine whether on refill we have to create a new - record or not. */ -@@ -398,7 +414,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - if (__glibc_likely (newp != NULL)) - { - /* Adjust pointer into the memory block. */ -- key_copy = (char *) newp + (key_copy - buffer); -+ key_copy = (char *) newp + (key_copy - (char *) dataset); - - dataset = memcpy (newp, dataset, total + req->key_len); - cacheable = true; -@@ -410,14 +426,12 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - } - - if (he == NULL && fd != -1) -- { -- /* We write the dataset before inserting it to the database -- since while inserting this thread might block and so would -- unnecessarily let the receiver wait. */ -- writeout: -+ /* We write the dataset before inserting it to the database since -+ while inserting this thread might block and so would -+ unnecessarily let the receiver wait. */ - writeall (fd, &dataset->resp, dataset->head.recsize); -- } - -+ maybe_cache_add: - if (cacheable) - { - /* If necessary, we also propagate the data to disk. */ -@@ -441,7 +455,7 @@ addgetnetgrentX (struct database_dyn *db, int fd, request_header *req, - } - - out: -- *resultp = dataset; -+ scratch->dataset = dataset; - - return timeout; - } -@@ -462,6 +476,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, - if (user != NULL) - key = (char *) rawmemchr (key, '\0') + 1; - const char *domain = *key++ ? key : NULL; -+ struct addgetnetgrentX_scratch scratch; -+ -+ addgetnetgrentX_scratch_init (&scratch); - - if (__glibc_unlikely (debug_level > 0)) - { -@@ -477,12 +494,8 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, - group, group_len, - db, uid); - time_t timeout; -- void *tofree; - if (result != NULL) -- { -- timeout = result->head.timeout; -- tofree = NULL; -- } -+ timeout = result->head.timeout; - else - { - request_header req_get = -@@ -491,7 +504,10 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, - .key_len = group_len - }; - timeout = addgetnetgrentX (db, -1, &req_get, group, uid, NULL, NULL, -- &result, &tofree); -+ &scratch); -+ result = scratch.dataset; -+ if (timeout < 0) -+ goto out; - } - - struct indataset -@@ -502,24 +518,26 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, - = (struct indataset *) mempool_alloc (db, - sizeof (*dataset) + req->key_len, - 1); -- struct indataset dataset_mem; - bool cacheable = true; - if (__glibc_unlikely (dataset == NULL)) - { - cacheable = false; -- dataset = &dataset_mem; -+ /* The alloca is safe because nscd_run_worker verfies that -+ key_len is not larger than MAXKEYLEN. */ -+ dataset = alloca (sizeof (*dataset) + req->key_len); - } - - datahead_init_pos (&dataset->head, sizeof (*dataset) + req->key_len, - sizeof (innetgroup_response_header), -- he == NULL ? 0 : dh->nreloads + 1, result->head.ttl); -+ he == NULL ? 0 : dh->nreloads + 1, -+ result == NULL ? db->negtimeout : result->head.ttl); - /* Set the notfound status and timeout based on the result from - getnetgrent. */ -- dataset->head.notfound = result->head.notfound; -+ dataset->head.notfound = result == NULL || result->head.notfound; - dataset->head.timeout = timeout; - - dataset->resp.version = NSCD_VERSION; -- dataset->resp.found = result->resp.found; -+ dataset->resp.found = result != NULL && result->resp.found; - /* Until we find a matching entry the result is 0. */ - dataset->resp.result = 0; - -@@ -567,7 +585,9 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, - goto out; - } - -- if (he == NULL) -+ /* addgetnetgrentX may have already sent a notfound response. Do -+ not send another one. */ -+ if (he == NULL && dataset->resp.found) - { - /* We write the dataset before inserting it to the database - since while inserting this thread might block and so would -@@ -601,7 +621,7 @@ addinnetgrX (struct database_dyn *db, int fd, request_header *req, - } - - out: -- free (tofree); -+ addgetnetgrentX_scratch_free (&scratch); - return timeout; - } - -@@ -611,11 +631,12 @@ addgetnetgrentX_ignore (struct database_dyn *db, int fd, request_header *req, - const char *key, uid_t uid, struct hashentry *he, - struct datahead *dh) - { -- struct dataset *ignore; -- void *tofree; -- time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, -- &ignore, &tofree); -- free (tofree); -+ struct addgetnetgrentX_scratch scratch; -+ addgetnetgrentX_scratch_init (&scratch); -+ time_t timeout = addgetnetgrentX (db, fd, req, key, uid, he, dh, &scratch); -+ addgetnetgrentX_scratch_free (&scratch); -+ if (timeout < 0) -+ timeout = 0; - return timeout; - } - -@@ -659,5 +680,9 @@ readdinnetgr (struct database_dyn *db, struct hashentry *he, - .key_len = he->len - }; - -- return addinnetgrX (db, -1, &req, db->data + he->key, he->owner, he, dh); -+ time_t timeout = addinnetgrX (db, -1, &req, db->data + he->key, he->owner, -+ he, dh); -+ if (timeout < 0) -+ timeout = 0; -+ return timeout; - } -diff --git a/nscd/nscd.h b/nscd/nscd.h -index 368091aef8..f15321585b 100644 ---- a/nscd/nscd.h -+++ b/nscd/nscd.h -@@ -65,7 +65,7 @@ typedef enum - struct traced_file - { - /* Tracks the last modified time of the traced file. */ -- time_t mtime; -+ __time64_t mtime; - /* Support multiple registered files per database. */ - struct traced_file *next; - int call_res_init; -diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c -index 9becb62033..31c64275f0 100644 ---- a/nscd/nscd_gethst_r.c -+++ b/nscd/nscd_gethst_r.c -@@ -112,7 +112,7 @@ __nscd_get_nl_timestamp (void) - if (map == NULL - || (map != NO_MAPPING - && map->head->nscd_certainly_running == 0 -- && map->head->timestamp + MAPPING_TIMEOUT < time_now ())) -+ && map->head->timestamp + MAPPING_TIMEOUT < time64_now ())) - map = __nscd_get_mapping (GETFDHST, "hosts", &__hst_map_handle.mapped); - - if (map == NO_MAPPING) -diff --git a/nss/Makefile b/nss/Makefile -index a978e3927a..7a52c68791 100644 ---- a/nss/Makefile -+++ b/nss/Makefile -@@ -81,6 +81,7 @@ tests-container := \ - tst-nss-test3 \ - tst-reload1 \ - tst-reload2 \ -+ tst-nss-gai-hv2-canonname \ - # tests-container - - # Tests which need libdl -@@ -144,7 +145,17 @@ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) - ifeq ($(build-static-nss),yes) - tests-static += tst-nss-static - endif --extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os -+extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \ -+ nss_test_gai_hv2_canonname.os -+ -+ifeq ($(run-built-tests),yes) -+ifneq (no,$(PERL)) -+tests-special += $(objpfx)mtrace-tst-nss-gai-hv2-canonname.out -+endif -+endif -+ -+generated += mtrace-tst-nss-gai-hv2-canonname.out \ -+ tst-nss-gai-hv2-canonname.mtrace - - include ../Rules - -@@ -179,12 +190,16 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver - libof-nss_test1 = extramodules - libof-nss_test2 = extramodules - libof-nss_test_errno = extramodules -+libof-nss_test_gai_hv2_canonname = extramodules - $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps) - $(build-module) - $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps) - $(build-module) - $(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps) - $(build-module) -+$(objpfx)/libnss_test_gai_hv2_canonname.so: \ -+ $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps) -+ $(build-module) - $(objpfx)nss_test2.os : nss_test1.c - # Use the nss_files suffix for these objects as well. - $(objpfx)/libnss_test1.so$(libnss_files.so-version): $(objpfx)/libnss_test1.so -@@ -194,10 +209,14 @@ $(objpfx)/libnss_test2.so$(libnss_files.so-version): $(objpfx)/libnss_test2.so - $(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \ - $(objpfx)/libnss_test_errno.so - $(make-link) -+$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \ -+ $(objpfx)/libnss_test_gai_hv2_canonname.so -+ $(make-link) - $(patsubst %,$(objpfx)%.out,$(tests) $(tests-container)) : \ - $(objpfx)/libnss_test1.so$(libnss_files.so-version) \ - $(objpfx)/libnss_test2.so$(libnss_files.so-version) \ -- $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) -+ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \ -+ $(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version) - - ifeq (yes,$(have-thread-library)) - $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) -@@ -206,6 +225,17 @@ endif - $(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so - $(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)/libnss_files.so - -+tst-nss-gai-hv2-canonname-ENV = \ -+ MALLOC_TRACE=$(objpfx)tst-nss-gai-hv2-canonname.mtrace \ -+ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so -+$(objpfx)mtrace-tst-nss-gai-hv2-canonname.out: \ -+ $(objpfx)tst-nss-gai-hv2-canonname.out -+ { test -r $(objpfx)tst-nss-gai-hv2-canonname.mtrace \ -+ || ( echo "tst-nss-gai-hv2-canonname.mtrace does not exist"; exit 77; ) \ -+ && $(common-objpfx)malloc/mtrace \ -+ $(objpfx)tst-nss-gai-hv2-canonname.mtrace; } > $@; \ -+ $(evaluate-test) -+ - # Disable DT_RUNPATH on NSS tests so that the glibc internal NSS - # functions can load testing NSS modules via DT_RPATH. - LDFLAGS-tst-nss-test1 = -Wl,--disable-new-dtags -@@ -214,3 +244,4 @@ LDFLAGS-tst-nss-test3 = -Wl,--disable-new-dtags - LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags - LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags - LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags -+LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags -diff --git a/nss/getent.c b/nss/getent.c -index 8178b4b470..d2d2524b0c 100644 ---- a/nss/getent.c -+++ b/nss/getent.c -@@ -58,6 +58,8 @@ static const struct argp_option args_options[] = - { - { "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") }, - { "no-idn", 'i', NULL, 0, N_("disable IDN encoding") }, -+ { "no-addrconfig", 'A', NULL, 0, -+ N_("do not filter out unsupported IPv4/IPv6 addresses (with ahosts*)") }, - { NULL, 0, NULL, 0, NULL }, - }; - -@@ -79,6 +81,9 @@ static struct argp argp = - /* Additional getaddrinfo flags for IDN encoding. */ - static int idn_flags = AI_IDN | AI_CANONIDN; - -+/* Set to 0 by --no-addrconfig. */ -+static int addrconfig_flags = AI_ADDRCONFIG; -+ - /* Print the version information. */ - static void - print_version (FILE *stream, struct argp_state *state) -@@ -346,7 +351,7 @@ ahosts_keys_int (int af, int xflags, int number, char *key[]) - - struct addrinfo hint; - memset (&hint, '\0', sizeof (hint)); -- hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME -+ hint.ai_flags = (AI_V4MAPPED | addrconfig_flags | AI_CANONNAME - | idn_flags | xflags); - hint.ai_family = af; - -@@ -905,6 +910,10 @@ parse_option (int key, char *arg, struct argp_state *state) - idn_flags = 0; - break; - -+ case 'A': -+ addrconfig_flags = 0; -+ break; -+ - default: - return ARGP_ERR_UNKNOWN; - } -diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c -new file mode 100644 -index 0000000000..4439c83c9f ---- /dev/null -+++ b/nss/nss_test_gai_hv2_canonname.c -@@ -0,0 +1,56 @@ -+/* NSS service provider that only provides gethostbyname2_r. -+ 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 -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include "nss/tst-nss-gai-hv2-canonname.h" -+ -+/* Catch misnamed and functions. */ -+#pragma GCC diagnostic error "-Wmissing-prototypes" -+NSS_DECLARE_MODULE_FUNCTIONS (test_gai_hv2_canonname) -+ -+extern enum nss_status _nss_files_gethostbyname2_r (const char *, int, -+ struct hostent *, char *, -+ size_t, int *, int *); -+ -+enum nss_status -+_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af, -+ struct hostent *result, -+ char *buffer, size_t buflen, -+ int *errnop, int *herrnop) -+{ -+ return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop, -+ herrnop); -+} -+ -+enum nss_status -+_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer, -+ size_t buflen, char **result, -+ int *errnop, int *h_errnop) -+{ -+ /* We expect QUERYNAME, which is a small enough string that it shouldn't fail -+ the test. */ -+ if (memcmp (QUERYNAME, name, sizeof (QUERYNAME)) -+ || buflen < sizeof (QUERYNAME)) -+ abort (); -+ -+ strncpy (buffer, name, buflen); -+ *result = buffer; -+ return NSS_STATUS_SUCCESS; -+} -diff --git a/nss/tst-nss-files-hosts-long.c b/nss/tst-nss-files-hosts-long.c -index 3942cf5fca..a7697e3143 100644 ---- a/nss/tst-nss-files-hosts-long.c -+++ b/nss/tst-nss-files-hosts-long.c -@@ -28,14 +28,15 @@ do_test (void) - { - int ret; - -- /* Run getent to fetch the IPv4 address for host test4. -- This forces /etc/hosts to be parsed. */ -- ret = system("getent ahostsv4 test4"); -+ /* Run getent to fetch the IPv4 address for host test4. This forces -+ /etc/hosts to be parsed. Use --no-addrconfig to return addresses -+ even in an IPv6-only environment. */ -+ ret = system("getent --no-addrconfig ahostsv4 test4"); - if (ret != 0) - FAIL_EXIT1("ahostsv4 failed"); - - /* Likewise for IPv6. */ -- ret = system("getent ahostsv6 test6"); -+ ret = system("getent --no-addrconfig ahostsv6 test6"); - if (ret != 0) - FAIL_EXIT1("ahostsv6 failed"); - -diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c -new file mode 100644 -index 0000000000..7db53cf09d ---- /dev/null -+++ b/nss/tst-nss-gai-hv2-canonname.c -@@ -0,0 +1,66 @@ -+/* Test NSS query path for plugins that only implement gethostbyname2 -+ (#30843). -+ 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 -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "nss/tst-nss-gai-hv2-canonname.h" -+ -+#define PREPARE do_prepare -+ -+static void do_prepare (int a, char **av) -+{ -+ FILE *hosts = xfopen ("/etc/hosts", "w"); -+ for (unsigned i = 2; i < 255; i++) -+ { -+ fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i); -+ fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i); -+ } -+ xfclose (hosts); -+} -+ -+static int -+do_test (void) -+{ -+ mtrace (); -+ -+ __nss_configure_lookup ("hosts", "test_gai_hv2_canonname"); -+ -+ struct addrinfo hints = {}; -+ struct addrinfo *result = NULL; -+ -+ hints.ai_family = AF_INET6; -+ hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME; -+ -+ int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result); -+ -+ if (ret != 0) -+ FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret)); -+ -+ TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME); -+ -+ freeaddrinfo(result); -+ return 0; -+} -+ -+#include -diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h -new file mode 100644 -index 0000000000..14f2a9cb08 ---- /dev/null -+++ b/nss/tst-nss-gai-hv2-canonname.h -@@ -0,0 +1 @@ -+#define QUERYNAME "test.example.com" -diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req -new file mode 100644 -index 0000000000..e69de29bb2 -diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script -new file mode 100644 -index 0000000000..31848b4a28 ---- /dev/null -+++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script -@@ -0,0 +1,2 @@ -+cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2 -+su -diff --git a/nss/tst-reload1.c b/nss/tst-reload1.c -index fdc5bdd65b..bc32bb132a 100644 ---- a/nss/tst-reload1.c -+++ b/nss/tst-reload1.c -@@ -43,12 +43,12 @@ static struct passwd pwd_table_1[] = { - - static const char *hostaddr_5[] = - { -- "ABCD", "abcd", "1234", NULL -+ "ABCd", "ABCD", "ABC4", NULL - }; - - static const char *hostaddr_15[] = - { -- "4321", "ghij", NULL -+ "4321", "4322", NULL - }; - - static const char *hostaddr_25[] = -@@ -86,12 +86,12 @@ static const char *hostaddr_6[] = - - static const char *hostaddr_16[] = - { -- "7890", "a1b2", NULL -+ "7890", "7891", NULL - }; - - static const char *hostaddr_26[] = - { -- "qwer", "tyui", NULL -+ "qwer", "qweR", NULL - }; - - static struct hostent host_table_2[] = { -diff --git a/resolv/Makefile b/resolv/Makefile -index 5b15321f9b..28cedf49ee 100644 ---- a/resolv/Makefile -+++ b/resolv/Makefile -@@ -40,12 +40,16 @@ routines := \ - inet_pton \ - ns_makecanon \ - ns_name_compress \ -+ ns_name_length_uncompressed \ - ns_name_ntop \ - ns_name_pack \ - ns_name_pton \ - ns_name_skip \ - ns_name_uncompress \ - ns_name_unpack \ -+ ns_rr_cursor_init \ -+ ns_rr_cursor_next \ -+ ns_samebinaryname \ - ns_samename \ - nsap_addr \ - nss_dns_functions \ -@@ -89,11 +93,15 @@ tests += \ - tst-ns_name_pton \ - tst-res_hconf_reorder \ - tst-res_hnok \ -+ tst-resolv-aliases \ - tst-resolv-basic \ - tst-resolv-binary \ -+ tst-resolv-byaddr \ - tst-resolv-edns \ -+ tst-resolv-invalid-cname \ - tst-resolv-network \ - tst-resolv-noaaaa \ -+ tst-resolv-noaaaa-vc \ - tst-resolv-nondecimal \ - tst-resolv-res_init-multi \ - tst-resolv-search \ -@@ -104,6 +112,18 @@ tests += \ - tests-internal += tst-resolv-txnid-collision - tests-static += tst-resolv-txnid-collision - -+# Likewise for __ns_samebinaryname. -+tests-internal += tst-ns_samebinaryname -+tests-static += tst-ns_samebinaryname -+ -+# Likewise for __ns_name_length_uncompressed. -+tests-internal += tst-ns_name_length_uncompressed -+tests-static += tst-ns_name_length_uncompressed -+ -+# Likewise for struct ns_rr_cursor and its functions. -+tests-internal += tst-ns_rr_cursor -+tests-static += tst-ns_rr_cursor -+ - # These tests need libdl. - ifeq (yes,$(build-shared)) - tests += \ -@@ -258,8 +278,10 @@ $(objpfx)tst-resolv-ai_idn.out: $(gen-locales) - $(objpfx)tst-resolv-ai_idn-latin1.out: $(gen-locales) - $(objpfx)tst-resolv-ai_idn-nolibidn2.out: \ - $(gen-locales) $(objpfx)tst-no-libidn2.so -+$(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library) -+$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so -@@ -267,7 +289,10 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ - $(shared-thread-library) - $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \ - $(shared-thread-library) -+$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \ -+ $(shared-thread-library) - $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library) -+$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) - $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) -diff --git a/resolv/README b/resolv/README -index 514e9bb617..2146bc3b27 100644 ---- a/resolv/README -+++ b/resolv/README -@@ -146,6 +146,3 @@ res_libc.c is home-brewn, although parts of it are taken from res_data.c. - - res_hconf.c and res_hconf.h were contributed by David Mosberger, and - do not come from BIND. -- --The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are --leftovers from BIND 4.9.7. -diff --git a/resolv/mapv4v6addr.h b/resolv/mapv4v6addr.h -deleted file mode 100644 -index 7f85f7d5e3..0000000000 ---- a/resolv/mapv4v6addr.h -+++ /dev/null -@@ -1,69 +0,0 @@ --/* -- * ++Copyright++ 1985, 1988, 1993 -- * - -- * Copyright (c) 1985, 1988, 1993 -- * The Regents of the University of California. All rights reserved. -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions -- * are met: -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. Redistributions in binary form must reproduce the above copyright -- * notice, this list of conditions and the following disclaimer in the -- * documentation and/or other materials provided with the distribution. -- * 4. Neither the name of the University nor the names of its contributors -- * may be used to endorse or promote products derived from this software -- * without specific prior written permission. -- * -- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -- * SUCH DAMAGE. -- * - -- * Portions Copyright (c) 1993 by Digital Equipment Corporation. -- * -- * Permission to use, copy, modify, and distribute this software for any -- * purpose with or without fee is hereby granted, provided that the above -- * copyright notice and this permission notice appear in all copies, and that -- * the name of Digital Equipment Corporation not be used in advertising or -- * publicity pertaining to distribution of the document or software without -- * specific, written prior permission. -- * -- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL -- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES -- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT -- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -- * SOFTWARE. -- * - -- * --Copyright-- -- */ -- --#include --#include -- --static void --map_v4v6_address (const char *src, char *dst) --{ -- u_char *p = (u_char *) dst; -- int i; -- -- /* Move the IPv4 part to the right position. */ -- memcpy (dst + 12, src, INADDRSZ); -- -- /* Mark this ipv6 addr as a mapped ipv4. */ -- for (i = 0; i < 10; i++) -- *p++ = 0x00; -- *p++ = 0xff; -- *p = 0xff; --} -diff --git a/resolv/mapv4v6hostent.h b/resolv/mapv4v6hostent.h -deleted file mode 100644 -index c11038adf3..0000000000 ---- a/resolv/mapv4v6hostent.h -+++ /dev/null -@@ -1,84 +0,0 @@ --/* -- * ++Copyright++ 1985, 1988, 1993 -- * - -- * Copyright (c) 1985, 1988, 1993 -- * The Regents of the University of California. All rights reserved. -- * -- * Redistribution and use in source and binary forms, with or without -- * modification, are permitted provided that the following conditions -- * are met: -- * 1. Redistributions of source code must retain the above copyright -- * notice, this list of conditions and the following disclaimer. -- * 2. Redistributions in binary form must reproduce the above copyright -- * notice, this list of conditions and the following disclaimer in the -- * documentation and/or other materials provided with the distribution. -- * 4. Neither the name of the University nor the names of its contributors -- * may be used to endorse or promote products derived from this software -- * without specific prior written permission. -- * -- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -- * SUCH DAMAGE. -- * - -- * Portions Copyright (c) 1993 by Digital Equipment Corporation. -- * -- * Permission to use, copy, modify, and distribute this software for any -- * purpose with or without fee is hereby granted, provided that the above -- * copyright notice and this permission notice appear in all copies, and that -- * the name of Digital Equipment Corporation not be used in advertising or -- * publicity pertaining to distribution of the document or software without -- * specific, written prior permission. -- * -- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL -- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES -- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT -- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -- * SOFTWARE. -- * - -- * --Copyright-- -- */ -- --#include --#include -- --typedef union { -- int32_t al; -- char ac; --} align; -- --static int --map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp) --{ -- char **ap; -- -- if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) -- return 0; -- hp->h_addrtype = AF_INET6; -- hp->h_length = IN6ADDRSZ; -- for (ap = hp->h_addr_list; *ap; ap++) -- { -- int i = sizeof (align) - ((u_long) *bpp % sizeof (align)); -- -- if (*lenp < (i + IN6ADDRSZ)) -- /* Out of memory. */ -- return 1; -- *bpp += i; -- *lenp -= i; -- map_v4v6_address (*ap, *bpp); -- *ap = *bpp; -- *bpp += IN6ADDRSZ; -- *lenp -= IN6ADDRSZ; -- } -- return 0; --} -diff --git a/resolv/ns_name_length_uncompressed.c b/resolv/ns_name_length_uncompressed.c -new file mode 100644 -index 0000000000..51296b47ef ---- /dev/null -+++ b/resolv/ns_name_length_uncompressed.c -@@ -0,0 +1,72 @@ -+/* Skip over an uncompressed name in wire format. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+ -+int -+__ns_name_length_uncompressed (const unsigned char *p, -+ const unsigned char *eom) -+{ -+ const unsigned char *start = p; -+ -+ while (true) -+ { -+ if (p == eom) -+ { -+ /* Truncated packet: no room for label length. */ -+ __set_errno (EMSGSIZE); -+ return -1; -+ } -+ -+ unsigned char b = *p; -+ ++p; -+ if (b == 0) -+ { -+ /* Root label. */ -+ size_t length = p - start; -+ if (length > NS_MAXCDNAME) -+ { -+ /* Domain name too long. */ -+ __set_errno (EMSGSIZE); -+ return -1; -+ } -+ return length; -+ } -+ -+ if (b <= 63) -+ { -+ /* Regular label. */ -+ if (b <= eom - p) -+ p += b; -+ else -+ { -+ /* Truncated packet: label incomplete. */ -+ __set_errno (EMSGSIZE); -+ return -1; -+ } -+ } -+ else -+ { -+ /* Compression reference or corrupted label length. */ -+ __set_errno (EMSGSIZE); -+ return -1; -+ } -+ } -+} -diff --git a/resolv/ns_rr_cursor_init.c b/resolv/ns_rr_cursor_init.c -new file mode 100644 -index 0000000000..6ee80b30e9 ---- /dev/null -+++ b/resolv/ns_rr_cursor_init.c -@@ -0,0 +1,62 @@ -+/* Initialize a simple DNS packet parser. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+ -+bool -+__ns_rr_cursor_init (struct ns_rr_cursor *c, -+ const unsigned char *buf, size_t len) -+{ -+ c->begin = buf; -+ c->end = buf + len; -+ -+ /* Check for header size and 16-bit question count value (it must be 1). */ -+ if (len < 12 || buf[4] != 0 || buf[5] != 1) -+ { -+ __set_errno (EMSGSIZE); -+ c->current = c->end; -+ return false; -+ } -+ c->current = buf + 12; -+ -+ int consumed = __ns_name_length_uncompressed (c->current, c->end); -+ if (consumed < 0) -+ { -+ __set_errno (EMSGSIZE); -+ c->current = c->end; -+ c->first_rr = NULL; -+ return false; -+ } -+ c->current += consumed; -+ -+ /* Ensure there is room for question type and class. */ -+ if (c->end - c->current < 4) -+ { -+ __set_errno (EMSGSIZE); -+ c->current = c->end; -+ c->first_rr = NULL; -+ return false; -+ } -+ c->current += 4; -+ c->first_rr = c->current; -+ -+ return true; -+} -diff --git a/resolv/ns_rr_cursor_next.c b/resolv/ns_rr_cursor_next.c -new file mode 100644 -index 0000000000..33652fc5da ---- /dev/null -+++ b/resolv/ns_rr_cursor_next.c -@@ -0,0 +1,74 @@ -+/* Simple DNS record parser without textual name decoding. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+ -+bool -+__ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr) -+{ -+ rr->rdata = NULL; -+ -+ /* Extract the record owner name. */ -+ int consumed = __ns_name_unpack (c->begin, c->end, c->current, -+ rr->rname, sizeof (rr->rname)); -+ if (consumed < 0) -+ { -+ memset (rr, 0, sizeof (*rr)); -+ __set_errno (EMSGSIZE); -+ return false; -+ } -+ c->current += consumed; -+ -+ /* Extract the metadata. */ -+ struct -+ { -+ uint16_t rtype; -+ uint16_t rclass; -+ uint32_t ttl; -+ uint16_t rdlength; -+ } __attribute__ ((packed)) metadata; -+ _Static_assert (sizeof (metadata) == 10, "sizeof metadata"); -+ if (c->end - c->current < sizeof (metadata)) -+ { -+ memset (rr, 0, sizeof (*rr)); -+ __set_errno (EMSGSIZE); -+ return false; -+ } -+ memcpy (&metadata, c->current, sizeof (metadata)); -+ c->current += sizeof (metadata); -+ /* Endianess conversion. */ -+ rr->rtype = ntohs (metadata.rtype); -+ rr->rclass = ntohs (metadata.rclass); -+ rr->ttl = ntohl (metadata.ttl); -+ rr->rdlength = ntohs (metadata.rdlength); -+ -+ /* Extract record data. */ -+ if (c->end - c->current < rr->rdlength) -+ { -+ memset (rr, 0, sizeof (*rr)); -+ __set_errno (EMSGSIZE); -+ return false; -+ } -+ rr->rdata = c->current; -+ c->current += rr->rdlength; -+ -+ return true; -+} -diff --git a/resolv/ns_samebinaryname.c b/resolv/ns_samebinaryname.c -new file mode 100644 -index 0000000000..9a47d8e97a ---- /dev/null -+++ b/resolv/ns_samebinaryname.c -@@ -0,0 +1,55 @@ -+/* Compare two binary domain names for quality. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+ -+/* Convert ASCII letters to upper case. */ -+static inline int -+ascii_toupper (unsigned char ch) -+{ -+ if (ch >= 'a' && ch <= 'z') -+ return ch - 'a' + 'A'; -+ else -+ return ch; -+} -+ -+bool -+__ns_samebinaryname (const unsigned char *a, const unsigned char *b) -+{ -+ while (*a != 0 && *b != 0) -+ { -+ if (*a != *b) -+ /* Different label length. */ -+ return false; -+ int labellen = *a; -+ ++a; -+ ++b; -+ for (int i = 0; i < labellen; ++i) -+ { -+ if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b)) -+ /* Different character in label. */ -+ return false; -+ ++a; -+ ++b; -+ } -+ } -+ -+ /* Match if both names are at the root label. */ -+ return *a == 0 && *b == 0; -+} -diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c -index 544cffbecd..227734da5c 100644 ---- a/resolv/nss_dns/dns-host.c -+++ b/resolv/nss_dns/dns-host.c -@@ -69,6 +69,7 @@ - * --Copyright-- - */ - -+#include - #include - #include - #include -@@ -86,10 +87,6 @@ - #include - #include - --/* Get implementations of some internal functions. */ --#include --#include -- - #define RESOLVSORT - - #if PACKETSZ > 65536 -@@ -103,32 +100,36 @@ - #endif - #define MAXHOSTNAMELEN 256 - --/* We need this time later. */ --typedef union querybuf --{ -- HEADER hdr; -- u_char buf[MAXPACKET]; --} querybuf; -- --static enum nss_status getanswer_r (struct resolv_context *ctx, -- const querybuf *answer, int anslen, -- const char *qname, int qtype, -- struct hostent *result, char *buffer, -- size_t buflen, int *errnop, int *h_errnop, -- int map, int32_t *ttlp, char **canonp); -- --static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, -- const querybuf *answer2, int anslen2, -- const char *qname, -+/* For historic reasons, pointers to IP addresses are char *, so use a -+ single list type for addresses and host names. */ -+#define DYNARRAY_STRUCT ptrlist -+#define DYNARRAY_ELEMENT char * -+#define DYNARRAY_PREFIX ptrlist_ -+#include -+ -+static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen, -+ uint16_t qtype, struct alloc_buffer *abuf, -+ struct ptrlist *addresses, -+ struct ptrlist *aliases, -+ int *errnop, int *h_errnop, int32_t *ttlp); -+static void addrsort (struct resolv_context *ctx, char **ap, int num); -+static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, -+ struct alloc_buffer *abuf, -+ char **hnamep, int *errnop, -+ int *h_errnop, int32_t *ttlp); -+ -+static enum nss_status gaih_getanswer (unsigned char *packet1, -+ size_t packet1len, -+ unsigned char *packet2, -+ size_t packet2len, -+ struct alloc_buffer *abuf, - struct gaih_addrtuple **pat, -- char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp); --static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1, -- int anslen1, -- const char *qname, -+static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet, -+ size_t packetlen, -+ struct alloc_buffer *abuf, - struct gaih_addrtuple **pat, -- char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp); - -@@ -183,16 +184,9 @@ gethostbyname3_context (struct resolv_context *ctx, - char *buffer, size_t buflen, int *errnop, - int *h_errnop, int32_t *ttlp, char **canonp) - { -- union -- { -- querybuf *buf; -- u_char *ptr; -- } host_buffer; -- querybuf *orig_host_buffer; - char tmp[NS_MAXDNAME]; - int size, type, n; - const char *cp; -- int map = 0; - int olderr = errno; - enum nss_status status; - -@@ -223,10 +217,12 @@ gethostbyname3_context (struct resolv_context *ctx, - && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL) - name = cp; - -- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); -+ unsigned char dns_packet_buffer[1024]; -+ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; - -- n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf, -- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); -+ n = __res_context_search (ctx, name, C_IN, type, -+ dns_packet_buffer, sizeof (dns_packet_buffer), -+ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); - if (n < 0) - { - switch (errno) -@@ -253,34 +249,79 @@ gethostbyname3_context (struct resolv_context *ctx, - *errnop = EAGAIN; - else - __set_errno (olderr); -+ } -+ else -+ { -+ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); - -- /* If we are looking for an IPv6 address and mapping is enabled -- by having the RES_USE_INET6 bit in _res.options set, we try -- another lookup. */ -- if (af == AF_INET6 && res_use_inet6 ()) -- n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf, -- host_buffer.buf != orig_host_buffer -- ? MAXPACKET : 1024, &host_buffer.ptr, -- NULL, NULL, NULL, NULL); -+ struct ptrlist addresses; -+ ptrlist_init (&addresses); -+ struct ptrlist aliases; -+ ptrlist_init (&aliases); - -- if (n < 0) -+ status = getanswer_r (alt_dns_packet_buffer, n, type, -+ &abuf, &addresses, &aliases, -+ errnop, h_errnop, ttlp); -+ if (status == NSS_STATUS_SUCCESS) - { -- if (host_buffer.buf != orig_host_buffer) -- free (host_buffer.buf); -- return status; -- } -+ if (ptrlist_has_failed (&addresses) -+ || ptrlist_has_failed (&aliases)) -+ { -+ /* malloc failure. Do not retry using the ERANGE protocol. */ -+ *errnop = ENOMEM; -+ *h_errnop = NETDB_INTERNAL; -+ status = NSS_STATUS_UNAVAIL; -+ } - -- map = 1; -+ /* Reserve the address and alias arrays in the result -+ buffer. Both are NULL-terminated, but the first element -+ of the alias array is stored in h_name, so no extra space -+ for the NULL terminator is needed there. */ -+ result->h_addr_list -+ = alloc_buffer_alloc_array (&abuf, char *, -+ ptrlist_size (&addresses) + 1); -+ result->h_aliases -+ = alloc_buffer_alloc_array (&abuf, char *, -+ ptrlist_size (&aliases)); -+ if (alloc_buffer_has_failed (&abuf)) -+ { -+ /* Retry using the ERANGE protocol. */ -+ *errnop = ERANGE; -+ *h_errnop = NETDB_INTERNAL; -+ status = NSS_STATUS_TRYAGAIN; -+ } -+ else -+ { -+ /* Copy the address list and NULL-terminate it. */ -+ memcpy (result->h_addr_list, ptrlist_begin (&addresses), -+ ptrlist_size (&addresses) * sizeof (char *)); -+ result->h_addr_list[ptrlist_size (&addresses)] = NULL; -+ -+ /* Sort the address list if requested. */ -+ if (type == T_A && __resolv_context_sort_count (ctx) > 0) -+ addrsort (ctx, result->h_addr_list, ptrlist_size (&addresses)); - -- result->h_addrtype = AF_INET; -- result->h_length = INADDRSZ; -+ /* Copy the aliases, excluding the last one. */ -+ memcpy (result->h_aliases, ptrlist_begin (&aliases), -+ (ptrlist_size (&aliases) - 1) * sizeof (char *)); -+ result->h_aliases[ptrlist_size (&aliases) - 1] = NULL; -+ -+ /* The last alias goes into h_name. */ -+ assert (ptrlist_size (&aliases) >= 1); -+ result->h_name = ptrlist_end (&aliases)[-1]; -+ -+ /* This is also the canonical name. */ -+ if (canonp != NULL) -+ *canonp = result->h_name; -+ } -+ } -+ -+ ptrlist_free (&aliases); -+ ptrlist_free (&addresses); - } - -- status = getanswer_r -- (ctx, host_buffer.buf, n, name, type, result, buffer, buflen, -- errnop, h_errnop, map, ttlp, canonp); -- if (host_buffer.buf != orig_host_buffer) -- free (host_buffer.buf); -+ if (alt_dns_packet_buffer != dns_packet_buffer) -+ free (alt_dns_packet_buffer); - return status; - } - -@@ -324,13 +365,8 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, - *h_errnop = NETDB_INTERNAL; - return NSS_STATUS_UNAVAIL; - } -- status = NSS_STATUS_NOTFOUND; -- if (res_use_inet6 ()) -- status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer, -- buflen, errnop, h_errnop, NULL, NULL); -- if (status == NSS_STATUS_NOTFOUND) -- status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, -- buflen, errnop, h_errnop, NULL, NULL); -+ status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, -+ buflen, errnop, h_errnop, NULL, NULL); - __resolv_context_put (ctx); - return status; - } -@@ -365,17 +401,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, - name = cp; - } - -- union -- { -- querybuf *buf; -- u_char *ptr; -- } host_buffer; -- querybuf *orig_host_buffer; -- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048); -+ unsigned char dns_packet_buffer[2048]; -+ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; - u_char *ans2p = NULL; - int nans2p = 0; - int resplen2 = 0; - int ans2p_malloced = 0; -+ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); - - - int olderr = errno; -@@ -384,22 +416,21 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, - if ((ctx->resp->options & RES_NOAAAA) == 0) - { - n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, -- host_buffer.buf->buf, 2048, &host_buffer.ptr, -- &ans2p, &nans2p, &resplen2, &ans2p_malloced); -+ dns_packet_buffer, sizeof (dns_packet_buffer), -+ &alt_dns_packet_buffer, &ans2p, &nans2p, -+ &resplen2, &ans2p_malloced); - if (n >= 0) -- status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p, -- resplen2, name, pat, buffer, buflen, -- errnop, herrnop, ttlp); -+ status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2, -+ &abuf, pat, errnop, herrnop, ttlp); - } - else - { - n = __res_context_search (ctx, name, C_IN, T_A, -- host_buffer.buf->buf, 2048, NULL, -- NULL, NULL, NULL, NULL); -+ dns_packet_buffer, sizeof (dns_packet_buffer), -+ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); - if (n >= 0) -- status = gaih_getanswer_noaaaa (host_buffer.buf, n, -- name, pat, buffer, buflen, -- errnop, herrnop, ttlp); -+ status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n, -+ &abuf, pat, errnop, herrnop, ttlp); - } - if (n < 0) - { -@@ -430,12 +461,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, - __set_errno (olderr); - } - -+ /* Implement the buffer resizing protocol. */ -+ if (alloc_buffer_has_failed (&abuf)) -+ { -+ *errnop = ERANGE; -+ *herrnop = NETDB_INTERNAL; -+ status = NSS_STATUS_TRYAGAIN; -+ } -+ - /* Check whether ans2p was separately allocated. */ - if (ans2p_malloced) - free (ans2p); - -- if (host_buffer.buf != orig_host_buffer) -- free (host_buffer.buf); -+ if (alt_dns_packet_buffer != dns_packet_buffer) -+ free (alt_dns_packet_buffer); - - __resolv_context_put (ctx); - return status; -@@ -451,36 +490,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, - static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; - static const u_char v6local[] = { 0,0, 0,1 }; - const u_char *uaddr = (const u_char *)addr; -- struct host_data -- { -- char *aliases[MAX_NR_ALIASES]; -- unsigned char host_addr[16]; /* IPv4 or IPv6 */ -- char *h_addr_ptrs[MAX_NR_ADDRS + 1]; -- char linebuffer[0]; -- } *host_data = (struct host_data *) buffer; -- union -- { -- querybuf *buf; -- u_char *ptr; -- } host_buffer; -- querybuf *orig_host_buffer; - char qbuf[MAXDNAME+1], *qp = NULL; - size_t size; - int n, status; - int olderr = errno; - -- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); -- buffer += pad; -- buflen = buflen > pad ? buflen - pad : 0; -- -- if (__glibc_unlikely (buflen < sizeof (struct host_data))) -- { -- *errnop = ERANGE; -- *h_errnop = NETDB_INTERNAL; -- return NSS_STATUS_TRYAGAIN; -- } -- -- host_data = (struct host_data *) buffer; -+ /* Prepare the allocation buffer. Store the pointer array first, to -+ benefit from buffer alignment. */ -+ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); -+ char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2); -+ if (address_array == NULL) -+ { -+ *errnop = ERANGE; -+ *h_errnop = NETDB_INTERNAL; -+ return NSS_STATUS_TRYAGAIN; -+ } - - struct resolv_context *ctx = __resolv_context_get (); - if (ctx == NULL) -@@ -524,8 +548,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, - return NSS_STATUS_UNAVAIL; - } - -- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); -- - switch (af) - { - case AF_INET: -@@ -549,36 +571,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, - break; - } - -- n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf, -- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); -+ unsigned char dns_packet_buffer[1024]; -+ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; -+ n = __res_context_query (ctx, qbuf, C_IN, T_PTR, -+ dns_packet_buffer, sizeof (dns_packet_buffer), -+ &alt_dns_packet_buffer, -+ NULL, NULL, NULL, NULL); - if (n < 0) - { - *h_errnop = h_errno; - __set_errno (olderr); -- if (host_buffer.buf != orig_host_buffer) -- free (host_buffer.buf); -+ if (alt_dns_packet_buffer != dns_packet_buffer) -+ free (alt_dns_packet_buffer); - __resolv_context_put (ctx); - return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; - } - -- status = getanswer_r -- (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen, -- errnop, h_errnop, 0 /* XXX */, ttlp, NULL); -- if (host_buffer.buf != orig_host_buffer) -- free (host_buffer.buf); -+ status = getanswer_ptr (alt_dns_packet_buffer, n, -+ &abuf, &result->h_name, errnop, h_errnop, ttlp); -+ -+ if (alt_dns_packet_buffer != dns_packet_buffer) -+ free (alt_dns_packet_buffer); -+ __resolv_context_put (ctx); -+ - if (status != NSS_STATUS_SUCCESS) -- { -- __resolv_context_put (ctx); -- return status; -- } -+ return status; - -+ /* result->h_name has already been set by getanswer_ptr. */ - result->h_addrtype = af; - result->h_length = len; -- memcpy (host_data->host_addr, addr, len); -- host_data->h_addr_ptrs[0] = (char *) host_data->host_addr; -- host_data->h_addr_ptrs[1] = NULL; -+ /* Increase the alignment to 4, in case there are applications out -+ there that expect at least this level of address alignment. */ -+ address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t); -+ alloc_buffer_copy_bytes (&abuf, uaddr, len); -+ address_array[1] = NULL; -+ -+ /* This check also covers allocation failure in getanswer_ptr. */ -+ if (alloc_buffer_has_failed (&abuf)) -+ { -+ *errnop = ERANGE; -+ *h_errnop = NETDB_INTERNAL; -+ return NSS_STATUS_TRYAGAIN; -+ } -+ result->h_addr_list = address_array; -+ result->h_aliases = &address_array[1]; /* Points to NULL. */ -+ - *h_errnop = NETDB_SUCCESS; -- __resolv_context_put (ctx); - return NSS_STATUS_SUCCESS; - } - libc_hidden_def (_nss_dns_gethostbyaddr2_r) -@@ -640,650 +678,362 @@ addrsort (struct resolv_context *ctx, char **ap, int num) - break; - } - --static enum nss_status --getanswer_r (struct resolv_context *ctx, -- const querybuf *answer, int anslen, const char *qname, int qtype, -- struct hostent *result, char *buffer, size_t buflen, -- int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp) -+/* Convert the uncompressed, binary domain name CDNAME into its -+ textual representation and add it to the end of ALIASES, allocating -+ space for a copy of the name from ABUF. Skip adding the name if it -+ is not a valid host name, and return false in that case, otherwise -+ true. */ -+static bool -+getanswer_r_store_alias (const unsigned char *cdname, -+ struct alloc_buffer *abuf, -+ struct ptrlist *aliases) - { -- struct host_data -- { -- char *aliases[MAX_NR_ALIASES]; -- unsigned char host_addr[16]; /* IPv4 or IPv6 */ -- char *h_addr_ptrs[0]; -- } *host_data; -- int linebuflen; -- const HEADER *hp; -- const u_char *end_of_message, *cp; -- int n, ancount, qdcount; -- int haveanswer, had_error; -- char *bp, **ap, **hap; -- char tbuf[MAXDNAME]; -- const char *tname; -- int (*name_ok) (const char *); -- u_char packtmp[NS_MAXCDNAME]; -- int have_to_map = 0; -- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); -- buffer += pad; -- buflen = buflen > pad ? buflen - pad : 0; -- if (__glibc_unlikely (buflen < sizeof (struct host_data))) -- { -- /* The buffer is too small. */ -- too_small: -- *errnop = ERANGE; -- *h_errnop = NETDB_INTERNAL; -- return NSS_STATUS_TRYAGAIN; -- } -- host_data = (struct host_data *) buffer; -- linebuflen = buflen - sizeof (struct host_data); -- if (buflen - sizeof (struct host_data) != linebuflen) -- linebuflen = INT_MAX; -- -- tname = qname; -- result->h_name = NULL; -- end_of_message = answer->buf + anslen; -- switch (qtype) -- { -- case T_A: -- case T_AAAA: -- name_ok = __libc_res_hnok; -- break; -- case T_PTR: -- name_ok = __libc_res_dnok; -- break; -- default: -- *errnop = ENOENT; -- return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */ -- } -+ /* Filter out domain names that are not host names. */ -+ if (!__res_binary_hnok (cdname)) -+ return false; -+ -+ /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks -+ for length. */ -+ char dname[MAXHOSTNAMELEN + 1]; -+ if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0) -+ return false; -+ /* Do not report an error on allocation failure, instead store NULL -+ or do nothing. getanswer_r's caller will see NSS_STATUS_SUCCESS -+ and detect the memory allocation failure or buffer space -+ exhaustion, and report it accordingly. */ -+ ptrlist_add (aliases, alloc_buffer_copy_string (abuf, dname)); -+ return true; -+} - -- /* -- * find first satisfactory answer -- */ -- hp = &answer->hdr; -- ancount = ntohs (hp->ancount); -- qdcount = ntohs (hp->qdcount); -- cp = answer->buf + HFIXEDSZ; -- if (__glibc_unlikely (qdcount != 1)) -+static enum nss_status __attribute__ ((noinline)) -+getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype, -+ struct alloc_buffer *abuf, -+ struct ptrlist *addresses, struct ptrlist *aliases, -+ int *errnop, int *h_errnop, int32_t *ttlp) -+{ -+ struct ns_rr_cursor c; -+ if (!__ns_rr_cursor_init (&c, packet, packetlen)) - { -+ /* This should not happen because __res_context_query already -+ perfroms response validation. */ - *h_errnop = NO_RECOVERY; - return NSS_STATUS_UNAVAIL; - } -- if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen) -- goto too_small; -- bp = (char *) &host_data->h_addr_ptrs[ancount + 1]; -- linebuflen -= (ancount + 1) * sizeof (char *); -- -- n = __ns_name_unpack (answer->buf, end_of_message, cp, -- packtmp, sizeof packtmp); -- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) -- { -- if (__glibc_unlikely (errno == EMSGSIZE)) -- goto too_small; - -- n = -1; -- } -- -- if (__glibc_unlikely (n < 0)) -+ /* Treat the QNAME just like an alias. Error out if it is not a -+ valid host name. */ -+ if (ns_rr_cursor_rcode (&c) == NXDOMAIN -+ || !getanswer_r_store_alias (ns_rr_cursor_qname (&c), abuf, aliases)) - { -- *errnop = errno; -- *h_errnop = NO_RECOVERY; -- return NSS_STATUS_UNAVAIL; -- } -- if (__glibc_unlikely (name_ok (bp) == 0)) -- { -- errno = EBADMSG; -- *errnop = EBADMSG; -- *h_errnop = NO_RECOVERY; -- return NSS_STATUS_UNAVAIL; -+ if (ttlp != NULL) -+ /* No negative caching. */ -+ *ttlp = 0; -+ *h_errnop = HOST_NOT_FOUND; -+ *errnop = ENOENT; -+ return NSS_STATUS_NOTFOUND; - } -- cp += n + QFIXEDSZ; - -- if (qtype == T_A || qtype == T_AAAA) -+ int ancount = ns_rr_cursor_ancount (&c); -+ const unsigned char *expected_name = ns_rr_cursor_qname (&c); -+ /* expected_name may be updated to point into this buffer. */ -+ unsigned char name_buffer[NS_MAXCDNAME]; -+ -+ for (; ancount > 0; --ancount) - { -- /* res_send() has already verified that the query name is the -- * same as the one we sent; this just gets the expanded name -- * (i.e., with the succeeding search-domain tacked on). -- */ -- n = strlen (bp) + 1; /* for the \0 */ -- if (n >= MAXHOSTNAMELEN) -+ struct ns_rr_wire rr; -+ if (!__ns_rr_cursor_next (&c, &rr)) - { - *h_errnop = NO_RECOVERY; -- *errnop = ENOENT; -- return NSS_STATUS_TRYAGAIN; -+ return NSS_STATUS_UNAVAIL; - } -- result->h_name = bp; -- bp += n; -- linebuflen -= n; -- if (linebuflen < 0) -- goto too_small; -- /* The qname can be abbreviated, but h_name is now absolute. */ -- qname = result->h_name; -- } - -- ap = host_data->aliases; -- *ap = NULL; -- result->h_aliases = host_data->aliases; -- hap = host_data->h_addr_ptrs; -- *hap = NULL; -- result->h_addr_list = host_data->h_addr_ptrs; -- haveanswer = 0; -- had_error = 0; -+ /* Skip over records with the wrong class. */ -+ if (rr.rclass != C_IN) -+ continue; - -- while (ancount-- > 0 && cp < end_of_message && had_error == 0) -- { -- int type, class; -+ /* Update TTL for recognized record types. */ -+ if ((rr.rtype == T_CNAME || rr.rtype == qtype) -+ && ttlp != NULL && *ttlp > rr.ttl) -+ *ttlp = rr.ttl; - -- n = __ns_name_unpack (answer->buf, end_of_message, cp, -- packtmp, sizeof packtmp); -- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) -+ if (rr.rtype == T_CNAME) - { -- if (__glibc_unlikely (errno == EMSGSIZE)) -- goto too_small; -- -- n = -1; -+ /* NB: No check for owner name match, based on historic -+ precedent. Record the CNAME target as the new expected -+ name. */ -+ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, -+ name_buffer, sizeof (name_buffer)); -+ if (n < 0) -+ { -+ *h_errnop = NO_RECOVERY; -+ return NSS_STATUS_UNAVAIL; -+ } -+ /* And store the new name as an alias. */ -+ getanswer_r_store_alias (name_buffer, abuf, aliases); -+ expected_name = name_buffer; - } -- -- if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0)) -+ else if (rr.rtype == qtype -+ && __ns_samebinaryname (rr.rname, expected_name) -+ && rr.rdlength == rrtype_to_rdata_length (qtype)) - { -- ++had_error; -- continue; -+ /* Make a copy of the address and store it. Increase the -+ alignment to 4, in case there are applications out there -+ that expect at least this level of address alignment. */ -+ ptrlist_add (addresses, (char *) alloc_buffer_next (abuf, uint32_t)); -+ alloc_buffer_copy_bytes (abuf, rr.rdata, rr.rdlength); - } -- cp += n; /* name */ -+ } - -- if (__glibc_unlikely (cp + 10 > end_of_message)) -- { -- ++had_error; -- continue; -- } -+ if (ptrlist_size (addresses) == 0) -+ { -+ /* No address record found. */ -+ if (ttlp != NULL) -+ /* No caching of negative responses. */ -+ *ttlp = 0; - -- NS_GET16 (type, cp); -- NS_GET16 (class, cp); -- int32_t ttl; -- NS_GET32 (ttl, cp); -- NS_GET16 (n, cp); /* RDATA length. */ -+ *h_errnop = NO_RECOVERY; -+ *errnop = ENOENT; -+ return NSS_STATUS_TRYAGAIN; -+ } -+ else -+ { -+ *h_errnop = NETDB_SUCCESS; -+ return NSS_STATUS_SUCCESS; -+ } -+} - -- if (end_of_message - cp < n) -- { -- /* RDATA extends beyond the end of the packet. */ -- ++had_error; -- continue; -- } -+static enum nss_status -+getanswer_ptr (unsigned char *packet, size_t packetlen, -+ struct alloc_buffer *abuf, char **hnamep, -+ int *errnop, int *h_errnop, int32_t *ttlp) -+{ -+ struct ns_rr_cursor c; -+ if (!__ns_rr_cursor_init (&c, packet, packetlen)) -+ { -+ /* This should not happen because __res_context_query already -+ perfroms response validation. */ -+ *h_errnop = NO_RECOVERY; -+ return NSS_STATUS_UNAVAIL; -+ } -+ int ancount = ns_rr_cursor_ancount (&c); -+ const unsigned char *expected_name = ns_rr_cursor_qname (&c); -+ /* expected_name may be updated to point into this buffer. */ -+ unsigned char name_buffer[NS_MAXCDNAME]; - -- if (__glibc_unlikely (class != C_IN)) -+ while (ancount > 0) -+ { -+ struct ns_rr_wire rr; -+ if (!__ns_rr_cursor_next (&c, &rr)) - { -- /* XXX - debug? syslog? */ -- cp += n; -- continue; /* XXX - had_error++ ? */ -+ *h_errnop = NO_RECOVERY; -+ return NSS_STATUS_UNAVAIL; - } - -- if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) -- { -- /* A CNAME could also have a TTL entry. */ -- if (ttlp != NULL && ttl < *ttlp) -- *ttlp = ttl; -- -- if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1]) -- continue; -- n = __libc_dn_expand (answer->buf, end_of_message, cp, -- tbuf, sizeof tbuf); -- if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0)) -- { -- ++had_error; -- continue; -- } -- cp += n; -- /* Store alias. */ -- *ap++ = bp; -- n = strlen (bp) + 1; /* For the \0. */ -- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) -- { -- ++had_error; -- continue; -- } -- bp += n; -- linebuflen -= n; -- /* Get canonical name. */ -- n = strlen (tbuf) + 1; /* For the \0. */ -- if (__glibc_unlikely (n > linebuflen)) -- goto too_small; -- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) -- { -- ++had_error; -- continue; -- } -- result->h_name = bp; -- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ -- linebuflen -= n; -- continue; -- } -+ /* Skip over records with the wrong class. */ -+ if (rr.rclass != C_IN) -+ continue; - -- if (qtype == T_PTR && type == T_CNAME) -- { -- /* A CNAME could also have a TTL entry. */ -- if (ttlp != NULL && ttl < *ttlp) -- *ttlp = ttl; -+ /* Update TTL for known record types. */ -+ if ((rr.rtype == T_CNAME || rr.rtype == T_PTR) -+ && ttlp != NULL && *ttlp > rr.ttl) -+ *ttlp = rr.ttl; - -- n = __libc_dn_expand (answer->buf, end_of_message, cp, -- tbuf, sizeof tbuf); -- if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0)) -- { -- ++had_error; -- continue; -- } -- cp += n; -- /* Get canonical name. */ -- n = strlen (tbuf) + 1; /* For the \0. */ -- if (__glibc_unlikely (n > linebuflen)) -- goto too_small; -- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) -+ if (rr.rtype == T_CNAME) -+ { -+ /* NB: No check for owner name match, based on historic -+ precedent. Record the CNAME target as the new expected -+ name. */ -+ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, -+ name_buffer, sizeof (name_buffer)); -+ if (n < 0) - { -- ++had_error; -- continue; -+ *h_errnop = NO_RECOVERY; -+ return NSS_STATUS_UNAVAIL; - } -- tname = bp; -- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ -- linebuflen -= n; -- continue; -+ expected_name = name_buffer; - } -- -- if (type == T_A && qtype == T_AAAA && map) -- have_to_map = 1; -- else if (__glibc_unlikely (type != qtype)) -+ else if (rr.rtype == T_PTR -+ && __ns_samebinaryname (rr.rname, expected_name)) - { -- cp += n; -- continue; /* XXX - had_error++ ? */ -- } -- -- switch (type) -- { -- case T_PTR: -- if (__glibc_unlikely (__strcasecmp (tname, bp) != 0)) -+ /* Decompress the target of the PTR record. This is the -+ host name we are looking for. We can only use it if it -+ is syntactically valid. Historically, only one host name -+ is returned here. If the recursive resolver performs DNS -+ record rotation, the returned host name is essentially -+ random, which is why multiple PTR records are rarely -+ used. Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for -+ additional length checking. */ -+ char hname[MAXHOSTNAMELEN + 1]; -+ if (__ns_name_unpack (c.begin, c.end, rr.rdata, -+ name_buffer, sizeof (name_buffer)) < 0 -+ || !__res_binary_hnok (expected_name) -+ || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0) - { -- cp += n; -- continue; /* XXX - had_error++ ? */ -+ *h_errnop = NO_RECOVERY; -+ return NSS_STATUS_UNAVAIL; - } -- -- n = __ns_name_unpack (answer->buf, end_of_message, cp, -- packtmp, sizeof packtmp); -- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) -- { -- if (__glibc_unlikely (errno == EMSGSIZE)) -- goto too_small; -- -- n = -1; -- } -- -- if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0)) -- { -- ++had_error; -- break; -- } -- if (ttlp != NULL && ttl < *ttlp) -- *ttlp = ttl; -- /* bind would put multiple PTR records as aliases, but we don't do -- that. */ -- result->h_name = bp; -- *h_errnop = NETDB_SUCCESS; -+ /* Successful allocation is checked by the caller. */ -+ *hnamep = alloc_buffer_copy_string (abuf, hname); - return NSS_STATUS_SUCCESS; -- case T_A: -- case T_AAAA: -- if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0)) -- { -- cp += n; -- continue; /* XXX - had_error++ ? */ -- } -- -- /* Stop parsing at a record whose length is incorrect. */ -- if (n != rrtype_to_rdata_length (type)) -- { -- ++had_error; -- break; -- } -- -- /* Skip records of the wrong type. */ -- if (n != result->h_length) -- { -- cp += n; -- continue; -- } -- if (!haveanswer) -- { -- int nn; -- -- /* We compose a single hostent out of the entire chain of -- entries, so the TTL of the hostent is essentially the lowest -- TTL in the chain. */ -- if (ttlp != NULL && ttl < *ttlp) -- *ttlp = ttl; -- if (canonp != NULL) -- *canonp = bp; -- result->h_name = bp; -- nn = strlen (bp) + 1; /* for the \0 */ -- bp += nn; -- linebuflen -= nn; -- } -- -- /* Provide sufficient alignment for both address -- families. */ -- enum { align = 4 }; -- _Static_assert ((align % __alignof__ (struct in_addr)) == 0, -- "struct in_addr alignment"); -- _Static_assert ((align % __alignof__ (struct in6_addr)) == 0, -- "struct in6_addr alignment"); -- { -- char *new_bp = PTR_ALIGN_UP (bp, align); -- linebuflen -= new_bp - bp; -- bp = new_bp; -- } -- -- if (__glibc_unlikely (n > linebuflen)) -- goto too_small; -- bp = __mempcpy (*hap++ = bp, cp, n); -- cp += n; -- linebuflen -= n; -- break; -- default: -- abort (); - } -- if (had_error == 0) -- ++haveanswer; - } - -- if (haveanswer > 0) -- { -- *ap = NULL; -- *hap = NULL; -- /* -- * Note: we sort even if host can take only one address -- * in its return structures - should give it the "best" -- * address in that case, not some random one -- */ -- if (haveanswer > 1 && qtype == T_A -- && __resolv_context_sort_count (ctx) > 0) -- addrsort (ctx, host_data->h_addr_ptrs, haveanswer); -- -- if (result->h_name == NULL) -- { -- n = strlen (qname) + 1; /* For the \0. */ -- if (n > linebuflen) -- goto too_small; -- if (n >= MAXHOSTNAMELEN) -- goto no_recovery; -- result->h_name = bp; -- bp = __mempcpy (bp, qname, n); /* Cannot overflow. */ -- linebuflen -= n; -- } -+ /* No PTR record found. */ -+ if (ttlp != NULL) -+ /* No caching of negative responses. */ -+ *ttlp = 0; - -- if (have_to_map) -- if (map_v4v6_hostent (result, &bp, &linebuflen)) -- goto too_small; -- *h_errnop = NETDB_SUCCESS; -- return NSS_STATUS_SUCCESS; -- } -- no_recovery: - *h_errnop = NO_RECOVERY; - *errnop = ENOENT; -- /* Special case here: if the resolver sent a result but it only -- contains a CNAME while we are looking for a T_A or T_AAAA record, -- we fail with NOTFOUND instead of TRYAGAIN. */ -- return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases -- ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN); -+ return NSS_STATUS_TRYAGAIN; - } - -- -+/* Parses DNS data found in PACKETLEN bytes at PACKET in struct -+ gaih_addrtuple address tuples. The new address tuples are linked -+ from **TAILP, with backing store allocated from ABUF, and *TAILP is -+ updated to point where the next tuple pointer should be stored. If -+ TTLP is not null, *TTLP is updated to reflect the minimum TTL. If -+ STORE_CANON is true, the canonical name is stored as part of the -+ first address tuple being written. */ - static enum nss_status --gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, -- struct gaih_addrtuple ***patp, -- char **bufferp, size_t *buflenp, -- int *errnop, int *h_errnop, int32_t *ttlp, int *firstp) -+gaih_getanswer_slice (unsigned char *packet, size_t packetlen, -+ struct alloc_buffer *abuf, -+ struct gaih_addrtuple ***tailp, -+ int *errnop, int *h_errnop, int32_t *ttlp, -+ bool store_canon) - { -- char *buffer = *bufferp; -- size_t buflen = *buflenp; -- -- struct gaih_addrtuple **pat = *patp; -- const HEADER *hp = &answer->hdr; -- int ancount = ntohs (hp->ancount); -- int qdcount = ntohs (hp->qdcount); -- const u_char *cp = answer->buf + HFIXEDSZ; -- const u_char *end_of_message = answer->buf + anslen; -- if (__glibc_unlikely (qdcount != 1)) -- { -- *h_errnop = NO_RECOVERY; -- return NSS_STATUS_UNAVAIL; -- } -- -- u_char packtmp[NS_MAXCDNAME]; -- int n = __ns_name_unpack (answer->buf, end_of_message, cp, -- packtmp, sizeof packtmp); -- /* We unpack the name to check it for validity. But we do not need -- it later. */ -- if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1) -- { -- if (__glibc_unlikely (errno == EMSGSIZE)) -- { -- too_small: -- *errnop = ERANGE; -- *h_errnop = NETDB_INTERNAL; -- return NSS_STATUS_TRYAGAIN; -- } -- -- n = -1; -- } -- -- if (__glibc_unlikely (n < 0)) -+ struct ns_rr_cursor c; -+ if (!__ns_rr_cursor_init (&c, packet, packetlen)) - { -- *errnop = errno; -+ /* This should not happen because __res_context_query already -+ perfroms response validation. */ - *h_errnop = NO_RECOVERY; - return NSS_STATUS_UNAVAIL; - } -- if (__glibc_unlikely (__libc_res_hnok (buffer) == 0)) -- { -- errno = EBADMSG; -- *errnop = EBADMSG; -- *h_errnop = NO_RECOVERY; -- return NSS_STATUS_UNAVAIL; -- } -- cp += n + QFIXEDSZ; -- -- int haveanswer = 0; -- int had_error = 0; -- char *canon = NULL; -- char *h_name = NULL; -- int h_namelen = 0; -- -- if (ancount == 0) -+ bool haveanswer = false; /* Set to true if at least one address. */ -+ uint16_t qtype = ns_rr_cursor_qtype (&c); -+ int ancount = ns_rr_cursor_ancount (&c); -+ const unsigned char *expected_name = ns_rr_cursor_qname (&c); -+ /* expected_name may be updated to point into this buffer. */ -+ unsigned char name_buffer[NS_MAXCDNAME]; -+ -+ /* This is a pointer to a possibly-compressed name in the packet. -+ Eventually it is equivalent to the canonical name. If needed, it -+ is uncompressed and translated to text form when the first -+ address tuple is encountered. */ -+ const unsigned char *compressed_alias_name = expected_name; -+ -+ if (ancount == 0 || !__res_binary_hnok (compressed_alias_name)) - { - *h_errnop = HOST_NOT_FOUND; - return NSS_STATUS_NOTFOUND; - } - -- while (ancount-- > 0 && cp < end_of_message && had_error == 0) -+ for (; ancount > -0; --ancount) - { -- n = __ns_name_unpack (answer->buf, end_of_message, cp, -- packtmp, sizeof packtmp); -- if (n != -1 && -- (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1) -+ struct ns_rr_wire rr; -+ if (!__ns_rr_cursor_next (&c, &rr)) - { -- if (__glibc_unlikely (errno == EMSGSIZE)) -- goto too_small; -- -- n = -1; -- } -- if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0)) -- { -- ++had_error; -- continue; -- } -- if (*firstp && canon == NULL) -- { -- h_name = buffer; -- buffer += h_namelen; -- buflen -= h_namelen; -- } -- -- cp += n; /* name */ -- -- if (__glibc_unlikely (cp + 10 > end_of_message)) -- { -- ++had_error; -- continue; -+ *h_errnop = NO_RECOVERY; -+ return NSS_STATUS_UNAVAIL; - } - -- uint16_t type; -- NS_GET16 (type, cp); -- uint16_t class; -- NS_GET16 (class, cp); -- int32_t ttl; -- NS_GET32 (ttl, cp); -- NS_GET16 (n, cp); /* RDATA length. */ -+ /* Update TTL for known record types. */ -+ if ((rr.rtype == T_CNAME || rr.rtype == qtype) -+ && ttlp != NULL && *ttlp > rr.ttl) -+ *ttlp = rr.ttl; - -- if (end_of_message - cp < n) -+ if (rr.rtype == T_CNAME) - { -- /* RDATA extends beyond the end of the packet. */ -- ++had_error; -- continue; -- } -- -- if (class != C_IN) -- { -- cp += n; -- continue; -- } -- -- if (type == T_CNAME) -- { -- char tbuf[MAXDNAME]; -- -- /* A CNAME could also have a TTL entry. */ -- if (ttlp != NULL && ttl < *ttlp) -- *ttlp = ttl; -- -- n = __libc_dn_expand (answer->buf, end_of_message, cp, -- tbuf, sizeof tbuf); -- if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0)) -+ /* NB: No check for owner name match, based on historic -+ precedent. Record the CNAME target as the new expected -+ name. */ -+ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, -+ name_buffer, sizeof (name_buffer)); -+ if (n < 0) - { -- ++had_error; -- continue; -- } -- cp += n; -- -- if (*firstp) -- { -- /* Reclaim buffer space. */ -- if (h_name + h_namelen == buffer) -- { -- buffer = h_name; -- buflen += h_namelen; -- } -- -- n = strlen (tbuf) + 1; -- if (__glibc_unlikely (n > buflen)) -- goto too_small; -- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) -- { -- ++had_error; -- continue; -- } -- -- canon = buffer; -- buffer = __mempcpy (buffer, tbuf, n); -- buflen -= n; -- h_namelen = 0; -+ *h_errnop = NO_RECOVERY; -+ return NSS_STATUS_UNAVAIL; - } -- continue; -+ expected_name = name_buffer; -+ if (store_canon && __res_binary_hnok (name_buffer)) -+ /* This name can be used as a canonical name. Do not -+ translate to text form here to conserve buffer space. -+ Point to the compressed name because name_buffer can be -+ overwritten with an unusable name later. */ -+ compressed_alias_name = rr.rdata; - } -- -- /* Stop parsing if we encounter a record with incorrect RDATA -- length. */ -- if (type == T_A || type == T_AAAA) -+ else if (rr.rtype == qtype -+ && __ns_samebinaryname (rr.rname, expected_name) -+ && rr.rdlength == rrtype_to_rdata_length (qtype)) - { -- if (n != rrtype_to_rdata_length (type)) -+ struct gaih_addrtuple *ntup -+ = alloc_buffer_alloc (abuf, struct gaih_addrtuple); -+ /* Delay error reporting to the callers (they implement the -+ ERANGE buffer resizing handshake). */ -+ if (ntup != NULL) - { -- ++had_error; -- continue; -+ ntup->next = NULL; -+ if (store_canon && compressed_alias_name != NULL) -+ { -+ /* This assumes that all the CNAME records come -+ first. Use MAXHOSTNAMELEN instead of -+ NS_MAXCDNAME for additional length checking. -+ However, these checks are not expected to fail -+ because all size NS_MAXCDNAME names should into -+ the hname buffer because no escaping is -+ needed. */ -+ char unsigned nbuf[NS_MAXCDNAME]; -+ char hname[MAXHOSTNAMELEN + 1]; -+ if (__ns_name_unpack (c.begin, c.end, -+ compressed_alias_name, -+ nbuf, sizeof (nbuf)) >= 0 -+ && __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0) -+ /* Space checking is performed by the callers. */ -+ ntup->name = alloc_buffer_copy_string (abuf, hname); -+ store_canon = false; -+ } -+ else -+ ntup->name = NULL; -+ if (rr.rdlength == 4) -+ ntup->family = AF_INET; -+ else -+ ntup->family = AF_INET6; -+ memcpy (ntup->addr, rr.rdata, rr.rdlength); -+ ntup->scopeid = 0; -+ -+ /* Link in the new tuple, and update the tail pointer to -+ point to its next field. */ -+ **tailp = ntup; -+ *tailp = &ntup->next; -+ -+ haveanswer = true; - } - } -- else -- { -- /* Skip unknown records. */ -- cp += n; -- continue; -- } -- -- assert (type == T_A || type == T_AAAA); -- if (*pat == NULL) -- { -- uintptr_t pad = (-(uintptr_t) buffer -- % __alignof__ (struct gaih_addrtuple)); -- buffer += pad; -- buflen = buflen > pad ? buflen - pad : 0; -- -- if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple))) -- goto too_small; -- -- *pat = (struct gaih_addrtuple *) buffer; -- buffer += sizeof (struct gaih_addrtuple); -- buflen -= sizeof (struct gaih_addrtuple); -- } -- -- (*pat)->name = NULL; -- (*pat)->next = NULL; -- -- if (*firstp) -- { -- /* We compose a single hostent out of the entire chain of -- entries, so the TTL of the hostent is essentially the lowest -- TTL in the chain. */ -- if (ttlp != NULL && ttl < *ttlp) -- *ttlp = ttl; -- -- (*pat)->name = canon ?: h_name; -- -- *firstp = 0; -- } -- -- (*pat)->family = type == T_A ? AF_INET : AF_INET6; -- memcpy ((*pat)->addr, cp, n); -- cp += n; -- (*pat)->scopeid = 0; -- -- pat = &((*pat)->next); -- -- haveanswer = 1; - } - - if (haveanswer) - { -- *patp = pat; -- *bufferp = buffer; -- *buflenp = buflen; -- - *h_errnop = NETDB_SUCCESS; - return NSS_STATUS_SUCCESS; - } -- -- /* Special case here: if the resolver sent a result but it only -- contains a CNAME while we are looking for a T_A or T_AAAA record, -- we fail with NOTFOUND instead of TRYAGAIN. */ -- if (canon != NULL) -+ else - { -+ /* Special case here: if the resolver sent a result but it only -+ contains a CNAME while we are looking for a T_A or T_AAAA -+ record, we fail with NOTFOUND. */ - *h_errnop = HOST_NOT_FOUND; - return NSS_STATUS_NOTFOUND; - } -- -- *h_errnop = NETDB_INTERNAL; -- return NSS_STATUS_TRYAGAIN; - } - - - static enum nss_status --gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, -- int anslen2, const char *qname, -- struct gaih_addrtuple **pat, char *buffer, size_t buflen, -+gaih_getanswer (unsigned char *packet1, size_t packet1len, -+ unsigned char *packet2, size_t packet2len, -+ struct alloc_buffer *abuf, struct gaih_addrtuple **pat, - int *errnop, int *h_errnop, int32_t *ttlp) - { -- int first = 1; -- - enum nss_status status = NSS_STATUS_NOTFOUND; - - /* Combining the NSS status of two distinct queries requires some -@@ -1295,7 +1045,10 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, - between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable). - A recoverable TRYAGAIN is almost always due to buffer size issues - and returns ERANGE in errno and the caller is expected to retry -- with a larger buffer. -+ with a larger buffer. (The caller, _nss_dns_gethostbyname4_r, -+ ignores the return status if it detects that the result buffer -+ has been exhausted and generates a TRYAGAIN failure with an -+ ERANGE code.) - - Lastly, you may be tempted to make significant changes to the - conditions in this code to bring about symmetry between responses. -@@ -1375,36 +1128,30 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, - is a recoverable error we now return TRYAGIN even if the first - response was SUCCESS. */ - -- if (anslen1 > 0) -- status = gaih_getanswer_slice(answer1, anslen1, qname, -- &pat, &buffer, &buflen, -- errnop, h_errnop, ttlp, -- &first); -- -- if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND -- || (status == NSS_STATUS_TRYAGAIN -- /* We want to look at the second answer in case of an -- NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e. -- *h_errnop is NO_RECOVERY. If not, and if the failure was due to -- an insufficient buffer (ERANGE), then we need to drop the results -- and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can -- repeat the query with a larger buffer. */ -- && (*errnop != ERANGE || *h_errnop == NO_RECOVERY))) -- && answer2 != NULL && anslen2 > 0) -+ if (packet1len > 0) - { -- enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname, -- &pat, &buffer, &buflen, -- errnop, h_errnop, ttlp, -- &first); -+ status = gaih_getanswer_slice (packet1, packet1len, -+ abuf, &pat, errnop, h_errnop, ttlp, true); -+ if (alloc_buffer_has_failed (abuf)) -+ /* Do not try parsing the second packet if a larger result -+ buffer is needed. The caller implements the resizing -+ protocol because *abuf has been exhausted. */ -+ return NSS_STATUS_TRYAGAIN; /* Ignored by the caller. */ -+ } -+ -+ if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND) -+ && packet2 != NULL && packet2len > 0) -+ { -+ enum nss_status status2 -+ = gaih_getanswer_slice (packet2, packet2len, -+ abuf, &pat, errnop, h_errnop, ttlp, -+ /* Success means that data with a -+ canonical name has already been -+ stored. Do not store the name again. */ -+ status != NSS_STATUS_SUCCESS); - /* Use the second response status in some cases. */ - if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND) - status = status2; -- /* Do not return a truncated second response (unless it was -- unavoidable e.g. unrecoverable TRYAGAIN). */ -- if (status == NSS_STATUS_SUCCESS -- && (status2 == NSS_STATUS_TRYAGAIN -- && *errnop == ERANGE && *h_errnop != NO_RECOVERY)) -- status = NSS_STATUS_TRYAGAIN; - } - - return status; -@@ -1412,18 +1159,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, - - /* Variant of gaih_getanswer without a second (AAAA) response. */ - static enum nss_status --gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname, -- struct gaih_addrtuple **pat, -- char *buffer, size_t buflen, -+gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen, -+ struct alloc_buffer *abuf, struct gaih_addrtuple **pat, - int *errnop, int *h_errnop, int32_t *ttlp) - { -- int first = 1; -- - enum nss_status status = NSS_STATUS_NOTFOUND; -- if (anslen1 > 0) -- status = gaih_getanswer_slice (answer1, anslen1, qname, -- &pat, &buffer, &buflen, -- errnop, h_errnop, ttlp, -- &first); -+ if (packetlen > 0) -+ status = gaih_getanswer_slice (packet, packetlen, -+ abuf, &pat, errnop, h_errnop, ttlp, true); - return status; - } -diff --git a/resolv/res-name-checking.c b/resolv/res-name-checking.c -index 07a412d8ff..213edceaf3 100644 ---- a/resolv/res-name-checking.c -+++ b/resolv/res-name-checking.c -@@ -138,6 +138,12 @@ binary_leading_dash (const unsigned char *dn) - return dn[0] > 0 && dn[1] == '-'; - } - -+bool -+__res_binary_hnok (const unsigned char *dn) -+{ -+ return !binary_leading_dash (dn) && binary_hnok (dn); -+} -+ - /* Return 1 if res_hnok is a valid host name. Labels must only - contain [0-9a-zA-Z_-] characters, and the name must not start with - a '-'. The latter is to avoid confusion with program options. */ -@@ -145,11 +151,9 @@ int - ___res_hnok (const char *dn) - { - unsigned char buf[NS_MAXCDNAME]; -- if (!printable_string (dn) -- || __ns_name_pton (dn, buf, sizeof (buf)) < 0 -- || binary_leading_dash (buf)) -- return 0; -- return binary_hnok (buf); -+ return (printable_string (dn) -+ && __ns_name_pton (dn, buf, sizeof (buf)) >= 0 -+ && __res_binary_hnok (buf)); - } - versioned_symbol (libc, ___res_hnok, res_hnok, GLIBC_2_34); - versioned_symbol (libc, ___res_hnok, __libc_res_hnok, GLIBC_PRIVATE); -diff --git a/resolv/tst-ns_name_length_uncompressed.c b/resolv/tst-ns_name_length_uncompressed.c -new file mode 100644 -index 0000000000..c4a2904db7 ---- /dev/null -+++ b/resolv/tst-ns_name_length_uncompressed.c -@@ -0,0 +1,135 @@ -+/* Test __ns_name_length_uncompressed. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Reference implementation based on other building blocks. */ -+static int -+reference_length (const unsigned char *p, const unsigned char *eom) -+{ -+ unsigned char buf[NS_MAXCDNAME]; -+ int n = __ns_name_unpack (p, eom, p, buf, sizeof (buf)); -+ if (n < 0) -+ return n; -+ const unsigned char *q = buf; -+ if (__ns_name_skip (&q, array_end (buf)) < 0) -+ return -1; -+ if (q - buf != n) -+ /* Compressed name. */ -+ return -1; -+ return n; -+} -+ -+static int -+do_test (void) -+{ -+ { -+ unsigned char buf[] = { 3, 'w', 'w', 'w', 0, 0, 0 }; -+ TEST_COMPARE (reference_length (buf, array_end (buf)), sizeof (buf) - 2); -+ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -+ sizeof (buf) - 2); -+ TEST_COMPARE (reference_length (array_end (buf) - 1, array_end (buf)), 1); -+ TEST_COMPARE (__ns_name_length_uncompressed (array_end (buf) - 1, -+ array_end (buf)), 1); -+ buf[4] = 0xc0; /* Forward compression reference. */ -+ buf[5] = 0x06; -+ TEST_COMPARE (reference_length (buf, array_end (buf)), -1); -+ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -1); -+ } -+ -+ struct support_next_to_fault ntf = support_next_to_fault_allocate (300); -+ -+ /* Buffer region with all possible bytes at start and end. */ -+ for (int length = 1; length <= 300; ++length) -+ { -+ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length; -+ unsigned char *start = end - length; -+ memset (start, 'X', length); -+ for (int first = 0; first <= 255; ++first) -+ { -+ *start = first; -+ for (int last = 0; last <= 255; ++last) -+ { -+ start[length - 1] = last; -+ TEST_COMPARE (reference_length (start, end), -+ __ns_name_length_uncompressed (start, end)); -+ } -+ } -+ } -+ -+ /* Poor man's fuzz testing: patch two bytes. */ -+ { -+ unsigned char ref[] = -+ { -+ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, 0, 0 -+ }; -+ TEST_COMPARE (reference_length (ref, array_end (ref)), 13); -+ TEST_COMPARE (__ns_name_length_uncompressed (ref, array_end (ref)), 13); -+ -+ int good = 0; -+ int bad = 0; -+ for (int length = 1; length <= sizeof (ref); ++length) -+ { -+ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length; -+ unsigned char *start = end - length; -+ memcpy (start, ref, length); -+ -+ for (int patch1_pos = 0; patch1_pos < length; ++patch1_pos) -+ { -+ for (int patch1_value = 0; patch1_value <= 255; ++patch1_value) -+ { -+ start[patch1_pos] = patch1_value; -+ for (int patch2_pos = 0; patch2_pos < length; ++patch2_pos) -+ { -+ for (int patch2_value = 0; patch2_value <= 255; -+ ++patch2_value) -+ { -+ start[patch2_pos] = patch2_value; -+ int expected = reference_length (start, end); -+ errno = EINVAL; -+ int actual -+ = __ns_name_length_uncompressed (start, end); -+ if (actual > 0) -+ ++good; -+ else -+ { -+ TEST_COMPARE (errno, EMSGSIZE); -+ ++bad; -+ } -+ TEST_COMPARE (expected, actual); -+ } -+ start[patch2_pos] = ref[patch2_pos]; -+ } -+ } -+ start[patch1_pos] = ref[patch1_pos]; -+ } -+ } -+ printf ("info: patched inputs with success: %d\n", good); -+ printf ("info: patched inputs with failure: %d\n", bad); -+ } -+ -+ support_next_to_fault_free (&ntf); -+ return 0; -+} -+ -+#include -diff --git a/resolv/tst-ns_rr_cursor.c b/resolv/tst-ns_rr_cursor.c -new file mode 100644 -index 0000000000..c3c0908905 ---- /dev/null -+++ b/resolv/tst-ns_rr_cursor.c -@@ -0,0 +1,227 @@ -+/* Tests for resource record parsing. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+ -+/* Reference packet for packet parsing. */ -+static const unsigned char valid_packet[] = -+ { 0x11, 0x12, 0x13, 0x14, -+ 0x00, 0x01, /* Question count. */ -+ 0x00, 0x02, /* Answer count. */ -+ 0x21, 0x22, 0x23, 0x24, /* Other counts (not actually in packet). */ -+ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0, -+ 0x00, 0x1c, /* Question type: AAAA. */ -+ 0x00, 0x01, /* Question class: IN. */ -+ 0xc0, 0x0c, /* Compression reference to QNAME. */ -+ 0x00, 0x1c, /* Record type: AAAA. */ -+ 0x00, 0x01, /* Record class: IN. */ -+ 0x12, 0x34, 0x56, 0x78, /* Record TTL. */ -+ 0x00, 0x10, /* Record data length (16 bytes). */ -+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, -+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* IPv6 address. */ -+ 0xc0, 0x0c, /* Compression reference to QNAME. */ -+ 0x00, 0x1c, /* Record type: AAAA. */ -+ 0x00, 0x01, /* Record class: IN. */ -+ 0x11, 0x33, 0x55, 0x77, /* Record TTL. */ -+ 0x00, 0x10, /* Record data length (16 bytes). */ -+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, -+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* IPv6 address. */ -+ }; -+ -+/* Special offsets in valid_packet. */ -+enum -+ { -+ offset_of_first_record = 29, -+ offset_of_second_record = 57, -+ }; -+ -+/* Check that parsing valid_packet succeeds. */ -+static void -+test_valid (void) -+{ -+ struct ns_rr_cursor c; -+ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, valid_packet, -+ sizeof (valid_packet))); -+ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); -+ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); -+ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); -+ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); -+ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); -+ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); -+ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); -+ TEST_COMPARE (c.current - valid_packet, offset_of_first_record); -+ -+ struct ns_rr_wire r; -+ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); -+ TEST_COMPARE (r.rtype, T_AAAA); -+ TEST_COMPARE (r.rclass, C_IN); -+ TEST_COMPARE (r.ttl, 0x12345678); -+ TEST_COMPARE_BLOB (r.rdata, r.rdlength, -+ "\x90\x91\x92\x93\x94\x95\x96\x97" -+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16); -+ TEST_COMPARE (c.current - valid_packet, offset_of_second_record); -+ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); -+ TEST_COMPARE (r.rtype, T_AAAA); -+ TEST_COMPARE (r.rclass, C_IN); -+ TEST_COMPARE (r.ttl, 0x11335577); -+ TEST_COMPARE_BLOB (r.rdata, r.rdlength, -+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" -+ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 16); -+ TEST_VERIFY (c.current == c.end); -+} -+ -+/* Check that trying to parse a packet with a compressed QNAME fails. */ -+static void -+test_compressed_qname (void) -+{ -+ static const unsigned char packet[] = -+ { 0x11, 0x12, 0x13, 0x14, -+ 0x00, 0x01, /* Question count. */ -+ 0x00, 0x00, /* Answer count. */ -+ 0x00, 0x00, 0x00, 0x00, /* Other counts. */ -+ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, -+ 0x00, 0x01, /* Question type: A. */ -+ 0x00, 0x01, /* Question class: IN. */ -+ }; -+ -+ struct ns_rr_cursor c; -+ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet))); -+} -+ -+/* Check that trying to parse a packet with two questions fails. */ -+static void -+test_two_questions (void) -+{ -+ static const unsigned char packet[] = -+ { 0x11, 0x12, 0x13, 0x14, -+ 0x00, 0x02, /* Question count. */ -+ 0x00, 0x00, /* Answer count. */ -+ 0x00, 0x00, 0x00, 0x00, /* Other counts. */ -+ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, -+ 0x00, 0x01, /* Question type: A. */ -+ 0x00, 0x01, /* Question class: IN. */ -+ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, -+ 0x00, 0x1c, /* Question type: AAAA. */ -+ 0x00, 0x01, /* Question class: IN. */ -+ }; -+ -+ struct ns_rr_cursor c; -+ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet))); -+} -+ -+/* Used to check that parsing truncated packets does not over-read. */ -+static struct support_next_to_fault ntf; -+ -+/* Truncated packet in the second resource record. */ -+static void -+test_truncated_one_rr (size_t length) -+{ -+ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; -+ unsigned char *start = end - length; -+ -+ /* Produce the truncated packet. */ -+ memcpy (start, valid_packet, length); -+ -+ struct ns_rr_cursor c; -+ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length)); -+ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); -+ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); -+ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); -+ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); -+ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); -+ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); -+ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); -+ TEST_COMPARE (c.current - start, offset_of_first_record); -+ -+ struct ns_rr_wire r; -+ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); -+ TEST_COMPARE (r.rtype, T_AAAA); -+ TEST_COMPARE (r.rclass, C_IN); -+ TEST_COMPARE (r.ttl, 0x12345678); -+ TEST_COMPARE_BLOB (r.rdata, r.rdlength, -+ "\x90\x91\x92\x93\x94\x95\x96\x97" -+ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16); -+ TEST_COMPARE (c.current - start, offset_of_second_record); -+ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r)); -+} -+ -+/* Truncated packet in the first resource record. */ -+static void -+test_truncated_no_rr (size_t length) -+{ -+ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; -+ unsigned char *start = end - length; -+ -+ /* Produce the truncated packet. */ -+ memcpy (start, valid_packet, length); -+ -+ struct ns_rr_cursor c; -+ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length)); -+ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); -+ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); -+ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); -+ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); -+ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); -+ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); -+ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); -+ TEST_COMPARE (c.current - start, offset_of_first_record); -+ -+ struct ns_rr_wire r; -+ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r)); -+} -+ -+/* Truncated packet before first resource record. */ -+static void -+test_truncated_before_rr (size_t length) -+{ -+ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; -+ unsigned char *start = end - length; -+ -+ /* Produce the truncated packet. */ -+ memcpy (start, valid_packet, length); -+ -+ struct ns_rr_cursor c; -+ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, start, length)); -+} -+ -+static int -+do_test (void) -+{ -+ ntf = support_next_to_fault_allocate (sizeof (valid_packet)); -+ -+ test_valid (); -+ test_compressed_qname (); -+ test_two_questions (); -+ -+ for (int length = offset_of_second_record; length < sizeof (valid_packet); -+ ++length) -+ test_truncated_one_rr (length); -+ for (int length = offset_of_first_record; length < offset_of_second_record; -+ ++length) -+ test_truncated_no_rr (length); -+ for (int length = 0; length < offset_of_first_record; ++length) -+ test_truncated_before_rr (length); -+ -+ support_next_to_fault_free (&ntf); -+ return 0; -+} -+ -+#include -diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c -new file mode 100644 -index 0000000000..b06ac610b4 ---- /dev/null -+++ b/resolv/tst-ns_samebinaryname.c -@@ -0,0 +1,62 @@ -+/* Test the __ns_samebinaryname function. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+/* First character denotes the comparison group: All names with the -+ same first character are expected to compare equal. */ -+static const char *const cases[] = -+ { -+ " ", -+ "1\001a", "1\001A", -+ "2\002ab", "2\002aB", "2\002Ab", "2\002AB", -+ "3\001a\002ab", "3\001A\002ab", -+ "w\003www\007example\003com", "w\003Www\007Example\003Com", -+ "w\003WWW\007EXAMPLE\003COM", -+ "W\003WWW", "W\003www", -+ }; -+ -+static int -+do_test (void) -+{ -+ for (int i = 0; i < array_length (cases); ++i) -+ for (int j = 0; j < array_length (cases); ++j) -+ { -+ unsigned char *a = (unsigned char *) &cases[i][1]; -+ unsigned char *b = (unsigned char *) &cases[j][1]; -+ bool actual = __ns_samebinaryname (a, b); -+ bool expected = cases[i][0] == cases[j][0]; -+ if (actual != expected) -+ { -+ char a1[NS_MAXDNAME]; -+ TEST_VERIFY (ns_name_ntop (a, a1, sizeof (a1)) > 0); -+ char b1[NS_MAXDNAME]; -+ TEST_VERIFY (ns_name_ntop (b, b1, sizeof (b1)) > 0); -+ printf ("error: \"%s\" \"%s\": expected %s\n", -+ a1, b1, expected ? "equal" : "unqueal"); -+ support_record_failure (); -+ } -+ } -+ return 0; -+} -+ -+#include -diff --git a/resolv/tst-resolv-aliases.c b/resolv/tst-resolv-aliases.c -new file mode 100644 -index 0000000000..b212823aa0 ---- /dev/null -+++ b/resolv/tst-resolv-aliases.c -@@ -0,0 +1,254 @@ -+/* Test alias handling (mainly for gethostbyname). -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tst-resolv-maybe_insert_sig.h" -+ -+/* QNAME format: -+ -+ aADDRESSES-cCNAMES.example.net -+ -+ CNAMES is the length of the CNAME chain, ADDRESSES is the number of -+ addresses in the response. The special value 255 means that there -+ are no addresses, and the RCODE is NXDOMAIN. */ -+static void -+response (const struct resolv_response_context *ctx, -+ struct resolv_response_builder *b, -+ const char *qname, uint16_t qclass, uint16_t qtype) -+{ -+ TEST_COMPARE (qclass, C_IN); -+ if (qtype != T_A) -+ TEST_COMPARE (qtype, T_AAAA); -+ -+ unsigned int addresses, cnames; -+ char *tail; -+ if (sscanf (qname, "a%u-c%u%ms", &addresses, &cnames, &tail) == 3) -+ { -+ if (strcmp (tail, ".example.com") == 0 -+ || strcmp (tail, ".example.net.example.net") == 0 -+ || strcmp (tail, ".example.net.example.com") == 0) -+ /* These only happen after NXDOMAIN. */ -+ TEST_VERIFY (addresses == 255); -+ else if (strcmp (tail, ".example.net") != 0) -+ FAIL_EXIT1 ("invalid QNAME: %s", qname); -+ } -+ free (tail); -+ -+ int rcode; -+ if (addresses == 255) -+ { -+ /* Special case: Use no addresses with NXDOMAIN response. */ -+ rcode = ns_r_nxdomain; -+ addresses = 0; -+ } -+ else -+ rcode = 0; -+ -+ struct resolv_response_flags flags = { .rcode = rcode }; -+ resolv_response_init (b, flags); -+ resolv_response_add_question (b, qname, qclass, qtype); -+ resolv_response_section (b, ns_s_an); -+ maybe_insert_sig (b, qname); -+ -+ /* Provide the requested number of CNAME records. */ -+ char *previous_name = (char *) qname; -+ for (int unique = 0; unique < cnames; ++unique) -+ { -+ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); -+ char *new_name = xasprintf ("%d.alias.example", unique); -+ resolv_response_add_name (b, new_name); -+ resolv_response_close_record (b); -+ -+ maybe_insert_sig (b, qname); -+ -+ if (previous_name != qname) -+ free (previous_name); -+ previous_name = new_name; -+ } -+ -+ for (int unique = 0; unique < addresses; ++unique) -+ { -+ resolv_response_open_record (b, previous_name, qclass, qtype, 60); -+ -+ if (qtype == T_A) -+ { -+ char ipv4[4] = {192, 0, 2, 1 + unique}; -+ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); -+ } -+ else if (qtype == T_AAAA) -+ { -+ char ipv6[16] = -+ { -+ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 1 + unique -+ }; -+ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); -+ } -+ resolv_response_close_record (b); -+ } -+ -+ if (previous_name != qname) -+ free (previous_name); -+} -+ -+static char * -+make_qname (bool do_search, int cnames, int addresses) -+{ -+ return xasprintf ("a%d-c%d%s", -+ addresses, cnames, do_search ? "" : ".example.net"); -+} -+ -+static void -+check_cnames_failure (int af, bool do_search, int cnames, int addresses) -+{ -+ char *qname = make_qname (do_search, cnames, addresses); -+ -+ struct hostent *e; -+ if (af == AF_UNSPEC) -+ e = gethostbyname (qname); -+ else -+ e = gethostbyname2 (qname, af); -+ -+ if (addresses == 0) -+ check_hostent (qname, e, "error: NO_RECOVERY\n"); -+ else -+ check_hostent (qname, e, "error: HOST_NOT_FOUND\n"); -+ -+ free (qname); -+} -+ -+static void -+check (int af, bool do_search, int cnames, int addresses) -+{ -+ char *qname = make_qname (do_search, cnames, addresses); -+ char *fqdn = make_qname (false, cnames, addresses); -+ -+ struct hostent *e; -+ if (af == AF_UNSPEC) -+ e = gethostbyname (qname); -+ else -+ e = gethostbyname2 (qname, af); -+ if (e == NULL) -+ FAIL_EXIT1 ("unexpected failure for %d, %d, %d", af, cnames, addresses); -+ -+ if (af == AF_UNSPEC || af == AF_INET) -+ { -+ TEST_COMPARE (e->h_addrtype, AF_INET); -+ TEST_COMPARE (e->h_length, 4); -+ } -+ else -+ { -+ TEST_COMPARE (e->h_addrtype, AF_INET6); -+ TEST_COMPARE (e->h_length, 16); -+ } -+ -+ for (int i = 0; i < addresses; ++i) -+ { -+ char ipv4[4] = {192, 0, 2, 1 + i}; -+ char ipv6[16] = -+ { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + i }; -+ char *expected = e->h_addrtype == AF_INET ? ipv4 : ipv6; -+ TEST_COMPARE_BLOB (e->h_addr_list[i], e->h_length, -+ expected, e->h_length); -+ } -+ TEST_VERIFY (e->h_addr_list[addresses] == NULL); -+ -+ -+ if (cnames == 0) -+ { -+ /* QNAME is fully qualified. */ -+ TEST_COMPARE_STRING (e->h_name, fqdn); -+ TEST_VERIFY (e->h_aliases[0] == NULL); -+ } -+ else -+ { -+ /* Fully-qualified QNAME is demoted to an aliases. */ -+ TEST_COMPARE_STRING (e->h_aliases[0], fqdn); -+ -+ for (int i = 1; i <= cnames; ++i) -+ { -+ char *expected = xasprintf ("%d.alias.example", i - 1); -+ if (i == cnames) -+ TEST_COMPARE_STRING (e->h_name, expected); -+ else -+ TEST_COMPARE_STRING (e->h_aliases[i], expected); -+ free (expected); -+ } -+ TEST_VERIFY (e->h_aliases[cnames] == NULL); -+ } -+ -+ free (fqdn); -+ free (qname); -+} -+ -+static int -+do_test (void) -+{ -+ struct resolv_test *obj = resolv_test_start -+ ((struct resolv_redirect_config) -+ { -+ .response_callback = response, -+ .search = { "example.net", "example.com" }, -+ }); -+ -+ static const int families[] = { AF_UNSPEC, AF_INET, AF_INET6 }; -+ -+ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig) -+ { -+ insert_sig = do_insert_sig; -+ -+ /* If do_search is true, a bare host name (for example, a1-c1) -+ is used. This exercises search path processing and FQDN -+ qualification. */ -+ for (int do_search = 0; do_search < 2; ++do_search) -+ for (const int *paf = families; paf != array_end (families); ++paf) -+ { -+ for (int cnames = 0; cnames <= 100; ++cnames) -+ { -+ check_cnames_failure (*paf, do_search, cnames, 0); -+ /* Now with NXDOMAIN responses. */ -+ check_cnames_failure (*paf, do_search, cnames, 255); -+ } -+ -+ for (int cnames = 0; cnames <= 10; ++cnames) -+ for (int addresses = 1; addresses <= 10; ++addresses) -+ check (*paf, do_search, cnames, addresses); -+ -+ /* The current implementation is limited to 47 aliases. -+ Addresses do not have such a limit. */ -+ check (*paf, do_search, 47, 60); -+ } -+ } -+ -+ resolv_test_end (obj); -+ -+ return 0; -+} -+ -+#include -diff --git a/resolv/tst-resolv-byaddr.c b/resolv/tst-resolv-byaddr.c -new file mode 100644 -index 0000000000..6299e89837 ---- /dev/null -+++ b/resolv/tst-resolv-byaddr.c -@@ -0,0 +1,326 @@ -+/* Test reverse DNS lookup. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "tst-resolv-maybe_insert_sig.h" -+ -+/* QNAME format: -+ -+ ADDRESSES.CNAMES...(lots of 0s)...8.b.d.0.1.0.0.2.ip6.arpa. -+ CNAMES|ADDRESSES.2.0.192.in-addr-arpa. -+ -+ For the IPv4 reverse lookup, the address count is in the lower -+ bits. -+ -+ CNAMES is the length of the CNAME chain, ADDRESSES is the number of -+ addresses in the response. The special value 15 means that there -+ are no addresses, and the RCODE is NXDOMAIN. */ -+static void -+response (const struct resolv_response_context *ctx, -+ struct resolv_response_builder *b, -+ const char *qname, uint16_t qclass, uint16_t qtype) -+{ -+ TEST_COMPARE (qclass, C_IN); -+ TEST_COMPARE (qtype, T_PTR); -+ -+ unsigned int addresses, cnames, bits; -+ char *tail; -+ if (strstr (qname, "ip6.arpa") != NULL -+ && sscanf (qname, "%x.%x.%ms", &addresses, &cnames, &tail) == 3) -+ TEST_COMPARE_STRING (tail, "\ -+0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"); -+ else if (sscanf (qname, "%u.%ms", &bits, &tail) == 2) -+ { -+ TEST_COMPARE_STRING (tail, "2.0.192.in-addr.arpa"); -+ addresses = bits & 0x0f; -+ cnames = bits >> 4; -+ } -+ else -+ FAIL_EXIT1 ("invalid QNAME: %s", qname); -+ free (tail); -+ -+ int rcode; -+ if (addresses == 15) -+ { -+ /* Special case: Use no addresses with NXDOMAIN response. */ -+ rcode = ns_r_nxdomain; -+ addresses = 0; -+ } -+ else -+ rcode = 0; -+ -+ struct resolv_response_flags flags = { .rcode = rcode }; -+ resolv_response_init (b, flags); -+ resolv_response_add_question (b, qname, qclass, qtype); -+ resolv_response_section (b, ns_s_an); -+ maybe_insert_sig (b, qname); -+ -+ /* Provide the requested number of CNAME records. */ -+ char *previous_name = (char *) qname; -+ for (int unique = 0; unique < cnames; ++unique) -+ { -+ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); -+ char *new_name = xasprintf ("%d.alias.example", unique); -+ resolv_response_add_name (b, new_name); -+ resolv_response_close_record (b); -+ -+ maybe_insert_sig (b, qname); -+ -+ if (previous_name != qname) -+ free (previous_name); -+ previous_name = new_name; -+ } -+ -+ for (int unique = 0; unique < addresses; ++unique) -+ { -+ resolv_response_open_record (b, previous_name, qclass, T_PTR, 60); -+ char *ptr = xasprintf ("unique-%d.cnames-%u.addresses-%u.example", -+ unique, cnames, addresses); -+ resolv_response_add_name (b, ptr); -+ free (ptr); -+ resolv_response_close_record (b); -+ } -+ -+ if (previous_name != qname) -+ free (previous_name); -+} -+ -+/* Used to check that gethostbyaddr_r does not write past the buffer -+ end. */ -+static struct support_next_to_fault ntf; -+ -+/* Perform a gethostbyaddr call and check the result. */ -+static void -+check_gethostbyaddr (const char *address, const char *expected) -+{ -+ unsigned char bytes[16]; -+ unsigned int byteslen; -+ int family; -+ if (strchr (address, ':') != NULL) -+ { -+ family = AF_INET6; -+ byteslen = 16; -+ } -+ else -+ { -+ family = AF_INET; -+ byteslen = 4; -+ } -+ TEST_COMPARE (inet_pton (family, address, bytes), 1); -+ -+ struct hostent *e = gethostbyaddr (bytes, byteslen, family); -+ check_hostent (address, e, expected); -+ -+ if (e == NULL) -+ return; -+ -+ /* Try gethostbyaddr_r with increasing sizes until success. First -+ compute a reasonable minimum buffer size, to avoid many pointless -+ attempts. */ -+ size_t minimum_size = strlen (e->h_name); -+ for (int i = 0; e->h_addr_list[i] != NULL; ++i) -+ minimum_size += e->h_length + sizeof (char *); -+ for (int i = 0; e->h_aliases[i] != NULL; ++i) -+ minimum_size += strlen (e->h_aliases[i]) + 1 + sizeof (char *); -+ -+ /* Gradually increase the size until success. */ -+ for (size_t size = minimum_size; size < ntf.length; ++size) -+ { -+ struct hostent result; -+ int herrno; -+ int ret = gethostbyaddr_r (bytes, byteslen, family, &result, -+ ntf.buffer + ntf.length - size, size, -+ &e, &herrno); -+ if (ret == ERANGE) -+ /* Retry with larger size. */ -+ TEST_COMPARE (herrno, NETDB_INTERNAL); -+ else if (ret == 0) -+ { -+ TEST_VERIFY (size > minimum_size); -+ check_hostent (address, e, expected); -+ return; -+ } -+ else -+ FAIL_EXIT1 ("Unexpected gethostbyaddr_r failure: %d", ret); -+ } -+ -+ FAIL_EXIT1 ("gethostbyaddr_r always failed for: %s", address); -+} -+ -+/* Perform a getnameinfo call and check the result. */ -+static void -+check_getnameinfo (const char *address, const char *expected) -+{ -+ struct sockaddr_in sin = { }; -+ struct sockaddr_in6 sin6 = { }; -+ void *sa; -+ socklen_t salen; -+ if (strchr (address, ':') != NULL) -+ { -+ sin6.sin6_family = AF_INET6; -+ TEST_COMPARE (inet_pton (AF_INET6, address, &sin6.sin6_addr), 1); -+ sin6.sin6_port = htons (80); -+ sa = &sin6; -+ salen = sizeof (sin6); -+ } -+ else -+ { -+ sin.sin_family = AF_INET; -+ TEST_COMPARE (inet_pton (AF_INET, address, &sin.sin_addr), 1); -+ sin.sin_port = htons (80); -+ sa = &sin; -+ salen = sizeof (sin); -+ } -+ -+ char host[64]; -+ char service[64]; -+ int ret = getnameinfo (sa, salen, host, -+ sizeof (host), service, sizeof (service), -+ NI_NAMEREQD | NI_NUMERICSERV); -+ switch (ret) -+ { -+ case 0: -+ TEST_COMPARE_STRING (host, expected); -+ TEST_COMPARE_STRING (service, "80"); -+ break; -+ case EAI_SYSTEM: -+ TEST_COMPARE_STRING (strerror (errno), expected); -+ break; -+ default: -+ TEST_COMPARE_STRING (gai_strerror (ret), expected); -+ } -+} -+ -+static int -+do_test (void) -+{ -+ /* Some reasonably upper bound for the maximum response size. */ -+ ntf = support_next_to_fault_allocate (4096); -+ -+ struct resolv_test *obj = resolv_test_start -+ ((struct resolv_redirect_config) -+ { -+ .response_callback = response -+ }); -+ -+ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig) -+ { -+ insert_sig = do_insert_sig; -+ -+ /* No PTR record, RCODE=0. */ -+ check_gethostbyaddr ("192.0.2.0", "error: NO_RECOVERY\n"); -+ check_getnameinfo ("192.0.2.0", "Name or service not known"); -+ check_gethostbyaddr ("192.0.2.16", "error: NO_RECOVERY\n"); -+ check_getnameinfo ("192.0.2.16", "Name or service not known"); -+ check_gethostbyaddr ("192.0.2.32", "error: NO_RECOVERY\n"); -+ check_getnameinfo ("192.0.2.32", "Name or service not known"); -+ check_gethostbyaddr ("2001:db8::", "error: NO_RECOVERY\n"); -+ check_getnameinfo ("2001:db8::", "Name or service not known"); -+ check_gethostbyaddr ("2001:db8::10", "error: NO_RECOVERY\n"); -+ check_getnameinfo ("2001:db8::10", "Name or service not known"); -+ check_gethostbyaddr ("2001:db8::20", "error: NO_RECOVERY\n"); -+ check_getnameinfo ("2001:db8::20", "Name or service not known"); -+ -+ /* No PTR record, NXDOMAIN. */ -+ check_gethostbyaddr ("192.0.2.15", "error: HOST_NOT_FOUND\n"); -+ check_getnameinfo ("192.0.2.15", "Name or service not known"); -+ check_gethostbyaddr ("192.0.2.31", "error: HOST_NOT_FOUND\n"); -+ check_getnameinfo ("192.0.2.31", "Name or service not known"); -+ check_gethostbyaddr ("192.0.2.47", "error: HOST_NOT_FOUND\n"); -+ check_getnameinfo ("192.0.2.47", "Name or service not known"); -+ check_gethostbyaddr ("2001:db8::f", "error: HOST_NOT_FOUND\n"); -+ check_getnameinfo ("2001:db8::f", "Name or service not known"); -+ check_gethostbyaddr ("2001:db8::1f", "error: HOST_NOT_FOUND\n"); -+ check_getnameinfo ("2001:db8::1f", "Name or service not known"); -+ check_gethostbyaddr ("2001:db8::2f", "error: HOST_NOT_FOUND\n"); -+ check_getnameinfo ("2001:db8::2f", "Name or service not known"); -+ -+ /* Actual response data. Only the first PTR record is returned. */ -+ check_gethostbyaddr ("192.0.2.1", -+ "name: unique-0.cnames-0.addresses-1.example\n" -+ "address: 192.0.2.1\n"); -+ check_getnameinfo ("192.0.2.1", -+ "unique-0.cnames-0.addresses-1.example"); -+ check_gethostbyaddr ("192.0.2.17", -+ "name: unique-0.cnames-1.addresses-1.example\n" -+ "address: 192.0.2.17\n"); -+ check_getnameinfo ("192.0.2.17", -+ "unique-0.cnames-1.addresses-1.example"); -+ check_gethostbyaddr ("192.0.2.18", -+ "name: unique-0.cnames-1.addresses-2.example\n" -+ "address: 192.0.2.18\n"); -+ check_getnameinfo ("192.0.2.18", -+ "unique-0.cnames-1.addresses-2.example"); -+ check_gethostbyaddr ("192.0.2.33", -+ "name: unique-0.cnames-2.addresses-1.example\n" -+ "address: 192.0.2.33\n"); -+ check_getnameinfo ("192.0.2.33", -+ "unique-0.cnames-2.addresses-1.example"); -+ check_gethostbyaddr ("192.0.2.34", -+ "name: unique-0.cnames-2.addresses-2.example\n" -+ "address: 192.0.2.34\n"); -+ check_getnameinfo ("192.0.2.34", -+ "unique-0.cnames-2.addresses-2.example"); -+ -+ /* Same for IPv6 addresses. */ -+ check_gethostbyaddr ("2001:db8::1", -+ "name: unique-0.cnames-0.addresses-1.example\n" -+ "address: 2001:db8::1\n"); -+ check_getnameinfo ("2001:db8::1", -+ "unique-0.cnames-0.addresses-1.example"); -+ check_gethostbyaddr ("2001:db8::11", -+ "name: unique-0.cnames-1.addresses-1.example\n" -+ "address: 2001:db8::11\n"); -+ check_getnameinfo ("2001:db8::11", -+ "unique-0.cnames-1.addresses-1.example"); -+ check_gethostbyaddr ("2001:db8::12", -+ "name: unique-0.cnames-1.addresses-2.example\n" -+ "address: 2001:db8::12\n"); -+ check_getnameinfo ("2001:db8::12", -+ "unique-0.cnames-1.addresses-2.example"); -+ check_gethostbyaddr ("2001:db8::21", -+ "name: unique-0.cnames-2.addresses-1.example\n" -+ "address: 2001:db8::21\n"); -+ check_getnameinfo ("2001:db8::21", -+ "unique-0.cnames-2.addresses-1.example"); -+ check_gethostbyaddr ("2001:db8::22", -+ "name: unique-0.cnames-2.addresses-2.example\n" -+ "address: 2001:db8::22\n"); -+ check_getnameinfo ("2001:db8::22", -+ "unique-0.cnames-2.addresses-2.example"); -+ } -+ -+ resolv_test_end (obj); -+ -+ support_next_to_fault_free (&ntf); -+ return 0; -+} -+ -+#include -diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c -new file mode 100644 -index 0000000000..63dac90e02 ---- /dev/null -+++ b/resolv/tst-resolv-invalid-cname.c -@@ -0,0 +1,406 @@ -+/* Test handling of CNAMEs with non-host domain names (bug 12154). -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Query strings describe the CNAME chain in the response. They have -+ the format "bitsBITS.countCOUNT.example.", where BITS and COUNT are -+ replaced by unsigned decimal numbers. COUNT is the number of CNAME -+ records in the response. BITS has two bits for each CNAME record, -+ describing a special prefix that is added to that CNAME. -+ -+ 0: No special leading label. -+ 1: Starting with "*.". -+ 2: Starting with "-x.". -+ 3: Starting with "star.*.". -+ -+ The first CNAME in the response using the two least significant -+ bits. -+ -+ For PTR queries, the QNAME format is different, it is either -+ COUNT.BITS.168.192.in-addr.arpa. (with BITS and COUNT still -+ decimal), or: -+ -+COUNT.BITS0.BITS1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. -+ -+ where BITS and COUNT are hexadecimal. */ -+ -+static void -+response (const struct resolv_response_context *ctx, -+ struct resolv_response_builder *b, -+ const char *qname, uint16_t qclass, uint16_t qtype) -+{ -+ TEST_COMPARE (qclass, C_IN); -+ -+ /* The only other query type besides A is PTR. */ -+ if (qtype != T_A && qtype != T_AAAA) -+ TEST_COMPARE (qtype, T_PTR); -+ -+ unsigned int bits, bits1, count; -+ char *tail = NULL; -+ if (sscanf (qname, "bits%u.count%u.%ms", &bits, &count, &tail) == 3) -+ TEST_COMPARE_STRING (tail, "example"); -+ else if (strstr (qname, "in-addr.arpa") != NULL -+ && sscanf (qname, "%u.%u.%ms", &bits, &count, &tail) == 3) -+ TEST_COMPARE_STRING (tail, "168.192.in-addr.arpa"); -+ else if (sscanf (qname, "%x.%x.%x.%ms", &bits, &bits1, &count, &tail) == 4) -+ { -+ TEST_COMPARE_STRING (tail, "\ -+0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"); -+ bits |= bits1 << 4; -+ } -+ else -+ FAIL_EXIT1 ("invalid QNAME: %s\n", qname); -+ free (tail); -+ -+ struct resolv_response_flags flags = {}; -+ resolv_response_init (b, flags); -+ resolv_response_add_question (b, qname, qclass, qtype); -+ resolv_response_section (b, ns_s_an); -+ -+ /* Provide the requested number of CNAME records. */ -+ char *previous_name = (char *) qname; -+ unsigned int original_bits = bits; -+ for (int unique = 0; unique < count; ++unique) -+ { -+ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); -+ -+ static const char bits_to_prefix[4][8] = { "", "*.", "-x.", "star.*." }; -+ char *new_name = xasprintf ("%sunique%d.example", -+ bits_to_prefix[bits & 3], unique); -+ bits >>= 2; -+ resolv_response_add_name (b, new_name); -+ resolv_response_close_record (b); -+ -+ if (previous_name != qname) -+ free (previous_name); -+ previous_name = new_name; -+ } -+ -+ /* Actual answer record. */ -+ resolv_response_open_record (b, previous_name, qclass, qtype, 60); -+ switch (qtype) -+ { -+ case T_A: -+ { -+ char ipv4[4] = {192, 168, count, original_bits}; -+ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); -+ } -+ break; -+ case T_AAAA: -+ { -+ char ipv6[16] = -+ { -+ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ count, original_bits -+ }; -+ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); -+ } -+ break; -+ -+ case T_PTR: -+ { -+ char *name = xasprintf ("bits%u.count%u.example", -+ original_bits, count); -+ resolv_response_add_name (b, name); -+ free (name); -+ } -+ break; -+ } -+ resolv_response_close_record (b); -+ -+ if (previous_name != qname) -+ free (previous_name); -+} -+ -+/* Controls which name resolution function is invoked. */ -+enum test_mode -+ { -+ byname, /* gethostbyname. */ -+ byname2, /* gethostbyname2. */ -+ gai, /* getaddrinfo without AI_CANONNAME. */ -+ gai_canon, /* getaddrinfo with AI_CANONNAME. */ -+ -+ test_mode_num /* Number of enum values. */ -+ }; -+ -+static const char * -+test_mode_to_string (enum test_mode mode) -+{ -+ switch (mode) -+ { -+ case byname: -+ return "byname"; -+ case byname2: -+ return "byname2"; -+ case gai: -+ return "gai"; -+ case gai_canon: -+ return "gai_canon"; -+ case test_mode_num: -+ break; /* Report error below. */ -+ } -+ FAIL_EXIT1 ("invalid test_mode: %d", mode); -+} -+ -+/* Append the name and aliases to OUT. */ -+static void -+append_names (FILE *out, const char *qname, int bits, int count, -+ enum test_mode mode) -+{ -+ /* Largest valid index which has a corresponding zero in bits -+ (meaning a syntactically valid CNAME). */ -+ int last_valid_cname = -1; -+ -+ for (int i = 0; i < count; ++i) -+ if ((bits & (3 << (i * 2))) == 0) -+ last_valid_cname = i; -+ -+ if (mode != gai) -+ { -+ const char *label; -+ if (mode == gai_canon) -+ label = "canonname"; -+ else -+ label = "name"; -+ if (last_valid_cname >= 0) -+ fprintf (out, "%s: unique%d.example\n", label, last_valid_cname); -+ else -+ fprintf (out, "%s: %s\n", label, qname); -+ } -+ -+ if (mode == byname || mode == byname2) -+ { -+ if (last_valid_cname >= 0) -+ fprintf (out, "alias: %s\n", qname); -+ for (int i = 0; i < count; ++i) -+ { -+ if ((bits & (3 << (i * 2))) == 0 && i != last_valid_cname) -+ fprintf (out, "alias: unique%d.example\n", i); -+ } -+ } -+} -+ -+/* Append the address information to OUT. */ -+static void -+append_addresses (FILE *out, int af, int bits, int count, enum test_mode mode) -+{ -+ int last = count * 256 + bits; -+ if (mode == gai || mode == gai_canon) -+ { -+ if (af == AF_INET || af == AF_UNSPEC) -+ fprintf (out, "address: STREAM/TCP 192.168.%d.%d 80\n", count, bits); -+ if (af == AF_INET6 || af == AF_UNSPEC) -+ { -+ if (last == 0) -+ fprintf (out, "address: STREAM/TCP 2001:db8:: 80\n"); -+ else -+ fprintf (out, "address: STREAM/TCP 2001:db8::%x 80\n", last); -+ } -+ } -+ else -+ { -+ TEST_VERIFY (af != AF_UNSPEC); -+ if (af == AF_INET) -+ fprintf (out, "address: 192.168.%d.%d\n", count, bits); -+ if (af == AF_INET6) -+ { -+ if (last == 0) -+ fprintf (out, "address: 2001:db8::\n"); -+ else -+ fprintf (out, "address: 2001:db8::%x\n", last); -+ } -+ } -+} -+ -+/* Perform one test using a forward lookup. */ -+static void -+check_forward (int af, int bits, int count, enum test_mode mode) -+{ -+ char *qname = xasprintf ("bits%d.count%d.example", bits, count); -+ char *label = xasprintf ("af=%d bits=%d count=%d mode=%s qname=%s", -+ af, bits, count, test_mode_to_string (mode), qname); -+ -+ struct xmemstream expected; -+ xopen_memstream (&expected); -+ if (mode == gai_canon) -+ fprintf (expected.out, "flags: AI_CANONNAME\n"); -+ append_names (expected.out, qname, bits, count, mode); -+ append_addresses (expected.out, af, bits, count, mode); -+ xfclose_memstream (&expected); -+ -+ if (mode == gai || mode == gai_canon) -+ { -+ struct addrinfo *ai; -+ struct addrinfo hints = -+ { -+ .ai_family = af, -+ .ai_socktype = SOCK_STREAM, -+ }; -+ if (mode == gai_canon) -+ hints.ai_flags |= AI_CANONNAME; -+ int ret = getaddrinfo (qname, "80", &hints, &ai); -+ check_addrinfo (label, ai, ret, expected.buffer); -+ if (ret == 0) -+ freeaddrinfo (ai); -+ } -+ else -+ { -+ struct hostent *e; -+ if (mode == gai) -+ { -+ TEST_COMPARE (af, AF_INET); -+ e = gethostbyname (qname); -+ } -+ else -+ { -+ if (af != AF_INET) -+ TEST_COMPARE (af, AF_INET6); -+ e = gethostbyname2 (qname, af); -+ } -+ check_hostent (label, e, expected.buffer); -+ } -+ -+ free (expected.buffer); -+ free (label); -+ free (qname); -+} -+ -+/* Perform one check using a reverse lookup. */ -+ -+static void -+check_reverse (int af, int bits, int count) -+{ -+ TEST_VERIFY (af == AF_INET || af == AF_INET6); -+ -+ char *label = xasprintf ("af=%d bits=%d count=%d", af, bits, count); -+ char *fqdn = xasprintf ("bits%d.count%d.example", bits, count); -+ -+ struct xmemstream expected; -+ xopen_memstream (&expected); -+ fprintf (expected.out, "name: %s\n", fqdn); -+ append_addresses (expected.out, af, bits, count, byname); -+ xfclose_memstream (&expected); -+ -+ char addr[16] = { 0 }; -+ socklen_t addrlen; -+ if (af == AF_INET) -+ { -+ addr[0] = 192; -+ addr[1] = 168; -+ addr[2] = count; -+ addr[3] = bits; -+ addrlen = 4; -+ } -+ else -+ { -+ addr[0] = 0x20; -+ addr[1] = 0x01; -+ addr[2] = 0x0d; -+ addr[3] = 0xb8; -+ addr[14] = count; -+ addr[15] = bits; -+ addrlen = 16; -+ } -+ -+ struct hostent *e = gethostbyaddr (addr, addrlen, af); -+ check_hostent (label, e, expected.buffer); -+ -+ /* getnameinfo check is different. There is no generic check_* -+ function for it. */ -+ { -+ struct sockaddr_in sin = { }; -+ struct sockaddr_in6 sin6 = { }; -+ void *sa; -+ socklen_t salen; -+ if (af == AF_INET) -+ { -+ sin.sin_family = AF_INET; -+ memcpy (&sin.sin_addr, addr, addrlen); -+ sin.sin_port = htons (80); -+ sa = &sin; -+ salen = sizeof (sin); -+ } -+ else -+ { -+ sin6.sin6_family = AF_INET6; -+ memcpy (&sin6.sin6_addr, addr, addrlen); -+ sin6.sin6_port = htons (80); -+ sa = &sin6; -+ salen = sizeof (sin6); -+ } -+ -+ char host[64]; -+ char service[64]; -+ int ret = getnameinfo (sa, salen, host, -+ sizeof (host), service, sizeof (service), -+ NI_NAMEREQD | NI_NUMERICSERV); -+ TEST_COMPARE (ret, 0); -+ TEST_COMPARE_STRING (host, fqdn); -+ TEST_COMPARE_STRING (service, "80"); -+ } -+ -+ free (expected.buffer); -+ free (fqdn); -+ free (label); -+} -+ -+static int -+do_test (void) -+{ -+ struct resolv_test *obj = resolv_test_start -+ ((struct resolv_redirect_config) -+ { -+ .response_callback = response -+ }); -+ -+ for (int count = 0; count <= 3; ++count) -+ for (int bits = 0; bits <= 1 << (count * 2); ++bits) -+ { -+ if (count > 0 && bits == count) -+ /* The last bits value is only checked if count == 0. */ -+ continue; -+ -+ for (enum test_mode mode = 0; mode < test_mode_num; ++mode) -+ { -+ check_forward (AF_INET, bits, count, mode); -+ if (mode != byname) -+ check_forward (AF_INET6, bits, count, mode); -+ if (mode == gai || mode == gai_canon) -+ check_forward (AF_UNSPEC, bits, count, mode); -+ } -+ -+ check_reverse (AF_INET, bits, count); -+ check_reverse (AF_INET6, bits, count); -+ } -+ -+ resolv_test_end (obj); -+ -+ return 0; -+} -+ -+#include -diff --git a/resolv/tst-resolv-maybe_insert_sig.h b/resolv/tst-resolv-maybe_insert_sig.h -new file mode 100644 -index 0000000000..05725225af ---- /dev/null -+++ b/resolv/tst-resolv-maybe_insert_sig.h -@@ -0,0 +1,32 @@ -+/* Code snippet for optionally inserting ignored SIG records in resolver tests. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+/* Set to true for an alternative pass that inserts (ignored) SIG -+ records. This does not alter the response, so this property is not -+ encoded in the QNAME. The variable needs to be volatile because -+ leaf attributes tell GCC that the response function is not -+ called. */ -+static volatile bool insert_sig; -+ -+static void -+maybe_insert_sig (struct resolv_response_builder *b, const char *owner) -+{ -+ resolv_response_open_record (b, owner, C_IN, T_SIG, 60); -+ resolv_response_add_data (b, "", 1); -+ resolv_response_close_record (b); -+} -diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c -new file mode 100644 -index 0000000000..9f5aebd99f ---- /dev/null -+++ b/resolv/tst-resolv-noaaaa-vc.c -@@ -0,0 +1,129 @@ -+/* Test the RES_NOAAAA resolver option with a large response. -+ Copyright (C) 2022-2023 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Used to keep track of the number of queries. */ -+static volatile unsigned int queries; -+ -+/* If true, add a large TXT record at the start of the answer section. */ -+static volatile bool stuff_txt; -+ -+static void -+response (const struct resolv_response_context *ctx, -+ struct resolv_response_builder *b, -+ const char *qname, uint16_t qclass, uint16_t qtype) -+{ -+ /* If not using TCP, just force its use. */ -+ if (!ctx->tcp) -+ { -+ struct resolv_response_flags flags = {.tc = true}; -+ resolv_response_init (b, flags); -+ resolv_response_add_question (b, qname, qclass, qtype); -+ return; -+ } -+ -+ /* The test needs to send four queries, the first three are used to -+ grow the NSS buffer via the ERANGE handshake. */ -+ ++queries; -+ TEST_VERIFY (queries <= 4); -+ -+ /* AAAA queries are supposed to be disabled. */ -+ TEST_COMPARE (qtype, T_A); -+ TEST_COMPARE (qclass, C_IN); -+ TEST_COMPARE_STRING (qname, "example.com"); -+ -+ struct resolv_response_flags flags = {}; -+ resolv_response_init (b, flags); -+ resolv_response_add_question (b, qname, qclass, qtype); -+ -+ resolv_response_section (b, ns_s_an); -+ -+ if (stuff_txt) -+ { -+ resolv_response_open_record (b, qname, qclass, T_TXT, 60); -+ int zero = 0; -+ for (int i = 0; i <= 15000; ++i) -+ resolv_response_add_data (b, &zero, sizeof (zero)); -+ resolv_response_close_record (b); -+ } -+ -+ for (int i = 0; i < 200; ++i) -+ { -+ resolv_response_open_record (b, qname, qclass, qtype, 60); -+ char ipv4[4] = {192, 0, 2, i + 1}; -+ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); -+ resolv_response_close_record (b); -+ } -+} -+ -+static int -+do_test (void) -+{ -+ struct resolv_test *obj = resolv_test_start -+ ((struct resolv_redirect_config) -+ { -+ .response_callback = response -+ }); -+ -+ _res.options |= RES_NOAAAA; -+ -+ for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt) -+ { -+ queries = 0; -+ stuff_txt = do_stuff_txt; -+ -+ struct addrinfo *ai = NULL; -+ int ret; -+ ret = getaddrinfo ("example.com", "80", -+ &(struct addrinfo) -+ { -+ .ai_family = AF_UNSPEC, -+ .ai_socktype = SOCK_STREAM, -+ }, &ai); -+ -+ char *expected_result; -+ { -+ struct xmemstream mem; -+ xopen_memstream (&mem); -+ for (int i = 0; i < 200; ++i) -+ fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1); -+ xfclose_memstream (&mem); -+ expected_result = mem.buffer; -+ } -+ -+ check_addrinfo ("example.com", ai, ret, expected_result); -+ -+ free (expected_result); -+ freeaddrinfo (ai); -+ } -+ -+ resolv_test_end (obj); -+ return 0; -+} -+ -+#include -diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py -index 2dd6bfda18..b87cf2f809 100644 ---- a/scripts/dso-ordering-test.py -+++ b/scripts/dso-ordering-test.py -@@ -707,13 +707,12 @@ def process_testcase(t): - "\t$(compile.c) $(OUTPUT_OPTION)\n") - makefile.write (rule) - -- not_depended_objs = find_objs_not_depended_on(test_descr) -- if not_depended_objs: -- depstr = "" -- for dep in not_depended_objs: -- depstr += (" $(objpfx)" + test_subdir + "/" -- + test_name + "-" + dep + ".so") -- makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr)) -+ # Ensure that all shared objects are built before running the -+ # test, whether there link-time dependencies or not. -+ depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep) -+ for dep in test_descr.objs] -+ makefile.write("$(objpfx){}.out: {}\n".format( -+ base_test_name, " ".join(depobjs))) - - # Add main executable to test-srcs - makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name)) -diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py -index 43ab58ffe2..36d204c9b0 100644 ---- a/scripts/glibcextract.py -+++ b/scripts/glibcextract.py -@@ -17,6 +17,7 @@ - # License along with the GNU C Library; if not, see - # . - -+import collections - import os.path - import re - import subprocess -@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None, - if not allow_extra_2: - ret = 1 - return ret -+ -+CompileResult = collections.namedtuple("CompileResult", "returncode output") -+ -+def compile_c_snippet(snippet, cc, extra_cc_args=''): -+ """Compile and return whether the SNIPPET can be build with CC along -+ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE -+ being 0 for success, or the failure value and the compiler output. -+ """ -+ with tempfile.TemporaryDirectory() as temp_dir: -+ c_file_name = os.path.join(temp_dir, 'test.c') -+ obj_file_name = os.path.join(temp_dir, 'test.o') -+ with open(c_file_name, 'w') as c_file: -+ c_file.write(snippet + '\n') -+ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name, -+ c_file_name] -+ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE, -+ stderr=subprocess.STDOUT) -+ return CompileResult(r.returncode, r.stdout) -diff --git a/socket/Makefile b/socket/Makefile -index 156eec6c85..2bde78387f 100644 ---- a/socket/Makefile -+++ b/socket/Makefile -@@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt \ - tests := \ - tst-accept4 \ - tst-sockopt \ -+ tst-cmsghdr \ - # tests - - tests-internal := \ -diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c -new file mode 100644 -index 0000000000..4c6898569b ---- /dev/null -+++ b/socket/tst-cmsghdr-skeleton.c -@@ -0,0 +1,92 @@ -+/* Test ancillary data header creation. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+/* We use the preprocessor to generate the function/macro tests instead of -+ using indirection because having all the macro expansions alongside -+ each other lets the compiler warn us about suspicious pointer -+ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */ -+ -+#include -+ -+#define RUN_TEST_CONCAT(suffix) run_test_##suffix -+#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix) -+ -+static void -+RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void) -+{ -+ struct msghdr m = {0}; -+ struct cmsghdr *cmsg; -+ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0}; -+ -+ m.msg_control = cmsgbuf; -+ m.msg_controllen = sizeof (cmsgbuf); -+ -+ /* First header should point to the start of the buffer. */ -+ cmsg = CMSG_FIRSTHDR (&m); -+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); -+ -+ /* If the first header length consumes the entire buffer, there is no -+ space remaining for additional headers. */ -+ cmsg->cmsg_len = sizeof (cmsgbuf); -+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); -+ TEST_VERIFY_EXIT (cmsg == NULL); -+ -+ /* The first header length is so big, using it would cause an overflow. */ -+ cmsg = CMSG_FIRSTHDR (&m); -+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); -+ cmsg->cmsg_len = SIZE_MAX; -+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); -+ TEST_VERIFY_EXIT (cmsg == NULL); -+ -+ /* The first header leaves just enough space to hold another header. */ -+ cmsg = CMSG_FIRSTHDR (&m); -+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); -+ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr); -+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); -+ TEST_VERIFY_EXIT (cmsg != NULL); -+ -+ /* The first header leaves space but not enough for another header. */ -+ cmsg = CMSG_FIRSTHDR (&m); -+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); -+ cmsg->cmsg_len ++; -+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); -+ TEST_VERIFY_EXIT (cmsg == NULL); -+ -+ /* The second header leaves just enough space to hold another header. */ -+ cmsg = CMSG_FIRSTHDR (&m); -+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); -+ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD)); -+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); -+ TEST_VERIFY_EXIT (cmsg != NULL); -+ cmsg->cmsg_len = sizeof (cmsgbuf) -+ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */ -+ - sizeof (struct cmsghdr); -+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); -+ TEST_VERIFY_EXIT (cmsg != NULL); -+ -+ /* The second header leaves space but not enough for another header. */ -+ cmsg = CMSG_FIRSTHDR (&m); -+ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); -+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); -+ TEST_VERIFY_EXIT (cmsg != NULL); -+ cmsg->cmsg_len ++; -+ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); -+ TEST_VERIFY_EXIT (cmsg == NULL); -+ -+ return; -+} -diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c -new file mode 100644 -index 0000000000..68c96d3c9d ---- /dev/null -+++ b/socket/tst-cmsghdr.c -@@ -0,0 +1,56 @@ -+/* Test ancillary data header creation. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+ -+#define PAYLOAD "Hello, World!" -+ -+/* CMSG_NXTHDR is a macro that calls an inline function defined in -+ bits/socket.h. In case the function cannot be inlined, libc.so carries -+ a copy. Both versions need to be tested. */ -+ -+#define CMSG_NXTHDR_IMPL CMSG_NXTHDR -+#include "tst-cmsghdr-skeleton.c" -+#undef CMSG_NXTHDR_IMPL -+ -+static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *); -+ -+#define CMSG_NXTHDR_IMPL cmsg_nxthdr -+#include "tst-cmsghdr-skeleton.c" -+#undef CMSG_NXTHDR_IMPL -+ -+static int -+do_test (void) -+{ -+ static void *handle; -+ -+ run_test_CMSG_NXTHDR (); -+ -+ handle = xdlopen (LIBC_SO, RTLD_LAZY); -+ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *)) -+ xdlsym (handle, "__cmsg_nxthdr"); -+ -+ run_test_cmsg_nxthdr (); -+ -+ return 0; -+} -+ -+#include -diff --git a/stdlib/Makefile b/stdlib/Makefile -index f7b25c1981..3d49c4941a 100644 ---- a/stdlib/Makefile -+++ b/stdlib/Makefile -@@ -171,6 +171,7 @@ tests := \ - test-a64l \ - test-at_quick_exit-race \ - test-atexit-race \ -+ test-atexit-recursive \ - test-bz22786 \ - test-canon \ - test-canon2 \ -diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c -index e417ef624d..960a38f295 100644 ---- a/stdlib/arc4random.c -+++ b/stdlib/arc4random.c -@@ -34,7 +34,7 @@ void - __arc4random_buf (void *p, size_t n) - { - static int seen_initialized; -- size_t l; -+ ssize_t l; - int fd; - - if (n == 0) -diff --git a/stdlib/exit.c b/stdlib/exit.c -index bc46109f3e..dc12e212bc 100644 ---- a/stdlib/exit.c -+++ b/stdlib/exit.c -@@ -53,7 +53,10 @@ __run_exit_handlers (int status, struct exit_function_list **listp, - exit (). */ - while (true) - { -- struct exit_function_list *cur = *listp; -+ struct exit_function_list *cur; -+ -+ restart: -+ cur = *listp; - - if (cur == NULL) - { -@@ -118,7 +121,7 @@ __run_exit_handlers (int status, struct exit_function_list **listp, - if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called)) - /* The last exit function, or another thread, has registered - more exit functions. Start the loop over. */ -- continue; -+ goto restart; - } - - *listp = cur->next; -diff --git a/stdlib/longlong.h b/stdlib/longlong.h -index 9b89469ac2..d8f76a43b5 100644 ---- a/stdlib/longlong.h -+++ b/stdlib/longlong.h -@@ -593,6 +593,18 @@ extern UDItype __umulsidi3 (USItype, USItype); - #define UMUL_TIME 14 - #endif - -+#ifdef __loongarch__ -+# if W_TYPE_SIZE == 32 -+# define count_leading_zeros(count, x) ((count) = __builtin_clz (x)) -+# define count_trailing_zeros(count, x) ((count) = __builtin_ctz (x)) -+# define COUNT_LEADING_ZEROS_0 32 -+# elif W_TYPE_SIZE == 64 -+# define count_leading_zeros(count, x) ((count) = __builtin_clzll (x)) -+# define count_trailing_zeros(count, x) ((count) = __builtin_ctzll (x)) -+# define COUNT_LEADING_ZEROS_0 64 -+# endif -+#endif -+ - #if defined (__M32R__) && W_TYPE_SIZE == 32 - #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ - /* The cmp clears the condition bit. */ \ -diff --git a/stdlib/test-atexit-recursive.c b/stdlib/test-atexit-recursive.c -new file mode 100644 -index 0000000000..0596b9763b ---- /dev/null -+++ b/stdlib/test-atexit-recursive.c -@@ -0,0 +1,75 @@ -+/* Support file for atexit/exit, etc. race tests (BZ #27749). -+ Copyright (C) 2023 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 -+ . */ -+ -+/* Check that atexit handler registed from another handler still called. */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static void -+atexit_cb (void) -+{ -+} -+ -+static void -+atexit_last (void) -+{ -+ _exit (1); -+} -+ -+static void -+atexit_recursive (void) -+{ -+ atexit (&atexit_cb); -+ atexit (&atexit_last); -+} -+ -+_Noreturn static void -+test_and_exit (int count) -+{ -+ for (int i = 0; i < count; ++i) -+ atexit (&atexit_cb); -+ atexit (&atexit_recursive); -+ exit (0); -+} -+ -+static int -+do_test (void) -+{ -+ for (int i = 0; i < 100; ++i) -+ if (xfork () == 0) -+ test_and_exit (i); -+ -+ for (int i = 0; i < 100; ++i) -+ { -+ int status; -+ xwaitpid (0, &status, 0); -+ if (!WIFEXITED (status)) -+ FAIL_EXIT1 ("Failed iterations %d", i); -+ TEST_COMPARE (WEXITSTATUS (status), 1); -+ } -+ -+ return 0; -+} -+ -+#define TEST_FUNCTION do_test -+#include -diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c -index f7fa74b2a6..5e0c79475f 100644 ---- a/stdlib/tst-system.c -+++ b/stdlib/tst-system.c -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - #include - - static char *tmpdir; -@@ -71,6 +72,20 @@ call_system (void *closure) - } - } - -+static void * -+sleep_and_check_sigchld (void *closure) -+{ -+ double *seconds = (double *) closure; -+ char cmd[namemax]; -+ sprintf (cmd, "sleep %lf" , *seconds); -+ TEST_COMPARE (system (cmd), 0); -+ -+ sigset_t blocked = {0}; -+ TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0); -+ TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0); -+ return NULL; -+} -+ - static int - do_test (void) - { -@@ -154,6 +169,17 @@ do_test (void) - xchmod (_PATH_BSHELL, st.st_mode); - } - -+ { -+ pthread_t long_sleep_thread = xpthread_create (NULL, -+ sleep_and_check_sigchld, -+ &(double) { 0.2 }); -+ pthread_t short_sleep_thread = xpthread_create (NULL, -+ sleep_and_check_sigchld, -+ &(double) { 0.1 }); -+ xpthread_join (short_sleep_thread); -+ xpthread_join (long_sleep_thread); -+ } -+ - TEST_COMPARE (system (""), 0); - - return 0; -diff --git a/string/test-strnlen.c b/string/test-strnlen.c -index 4a9375112a..5cbaf4b734 100644 ---- a/string/test-strnlen.c -+++ b/string/test-strnlen.c -@@ -73,7 +73,7 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char) - { - size_t i; - -- align &= 63; -+ align &= (getpagesize () / sizeof (CHAR) - 1); - if ((align + len) * sizeof (CHAR) >= page_size) - return; - -@@ -90,38 +90,50 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char) - static void - do_overflow_tests (void) - { -- size_t i, j, len; -+ size_t i, j, al_idx, repeats, len; - const size_t one = 1; - uintptr_t buf_addr = (uintptr_t) buf1; -+ const size_t alignments[] = { 0, 1, 7, 9, 31, 33, 63, 65, 95, 97, 127, 129 }; - -- for (i = 0; i < 750; ++i) -+ for (al_idx = 0; al_idx < sizeof (alignments) / sizeof (alignments[0]); -+ al_idx++) - { -- do_test (1, i, SIZE_MAX, BIG_CHAR); -- -- do_test (0, i, SIZE_MAX - i, BIG_CHAR); -- do_test (0, i, i - buf_addr, BIG_CHAR); -- do_test (0, i, -buf_addr - i, BIG_CHAR); -- do_test (0, i, SIZE_MAX - buf_addr - i, BIG_CHAR); -- do_test (0, i, SIZE_MAX - buf_addr + i, BIG_CHAR); -- -- len = 0; -- for (j = 8 * sizeof(size_t) - 1; j ; --j) -- { -- len |= one << j; -- do_test (0, i, len - i, BIG_CHAR); -- do_test (0, i, len + i, BIG_CHAR); -- do_test (0, i, len - buf_addr - i, BIG_CHAR); -- do_test (0, i, len - buf_addr + i, BIG_CHAR); -- -- do_test (0, i, ~len - i, BIG_CHAR); -- do_test (0, i, ~len + i, BIG_CHAR); -- do_test (0, i, ~len - buf_addr - i, BIG_CHAR); -- do_test (0, i, ~len - buf_addr + i, BIG_CHAR); -- -- do_test (0, i, -buf_addr, BIG_CHAR); -- do_test (0, i, j - buf_addr, BIG_CHAR); -- do_test (0, i, -buf_addr - j, BIG_CHAR); -- } -+ for (repeats = 0; repeats < 2; ++repeats) -+ { -+ size_t align = repeats ? (getpagesize () - alignments[al_idx]) -+ : alignments[al_idx]; -+ align /= sizeof (CHAR); -+ for (i = 0; i < 750; ++i) -+ { -+ do_test (align, i, SIZE_MAX, BIG_CHAR); -+ -+ do_test (align, i, SIZE_MAX - i, BIG_CHAR); -+ do_test (align, i, i - buf_addr, BIG_CHAR); -+ do_test (align, i, -buf_addr - i, BIG_CHAR); -+ do_test (align, i, SIZE_MAX - buf_addr - i, BIG_CHAR); -+ do_test (align, i, SIZE_MAX - buf_addr + i, BIG_CHAR); -+ -+ len = 0; -+ for (j = 8 * sizeof (size_t) - 1; j; --j) -+ { -+ len |= one << j; -+ do_test (align, i, len, BIG_CHAR); -+ do_test (align, i, len - i, BIG_CHAR); -+ do_test (align, i, len + i, BIG_CHAR); -+ do_test (align, i, len - buf_addr - i, BIG_CHAR); -+ do_test (align, i, len - buf_addr + i, BIG_CHAR); -+ -+ do_test (align, i, ~len - i, BIG_CHAR); -+ do_test (align, i, ~len + i, BIG_CHAR); -+ do_test (align, i, ~len - buf_addr - i, BIG_CHAR); -+ do_test (align, i, ~len - buf_addr + i, BIG_CHAR); -+ -+ do_test (align, i, -buf_addr, BIG_CHAR); -+ do_test (align, i, j - buf_addr, BIG_CHAR); -+ do_test (align, i, -buf_addr - j, BIG_CHAR); -+ } -+ } -+ } - } - } - -diff --git a/sunrpc/netname.c b/sunrpc/netname.c -index bf7f0b81c4..c1d1c43e50 100644 ---- a/sunrpc/netname.c -+++ b/sunrpc/netname.c -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - - #include "nsswitch.h" - -@@ -48,7 +49,12 @@ user2netname (char netname[MAXNETNAMELEN + 1], const uid_t uid, - if ((strlen (dfltdom) + OPSYS_LEN + 3 + MAXIPRINT) > (size_t) MAXNETNAMELEN) - return 0; - -+ /* GCC with -Os warns that sprint might overflow while handling dfltdom, -+ however the above test does check if an overflow would happen. */ -+ DIAG_PUSH_NEEDS_COMMENT; -+ DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wformat-overflow"); - sprintf (netname, "%s.%d@%s", OPSYS, uid, dfltdom); -+ DIAG_POP_NEEDS_COMMENT; - i = strlen (netname); - if (netname[i - 1] == '.') - netname[i - 1] = '\0'; -diff --git a/support/Makefile b/support/Makefile -index 9b50eac117..75b96c35f5 100644 ---- a/support/Makefile -+++ b/support/Makefile -@@ -32,6 +32,8 @@ libsupport-routines = \ - check_hostent \ - check_netent \ - delayed_exit \ -+ dtotimespec \ -+ dtotimespec-time64 \ - ignore_stderr \ - next_to_fault \ - oom_error \ -@@ -237,6 +239,24 @@ CFLAGS-support_paths.c = \ - CFLAGS-timespec.c += -fexcess-precision=standard - CFLAGS-timespec-time64.c += -fexcess-precision=standard - -+# Ensure that general support files use 64-bit time_t -+CFLAGS-delayed_exit.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-shell-container.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-support_can_chroot.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-support_copy_file.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-support_copy_file_range.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-support_descriptor_supports_holes.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-support_descriptors.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-support_process_state.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-support_stat_nanoseconds.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-support_subprocess.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-support_test_main.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-test-container.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+CFLAGS-xmkdirp.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+# This is required to get an mkstemp which can create large files on some -+# 32-bit platforms. -+CFLAGS-temp_file.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -+ - ifeq (,$(CXX)) - LINKS_DSO_PROGRAM = links-dso-program-c - else -diff --git a/support/dtotimespec-time64.c b/support/dtotimespec-time64.c -new file mode 100644 -index 0000000000..b3d5e351e3 ---- /dev/null -+++ b/support/dtotimespec-time64.c -@@ -0,0 +1,27 @@ -+/* Convert double to timespec. 64-bit time support. -+ Copyright (C) 2011-2023 Free Software Foundation, Inc. -+ This file is part of the GNU C Library and is also part of gnulib. -+ Patches to this file should be submitted to both projects. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+ -+#if __TIMESIZE != 64 -+# define timespec __timespec64 -+# define time_t __time64_t -+# define dtotimespec dtotimespec_time64 -+# include "dtotimespec.c" -+#endif -diff --git a/support/dtotimespec.c b/support/dtotimespec.c -new file mode 100644 -index 0000000000..cde5b4d74c ---- /dev/null -+++ b/support/dtotimespec.c -@@ -0,0 +1,50 @@ -+/* Convert double to timespec. -+ Copyright (C) 2011-2023 Free Software Foundation, Inc. -+ This file is part of the GNU C Library and is also part of gnulib. -+ Patches to this file should be submitted to both projects. -+ -+ 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 -+ . */ -+ -+/* Convert the double value SEC to a struct timespec. Round toward -+ positive infinity. On overflow, return an extremal value. */ -+ -+#include -+#include -+ -+struct timespec -+dtotimespec (double sec) -+{ -+ if (sec <= TYPE_MINIMUM (time_t)) -+ return make_timespec (TYPE_MINIMUM (time_t), 0); -+ else if (sec >= 1.0 + TYPE_MAXIMUM (time_t)) -+ return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1); -+ else -+ { -+ time_t s = sec; -+ double frac = TIMESPEC_HZ * (sec - s); -+ long ns = frac; -+ ns += ns < frac; -+ s += ns / TIMESPEC_HZ; -+ ns %= TIMESPEC_HZ; -+ -+ if (ns < 0) -+ { -+ s--; -+ ns += TIMESPEC_HZ; -+ } -+ -+ return make_timespec (s, ns); -+ } -+} -diff --git a/support/shell-container.c b/support/shell-container.c -index 1c73666f0a..019a6c47d1 100644 ---- a/support/shell-container.c -+++ b/support/shell-container.c -@@ -16,8 +16,6 @@ - License along with the GNU C Library; if not, see - . */ - --#define _FILE_OFFSET_BITS 64 -- - #include - #include - #include -@@ -39,6 +37,7 @@ - #include - - #include -+#include - - /* Design considerations - -@@ -171,6 +170,32 @@ kill_func (char **argv) - return 0; - } - -+/* Emulate the "/bin/sleep" command. No suffix support. Options are -+ ignored. */ -+static int -+sleep_func (char **argv) -+{ -+ if (argv[0] == NULL) -+ { -+ fprintf (stderr, "sleep: missing operand\n"); -+ return 1; -+ } -+ char *endptr = NULL; -+ double sec = strtod (argv[0], &endptr); -+ if (endptr == argv[0] || errno == ERANGE || sec < 0) -+ { -+ fprintf (stderr, "sleep: invalid time interval '%s'\n", argv[0]); -+ return 1; -+ } -+ struct timespec ts = dtotimespec (sec); -+ if (nanosleep (&ts, NULL) < 0) -+ { -+ fprintf (stderr, "sleep: failed to nanosleep: %s\n", strerror (errno)); -+ return 1; -+ } -+ return 0; -+} -+ - /* This is a list of all the built-in commands we understand. */ - static struct { - const char *name; -@@ -181,6 +206,7 @@ static struct { - { "cp", copy_func }, - { "exit", exit_func }, - { "kill", kill_func }, -+ { "sleep", sleep_func }, - { NULL, NULL } - }; - -diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c -index ca0e5f7ef4..43979f7c3f 100644 ---- a/support/support_can_chroot.c -+++ b/support/support_can_chroot.c -@@ -29,14 +29,14 @@ static void - callback (void *closure) - { - int *result = closure; -- struct stat64 before; -+ struct stat before; - xstat ("/dev", &before); - if (chroot ("/dev") != 0) - { - *result = errno; - return; - } -- struct stat64 after; -+ struct stat after; - xstat ("/", &after); - TEST_VERIFY (before.st_dev == after.st_dev); - TEST_VERIFY (before.st_ino == after.st_ino); -diff --git a/support/support_copy_file.c b/support/support_copy_file.c -index 9a936b37c7..52ed90fae0 100644 ---- a/support/support_copy_file.c -+++ b/support/support_copy_file.c -@@ -24,7 +24,7 @@ - void - support_copy_file (const char *from, const char *to) - { -- struct stat64 st; -+ struct stat st; - xstat (from, &st); - int fd_from = xopen (from, O_RDONLY, 0); - mode_t mode = st.st_mode & 0777; -diff --git a/support/support_descriptor_supports_holes.c b/support/support_descriptor_supports_holes.c -index d9bcade1cf..83f02f7cf6 100644 ---- a/support/support_descriptor_supports_holes.c -+++ b/support/support_descriptor_supports_holes.c -@@ -40,7 +40,7 @@ support_descriptor_supports_holes (int fd) - block_headroom = 32, - }; - -- struct stat64 st; -+ struct stat st; - xfstat (fd, &st); - if (!S_ISREG (st.st_mode)) - FAIL_EXIT1 ("descriptor %d does not refer to a regular file", fd); -diff --git a/support/test-container.c b/support/test-container.c -index b6a1158ae1..2033985a67 100644 ---- a/support/test-container.c -+++ b/support/test-container.c -@@ -16,8 +16,6 @@ - License along with the GNU C Library; if not, see - . */ - --#define _FILE_OFFSET_BITS 64 -- - #include - #include - #include -diff --git a/support/timespec.h b/support/timespec.h -index 4d2ac2737d..1bba3a6837 100644 ---- a/support/timespec.h -+++ b/support/timespec.h -@@ -57,6 +57,8 @@ int support_timespec_check_in_range (struct timespec expected, - struct timespec observed, - double lower_bound, double upper_bound); - -+struct timespec dtotimespec (double sec) __attribute__((const)); -+ - #else - struct timespec __REDIRECT (timespec_add, (struct timespec, struct timespec), - timespec_add_time64); -@@ -82,6 +84,8 @@ int __REDIRECT (support_timespec_check_in_range, (struct timespec expected, - double lower_bound, - double upper_bound), - support_timespec_check_in_range_time64); -+ -+struct timespec __REDIRECT (dtotimespec, (double sec), dtotimespec_time64); - #endif - - /* Check that the timespec on the left represents a time before the -diff --git a/sysdeps/aarch64/configure b/sysdeps/aarch64/configure -old mode 100644 -new mode 100755 -index bf972122b1..19d2b46cbf ---- a/sysdeps/aarch64/configure -+++ b/sysdeps/aarch64/configure -@@ -303,13 +303,14 @@ aarch64-variant-pcs = $libc_cv_aarch64_variant_pcs" - # Check if asm support armv8.2-a+sve - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SVE support in assembler" >&5 - $as_echo_n "checking for SVE support in assembler... " >&6; } --if ${libc_cv_asm_sve+:} false; then : -+if ${libc_cv_aarch64_sve_asm+:} false; then : - $as_echo_n "(cached) " >&6 - else - cat > conftest.s <<\EOF -- ptrue p0.b -+ .arch armv8.2-a+sve -+ ptrue p0.b - EOF --if { ac_try='${CC-cc} -c -march=armv8.2-a+sve conftest.s 1>&5' -+if { ac_try='${CC-cc} -c conftest.s 1>&5' - { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 - (eval $ac_try) 2>&5 - ac_status=$? -@@ -321,8 +322,8 @@ else - fi - rm -f conftest* - fi --{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_asm_sve" >&5 --$as_echo "$libc_cv_asm_sve" >&6; } -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_aarch64_sve_asm" >&5 -+$as_echo "$libc_cv_aarch64_sve_asm" >&6; } - if test $libc_cv_aarch64_sve_asm = yes; then - $as_echo "#define HAVE_AARCH64_SVE_ASM 1" >>confdefs.h - -diff --git a/sysdeps/aarch64/configure.ac b/sysdeps/aarch64/configure.ac -index 51253d9802..bb5adb1782 100644 ---- a/sysdeps/aarch64/configure.ac -+++ b/sysdeps/aarch64/configure.ac -@@ -88,11 +88,12 @@ EOF - LIBC_CONFIG_VAR([aarch64-variant-pcs], [$libc_cv_aarch64_variant_pcs]) - - # Check if asm support armv8.2-a+sve --AC_CACHE_CHECK(for SVE support in assembler, libc_cv_asm_sve, [dnl -+AC_CACHE_CHECK([for SVE support in assembler], [libc_cv_aarch64_sve_asm], [dnl - cat > conftest.s <<\EOF -- ptrue p0.b -+ .arch armv8.2-a+sve -+ ptrue p0.b - EOF --if AC_TRY_COMMAND(${CC-cc} -c -march=armv8.2-a+sve conftest.s 1>&AS_MESSAGE_LOG_FD); then -+if AC_TRY_COMMAND(${CC-cc} -c conftest.s 1>&AS_MESSAGE_LOG_FD); then - libc_cv_aarch64_sve_asm=yes - else - libc_cv_aarch64_sve_asm=no -diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S -index 909b208578..d66f0b9c45 100644 ---- a/sysdeps/aarch64/dl-trampoline.S -+++ b/sysdeps/aarch64/dl-trampoline.S -@@ -298,12 +298,11 @@ _dl_runtime_profile: - stp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] - stp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] - stp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] -- str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] - stp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] - stp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] - stp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] - stp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] -- str xzr, [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS] -+ str xzr, [X29, #OFFSET_RV + DL_OFFSET_RV_VPCS] - - /* Setup call to pltexit */ - ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0] -@@ -315,7 +314,6 @@ _dl_runtime_profile: - ldp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] - ldp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] - ldp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] -- ldr x8, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4] - ldp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] - ldp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] - ldp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] -diff --git a/sysdeps/aarch64/memchr.S b/sysdeps/aarch64/memchr.S -index 2053a977b6..79aa910da4 100644 ---- a/sysdeps/aarch64/memchr.S -+++ b/sysdeps/aarch64/memchr.S -@@ -30,7 +30,6 @@ - # define MEMCHR __memchr - #endif - --/* Arguments and results. */ - #define srcin x0 - #define chrin w1 - #define cntin x2 -@@ -73,42 +72,44 @@ ENTRY (MEMCHR) - - rbit synd, synd - clz synd, synd -- add result, srcin, synd, lsr 2 - cmp cntin, synd, lsr 2 -+ add result, srcin, synd, lsr 2 - csel result, result, xzr, hi - ret - -+ .p2align 3 - L(start_loop): - sub tmp, src, srcin -- add tmp, tmp, 16 -+ add tmp, tmp, 17 - subs cntrem, cntin, tmp -- b.ls L(nomatch) -+ b.lo L(nomatch) - - /* Make sure that it won't overread by a 16-byte chunk */ -- add tmp, cntrem, 15 -- tbnz tmp, 4, L(loop32_2) -- -+ tbz cntrem, 4, L(loop32_2) -+ sub src, src, 16 - .p2align 4 - L(loop32): -- ldr qdata, [src, 16]! -+ ldr qdata, [src, 32]! - cmeq vhas_chr.16b, vdata.16b, vrepchr.16b - umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ - fmov synd, dend - cbnz synd, L(end) - - L(loop32_2): -- ldr qdata, [src, 16]! -- subs cntrem, cntrem, 32 -+ ldr qdata, [src, 16] - cmeq vhas_chr.16b, vdata.16b, vrepchr.16b -- b.ls L(end) -+ subs cntrem, cntrem, 32 -+ b.lo L(end_2) - umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ - fmov synd, dend - cbz synd, L(loop32) -+L(end_2): -+ add src, src, 16 - L(end): - shrn vend.8b, vhas_chr.8h, 4 /* 128->64 */ -+ sub cntrem, src, srcin - fmov synd, dend -- add tmp, srcin, cntin -- sub cntrem, tmp, src -+ sub cntrem, cntin, cntrem - #ifndef __AARCH64EB__ - rbit synd, synd - #endif -diff --git a/sysdeps/aarch64/memcpy.S b/sysdeps/aarch64/memcpy.S -index 98d4e2c0e2..7b396b202f 100644 ---- a/sysdeps/aarch64/memcpy.S -+++ b/sysdeps/aarch64/memcpy.S -@@ -1,4 +1,5 @@ --/* Copyright (C) 2012-2022 Free Software Foundation, Inc. -+/* Generic optimized memcpy using SIMD. -+ Copyright (C) 2012-2022 Free Software Foundation, Inc. - - This file is part of the GNU C Library. - -@@ -20,7 +21,7 @@ - - /* Assumptions: - * -- * ARMv8-a, AArch64, unaligned accesses. -+ * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses. - * - */ - -@@ -36,21 +37,18 @@ - #define B_l x8 - #define B_lw w8 - #define B_h x9 --#define C_l x10 - #define C_lw w10 --#define C_h x11 --#define D_l x12 --#define D_h x13 --#define E_l x14 --#define E_h x15 --#define F_l x16 --#define F_h x17 --#define G_l count --#define G_h dst --#define H_l src --#define H_h srcend - #define tmp1 x14 - -+#define A_q q0 -+#define B_q q1 -+#define C_q q2 -+#define D_q q3 -+#define E_q q4 -+#define F_q q5 -+#define G_q q6 -+#define H_q q7 -+ - #ifndef MEMMOVE - # define MEMMOVE memmove - #endif -@@ -69,10 +67,9 @@ - Large copies use a software pipelined loop processing 64 bytes per - iteration. The destination pointer is 16-byte aligned to minimize - unaligned accesses. The loop tail is handled by always copying 64 bytes -- from the end. --*/ -+ from the end. */ - --ENTRY_ALIGN (MEMCPY, 6) -+ENTRY (MEMCPY) - PTR_ARG (0) - PTR_ARG (1) - SIZE_ARG (2) -@@ -87,10 +84,10 @@ ENTRY_ALIGN (MEMCPY, 6) - /* Small copies: 0..32 bytes. */ - cmp count, 16 - b.lo L(copy16) -- ldp A_l, A_h, [src] -- ldp D_l, D_h, [srcend, -16] -- stp A_l, A_h, [dstin] -- stp D_l, D_h, [dstend, -16] -+ ldr A_q, [src] -+ ldr B_q, [srcend, -16] -+ str A_q, [dstin] -+ str B_q, [dstend, -16] - ret - - /* Copy 8-15 bytes. */ -@@ -102,7 +99,6 @@ L(copy16): - str A_h, [dstend, -8] - ret - -- .p2align 3 - /* Copy 4-7 bytes. */ - L(copy8): - tbz count, 2, L(copy4) -@@ -128,87 +124,69 @@ L(copy0): - .p2align 4 - /* Medium copies: 33..128 bytes. */ - L(copy32_128): -- ldp A_l, A_h, [src] -- ldp B_l, B_h, [src, 16] -- ldp C_l, C_h, [srcend, -32] -- ldp D_l, D_h, [srcend, -16] -+ ldp A_q, B_q, [src] -+ ldp C_q, D_q, [srcend, -32] - cmp count, 64 - b.hi L(copy128) -- stp A_l, A_h, [dstin] -- stp B_l, B_h, [dstin, 16] -- stp C_l, C_h, [dstend, -32] -- stp D_l, D_h, [dstend, -16] -+ stp A_q, B_q, [dstin] -+ stp C_q, D_q, [dstend, -32] - ret - - .p2align 4 - /* Copy 65..128 bytes. */ - L(copy128): -- ldp E_l, E_h, [src, 32] -- ldp F_l, F_h, [src, 48] -+ ldp E_q, F_q, [src, 32] - cmp count, 96 - b.ls L(copy96) -- ldp G_l, G_h, [srcend, -64] -- ldp H_l, H_h, [srcend, -48] -- stp G_l, G_h, [dstend, -64] -- stp H_l, H_h, [dstend, -48] -+ ldp G_q, H_q, [srcend, -64] -+ stp G_q, H_q, [dstend, -64] - L(copy96): -- stp A_l, A_h, [dstin] -- stp B_l, B_h, [dstin, 16] -- stp E_l, E_h, [dstin, 32] -- stp F_l, F_h, [dstin, 48] -- stp C_l, C_h, [dstend, -32] -- stp D_l, D_h, [dstend, -16] -+ stp A_q, B_q, [dstin] -+ stp E_q, F_q, [dstin, 32] -+ stp C_q, D_q, [dstend, -32] - ret - -- .p2align 4 -+ /* Align loop64 below to 16 bytes. */ -+ nop -+ - /* Copy more than 128 bytes. */ - L(copy_long): -- /* Copy 16 bytes and then align dst to 16-byte alignment. */ -- ldp D_l, D_h, [src] -- and tmp1, dstin, 15 -- bic dst, dstin, 15 -- sub src, src, tmp1 -+ /* Copy 16 bytes and then align src to 16-byte alignment. */ -+ ldr D_q, [src] -+ and tmp1, src, 15 -+ bic src, src, 15 -+ sub dst, dstin, tmp1 - add count, count, tmp1 /* Count is now 16 too large. */ -- ldp A_l, A_h, [src, 16] -- stp D_l, D_h, [dstin] -- ldp B_l, B_h, [src, 32] -- ldp C_l, C_h, [src, 48] -- ldp D_l, D_h, [src, 64]! -+ ldp A_q, B_q, [src, 16] -+ str D_q, [dstin] -+ ldp C_q, D_q, [src, 48] - subs count, count, 128 + 16 /* Test and readjust count. */ - b.ls L(copy64_from_end) -- - L(loop64): -- stp A_l, A_h, [dst, 16] -- ldp A_l, A_h, [src, 16] -- stp B_l, B_h, [dst, 32] -- ldp B_l, B_h, [src, 32] -- stp C_l, C_h, [dst, 48] -- ldp C_l, C_h, [src, 48] -- stp D_l, D_h, [dst, 64]! -- ldp D_l, D_h, [src, 64]! -+ stp A_q, B_q, [dst, 16] -+ ldp A_q, B_q, [src, 80] -+ stp C_q, D_q, [dst, 48] -+ ldp C_q, D_q, [src, 112] -+ add src, src, 64 -+ add dst, dst, 64 - subs count, count, 64 - b.hi L(loop64) - - /* Write the last iteration and copy 64 bytes from the end. */ - L(copy64_from_end): -- ldp E_l, E_h, [srcend, -64] -- stp A_l, A_h, [dst, 16] -- ldp A_l, A_h, [srcend, -48] -- stp B_l, B_h, [dst, 32] -- ldp B_l, B_h, [srcend, -32] -- stp C_l, C_h, [dst, 48] -- ldp C_l, C_h, [srcend, -16] -- stp D_l, D_h, [dst, 64] -- stp E_l, E_h, [dstend, -64] -- stp A_l, A_h, [dstend, -48] -- stp B_l, B_h, [dstend, -32] -- stp C_l, C_h, [dstend, -16] -+ ldp E_q, F_q, [srcend, -64] -+ stp A_q, B_q, [dst, 16] -+ ldp A_q, B_q, [srcend, -32] -+ stp C_q, D_q, [dst, 48] -+ stp E_q, F_q, [dstend, -64] -+ stp A_q, B_q, [dstend, -32] - ret - - END (MEMCPY) - libc_hidden_builtin_def (MEMCPY) - --ENTRY_ALIGN (MEMMOVE, 4) -+ -+ENTRY (MEMMOVE) - PTR_ARG (0) - PTR_ARG (1) - SIZE_ARG (2) -@@ -220,64 +198,56 @@ ENTRY_ALIGN (MEMMOVE, 4) - cmp count, 32 - b.hi L(copy32_128) - -- /* Small copies: 0..32 bytes. */ -+ /* Small moves: 0..32 bytes. */ - cmp count, 16 - b.lo L(copy16) -- ldp A_l, A_h, [src] -- ldp D_l, D_h, [srcend, -16] -- stp A_l, A_h, [dstin] -- stp D_l, D_h, [dstend, -16] -+ ldr A_q, [src] -+ ldr B_q, [srcend, -16] -+ str A_q, [dstin] -+ str B_q, [dstend, -16] - ret - -- .p2align 4 - L(move_long): - /* Only use backward copy if there is an overlap. */ - sub tmp1, dstin, src -- cbz tmp1, L(copy0) -+ cbz tmp1, L(move0) - cmp tmp1, count - b.hs L(copy_long) - - /* Large backwards copy for overlapping copies. -- Copy 16 bytes and then align dst to 16-byte alignment. */ -- ldp D_l, D_h, [srcend, -16] -- and tmp1, dstend, 15 -- sub srcend, srcend, tmp1 -+ Copy 16 bytes and then align srcend to 16-byte alignment. */ -+L(copy_long_backwards): -+ ldr D_q, [srcend, -16] -+ and tmp1, srcend, 15 -+ bic srcend, srcend, 15 - sub count, count, tmp1 -- ldp A_l, A_h, [srcend, -16] -- stp D_l, D_h, [dstend, -16] -- ldp B_l, B_h, [srcend, -32] -- ldp C_l, C_h, [srcend, -48] -- ldp D_l, D_h, [srcend, -64]! -+ ldp A_q, B_q, [srcend, -32] -+ str D_q, [dstend, -16] -+ ldp C_q, D_q, [srcend, -64] - sub dstend, dstend, tmp1 - subs count, count, 128 - b.ls L(copy64_from_start) - - L(loop64_backwards): -- stp A_l, A_h, [dstend, -16] -- ldp A_l, A_h, [srcend, -16] -- stp B_l, B_h, [dstend, -32] -- ldp B_l, B_h, [srcend, -32] -- stp C_l, C_h, [dstend, -48] -- ldp C_l, C_h, [srcend, -48] -- stp D_l, D_h, [dstend, -64]! -- ldp D_l, D_h, [srcend, -64]! -+ str B_q, [dstend, -16] -+ str A_q, [dstend, -32] -+ ldp A_q, B_q, [srcend, -96] -+ str D_q, [dstend, -48] -+ str C_q, [dstend, -64]! -+ ldp C_q, D_q, [srcend, -128] -+ sub srcend, srcend, 64 - subs count, count, 64 - b.hi L(loop64_backwards) - - /* Write the last iteration and copy 64 bytes from the start. */ - L(copy64_from_start): -- ldp G_l, G_h, [src, 48] -- stp A_l, A_h, [dstend, -16] -- ldp A_l, A_h, [src, 32] -- stp B_l, B_h, [dstend, -32] -- ldp B_l, B_h, [src, 16] -- stp C_l, C_h, [dstend, -48] -- ldp C_l, C_h, [src] -- stp D_l, D_h, [dstend, -64] -- stp G_l, G_h, [dstin, 48] -- stp A_l, A_h, [dstin, 32] -- stp B_l, B_h, [dstin, 16] -- stp C_l, C_h, [dstin] -+ ldp E_q, F_q, [src, 32] -+ stp A_q, B_q, [dstend, -32] -+ ldp A_q, B_q, [src] -+ stp C_q, D_q, [dstend, -64] -+ stp E_q, F_q, [dstin, 32] -+ stp A_q, B_q, [dstin] -+L(move0): - ret - - END (MEMMOVE) -diff --git a/sysdeps/aarch64/memrchr.S b/sysdeps/aarch64/memrchr.S -index 5179320720..428af51f70 100644 ---- a/sysdeps/aarch64/memrchr.S -+++ b/sysdeps/aarch64/memrchr.S -@@ -26,7 +26,6 @@ - * MTE compatible. - */ - --/* Arguments and results. */ - #define srcin x0 - #define chrin w1 - #define cntin x2 -@@ -77,31 +76,34 @@ ENTRY (__memrchr) - csel result, result, xzr, hi - ret - -+ nop - L(start_loop): -- sub tmp, end, src -- subs cntrem, cntin, tmp -+ subs cntrem, src, srcin - b.ls L(nomatch) - - /* Make sure that it won't overread by a 16-byte chunk */ -- add tmp, cntrem, 15 -- tbnz tmp, 4, L(loop32_2) -+ sub cntrem, cntrem, 1 -+ tbz cntrem, 4, L(loop32_2) -+ add src, src, 16 - -- .p2align 4 -+ .p2align 5 - L(loop32): -- ldr qdata, [src, -16]! -+ ldr qdata, [src, -32]! - cmeq vhas_chr.16b, vdata.16b, vrepchr.16b - umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ - fmov synd, dend - cbnz synd, L(end) - - L(loop32_2): -- ldr qdata, [src, -16]! -+ ldr qdata, [src, -16] - subs cntrem, cntrem, 32 - cmeq vhas_chr.16b, vdata.16b, vrepchr.16b -- b.ls L(end) -+ b.lo L(end_2) - umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ - fmov synd, dend - cbz synd, L(loop32) -+L(end_2): -+ sub src, src, 16 - L(end): - shrn vend.8b, vhas_chr.8h, 4 /* 128->64 */ - fmov synd, dend -diff --git a/sysdeps/aarch64/memset.S b/sysdeps/aarch64/memset.S -index 957996bd19..b76d1c3e5e 100644 ---- a/sysdeps/aarch64/memset.S -+++ b/sysdeps/aarch64/memset.S -@@ -29,7 +29,7 @@ - * - */ - --ENTRY_ALIGN (MEMSET, 6) -+ENTRY (MEMSET) - - PTR_ARG (0) - SIZE_ARG (2) -@@ -101,19 +101,19 @@ L(tail64): - ret - - L(try_zva): --#ifdef ZVA_MACRO -- zva_macro --#else -+#ifndef ZVA64_ONLY - .p2align 3 - mrs tmp1, dczid_el0 - tbnz tmp1w, 4, L(no_zva) - and tmp1w, tmp1w, 15 - cmp tmp1w, 4 /* ZVA size is 64 bytes. */ - b.ne L(zva_128) -- -+ nop -+#endif - /* Write the first and last 64 byte aligned block using stp rather - than using DC ZVA. This is faster on some cores. - */ -+ .p2align 4 - L(zva_64): - str q0, [dst, 16] - stp q0, q0, [dst, 32] -@@ -123,7 +123,6 @@ L(zva_64): - sub count, dstend, dst /* Count is now 128 too large. */ - sub count, count, 128+64+64 /* Adjust count and bias for loop. */ - add dst, dst, 128 -- nop - 1: dc zva, dst - add dst, dst, 64 - subs count, count, 64 -@@ -134,6 +133,7 @@ L(zva_64): - stp q0, q0, [dstend, -32] - ret - -+#ifndef ZVA64_ONLY - .p2align 3 - L(zva_128): - cmp tmp1w, 5 /* ZVA size is 128 bytes. */ -diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile -index 16297192ee..e4720b7468 100644 ---- a/sysdeps/aarch64/multiarch/Makefile -+++ b/sysdeps/aarch64/multiarch/Makefile -@@ -3,18 +3,19 @@ sysdep_routines += \ - memchr_generic \ - memchr_nosimd \ - memcpy_a64fx \ -- memcpy_advsimd \ -- memcpy_falkor \ - memcpy_generic \ -+ memcpy_mops \ - memcpy_sve \ - memcpy_thunderx \ - memcpy_thunderx2 \ -+ memmove_mops \ - memset_a64fx \ - memset_emag \ -- memset_falkor \ - memset_generic \ - memset_kunpeng \ -+ memset_mops \ -+ memset_zva64 \ - strlen_asimd \ -- strlen_mte \ -+ strlen_generic \ - # sysdep_routines - endif -diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c -index 4144615ab2..1c712ce913 100644 ---- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c -+++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c -@@ -36,32 +36,29 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - IFUNC_IMPL (i, name, memcpy, - IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx) - IFUNC_IMPL_ADD (array, i, memcpy, !bti, __memcpy_thunderx2) -- IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_falkor) -- IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_simd) - #if HAVE_AARCH64_SVE_ASM - IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_a64fx) - IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_sve) - #endif -+ IFUNC_IMPL_ADD (array, i, memcpy, mops, __memcpy_mops) - IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic)) - IFUNC_IMPL (i, name, memmove, - IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx) - IFUNC_IMPL_ADD (array, i, memmove, !bti, __memmove_thunderx2) -- IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor) -- IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_simd) - #if HAVE_AARCH64_SVE_ASM - IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_a64fx) - IFUNC_IMPL_ADD (array, i, memmove, sve, __memmove_sve) - #endif -+ IFUNC_IMPL_ADD (array, i, memmove, mops, __memmove_mops) - IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic)) - IFUNC_IMPL (i, name, memset, -- /* Enable this on non-falkor processors too so that other cores -- can do a comparative analysis with __memset_generic. */ -- IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_falkor) -- IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_emag) -+ IFUNC_IMPL_ADD (array, i, memset, (zva_size == 64), __memset_zva64) -+ IFUNC_IMPL_ADD (array, i, memset, 1, __memset_emag) - IFUNC_IMPL_ADD (array, i, memset, 1, __memset_kunpeng) - #if HAVE_AARCH64_SVE_ASM -- IFUNC_IMPL_ADD (array, i, memset, sve, __memset_a64fx) -+ IFUNC_IMPL_ADD (array, i, memset, sve && zva_size == 256, __memset_a64fx) - #endif -+ IFUNC_IMPL_ADD (array, i, memset, mops, __memset_mops) - IFUNC_IMPL_ADD (array, i, memset, 1, __memset_generic)) - IFUNC_IMPL (i, name, memchr, - IFUNC_IMPL_ADD (array, i, memchr, !mte, __memchr_nosimd) -@@ -69,7 +66,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - - IFUNC_IMPL (i, name, strlen, - IFUNC_IMPL_ADD (array, i, strlen, !mte, __strlen_asimd) -- IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_mte)) -+ IFUNC_IMPL_ADD (array, i, strlen, 1, __strlen_generic)) - - return 0; - } -diff --git a/sysdeps/aarch64/multiarch/init-arch.h b/sysdeps/aarch64/multiarch/init-arch.h -index a4dcac0019..5b2cf5cb12 100644 ---- a/sysdeps/aarch64/multiarch/init-arch.h -+++ b/sysdeps/aarch64/multiarch/init-arch.h -@@ -35,4 +35,8 @@ - bool __attribute__((unused)) mte = \ - MTE_ENABLED (); \ - bool __attribute__((unused)) sve = \ -- GLRO(dl_aarch64_cpu_features).sve; -+ GLRO(dl_aarch64_cpu_features).sve; \ -+ bool __attribute__((unused)) prefer_sve_ifuncs = \ -+ GLRO(dl_aarch64_cpu_features).prefer_sve_ifuncs; \ -+ bool __attribute__((unused)) mops = \ -+ GLRO(dl_aarch64_cpu_features).mops; -diff --git a/sysdeps/aarch64/multiarch/memchr_nosimd.S b/sysdeps/aarch64/multiarch/memchr_nosimd.S -index ddf7533943..e39f39e6b3 100644 ---- a/sysdeps/aarch64/multiarch/memchr_nosimd.S -+++ b/sysdeps/aarch64/multiarch/memchr_nosimd.S -@@ -26,10 +26,6 @@ - * Use base integer registers. - */ - --#ifndef MEMCHR --# define MEMCHR __memchr_nosimd --#endif -- - /* Arguments and results. */ - #define srcin x0 - #define chrin x1 -@@ -62,7 +58,7 @@ - #define REP8_7f 0x7f7f7f7f7f7f7f7f - - --ENTRY_ALIGN (MEMCHR, 6) -+ENTRY (__memchr_nosimd) - - PTR_ARG (0) - SIZE_ARG (2) -@@ -219,5 +215,4 @@ L(none_chr): - mov result, 0 - ret - --END (MEMCHR) --libc_hidden_builtin_def (MEMCHR) -+END (__memchr_nosimd) -diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c -index 0486213f08..3de66c14d4 100644 ---- a/sysdeps/aarch64/multiarch/memcpy.c -+++ b/sysdeps/aarch64/multiarch/memcpy.c -@@ -29,26 +29,25 @@ - extern __typeof (__redirect_memcpy) __libc_memcpy; - - extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden; --extern __typeof (__redirect_memcpy) __memcpy_simd attribute_hidden; - extern __typeof (__redirect_memcpy) __memcpy_thunderx attribute_hidden; - extern __typeof (__redirect_memcpy) __memcpy_thunderx2 attribute_hidden; --extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden; - extern __typeof (__redirect_memcpy) __memcpy_a64fx attribute_hidden; - extern __typeof (__redirect_memcpy) __memcpy_sve attribute_hidden; -+extern __typeof (__redirect_memcpy) __memcpy_mops attribute_hidden; - - static inline __typeof (__redirect_memcpy) * - select_memcpy_ifunc (void) - { - INIT_ARCH (); - -- if (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr)) -- return __memcpy_simd; -+ if (mops) -+ return __memcpy_mops; - - if (sve && HAVE_AARCH64_SVE_ASM) - { - if (IS_A64FX (midr)) - return __memcpy_a64fx; -- return __memcpy_sve; -+ return prefer_sve_ifuncs ? __memcpy_sve : __memcpy_generic; - } - - if (IS_THUNDERX (midr)) -@@ -57,9 +56,6 @@ select_memcpy_ifunc (void) - if (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)) - return __memcpy_thunderx2; - -- if (IS_FALKOR (midr) || IS_PHECDA (midr)) -- return __memcpy_falkor; -- - return __memcpy_generic; - } - -diff --git a/sysdeps/aarch64/multiarch/memcpy_a64fx.S b/sysdeps/aarch64/multiarch/memcpy_a64fx.S -index c4eab06176..c254dc8b9f 100644 ---- a/sysdeps/aarch64/multiarch/memcpy_a64fx.S -+++ b/sysdeps/aarch64/multiarch/memcpy_a64fx.S -@@ -39,9 +39,6 @@ - #define vlen8 x8 - - #if HAVE_AARCH64_SVE_ASM --# if IS_IN (libc) --# define MEMCPY __memcpy_a64fx --# define MEMMOVE __memmove_a64fx - - .arch armv8.2-a+sve - -@@ -97,7 +94,7 @@ - #undef BTI_C - #define BTI_C - --ENTRY (MEMCPY) -+ENTRY (__memcpy_a64fx) - - PTR_ARG (0) - PTR_ARG (1) -@@ -234,11 +231,10 @@ L(last_bytes): - st1b z3.b, p0, [dstend, -1, mul vl] - ret - --END (MEMCPY) --libc_hidden_builtin_def (MEMCPY) -+END (__memcpy_a64fx) - - --ENTRY_ALIGN (MEMMOVE, 4) -+ENTRY_ALIGN (__memmove_a64fx, 4) - - PTR_ARG (0) - PTR_ARG (1) -@@ -307,7 +303,5 @@ L(full_overlap): - mov dst, dstin - b L(last_bytes) - --END (MEMMOVE) --libc_hidden_builtin_def (MEMMOVE) --# endif /* IS_IN (libc) */ -+END (__memmove_a64fx) - #endif /* HAVE_AARCH64_SVE_ASM */ -diff --git a/sysdeps/aarch64/multiarch/memcpy_advsimd.S b/sysdeps/aarch64/multiarch/memcpy_advsimd.S -deleted file mode 100644 -index fe9beaf5ea..0000000000 ---- a/sysdeps/aarch64/multiarch/memcpy_advsimd.S -+++ /dev/null -@@ -1,248 +0,0 @@ --/* Generic optimized memcpy using SIMD. -- Copyright (C) 2020-2022 Free Software Foundation, Inc. -- -- This file is part of the GNU C Library. -- -- The GNU C Library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- The GNU C Library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with the GNU C Library. If not, see -- . */ -- --#include -- --/* Assumptions: -- * -- * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses. -- * -- */ -- --#define dstin x0 --#define src x1 --#define count x2 --#define dst x3 --#define srcend x4 --#define dstend x5 --#define A_l x6 --#define A_lw w6 --#define A_h x7 --#define B_l x8 --#define B_lw w8 --#define B_h x9 --#define C_lw w10 --#define tmp1 x14 -- --#define A_q q0 --#define B_q q1 --#define C_q q2 --#define D_q q3 --#define E_q q4 --#define F_q q5 --#define G_q q6 --#define H_q q7 -- -- --/* This implementation supports both memcpy and memmove and shares most code. -- It uses unaligned accesses and branchless sequences to keep the code small, -- simple and improve performance. -- -- Copies are split into 3 main cases: small copies of up to 32 bytes, medium -- copies of up to 128 bytes, and large copies. The overhead of the overlap -- check in memmove is negligible since it is only required for large copies. -- -- Large copies use a software pipelined loop processing 64 bytes per -- iteration. The destination pointer is 16-byte aligned to minimize -- unaligned accesses. The loop tail is handled by always copying 64 bytes -- from the end. */ -- --ENTRY (__memcpy_simd) -- PTR_ARG (0) -- PTR_ARG (1) -- SIZE_ARG (2) -- -- add srcend, src, count -- add dstend, dstin, count -- cmp count, 128 -- b.hi L(copy_long) -- cmp count, 32 -- b.hi L(copy32_128) -- -- /* Small copies: 0..32 bytes. */ -- cmp count, 16 -- b.lo L(copy16) -- ldr A_q, [src] -- ldr B_q, [srcend, -16] -- str A_q, [dstin] -- str B_q, [dstend, -16] -- ret -- -- /* Copy 8-15 bytes. */ --L(copy16): -- tbz count, 3, L(copy8) -- ldr A_l, [src] -- ldr A_h, [srcend, -8] -- str A_l, [dstin] -- str A_h, [dstend, -8] -- ret -- -- /* Copy 4-7 bytes. */ --L(copy8): -- tbz count, 2, L(copy4) -- ldr A_lw, [src] -- ldr B_lw, [srcend, -4] -- str A_lw, [dstin] -- str B_lw, [dstend, -4] -- ret -- -- /* Copy 0..3 bytes using a branchless sequence. */ --L(copy4): -- cbz count, L(copy0) -- lsr tmp1, count, 1 -- ldrb A_lw, [src] -- ldrb C_lw, [srcend, -1] -- ldrb B_lw, [src, tmp1] -- strb A_lw, [dstin] -- strb B_lw, [dstin, tmp1] -- strb C_lw, [dstend, -1] --L(copy0): -- ret -- -- .p2align 4 -- /* Medium copies: 33..128 bytes. */ --L(copy32_128): -- ldp A_q, B_q, [src] -- ldp C_q, D_q, [srcend, -32] -- cmp count, 64 -- b.hi L(copy128) -- stp A_q, B_q, [dstin] -- stp C_q, D_q, [dstend, -32] -- ret -- -- .p2align 4 -- /* Copy 65..128 bytes. */ --L(copy128): -- ldp E_q, F_q, [src, 32] -- cmp count, 96 -- b.ls L(copy96) -- ldp G_q, H_q, [srcend, -64] -- stp G_q, H_q, [dstend, -64] --L(copy96): -- stp A_q, B_q, [dstin] -- stp E_q, F_q, [dstin, 32] -- stp C_q, D_q, [dstend, -32] -- ret -- -- /* Align loop64 below to 16 bytes. */ -- nop -- -- /* Copy more than 128 bytes. */ --L(copy_long): -- /* Copy 16 bytes and then align src to 16-byte alignment. */ -- ldr D_q, [src] -- and tmp1, src, 15 -- bic src, src, 15 -- sub dst, dstin, tmp1 -- add count, count, tmp1 /* Count is now 16 too large. */ -- ldp A_q, B_q, [src, 16] -- str D_q, [dstin] -- ldp C_q, D_q, [src, 48] -- subs count, count, 128 + 16 /* Test and readjust count. */ -- b.ls L(copy64_from_end) --L(loop64): -- stp A_q, B_q, [dst, 16] -- ldp A_q, B_q, [src, 80] -- stp C_q, D_q, [dst, 48] -- ldp C_q, D_q, [src, 112] -- add src, src, 64 -- add dst, dst, 64 -- subs count, count, 64 -- b.hi L(loop64) -- -- /* Write the last iteration and copy 64 bytes from the end. */ --L(copy64_from_end): -- ldp E_q, F_q, [srcend, -64] -- stp A_q, B_q, [dst, 16] -- ldp A_q, B_q, [srcend, -32] -- stp C_q, D_q, [dst, 48] -- stp E_q, F_q, [dstend, -64] -- stp A_q, B_q, [dstend, -32] -- ret -- --END (__memcpy_simd) --libc_hidden_builtin_def (__memcpy_simd) -- -- --ENTRY (__memmove_simd) -- PTR_ARG (0) -- PTR_ARG (1) -- SIZE_ARG (2) -- -- add srcend, src, count -- add dstend, dstin, count -- cmp count, 128 -- b.hi L(move_long) -- cmp count, 32 -- b.hi L(copy32_128) -- -- /* Small moves: 0..32 bytes. */ -- cmp count, 16 -- b.lo L(copy16) -- ldr A_q, [src] -- ldr B_q, [srcend, -16] -- str A_q, [dstin] -- str B_q, [dstend, -16] -- ret -- --L(move_long): -- /* Only use backward copy if there is an overlap. */ -- sub tmp1, dstin, src -- cbz tmp1, L(move0) -- cmp tmp1, count -- b.hs L(copy_long) -- -- /* Large backwards copy for overlapping copies. -- Copy 16 bytes and then align srcend to 16-byte alignment. */ --L(copy_long_backwards): -- ldr D_q, [srcend, -16] -- and tmp1, srcend, 15 -- bic srcend, srcend, 15 -- sub count, count, tmp1 -- ldp A_q, B_q, [srcend, -32] -- str D_q, [dstend, -16] -- ldp C_q, D_q, [srcend, -64] -- sub dstend, dstend, tmp1 -- subs count, count, 128 -- b.ls L(copy64_from_start) -- --L(loop64_backwards): -- str B_q, [dstend, -16] -- str A_q, [dstend, -32] -- ldp A_q, B_q, [srcend, -96] -- str D_q, [dstend, -48] -- str C_q, [dstend, -64]! -- ldp C_q, D_q, [srcend, -128] -- sub srcend, srcend, 64 -- subs count, count, 64 -- b.hi L(loop64_backwards) -- -- /* Write the last iteration and copy 64 bytes from the start. */ --L(copy64_from_start): -- ldp E_q, F_q, [src, 32] -- stp A_q, B_q, [dstend, -32] -- ldp A_q, B_q, [src] -- stp C_q, D_q, [dstend, -64] -- stp E_q, F_q, [dstin, 32] -- stp A_q, B_q, [dstin] --L(move0): -- ret -- --END (__memmove_simd) --libc_hidden_builtin_def (__memmove_simd) -diff --git a/sysdeps/aarch64/multiarch/memcpy_falkor.S b/sysdeps/aarch64/multiarch/memcpy_falkor.S -deleted file mode 100644 -index 117edd9cfc..0000000000 ---- a/sysdeps/aarch64/multiarch/memcpy_falkor.S -+++ /dev/null -@@ -1,315 +0,0 @@ --/* Optimized memcpy for Qualcomm Falkor processor. -- Copyright (C) 2017-2022 Free Software Foundation, Inc. -- -- This file is part of the GNU C Library. -- -- The GNU C Library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- The GNU C Library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with the GNU C Library. If not, see -- . */ -- --#include -- --/* Assumptions: -- -- ARMv8-a, AArch64, falkor, unaligned accesses. */ -- --#define dstin x0 --#define src x1 --#define count x2 --#define dst x3 --#define srcend x4 --#define dstend x5 --#define tmp1 x14 --#define A_x x6 --#define B_x x7 --#define A_w w6 --#define B_w w7 -- --#define A_q q0 --#define B_q q1 --#define C_q q2 --#define D_q q3 --#define E_q q4 --#define F_q q5 --#define G_q q6 --#define H_q q7 --#define Q_q q6 --#define S_q q22 -- --/* Copies are split into 3 main cases: -- -- 1. Small copies of up to 32 bytes -- 2. Medium copies of 33..128 bytes which are fully unrolled -- 3. Large copies of more than 128 bytes. -- -- Large copies align the source to a quad word and use an unrolled loop -- processing 64 bytes per iteration. -- -- FALKOR-SPECIFIC DESIGN: -- -- The smallest copies (32 bytes or less) focus on optimal pipeline usage, -- which is why the redundant copies of 0-3 bytes have been replaced with -- conditionals, since the former would unnecessarily break across multiple -- issue groups. The medium copy group has been enlarged to 128 bytes since -- bumping up the small copies up to 32 bytes allows us to do that without -- cost and also allows us to reduce the size of the prep code before loop64. -- -- The copy loop uses only one register q0. This is to ensure that all loads -- hit a single hardware prefetcher which can get correctly trained to prefetch -- a single stream. -- -- The non-temporal stores help optimize cache utilization. */ -- --#if IS_IN (libc) --ENTRY_ALIGN (__memcpy_falkor, 6) -- -- PTR_ARG (0) -- PTR_ARG (1) -- SIZE_ARG (2) -- -- cmp count, 32 -- add srcend, src, count -- add dstend, dstin, count -- b.ls L(copy32) -- cmp count, 128 -- b.hi L(copy_long) -- -- /* Medium copies: 33..128 bytes. */ --L(copy128): -- sub tmp1, count, 1 -- ldr A_q, [src] -- ldr B_q, [src, 16] -- ldr C_q, [srcend, -32] -- ldr D_q, [srcend, -16] -- tbz tmp1, 6, 1f -- ldr E_q, [src, 32] -- ldr F_q, [src, 48] -- ldr G_q, [srcend, -64] -- ldr H_q, [srcend, -48] -- str G_q, [dstend, -64] -- str H_q, [dstend, -48] -- str E_q, [dstin, 32] -- str F_q, [dstin, 48] --1: -- str A_q, [dstin] -- str B_q, [dstin, 16] -- str C_q, [dstend, -32] -- str D_q, [dstend, -16] -- ret -- -- .p2align 4 -- /* Small copies: 0..32 bytes. */ --L(copy32): -- /* 16-32 */ -- cmp count, 16 -- b.lo 1f -- ldr A_q, [src] -- ldr B_q, [srcend, -16] -- str A_q, [dstin] -- str B_q, [dstend, -16] -- ret -- .p2align 4 --1: -- /* 8-15 */ -- tbz count, 3, 1f -- ldr A_x, [src] -- ldr B_x, [srcend, -8] -- str A_x, [dstin] -- str B_x, [dstend, -8] -- ret -- .p2align 4 --1: -- /* 4-7 */ -- tbz count, 2, 1f -- ldr A_w, [src] -- ldr B_w, [srcend, -4] -- str A_w, [dstin] -- str B_w, [dstend, -4] -- ret -- .p2align 4 --1: -- /* 2-3 */ -- tbz count, 1, 1f -- ldrh A_w, [src] -- ldrh B_w, [srcend, -2] -- strh A_w, [dstin] -- strh B_w, [dstend, -2] -- ret -- .p2align 4 --1: -- /* 0-1 */ -- tbz count, 0, 1f -- ldrb A_w, [src] -- strb A_w, [dstin] --1: -- ret -- -- /* Align SRC to 16 bytes and copy; that way at least one of the -- accesses is aligned throughout the copy sequence. -- -- The count is off by 0 to 15 bytes, but this is OK because we trim -- off the last 64 bytes to copy off from the end. Due to this the -- loop never runs out of bounds. */ -- -- .p2align 4 -- nop /* Align loop64 below. */ --L(copy_long): -- ldr A_q, [src] -- sub count, count, 64 + 16 -- and tmp1, src, 15 -- str A_q, [dstin] -- bic src, src, 15 -- sub dst, dstin, tmp1 -- add count, count, tmp1 -- --L(loop64): -- ldr A_q, [src, 16]! -- str A_q, [dst, 16] -- ldr A_q, [src, 16]! -- subs count, count, 64 -- str A_q, [dst, 32] -- ldr A_q, [src, 16]! -- str A_q, [dst, 48] -- ldr A_q, [src, 16]! -- str A_q, [dst, 64]! -- b.hi L(loop64) -- -- /* Write the last full set of 64 bytes. The remainder is at most 64 -- bytes, so it is safe to always copy 64 bytes from the end even if -- there is just 1 byte left. */ -- ldr E_q, [srcend, -64] -- str E_q, [dstend, -64] -- ldr D_q, [srcend, -48] -- str D_q, [dstend, -48] -- ldr C_q, [srcend, -32] -- str C_q, [dstend, -32] -- ldr B_q, [srcend, -16] -- str B_q, [dstend, -16] -- ret -- --END (__memcpy_falkor) --libc_hidden_builtin_def (__memcpy_falkor) -- -- --/* RATIONALE: -- -- The move has 4 distinct parts: -- * Small moves of 32 bytes and under. -- * Medium sized moves of 33-128 bytes (fully unrolled). -- * Large moves where the source address is higher than the destination -- (forward copies) -- * Large moves where the destination address is higher than the source -- (copy backward, or move). -- -- We use only two registers q6 and q22 for the moves and move 32 bytes at a -- time to correctly train the hardware prefetcher for better throughput. -- -- For small and medium cases memcpy is used. */ -- --ENTRY_ALIGN (__memmove_falkor, 6) -- -- PTR_ARG (0) -- PTR_ARG (1) -- SIZE_ARG (2) -- -- cmp count, 32 -- add srcend, src, count -- add dstend, dstin, count -- b.ls L(copy32) -- cmp count, 128 -- b.ls L(copy128) -- sub tmp1, dstin, src -- ccmp tmp1, count, 2, hi -- b.lo L(move_long) -- -- /* CASE: Copy Forwards -- -- Align src to 16 byte alignment so that we don't cross cache line -- boundaries on both loads and stores. There are at least 128 bytes -- to copy, so copy 16 bytes unaligned and then align. The loop -- copies 32 bytes per iteration and prefetches one iteration ahead. */ -- -- ldr S_q, [src] -- and tmp1, src, 15 -- bic src, src, 15 -- sub dst, dstin, tmp1 -- add count, count, tmp1 /* Count is now 16 too large. */ -- ldr Q_q, [src, 16]! -- str S_q, [dstin] -- ldr S_q, [src, 16]! -- sub count, count, 32 + 32 + 16 /* Test and readjust count. */ -- -- .p2align 4 --1: -- subs count, count, 32 -- str Q_q, [dst, 16] -- ldr Q_q, [src, 16]! -- str S_q, [dst, 32]! -- ldr S_q, [src, 16]! -- b.hi 1b -- -- /* Copy 32 bytes from the end before writing the data prefetched in the -- last loop iteration. */ --2: -- ldr B_q, [srcend, -32] -- ldr C_q, [srcend, -16] -- str Q_q, [dst, 16] -- str S_q, [dst, 32] -- str B_q, [dstend, -32] -- str C_q, [dstend, -16] -- ret -- -- /* CASE: Copy Backwards -- -- Align srcend to 16 byte alignment so that we don't cross cache line -- boundaries on both loads and stores. There are at least 128 bytes -- to copy, so copy 16 bytes unaligned and then align. The loop -- copies 32 bytes per iteration and prefetches one iteration ahead. */ -- -- .p2align 4 -- nop -- nop --L(move_long): -- cbz tmp1, 3f /* Return early if src == dstin */ -- ldr S_q, [srcend, -16] -- and tmp1, srcend, 15 -- sub srcend, srcend, tmp1 -- ldr Q_q, [srcend, -16]! -- str S_q, [dstend, -16] -- sub count, count, tmp1 -- ldr S_q, [srcend, -16]! -- sub dstend, dstend, tmp1 -- sub count, count, 32 + 32 -- --1: -- subs count, count, 32 -- str Q_q, [dstend, -16] -- ldr Q_q, [srcend, -16]! -- str S_q, [dstend, -32]! -- ldr S_q, [srcend, -16]! -- b.hi 1b -- -- /* Copy 32 bytes from the start before writing the data prefetched in the -- last loop iteration. */ -- -- ldr B_q, [src, 16] -- ldr C_q, [src] -- str Q_q, [dstend, -16] -- str S_q, [dstend, -32] -- str B_q, [dstin, 16] -- str C_q, [dstin] --3: ret -- --END (__memmove_falkor) --libc_hidden_builtin_def (__memmove_falkor) --#endif -diff --git a/sysdeps/aarch64/multiarch/memcpy_mops.S b/sysdeps/aarch64/multiarch/memcpy_mops.S -new file mode 100644 -index 0000000000..4685629664 ---- /dev/null -+++ b/sysdeps/aarch64/multiarch/memcpy_mops.S -@@ -0,0 +1,39 @@ -+/* Optimized memcpy for MOPS. -+ Copyright (C) 2023 Free Software Foundation, Inc. -+ -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#include -+ -+/* Assumptions: -+ * -+ * AArch64, MOPS. -+ * -+ */ -+ -+ENTRY (__memcpy_mops) -+ PTR_ARG (0) -+ PTR_ARG (1) -+ SIZE_ARG (2) -+ -+ mov x3, x0 -+ .inst 0x19010443 /* cpyfp [x3]!, [x1]!, x2! */ -+ .inst 0x19410443 /* cpyfm [x3]!, [x1]!, x2! */ -+ .inst 0x19810443 /* cpyfe [x3]!, [x1]!, x2! */ -+ ret -+ -+END (__memcpy_mops) -diff --git a/sysdeps/aarch64/multiarch/memcpy_sve.S b/sysdeps/aarch64/multiarch/memcpy_sve.S -index a70907ec55..71d2f84f63 100644 ---- a/sysdeps/aarch64/multiarch/memcpy_sve.S -+++ b/sysdeps/aarch64/multiarch/memcpy_sve.S -@@ -67,14 +67,15 @@ ENTRY (__memcpy_sve) - - cmp count, 128 - b.hi L(copy_long) -- cmp count, 32 -+ cntb vlen -+ cmp count, vlen, lsl 1 - b.hi L(copy32_128) -- - whilelo p0.b, xzr, count -- cntb vlen -- tbnz vlen, 4, L(vlen128) -- ld1b z0.b, p0/z, [src] -- st1b z0.b, p0, [dstin] -+ whilelo p1.b, vlen, count -+ ld1b z0.b, p0/z, [src, 0, mul vl] -+ ld1b z1.b, p1/z, [src, 1, mul vl] -+ st1b z0.b, p0, [dstin, 0, mul vl] -+ st1b z1.b, p1, [dstin, 1, mul vl] - ret - - /* Medium copies: 33..128 bytes. */ -@@ -102,14 +103,6 @@ L(copy96): - stp C_q, D_q, [dstend, -32] - ret - --L(vlen128): -- whilelo p1.b, vlen, count -- ld1b z0.b, p0/z, [src, 0, mul vl] -- ld1b z1.b, p1/z, [src, 1, mul vl] -- st1b z0.b, p0, [dstin, 0, mul vl] -- st1b z1.b, p1, [dstin, 1, mul vl] -- ret -- - .p2align 4 - /* Copy more than 128 bytes. */ - L(copy_long): -@@ -148,7 +141,6 @@ L(copy64_from_end): - ret - - END (__memcpy_sve) --libc_hidden_builtin_def (__memcpy_sve) - - - ENTRY (__memmove_sve) -@@ -158,14 +150,15 @@ ENTRY (__memmove_sve) - - cmp count, 128 - b.hi L(move_long) -- cmp count, 32 -+ cntb vlen -+ cmp count, vlen, lsl 1 - b.hi L(copy32_128) -- - whilelo p0.b, xzr, count -- cntb vlen -- tbnz vlen, 4, L(vlen128) -- ld1b z0.b, p0/z, [src] -- st1b z0.b, p0, [dstin] -+ whilelo p1.b, vlen, count -+ ld1b z0.b, p0/z, [src, 0, mul vl] -+ ld1b z1.b, p1/z, [src, 1, mul vl] -+ st1b z0.b, p0, [dstin, 0, mul vl] -+ st1b z1.b, p1, [dstin, 1, mul vl] - ret - - .p2align 4 -@@ -214,5 +207,4 @@ L(return): - ret - - END (__memmove_sve) --libc_hidden_builtin_def (__memmove_sve) - #endif -diff --git a/sysdeps/aarch64/multiarch/memcpy_thunderx.S b/sysdeps/aarch64/multiarch/memcpy_thunderx.S -index 21e703dddd..2fb6be5c78 100644 ---- a/sysdeps/aarch64/multiarch/memcpy_thunderx.S -+++ b/sysdeps/aarch64/multiarch/memcpy_thunderx.S -@@ -65,21 +65,7 @@ - Overlapping large forward memmoves use a loop that copies backwards. - */ - --#ifndef MEMMOVE --# define MEMMOVE memmove --#endif --#ifndef MEMCPY --# define MEMCPY memcpy --#endif -- --#if IS_IN (libc) -- --# undef MEMCPY --# define MEMCPY __memcpy_thunderx --# undef MEMMOVE --# define MEMMOVE __memmove_thunderx -- --ENTRY_ALIGN (MEMMOVE, 6) -+ENTRY (__memmove_thunderx) - - PTR_ARG (0) - PTR_ARG (1) -@@ -91,9 +77,9 @@ ENTRY_ALIGN (MEMMOVE, 6) - b.lo L(move_long) - - /* Common case falls through into memcpy. */ --END (MEMMOVE) --libc_hidden_builtin_def (MEMMOVE) --ENTRY (MEMCPY) -+END (__memmove_thunderx) -+ -+ENTRY (__memcpy_thunderx) - - PTR_ARG (0) - PTR_ARG (1) -@@ -316,7 +302,4 @@ L(move_long): - stp C_l, C_h, [dstin] - 3: ret - --END (MEMCPY) --libc_hidden_builtin_def (MEMCPY) -- --#endif -+END (__memcpy_thunderx) -diff --git a/sysdeps/aarch64/multiarch/memcpy_thunderx2.S b/sysdeps/aarch64/multiarch/memcpy_thunderx2.S -index 5e0a59ee5d..3fceb1036d 100644 ---- a/sysdeps/aarch64/multiarch/memcpy_thunderx2.S -+++ b/sysdeps/aarch64/multiarch/memcpy_thunderx2.S -@@ -75,27 +75,12 @@ - #define I_v v16 - #define J_v v17 - --#ifndef MEMMOVE --# define MEMMOVE memmove --#endif --#ifndef MEMCPY --# define MEMCPY memcpy --#endif -- --#if IS_IN (libc) -- --#undef MEMCPY --#define MEMCPY __memcpy_thunderx2 --#undef MEMMOVE --#define MEMMOVE __memmove_thunderx2 -- -- - /* Overlapping large forward memmoves use a loop that copies backwards. - Otherwise memcpy is used. Small moves branch to memcopy16 directly. - The longer memcpy cases fall through to the memcpy head. - */ - --ENTRY_ALIGN (MEMMOVE, 6) -+ENTRY (__memmove_thunderx2) - - PTR_ARG (0) - PTR_ARG (1) -@@ -109,8 +94,7 @@ ENTRY_ALIGN (MEMMOVE, 6) - ccmp tmp1, count, 2, hi - b.lo L(move_long) - --END (MEMMOVE) --libc_hidden_builtin_def (MEMMOVE) -+END (__memmove_thunderx2) - - - /* Copies are split into 3 main cases: small copies of up to 16 bytes, -@@ -124,8 +108,7 @@ libc_hidden_builtin_def (MEMMOVE) - - #define MEMCPY_PREFETCH_LDR 640 - -- .p2align 4 --ENTRY (MEMCPY) -+ENTRY (__memcpy_thunderx2) - - PTR_ARG (0) - PTR_ARG (1) -@@ -449,7 +432,7 @@ L(move_long): - 3: ret - - --END (MEMCPY) -+END (__memcpy_thunderx2) - .section .rodata - .p2align 4 - -@@ -472,6 +455,3 @@ L(ext_table): - .word L(ext_size_13) -. - .word L(ext_size_14) -. - .word L(ext_size_15) -. -- --libc_hidden_builtin_def (MEMCPY) --#endif -diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c -index 261996ecc4..fdcf418820 100644 ---- a/sysdeps/aarch64/multiarch/memmove.c -+++ b/sysdeps/aarch64/multiarch/memmove.c -@@ -29,26 +29,25 @@ - extern __typeof (__redirect_memmove) __libc_memmove; - - extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden; --extern __typeof (__redirect_memmove) __memmove_simd attribute_hidden; - extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden; - extern __typeof (__redirect_memmove) __memmove_thunderx2 attribute_hidden; --extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden; - extern __typeof (__redirect_memmove) __memmove_a64fx attribute_hidden; - extern __typeof (__redirect_memmove) __memmove_sve attribute_hidden; -+extern __typeof (__redirect_memmove) __memmove_mops attribute_hidden; - - static inline __typeof (__redirect_memmove) * - select_memmove_ifunc (void) - { - INIT_ARCH (); - -- if (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr)) -- return __memmove_simd; -+ if (mops) -+ return __memmove_mops; - - if (sve && HAVE_AARCH64_SVE_ASM) - { - if (IS_A64FX (midr)) - return __memmove_a64fx; -- return __memmove_sve; -+ return prefer_sve_ifuncs ? __memmove_sve : __memmove_generic; - } - - if (IS_THUNDERX (midr)) -@@ -57,9 +56,6 @@ select_memmove_ifunc (void) - if (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)) - return __memmove_thunderx2; - -- if (IS_FALKOR (midr) || IS_PHECDA (midr)) -- return __memmove_falkor; -- - return __memmove_generic; - } - -diff --git a/sysdeps/aarch64/multiarch/memmove_mops.S b/sysdeps/aarch64/multiarch/memmove_mops.S -new file mode 100644 -index 0000000000..c5ea66be3a ---- /dev/null -+++ b/sysdeps/aarch64/multiarch/memmove_mops.S -@@ -0,0 +1,39 @@ -+/* Optimized memmove for MOPS. -+ Copyright (C) 2023 Free Software Foundation, Inc. -+ -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#include -+ -+/* Assumptions: -+ * -+ * AArch64, MOPS. -+ * -+ */ -+ -+ENTRY (__memmove_mops) -+ PTR_ARG (0) -+ PTR_ARG (1) -+ SIZE_ARG (2) -+ -+ mov x3, x0 -+ .inst 0x1d010443 /* cpyp [x3]!, [x1]!, x2! */ -+ .inst 0x1d410443 /* cpym [x3]!, [x1]!, x2! */ -+ .inst 0x1d810443 /* cpye [x3]!, [x1]!, x2! */ -+ ret -+ -+END (__memmove_mops) -diff --git a/sysdeps/aarch64/multiarch/memset.c b/sysdeps/aarch64/multiarch/memset.c -index c4008f346b..9ef9521fa6 100644 ---- a/sysdeps/aarch64/multiarch/memset.c -+++ b/sysdeps/aarch64/multiarch/memset.c -@@ -28,28 +28,40 @@ - - extern __typeof (__redirect_memset) __libc_memset; - --extern __typeof (__redirect_memset) __memset_falkor attribute_hidden; -+extern __typeof (__redirect_memset) __memset_zva64 attribute_hidden; - extern __typeof (__redirect_memset) __memset_emag attribute_hidden; - extern __typeof (__redirect_memset) __memset_kunpeng attribute_hidden; --# if HAVE_AARCH64_SVE_ASM - extern __typeof (__redirect_memset) __memset_a64fx attribute_hidden; --# endif - extern __typeof (__redirect_memset) __memset_generic attribute_hidden; -+extern __typeof (__redirect_memset) __memset_mops attribute_hidden; - --libc_ifunc (__libc_memset, -- IS_KUNPENG920 (midr) -- ?__memset_kunpeng -- : ((IS_FALKOR (midr) || IS_PHECDA (midr)) && zva_size == 64 -- ? __memset_falkor -- : (IS_EMAG (midr) && zva_size == 64 -- ? __memset_emag --# if HAVE_AARCH64_SVE_ASM -- : (IS_A64FX (midr) && sve -- ? __memset_a64fx -- : __memset_generic)))); --# else -- : __memset_generic))); --# endif -+static inline __typeof (__redirect_memset) * -+select_memset_ifunc (void) -+{ -+ INIT_ARCH (); -+ -+ if (mops) -+ return __memset_mops; -+ -+ if (sve && HAVE_AARCH64_SVE_ASM) -+ { -+ if (IS_A64FX (midr) && zva_size == 256) -+ return __memset_a64fx; -+ } -+ -+ if (IS_KUNPENG920 (midr)) -+ return __memset_kunpeng; -+ -+ if (IS_EMAG (midr)) -+ return __memset_emag; -+ -+ if (zva_size == 64) -+ return __memset_zva64; -+ -+ return __memset_generic; -+} -+ -+libc_ifunc (__libc_memset, select_memset_ifunc ()); - - # undef memset - strong_alias (__libc_memset, memset); -diff --git a/sysdeps/aarch64/multiarch/memset_a64fx.S b/sysdeps/aarch64/multiarch/memset_a64fx.S -index dc87190724..4a4d4ed504 100644 ---- a/sysdeps/aarch64/multiarch/memset_a64fx.S -+++ b/sysdeps/aarch64/multiarch/memset_a64fx.S -@@ -33,8 +33,6 @@ - #define vector_length x9 - - #if HAVE_AARCH64_SVE_ASM --# if IS_IN (libc) --# define MEMSET __memset_a64fx - - .arch armv8.2-a+sve - -@@ -49,7 +47,7 @@ - #undef BTI_C - #define BTI_C - --ENTRY (MEMSET) -+ENTRY (__memset_a64fx) - PTR_ARG (0) - SIZE_ARG (2) - -@@ -166,8 +164,6 @@ L(L2): - add count, count, CACHE_LINE_SIZE - b L(last) - --END (MEMSET) --libc_hidden_builtin_def (MEMSET) -+END (__memset_a64fx) - --#endif /* IS_IN (libc) */ - #endif /* HAVE_AARCH64_SVE_ASM */ -diff --git a/sysdeps/aarch64/multiarch/memset_base64.S b/sysdeps/aarch64/multiarch/memset_base64.S -deleted file mode 100644 -index 32d20d739e..0000000000 ---- a/sysdeps/aarch64/multiarch/memset_base64.S -+++ /dev/null -@@ -1,186 +0,0 @@ --/* Copyright (C) 2018-2022 Free Software Foundation, Inc. -- -- This file is part of the GNU C Library. -- -- The GNU C Library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- The GNU C Library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with the GNU C Library. If not, see -- . */ -- --#include --#include "memset-reg.h" -- --#ifndef MEMSET --# define MEMSET __memset_base64 --#endif -- --/* To disable DC ZVA, set this threshold to 0. */ --#ifndef DC_ZVA_THRESHOLD --# define DC_ZVA_THRESHOLD 512 --#endif -- --/* Assumptions: -- * -- * ARMv8-a, AArch64, unaligned accesses -- * -- */ -- --ENTRY_ALIGN (MEMSET, 6) -- -- PTR_ARG (0) -- SIZE_ARG (2) -- -- bfi valw, valw, 8, 8 -- bfi valw, valw, 16, 16 -- bfi val, val, 32, 32 -- -- add dstend, dstin, count -- -- cmp count, 96 -- b.hi L(set_long) -- cmp count, 16 -- b.hs L(set_medium) -- -- /* Set 0..15 bytes. */ -- tbz count, 3, 1f -- str val, [dstin] -- str val, [dstend, -8] -- ret -- -- .p2align 3 --1: tbz count, 2, 2f -- str valw, [dstin] -- str valw, [dstend, -4] -- ret --2: cbz count, 3f -- strb valw, [dstin] -- tbz count, 1, 3f -- strh valw, [dstend, -2] --3: ret -- -- .p2align 3 -- /* Set 16..96 bytes. */ --L(set_medium): -- stp val, val, [dstin] -- tbnz count, 6, L(set96) -- stp val, val, [dstend, -16] -- tbz count, 5, 1f -- stp val, val, [dstin, 16] -- stp val, val, [dstend, -32] --1: ret -- -- .p2align 4 -- /* Set 64..96 bytes. Write 64 bytes from the start and -- 32 bytes from the end. */ --L(set96): -- stp val, val, [dstin, 16] -- stp val, val, [dstin, 32] -- stp val, val, [dstin, 48] -- stp val, val, [dstend, -32] -- stp val, val, [dstend, -16] -- ret -- -- .p2align 4 --L(set_long): -- stp val, val, [dstin] -- bic dst, dstin, 15 --#if DC_ZVA_THRESHOLD -- cmp count, DC_ZVA_THRESHOLD -- ccmp val, 0, 0, cs -- b.eq L(zva_64) --#endif -- /* Small-size or non-zero memset does not use DC ZVA. */ -- sub count, dstend, dst -- -- /* -- * Adjust count and bias for loop. By substracting extra 1 from count, -- * it is easy to use tbz instruction to check whether loop tailing -- * count is less than 33 bytes, so as to bypass 2 unneccesary stps. -- */ -- sub count, count, 64+16+1 -- --#if DC_ZVA_THRESHOLD -- /* Align loop on 16-byte boundary, this might be friendly to i-cache. */ -- nop --#endif -- --1: stp val, val, [dst, 16] -- stp val, val, [dst, 32] -- stp val, val, [dst, 48] -- stp val, val, [dst, 64]! -- subs count, count, 64 -- b.hs 1b -- -- tbz count, 5, 1f /* Remaining count is less than 33 bytes? */ -- stp val, val, [dst, 16] -- stp val, val, [dst, 32] --1: stp val, val, [dstend, -32] -- stp val, val, [dstend, -16] -- ret -- --#if DC_ZVA_THRESHOLD -- .p2align 3 --L(zva_64): -- stp val, val, [dst, 16] -- stp val, val, [dst, 32] -- stp val, val, [dst, 48] -- bic dst, dst, 63 -- -- /* -- * Previous memory writes might cross cache line boundary, and cause -- * cache line partially dirty. Zeroing this kind of cache line using -- * DC ZVA will incur extra cost, for it requires loading untouched -- * part of the line from memory before zeoring. -- * -- * So, write the first 64 byte aligned block using stp to force -- * fully dirty cache line. -- */ -- stp val, val, [dst, 64] -- stp val, val, [dst, 80] -- stp val, val, [dst, 96] -- stp val, val, [dst, 112] -- -- sub count, dstend, dst -- /* -- * Adjust count and bias for loop. By substracting extra 1 from count, -- * it is easy to use tbz instruction to check whether loop tailing -- * count is less than 33 bytes, so as to bypass 2 unneccesary stps. -- */ -- sub count, count, 128+64+64+1 -- add dst, dst, 128 -- nop -- -- /* DC ZVA sets 64 bytes each time. */ --1: dc zva, dst -- add dst, dst, 64 -- subs count, count, 64 -- b.hs 1b -- -- /* -- * Write the last 64 byte aligned block using stp to force fully -- * dirty cache line. -- */ -- stp val, val, [dst, 0] -- stp val, val, [dst, 16] -- stp val, val, [dst, 32] -- stp val, val, [dst, 48] -- -- tbz count, 5, 1f /* Remaining count is less than 33 bytes? */ -- stp val, val, [dst, 64] -- stp val, val, [dst, 80] --1: stp val, val, [dstend, -32] -- stp val, val, [dstend, -16] -- ret --#endif -- --END (MEMSET) --libc_hidden_builtin_def (MEMSET) -diff --git a/sysdeps/aarch64/multiarch/memset_emag.S b/sysdeps/aarch64/multiarch/memset_emag.S -index 922c1ed57d..7ecf61dc59 100644 ---- a/sysdeps/aarch64/multiarch/memset_emag.S -+++ b/sysdeps/aarch64/multiarch/memset_emag.S -@@ -18,19 +18,95 @@ - . */ - - #include -+#include "memset-reg.h" - --#if IS_IN (libc) --# define MEMSET __memset_emag -- --/* -- * Using DC ZVA to zero memory does not produce better performance if -- * memory size is not very large, especially when there are multiple -- * processes/threads contending memory/cache. Here we set threshold to -- * zero to disable using DC ZVA, which is good for multi-process/thread -- * workloads. -+/* Assumptions: -+ * -+ * ARMv8-a, AArch64, unaligned accesses -+ * - */ - --# define DC_ZVA_THRESHOLD 0 -+ENTRY (__memset_emag) -+ -+ PTR_ARG (0) -+ SIZE_ARG (2) -+ -+ bfi valw, valw, 8, 8 -+ bfi valw, valw, 16, 16 -+ bfi val, val, 32, 32 -+ -+ add dstend, dstin, count -+ -+ cmp count, 96 -+ b.hi L(set_long) -+ cmp count, 16 -+ b.hs L(set_medium) -+ -+ /* Set 0..15 bytes. */ -+ tbz count, 3, 1f -+ str val, [dstin] -+ str val, [dstend, -8] -+ ret -+ -+ .p2align 3 -+1: tbz count, 2, 2f -+ str valw, [dstin] -+ str valw, [dstend, -4] -+ ret -+2: cbz count, 3f -+ strb valw, [dstin] -+ tbz count, 1, 3f -+ strh valw, [dstend, -2] -+3: ret -+ -+ .p2align 3 -+ /* Set 16..96 bytes. */ -+L(set_medium): -+ stp val, val, [dstin] -+ tbnz count, 6, L(set96) -+ stp val, val, [dstend, -16] -+ tbz count, 5, 1f -+ stp val, val, [dstin, 16] -+ stp val, val, [dstend, -32] -+1: ret -+ -+ .p2align 4 -+ /* Set 64..96 bytes. Write 64 bytes from the start and -+ 32 bytes from the end. */ -+L(set96): -+ stp val, val, [dstin, 16] -+ stp val, val, [dstin, 32] -+ stp val, val, [dstin, 48] -+ stp val, val, [dstend, -32] -+ stp val, val, [dstend, -16] -+ ret -+ -+ .p2align 4 -+L(set_long): -+ stp val, val, [dstin] -+ bic dst, dstin, 15 -+ /* Small-size or non-zero memset does not use DC ZVA. */ -+ sub count, dstend, dst -+ -+ /* -+ * Adjust count and bias for loop. By subtracting extra 1 from count, -+ * it is easy to use tbz instruction to check whether loop tailing -+ * count is less than 33 bytes, so as to bypass 2 unnecessary stps. -+ */ -+ sub count, count, 64+16+1 -+ -+1: stp val, val, [dst, 16] -+ stp val, val, [dst, 32] -+ stp val, val, [dst, 48] -+ stp val, val, [dst, 64]! -+ subs count, count, 64 -+ b.hs 1b -+ -+ tbz count, 5, 1f /* Remaining count is less than 33 bytes? */ -+ stp val, val, [dst, 16] -+ stp val, val, [dst, 32] -+1: stp val, val, [dstend, -32] -+ stp val, val, [dstend, -16] -+ ret - --# include "./memset_base64.S" --#endif -+END (__memset_emag) -diff --git a/sysdeps/aarch64/multiarch/memset_falkor.S b/sysdeps/aarch64/multiarch/memset_falkor.S -deleted file mode 100644 -index 657f4c60b4..0000000000 ---- a/sysdeps/aarch64/multiarch/memset_falkor.S -+++ /dev/null -@@ -1,54 +0,0 @@ --/* Memset for falkor. -- Copyright (C) 2017-2022 Free Software Foundation, Inc. -- -- This file is part of the GNU C Library. -- -- The GNU C Library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- The GNU C Library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with the GNU C Library. If not, see -- . */ -- --#include --#include -- --/* Reading dczid_el0 is expensive on falkor so move it into the ifunc -- resolver and assume ZVA size of 64 bytes. The IFUNC resolver takes care to -- use this function only when ZVA is enabled. */ -- --#if IS_IN (libc) --.macro zva_macro -- .p2align 4 -- /* Write the first and last 64 byte aligned block using stp rather -- than using DC ZVA. This is faster on some cores. */ -- str q0, [dst, 16] -- stp q0, q0, [dst, 32] -- bic dst, dst, 63 -- stp q0, q0, [dst, 64] -- stp q0, q0, [dst, 96] -- sub count, dstend, dst /* Count is now 128 too large. */ -- sub count, count, 128+64+64 /* Adjust count and bias for loop. */ -- add dst, dst, 128 --1: dc zva, dst -- add dst, dst, 64 -- subs count, count, 64 -- b.hi 1b -- stp q0, q0, [dst, 0] -- stp q0, q0, [dst, 32] -- stp q0, q0, [dstend, -64] -- stp q0, q0, [dstend, -32] -- ret --.endm -- --# define ZVA_MACRO zva_macro --# define MEMSET __memset_falkor --# include --#endif -diff --git a/sysdeps/aarch64/multiarch/memset_generic.S b/sysdeps/aarch64/multiarch/memset_generic.S -index c879be93d5..6efcb5f00d 100644 ---- a/sysdeps/aarch64/multiarch/memset_generic.S -+++ b/sysdeps/aarch64/multiarch/memset_generic.S -@@ -21,9 +21,15 @@ - - #if IS_IN (libc) - # define MEMSET __memset_generic -+ -+/* Do not hide the generic version of memset, we use it internally. */ -+# undef libc_hidden_builtin_def -+# define libc_hidden_builtin_def(name) -+ - /* Add a hidden definition for use within libc.so. */ - # ifdef SHARED - .globl __GI_memset; __GI_memset = __memset_generic - # endif --# include - #endif -+ -+#include <../memset.S> -diff --git a/sysdeps/aarch64/multiarch/memset_kunpeng.S b/sysdeps/aarch64/multiarch/memset_kunpeng.S -index a6d2c8c3bb..8f2deddb74 100644 ---- a/sysdeps/aarch64/multiarch/memset_kunpeng.S -+++ b/sysdeps/aarch64/multiarch/memset_kunpeng.S -@@ -20,16 +20,13 @@ - #include - #include - --#if IS_IN (libc) --# define MEMSET __memset_kunpeng -- - /* Assumptions: - * - * ARMv8-a, AArch64, unaligned accesses - * - */ - --ENTRY_ALIGN (MEMSET, 6) -+ENTRY (__memset_kunpeng) - - PTR_ARG (0) - SIZE_ARG (2) -@@ -108,6 +105,4 @@ L(set_long): - stp q0, q0, [dstend, -32] - ret - --END (MEMSET) --libc_hidden_builtin_def (MEMSET) --#endif -+END (__memset_kunpeng) -diff --git a/sysdeps/aarch64/multiarch/memset_mops.S b/sysdeps/aarch64/multiarch/memset_mops.S -new file mode 100644 -index 0000000000..ca820b8636 ---- /dev/null -+++ b/sysdeps/aarch64/multiarch/memset_mops.S -@@ -0,0 +1,38 @@ -+/* Optimized memset for MOPS. -+ Copyright (C) 2023 Free Software Foundation, Inc. -+ -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#include -+ -+/* Assumptions: -+ * -+ * AArch64, MOPS. -+ * -+ */ -+ -+ENTRY (__memset_mops) -+ PTR_ARG (0) -+ SIZE_ARG (2) -+ -+ mov x3, x0 -+ .inst 0x19c10443 /* setp [x3]!, x2!, x1 */ -+ .inst 0x19c14443 /* setm [x3]!, x2!, x1 */ -+ .inst 0x19c18443 /* sete [x3]!, x2!, x1 */ -+ ret -+ -+END (__memset_mops) -diff --git a/sysdeps/aarch64/multiarch/rtld-memset.S b/sysdeps/aarch64/multiarch/memset_zva64.S -similarity index 76% -rename from sysdeps/aarch64/multiarch/rtld-memset.S -rename to sysdeps/aarch64/multiarch/memset_zva64.S -index 7968d25e48..13f45fd3d8 100644 ---- a/sysdeps/aarch64/multiarch/rtld-memset.S -+++ b/sysdeps/aarch64/multiarch/memset_zva64.S -@@ -1,5 +1,5 @@ --/* Memset for aarch64, for the dynamic linker. -- Copyright (C) 2017-2022 Free Software Foundation, Inc. -+/* Optimized memset for zva size = 64. -+ Copyright (C) 2023 Free Software Foundation, Inc. - - This file is part of the GNU C Library. - -@@ -19,7 +19,9 @@ - - #include - --#if IS_IN (rtld) --# define MEMSET memset --# include --#endif -+#define ZVA64_ONLY 1 -+#define MEMSET __memset_zva64 -+#undef libc_hidden_builtin_def -+#define libc_hidden_builtin_def(X) -+ -+#include "../memset.S" -diff --git a/sysdeps/aarch64/multiarch/strlen.c b/sysdeps/aarch64/multiarch/strlen.c -index 6d27c126b0..a951967fcd 100644 ---- a/sysdeps/aarch64/multiarch/strlen.c -+++ b/sysdeps/aarch64/multiarch/strlen.c -@@ -28,10 +28,10 @@ - - extern __typeof (__redirect_strlen) __strlen; - --extern __typeof (__redirect_strlen) __strlen_mte attribute_hidden; -+extern __typeof (__redirect_strlen) __strlen_generic attribute_hidden; - extern __typeof (__redirect_strlen) __strlen_asimd attribute_hidden; - --libc_ifunc (__strlen, (mte ? __strlen_mte : __strlen_asimd)); -+libc_ifunc (__strlen, (mte ? __strlen_generic : __strlen_asimd)); - - # undef strlen - strong_alias (__strlen, strlen); -diff --git a/sysdeps/aarch64/multiarch/strlen_asimd.S b/sysdeps/aarch64/multiarch/strlen_asimd.S -index 6faeb91361..dcd4589d10 100644 ---- a/sysdeps/aarch64/multiarch/strlen_asimd.S -+++ b/sysdeps/aarch64/multiarch/strlen_asimd.S -@@ -48,6 +48,7 @@ - #define tmp x2 - #define tmpw w2 - #define synd x3 -+#define syndw w3 - #define shift x4 - - /* For the first 32 bytes, NUL detection works on the principle that -@@ -87,7 +88,6 @@ - - ENTRY (__strlen_asimd) - PTR_ARG (0) -- - and tmp1, srcin, MIN_PAGE_SIZE - 1 - cmp tmp1, MIN_PAGE_SIZE - 32 - b.hi L(page_cross) -@@ -123,7 +123,6 @@ ENTRY (__strlen_asimd) - add len, len, tmp1, lsr 3 - ret - -- .p2align 3 - /* Look for a NUL byte at offset 16..31 in the string. */ - L(bytes16_31): - ldp data1, data2, [srcin, 16] -@@ -151,6 +150,7 @@ L(bytes16_31): - add len, len, tmp1, lsr 3 - ret - -+ nop - L(loop_entry): - bic src, srcin, 31 - -@@ -166,18 +166,12 @@ L(loop): - /* Low 32 bits of synd are non-zero if a NUL was found in datav1. */ - cmeq maskv.16b, datav1.16b, 0 - sub len, src, srcin -- tst synd, 0xffffffff -- b.ne 1f -+ cbnz syndw, 1f - cmeq maskv.16b, datav2.16b, 0 - add len, len, 16 - 1: - /* Generate a bitmask and compute correct byte offset. */ --#ifdef __AARCH64EB__ -- bic maskv.8h, 0xf0 --#else -- bic maskv.8h, 0x0f, lsl 8 --#endif -- umaxp maskv.16b, maskv.16b, maskv.16b -+ shrn maskv.8b, maskv.8h, 4 - fmov synd, maskd - #ifndef __AARCH64EB__ - rbit synd, synd -@@ -186,8 +180,6 @@ L(loop): - add len, len, tmp, lsr 2 - ret - -- .p2align 4 -- - L(page_cross): - bic src, srcin, 31 - mov tmpw, 0x0c03 -@@ -211,4 +203,3 @@ L(page_cross): - ret - - END (__strlen_asimd) --libc_hidden_builtin_def (__strlen_asimd) -diff --git a/sysdeps/aarch64/multiarch/strlen_mte.S b/sysdeps/aarch64/multiarch/strlen_generic.S -similarity index 85% -rename from sysdeps/aarch64/multiarch/strlen_mte.S -rename to sysdeps/aarch64/multiarch/strlen_generic.S -index bf03ac53eb..014e376ec1 100644 ---- a/sysdeps/aarch64/multiarch/strlen_mte.S -+++ b/sysdeps/aarch64/multiarch/strlen_generic.S -@@ -17,14 +17,14 @@ - . */ - - /* The actual strlen code is in ../strlen.S. If we are building libc this file -- defines __strlen_mte. Otherwise the include of ../strlen.S will define -- the normal __strlen entry points. */ -+ defines __strlen_generic. Otherwise the include of ../strlen.S will define -+ the normal __strlen entry points. */ - - #include - - #if IS_IN (libc) - --# define STRLEN __strlen_mte -+# define STRLEN __strlen_generic - - /* Do not hide the generic version of strlen, we use it internally. */ - # undef libc_hidden_builtin_def -@@ -32,7 +32,7 @@ - - # ifdef SHARED - /* It doesn't make sense to send libc-internal strlen calls through a PLT. */ -- .globl __GI_strlen; __GI_strlen = __strlen_mte -+ .globl __GI_strlen; __GI_strlen = __strlen_generic - # endif - #endif - -diff --git a/sysdeps/aarch64/rawmemchr.S b/sysdeps/aarch64/rawmemchr.S -index 55d9e34d4f..f90ce2bf86 100644 ---- a/sysdeps/aarch64/rawmemchr.S -+++ b/sysdeps/aarch64/rawmemchr.S -@@ -31,7 +31,7 @@ ENTRY (__rawmemchr) - - L(do_strlen): - mov x15, x30 -- cfi_return_column (x15) -+ cfi_register (x30, x15) - mov x14, x0 - bl __strlen - add x0, x14, x0 -diff --git a/sysdeps/aarch64/strchr.S b/sysdeps/aarch64/strchr.S -index 003bf4a478..4781d45bd9 100644 ---- a/sysdeps/aarch64/strchr.S -+++ b/sysdeps/aarch64/strchr.S -@@ -32,8 +32,7 @@ - - #define src x2 - #define tmp1 x1 --#define wtmp2 w3 --#define tmp3 x3 -+#define tmp2 x3 - - #define vrepchr v0 - #define vdata v1 -@@ -41,39 +40,30 @@ - #define vhas_nul v2 - #define vhas_chr v3 - #define vrepmask v4 --#define vrepmask2 v5 --#define vend v6 --#define dend d6 -+#define vend v5 -+#define dend d5 - - /* Core algorithm. - - For each 16-byte chunk we calculate a 64-bit syndrome value with four bits -- per byte. For even bytes, bits 0-1 are set if the relevant byte matched the -- requested character, bits 2-3 are set if the byte is NUL (or matched), and -- bits 4-7 are not used and must be zero if none of bits 0-3 are set). Odd -- bytes set bits 4-7 so that adjacent bytes can be merged. Since the bits -- in the syndrome reflect the order in which things occur in the original -- string, counting trailing zeros identifies exactly which byte matched. */ -+ per byte. Bits 0-1 are set if the relevant byte matched the requested -+ character, bits 2-3 are set if the byte is NUL or matched. Count trailing -+ zeroes gives the position of the matching byte if it is a multiple of 4. -+ If it is not a multiple of 4, there was no match. */ - - ENTRY (strchr) - PTR_ARG (0) - bic src, srcin, 15 - dup vrepchr.16b, chrin - ld1 {vdata.16b}, [src] -- mov wtmp2, 0x3003 -- dup vrepmask.8h, wtmp2 -+ movi vrepmask.16b, 0x33 - cmeq vhas_nul.16b, vdata.16b, 0 - cmeq vhas_chr.16b, vdata.16b, vrepchr.16b -- mov wtmp2, 0xf00f -- dup vrepmask2.8h, wtmp2 -- - bit vhas_nul.16b, vhas_chr.16b, vrepmask.16b -- and vhas_nul.16b, vhas_nul.16b, vrepmask2.16b -- lsl tmp3, srcin, 2 -- addp vend.16b, vhas_nul.16b, vhas_nul.16b /* 128->64 */ -- -+ lsl tmp2, srcin, 2 -+ shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ - fmov tmp1, dend -- lsr tmp1, tmp1, tmp3 -+ lsr tmp1, tmp1, tmp2 - cbz tmp1, L(loop) - - rbit tmp1, tmp1 -@@ -87,28 +77,34 @@ ENTRY (strchr) - - .p2align 4 - L(loop): -- ldr qdata, [src, 16]! -+ ldr qdata, [src, 16] -+ cmeq vhas_chr.16b, vdata.16b, vrepchr.16b -+ cmhs vhas_nul.16b, vhas_chr.16b, vdata.16b -+ umaxp vend.16b, vhas_nul.16b, vhas_nul.16b -+ fmov tmp1, dend -+ cbnz tmp1, L(end) -+ ldr qdata, [src, 32]! - cmeq vhas_chr.16b, vdata.16b, vrepchr.16b - cmhs vhas_nul.16b, vhas_chr.16b, vdata.16b - umaxp vend.16b, vhas_nul.16b, vhas_nul.16b - fmov tmp1, dend - cbz tmp1, L(loop) -+ sub src, src, 16 -+L(end): - - #ifdef __AARCH64EB__ - bif vhas_nul.16b, vhas_chr.16b, vrepmask.16b -- and vhas_nul.16b, vhas_nul.16b, vrepmask2.16b -- addp vend.16b, vhas_nul.16b, vhas_nul.16b /* 128->64 */ -+ shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ - fmov tmp1, dend - #else - bit vhas_nul.16b, vhas_chr.16b, vrepmask.16b -- and vhas_nul.16b, vhas_nul.16b, vrepmask2.16b -- addp vend.16b, vhas_nul.16b, vhas_nul.16b /* 128->64 */ -+ shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ - fmov tmp1, dend - rbit tmp1, tmp1 - #endif -+ add src, src, 16 - clz tmp1, tmp1 -- /* Tmp1 is an even multiple of 2 if the target character was -- found first. Otherwise we've found the end of string. */ -+ /* Tmp1 is a multiple of 4 if the target character was found. */ - tst tmp1, 2 - add result, src, tmp1, lsr 2 - csel result, result, xzr, eq -diff --git a/sysdeps/aarch64/strchrnul.S b/sysdeps/aarch64/strchrnul.S -index ee154ab74b..94465fc088 100644 ---- a/sysdeps/aarch64/strchrnul.S -+++ b/sysdeps/aarch64/strchrnul.S -@@ -70,14 +70,22 @@ ENTRY (__strchrnul) - - .p2align 4 - L(loop): -- ldr qdata, [src, 16]! -+ ldr qdata, [src, 16] -+ cmeq vhas_chr.16b, vdata.16b, vrepchr.16b -+ cmhs vhas_chr.16b, vhas_chr.16b, vdata.16b -+ umaxp vend.16b, vhas_chr.16b, vhas_chr.16b -+ fmov tmp1, dend -+ cbnz tmp1, L(end) -+ ldr qdata, [src, 32]! - cmeq vhas_chr.16b, vdata.16b, vrepchr.16b - cmhs vhas_chr.16b, vhas_chr.16b, vdata.16b - umaxp vend.16b, vhas_chr.16b, vhas_chr.16b - fmov tmp1, dend - cbz tmp1, L(loop) -- -+ sub src, src, 16 -+L(end): - shrn vend.8b, vhas_chr.8h, 4 /* 128->64 */ -+ add src, src, 16 - fmov tmp1, dend - #ifndef __AARCH64EB__ - rbit tmp1, tmp1 -diff --git a/sysdeps/aarch64/strcpy.S b/sysdeps/aarch64/strcpy.S -index 78d27b4aa6..6eeda12df6 100644 ---- a/sysdeps/aarch64/strcpy.S -+++ b/sysdeps/aarch64/strcpy.S -@@ -30,7 +30,6 @@ - * MTE compatible. - */ - --/* Arguments and results. */ - #define dstin x0 - #define srcin x1 - #define result x0 -@@ -76,14 +75,14 @@ ENTRY (STRCPY) - ld1 {vdata.16b}, [src] - cmeq vhas_nul.16b, vdata.16b, 0 - lsl shift, srcin, 2 -- shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ -+ shrn vend.8b, vhas_nul.8h, 4 - fmov synd, dend - lsr synd, synd, shift - cbnz synd, L(tail) - - ldr dataq, [src, 16]! - cmeq vhas_nul.16b, vdata.16b, 0 -- shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ -+ shrn vend.8b, vhas_nul.8h, 4 - fmov synd, dend - cbz synd, L(start_loop) - -@@ -102,13 +101,10 @@ ENTRY (STRCPY) - IFSTPCPY (add result, dstin, len) - ret - -- .p2align 4,,8 - L(tail): - rbit synd, synd - clz len, synd - lsr len, len, 2 -- -- .p2align 4 - L(less16): - tbz len, 3, L(less8) - sub tmp, len, 7 -@@ -141,31 +137,37 @@ L(zerobyte): - - .p2align 4 - L(start_loop): -- sub len, src, srcin -+ sub tmp, srcin, dstin - ldr dataq2, [srcin] -- add dst, dstin, len -+ sub dst, src, tmp - str dataq2, [dstin] -- -- .p2align 5 - L(loop): -- str dataq, [dst], 16 -- ldr dataq, [src, 16]! -+ str dataq, [dst], 32 -+ ldr dataq, [src, 16] -+ cmeq vhas_nul.16b, vdata.16b, 0 -+ umaxp vend.16b, vhas_nul.16b, vhas_nul.16b -+ fmov synd, dend -+ cbnz synd, L(loopend) -+ str dataq, [dst, -16] -+ ldr dataq, [src, 32]! - cmeq vhas_nul.16b, vdata.16b, 0 - umaxp vend.16b, vhas_nul.16b, vhas_nul.16b - fmov synd, dend - cbz synd, L(loop) -- -+ add dst, dst, 16 -+L(loopend): - shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ - fmov synd, dend -+ sub dst, dst, 31 - #ifndef __AARCH64EB__ - rbit synd, synd - #endif - clz len, synd - lsr len, len, 2 -- sub tmp, len, 15 -- ldr dataq, [src, tmp] -- str dataq, [dst, tmp] -- IFSTPCPY (add result, dst, len) -+ add dst, dst, len -+ ldr dataq, [dst, tmp] -+ str dataq, [dst] -+ IFSTPCPY (add result, dst, 15) - ret - - END (STRCPY) -diff --git a/sysdeps/aarch64/strlen.S b/sysdeps/aarch64/strlen.S -index 3a5d088407..10b9ec0769 100644 ---- a/sysdeps/aarch64/strlen.S -+++ b/sysdeps/aarch64/strlen.S -@@ -43,12 +43,9 @@ - #define dend d2 - - /* Core algorithm: -- -- For each 16-byte chunk we calculate a 64-bit nibble mask value with four bits -- per byte. We take 4 bits of every comparison byte with shift right and narrow -- by 4 instruction. Since the bits in the nibble mask reflect the order in -- which things occur in the original string, counting trailing zeros identifies -- exactly which byte matched. */ -+ Process the string in 16-byte aligned chunks. Compute a 64-bit mask with -+ four bits per byte using the shrn instruction. A count trailing zeros then -+ identifies the first zero byte. */ - - ENTRY (STRLEN) - PTR_ARG (0) -@@ -68,18 +65,25 @@ ENTRY (STRLEN) - - .p2align 5 - L(loop): -- ldr data, [src, 16]! -+ ldr data, [src, 16] -+ cmeq vhas_nul.16b, vdata.16b, 0 -+ umaxp vend.16b, vhas_nul.16b, vhas_nul.16b -+ fmov synd, dend -+ cbnz synd, L(loop_end) -+ ldr data, [src, 32]! - cmeq vhas_nul.16b, vdata.16b, 0 - umaxp vend.16b, vhas_nul.16b, vhas_nul.16b - fmov synd, dend - cbz synd, L(loop) -- -+ sub src, src, 16 -+L(loop_end): - shrn vend.8b, vhas_nul.8h, 4 /* 128->64 */ - sub result, src, srcin - fmov synd, dend - #ifndef __AARCH64EB__ - rbit synd, synd - #endif -+ add result, result, 16 - clz tmp, synd - add result, result, tmp, lsr 2 - ret -diff --git a/sysdeps/aarch64/strnlen.S b/sysdeps/aarch64/strnlen.S -index 282bddc9aa..a44a49a920 100644 ---- a/sysdeps/aarch64/strnlen.S -+++ b/sysdeps/aarch64/strnlen.S -@@ -44,19 +44,16 @@ - - /* - Core algorithm: -- -- For each 16-byte chunk we calculate a 64-bit nibble mask value with four bits -- per byte. We take 4 bits of every comparison byte with shift right and narrow -- by 4 instruction. Since the bits in the nibble mask reflect the order in -- which things occur in the original string, counting trailing zeros identifies -- exactly which byte matched. */ -+ Process the string in 16-byte aligned chunks. Compute a 64-bit mask with -+ four bits per byte using the shrn instruction. A count trailing zeros then -+ identifies the first zero byte. */ - - ENTRY (__strnlen) - PTR_ARG (0) - SIZE_ARG (1) - bic src, srcin, 15 - cbz cntin, L(nomatch) -- ld1 {vdata.16b}, [src], 16 -+ ld1 {vdata.16b}, [src] - cmeq vhas_chr.16b, vdata.16b, 0 - lsl shift, srcin, 2 - shrn vend.8b, vhas_chr.8h, 4 /* 128->64 */ -@@ -71,36 +68,40 @@ L(finish): - csel result, cntin, result, ls - ret - -+L(nomatch): -+ mov result, cntin -+ ret -+ - L(start_loop): - sub tmp, src, srcin -+ add tmp, tmp, 17 - subs cntrem, cntin, tmp -- b.ls L(nomatch) -+ b.lo L(nomatch) - - /* Make sure that it won't overread by a 16-byte chunk */ -- add tmp, cntrem, 15 -- tbnz tmp, 4, L(loop32_2) -- -+ tbz cntrem, 4, L(loop32_2) -+ sub src, src, 16 - .p2align 5 - L(loop32): -- ldr qdata, [src], 16 -+ ldr qdata, [src, 32]! - cmeq vhas_chr.16b, vdata.16b, 0 - umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ - fmov synd, dend - cbnz synd, L(end) - L(loop32_2): -- ldr qdata, [src], 16 -+ ldr qdata, [src, 16] - subs cntrem, cntrem, 32 - cmeq vhas_chr.16b, vdata.16b, 0 -- b.ls L(end) -+ b.lo L(end_2) - umaxp vend.16b, vhas_chr.16b, vhas_chr.16b /* 128->64 */ - fmov synd, dend - cbz synd, L(loop32) -- -+L(end_2): -+ add src, src, 16 - L(end): - shrn vend.8b, vhas_chr.8h, 4 /* 128->64 */ -- sub src, src, 16 -- mov synd, vend.d[0] - sub result, src, srcin -+ fmov synd, dend - #ifndef __AARCH64EB__ - rbit synd, synd - #endif -@@ -110,10 +111,6 @@ L(end): - csel result, cntin, result, ls - ret - --L(nomatch): -- mov result, cntin -- ret -- - END (__strnlen) - libc_hidden_def (__strnlen) - weak_alias (__strnlen, strnlen) -diff --git a/sysdeps/aarch64/strrchr.S b/sysdeps/aarch64/strrchr.S -index 596e77c43b..eda6fefb99 100644 ---- a/sysdeps/aarch64/strrchr.S -+++ b/sysdeps/aarch64/strrchr.S -@@ -22,19 +22,16 @@ - - /* Assumptions: - * -- * ARMv8-a, AArch64 -- * Neon Available. -+ * ARMv8-a, AArch64, Advanced SIMD. - * MTE compatible. - */ - --/* Arguments and results. */ - #define srcin x0 - #define chrin w1 - #define result x0 - - #define src x2 - #define tmp x3 --#define wtmp w3 - #define synd x3 - #define shift x4 - #define src_match x4 -@@ -46,7 +43,6 @@ - #define vhas_nul v2 - #define vhas_chr v3 - #define vrepmask v4 --#define vrepmask2 v5 - #define vend v5 - #define dend d5 - -@@ -58,59 +54,71 @@ - the relevant byte matched the requested character; bits 2-3 are set - if the relevant byte matched the NUL end of string. */ - --ENTRY(strrchr) -+ENTRY (strrchr) - PTR_ARG (0) - bic src, srcin, 15 - dup vrepchr.16b, chrin -- mov wtmp, 0x3003 -- dup vrepmask.8h, wtmp -- tst srcin, 15 -- beq L(loop1) -- -- ld1 {vdata.16b}, [src], 16 -+ movi vrepmask.16b, 0x33 -+ ld1 {vdata.16b}, [src] - cmeq vhas_nul.16b, vdata.16b, 0 - cmeq vhas_chr.16b, vdata.16b, vrepchr.16b -- mov wtmp, 0xf00f -- dup vrepmask2.8h, wtmp - bit vhas_nul.16b, vhas_chr.16b, vrepmask.16b -- and vhas_nul.16b, vhas_nul.16b, vrepmask2.16b -- addp vend.16b, vhas_nul.16b, vhas_nul.16b -+ shrn vend.8b, vhas_nul.8h, 4 - lsl shift, srcin, 2 - fmov synd, dend - lsr synd, synd, shift - lsl synd, synd, shift - ands nul_match, synd, 0xcccccccccccccccc - bne L(tail) -- cbnz synd, L(loop2) -+ cbnz synd, L(loop2_start) - -- .p2align 5 -+ .p2align 4 - L(loop1): -- ld1 {vdata.16b}, [src], 16 -+ ldr q1, [src, 16] -+ cmeq vhas_chr.16b, vdata.16b, vrepchr.16b -+ cmhs vhas_nul.16b, vhas_chr.16b, vdata.16b -+ umaxp vend.16b, vhas_nul.16b, vhas_nul.16b -+ fmov synd, dend -+ cbnz synd, L(loop1_end) -+ ldr q1, [src, 32]! - cmeq vhas_chr.16b, vdata.16b, vrepchr.16b - cmhs vhas_nul.16b, vhas_chr.16b, vdata.16b - umaxp vend.16b, vhas_nul.16b, vhas_nul.16b - fmov synd, dend - cbz synd, L(loop1) -- -+ sub src, src, 16 -+L(loop1_end): -+ add src, src, 16 - cmeq vhas_nul.16b, vdata.16b, 0 -+#ifdef __AARCH64EB__ -+ bif vhas_nul.16b, vhas_chr.16b, vrepmask.16b -+ shrn vend.8b, vhas_nul.8h, 4 -+ fmov synd, dend -+ rbit synd, synd -+#else - bit vhas_nul.16b, vhas_chr.16b, vrepmask.16b -- bic vhas_nul.8h, 0x0f, lsl 8 -- addp vend.16b, vhas_nul.16b, vhas_nul.16b -+ shrn vend.8b, vhas_nul.8h, 4 - fmov synd, dend -+#endif - ands nul_match, synd, 0xcccccccccccccccc -- beq L(loop2) -- -+ beq L(loop2_start) - L(tail): - sub nul_match, nul_match, 1 - and chr_match, synd, 0x3333333333333333 - ands chr_match, chr_match, nul_match -- sub result, src, 1 -+ add result, src, 15 - clz tmp, chr_match - sub result, result, tmp, lsr 2 - csel result, result, xzr, ne - ret - - .p2align 4 -+ nop -+ nop -+L(loop2_start): -+ add src, src, 16 -+ bic vrepmask.8h, 0xf0 -+ - L(loop2): - cmp synd, 0 - csel src_match, src, src_match, ne -diff --git a/sysdeps/arc/utmp-size.h b/sysdeps/arc/utmp-size.h -new file mode 100644 -index 0000000000..a247fcd3da ---- /dev/null -+++ b/sysdeps/arc/utmp-size.h -@@ -0,0 +1,3 @@ -+/* arc has less padding than other architectures with 64-bit time_t. */ -+#define UTMP_SIZE 392 -+#define LASTLOG_SIZE 296 -diff --git a/sysdeps/arm/bits/wordsize.h b/sysdeps/arm/bits/wordsize.h -new file mode 100644 -index 0000000000..6ecbfe7c86 ---- /dev/null -+++ b/sysdeps/arm/bits/wordsize.h -@@ -0,0 +1,21 @@ -+/* Copyright (C) 1999-2024 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#define __WORDSIZE 32 -+#define __WORDSIZE_TIME64_COMPAT32 1 -+#define __WORDSIZE32_SIZE_ULONG 0 -+#define __WORDSIZE32_PTRDIFF_LONG 0 -diff --git a/sysdeps/arm/dl-machine.h b/sysdeps/arm/dl-machine.h -index 6a422713bd..659c6f16da 100644 ---- a/sysdeps/arm/dl-machine.h -+++ b/sysdeps/arm/dl-machine.h -@@ -137,7 +137,6 @@ _start:\n\ - _dl_start_user:\n\ - adr r6, .L_GET_GOT\n\ - add sl, sl, r6\n\ -- ldr r4, [sl, r4]\n\ - @ save the entry point in another register\n\ - mov r6, r0\n\ - @ get the original arg count\n\ -diff --git a/sysdeps/arm/utmp-size.h b/sysdeps/arm/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/arm/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/csky/bits/wordsize.h b/sysdeps/csky/bits/wordsize.h -new file mode 100644 -index 0000000000..6ecbfe7c86 ---- /dev/null -+++ b/sysdeps/csky/bits/wordsize.h -@@ -0,0 +1,21 @@ -+/* Copyright (C) 1999-2024 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#define __WORDSIZE 32 -+#define __WORDSIZE_TIME64_COMPAT32 1 -+#define __WORDSIZE32_SIZE_ULONG 0 -+#define __WORDSIZE32_PTRDIFF_LONG 0 -diff --git a/sysdeps/csky/utmp-size.h b/sysdeps/csky/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/csky/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h -index 050a3032de..c2627fced7 100644 ---- a/sysdeps/generic/ldsodefs.h -+++ b/sysdeps/generic/ldsodefs.h -@@ -105,6 +105,9 @@ typedef struct link_map *lookup_t; - DT_PREINIT_ARRAY. */ - typedef void (*dl_init_t) (int, char **, char **); - -+/* Type of a constructor function, in DT_FINI, DT_FINI_ARRAY. */ -+typedef void (*fini_t) (void); -+ - /* On some architectures a pointer to a function is not just a pointer - to the actual code of the function but rather an architecture - specific descriptor. */ -@@ -1048,9 +1051,16 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv, - initializer functions have completed. */ - extern void _dl_fini (void) attribute_hidden; - --/* Sort array MAPS according to dependencies of the contained objects. */ -+/* Invoke the DT_FINI_ARRAY and DT_FINI destructors for MAP, which -+ must be a struct link_map *. Can be used as an argument to -+ _dl_catch_exception. */ -+void _dl_call_fini (void *map) attribute_hidden; -+ -+/* Sort array MAPS according to dependencies of the contained objects. -+ If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies -+ say otherwise. */ - extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps, -- unsigned int skip, bool for_fini) attribute_hidden; -+ bool force_first, bool for_fini) attribute_hidden; - - /* The dynamic linker calls this function before and having changing - any shared object mappings. The `r_state' member of `struct r_debug' -diff --git a/sysdeps/generic/libc-lock-arch.h b/sysdeps/generic/libc-lock-arch.h -new file mode 100644 -index 0000000000..4713b30a8a ---- /dev/null -+++ b/sysdeps/generic/libc-lock-arch.h -@@ -0,0 +1,25 @@ -+/* Private libc-internal arch-specific definitions. Generic version. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of the -+ License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; see the file COPYING.LIB. If -+ not, see . */ -+ -+#ifndef _LIBC_LOCK_ARCH_H -+#define _LIBC_LOCK_ARCH_H -+ -+/* The default definition uses the natural alignment from the lock type. */ -+#define __LIBC_LOCK_ALIGNMENT -+ -+#endif -diff --git a/sysdeps/generic/utmp-size.h b/sysdeps/generic/utmp-size.h -new file mode 100644 -index 0000000000..89dbe878b0 ---- /dev/null -+++ b/sysdeps/generic/utmp-size.h -@@ -0,0 +1,23 @@ -+/* Expected sizes of utmp-related structures stored in files. 64-bit version. -+ Copyright (C) 2024 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+/* Expected size, in bytes, of struct utmp and struct utmpx. */ -+#define UTMP_SIZE 400 -+ -+/* Expected size, in bytes, of struct lastlog. */ -+#define LASTLOG_SIZE 296 -diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h -index c865713be1..1d51948566 100644 ---- a/sysdeps/hppa/dl-machine.h -+++ b/sysdeps/hppa/dl-machine.h -@@ -347,6 +347,16 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[], - its return value is the user program's entry point. */ - - #define RTLD_START \ -+/* Set up dp for any non-PIC lib constructors that may be called. */ \ -+static struct link_map * __attribute__((used)) \ -+set_dp (struct link_map *map) \ -+{ \ -+ register Elf32_Addr dp asm ("%r27"); \ -+ dp = D_PTR (map, l_info[DT_PLTGOT]); \ -+ asm volatile ("" : : "r" (dp)); \ -+ return map; \ -+} \ -+ \ - asm ( \ - " .text\n" \ - " .globl _start\n" \ -@@ -426,6 +436,13 @@ asm ( \ - direct loader invocation. Thus, argc and argv must be \ - reloaded from from _dl_argc and _dl_argv. */ \ - \ -+ /* Load main_map from _rtld_local and setup dp. */ \ -+" addil LT'_rtld_local,%r19\n" \ -+" ldw RT'_rtld_local(%r1),%r26\n" \ -+" bl set_dp, %r2\n" \ -+" ldw 0(%r26),%r26\n" \ -+" copy %ret0,%r26\n" \ -+ \ - /* Load argc from _dl_argc. */ \ - " addil LT'_dl_argc,%r19\n" \ - " ldw RT'_dl_argc(%r1),%r20\n" \ -@@ -438,13 +455,10 @@ asm ( \ - " ldw 0(%r20),%r24\n" \ - " stw %r24,-44(%sp)\n" \ - \ -- /* Call _dl_init(main_map, argc, argv, envp). */ \ --" addil LT'_rtld_local,%r19\n" \ --" ldw RT'_rtld_local(%r1),%r26\n" \ --" ldw 0(%r26),%r26\n" \ -- \ - /* envp = argv + argc + 1 */ \ - " sh2add %r25,%r24,%r23\n" \ -+ \ -+ /* Call _dl_init(main_map, argc, argv, envp). */ \ - " bl _dl_init,%r2\n" \ - " ldo 4(%r23),%r23\n" /* delay slot */ \ - \ -diff --git a/sysdeps/hppa/utmp-size.h b/sysdeps/hppa/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/hppa/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/ieee754/ldbl-128/e_j1l.c b/sysdeps/ieee754/ldbl-128/e_j1l.c -index 54c457681a..9a9c5c6f00 100644 ---- a/sysdeps/ieee754/ldbl-128/e_j1l.c -+++ b/sysdeps/ieee754/ldbl-128/e_j1l.c -@@ -869,10 +869,13 @@ __ieee754_y1l (_Float128 x) - { - /* 0 <= x <= 2 */ - SET_RESTORE_ROUNDL (FE_TONEAREST); -+ xx = math_opt_barrier (xx); -+ x = math_opt_barrier (x); - z = xx * xx; - p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D); - p = -TWOOPI / xx + p; - p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p; -+ math_force_eval (p); - return p; - } - -diff --git a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c -index f85ba94466..0a5fe68342 100644 ---- a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c -+++ b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c -@@ -792,10 +792,13 @@ __ieee754_y1l (long double x) - { - /* 0 <= x <= 2 */ - SET_RESTORE_ROUNDL (FE_TONEAREST); -+ xx = math_opt_barrier (xx); -+ x = math_opt_barrier (x); - z = xx * xx; - p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D); - p = -TWOOPI / xx + p; - p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p; -+ math_force_eval (p); - return p; - } - -diff --git a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c -index d85154e73a..d8c0de1faf 100644 ---- a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c -+++ b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c -@@ -66,38 +66,35 @@ __llroundl (long double x) - /* Peg at max/min values, assuming that the above conversions do so. - Strictly speaking, we can return anything for values that overflow, - but this is more useful. */ -- res = hi + lo; -- -- /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */ -- if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0))) -+ if (__glibc_unlikely (__builtin_add_overflow (hi, lo, &res))) - goto overflow; - - xh -= lo; - ldbl_canonicalize (&xh, &xl); - -- hi = res; - if (xh > 0.5) - { -- res += 1; -+ if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res))) -+ goto overflow; - } - else if (xh == 0.5) - { - if (xl > 0.0 || (xl == 0.0 && res >= 0)) -- res += 1; -+ if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res))) -+ goto overflow; - } - else if (-xh > 0.5) - { -- res -= 1; -+ if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res))) -+ goto overflow; - } - else if (-xh == 0.5) - { - if (xl < 0.0 || (xl == 0.0 && res <= 0)) -- res -= 1; -+ if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res))) -+ goto overflow; - } - -- if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0))) -- goto overflow; -- - return res; - } - else -diff --git a/sysdeps/m68k/bits/wordsize.h b/sysdeps/m68k/bits/wordsize.h -new file mode 100644 -index 0000000000..6ecbfe7c86 ---- /dev/null -+++ b/sysdeps/m68k/bits/wordsize.h -@@ -0,0 +1,21 @@ -+/* Copyright (C) 1999-2024 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#define __WORDSIZE 32 -+#define __WORDSIZE_TIME64_COMPAT32 1 -+#define __WORDSIZE32_SIZE_ULONG 0 -+#define __WORDSIZE32_PTRDIFF_LONG 0 -diff --git a/sysdeps/m68k/utmp-size.h b/sysdeps/m68k/utmp-size.h -new file mode 100644 -index 0000000000..5946685819 ---- /dev/null -+++ b/sysdeps/m68k/utmp-size.h -@@ -0,0 +1,3 @@ -+/* m68k has 2-byte alignment. */ -+#define UTMP_SIZE 382 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/mach/getsysstats.c b/sysdeps/mach/getsysstats.c -index 37ea5e6a7a..80ea7e17cb 100644 ---- a/sysdeps/mach/getsysstats.c -+++ b/sysdeps/mach/getsysstats.c -@@ -62,12 +62,6 @@ __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/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h -index 5b35ea81ec..70fce4fb27 100644 ---- a/sysdeps/mach/hurd/bits/socket.h -+++ b/sysdeps/mach/hurd/bits/socket.h -@@ -249,6 +249,12 @@ struct cmsghdr - + CMSG_ALIGN (sizeof (struct cmsghdr))) - #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) - -+/* Given a length, return the additional padding necessary such that -+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ -+#define __CMSG_PADDING(len) ((sizeof (size_t) \ -+ - ((len) & (sizeof (size_t) - 1))) \ -+ & (sizeof (size_t) - 1)) -+ - extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, - struct cmsghdr *__cmsg) __THROW; - #ifdef __USE_EXTERN_INLINES -@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, - _EXTERN_INLINE struct cmsghdr * - __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) - { -+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and -+ __mhdr->msg_controllen because the user is required to obtain the first -+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs -+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet -+ trust the value of __cmsg->cmsg_len and therefore do not use it in any -+ pointer arithmetic until we check its value. */ -+ -+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; -+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; -+ -+ size_t __size_needed = sizeof (struct cmsghdr) -+ + __CMSG_PADDING (__cmsg->cmsg_len); -+ -+ /* The current header is malformed, too small to be a full header. */ - if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) -- /* The kernel header does this so there may be a reason. */ - return (struct cmsghdr *) 0; - -+ /* There isn't enough space between __cmsg and the end of the buffer to -+ hold the current cmsg *and* the next one. */ -+ if (((size_t) -+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) -+ < __size_needed) -+ || ((size_t) -+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr -+ - __size_needed) -+ < __cmsg->cmsg_len)) -+ -+ return (struct cmsghdr *) 0; -+ -+ /* Now, we trust cmsg_len and can use it to find the next header. */ - __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg - + CMSG_ALIGN (__cmsg->cmsg_len)); -- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control -- + __mhdr->msg_controllen) -- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) -- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) -- /* No more entries. */ -- return (struct cmsghdr *) 0; - return __cmsg; - } - #endif /* Use `extern inline'. */ -diff --git a/sysdeps/microblaze/bits/wordsize.h b/sysdeps/microblaze/bits/wordsize.h -new file mode 100644 -index 0000000000..6ecbfe7c86 ---- /dev/null -+++ b/sysdeps/microblaze/bits/wordsize.h -@@ -0,0 +1,21 @@ -+/* Copyright (C) 1999-2024 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#define __WORDSIZE 32 -+#define __WORDSIZE_TIME64_COMPAT32 1 -+#define __WORDSIZE32_SIZE_ULONG 0 -+#define __WORDSIZE32_PTRDIFF_LONG 0 -diff --git a/sysdeps/microblaze/utmp-size.h b/sysdeps/microblaze/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/microblaze/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/mips/bits/wordsize.h b/sysdeps/mips/bits/wordsize.h -index e521dc589c..c6a4a4270b 100644 ---- a/sysdeps/mips/bits/wordsize.h -+++ b/sysdeps/mips/bits/wordsize.h -@@ -19,11 +19,7 @@ - - #define __WORDSIZE _MIPS_SZPTR - --#if _MIPS_SIM == _ABI64 --# define __WORDSIZE_TIME64_COMPAT32 1 --#else --# define __WORDSIZE_TIME64_COMPAT32 0 --#endif -+#define __WORDSIZE_TIME64_COMPAT32 1 - - #if __WORDSIZE == 32 - #define __WORDSIZE32_SIZE_ULONG 0 -diff --git a/sysdeps/mips/utmp-size.h b/sysdeps/mips/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/mips/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/nios2/bits/wordsize.h b/sysdeps/nios2/bits/wordsize.h -new file mode 100644 -index 0000000000..6ecbfe7c86 ---- /dev/null -+++ b/sysdeps/nios2/bits/wordsize.h -@@ -0,0 +1,21 @@ -+/* Copyright (C) 1999-2024 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#define __WORDSIZE 32 -+#define __WORDSIZE_TIME64_COMPAT32 1 -+#define __WORDSIZE32_SIZE_ULONG 0 -+#define __WORDSIZE32_PTRDIFF_LONG 0 -diff --git a/sysdeps/nios2/utmp-size.h b/sysdeps/nios2/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/nios2/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/nptl/libc-lock.h b/sysdeps/nptl/libc-lock.h -index 5af476c48b..63b3f3d75c 100644 ---- a/sysdeps/nptl/libc-lock.h -+++ b/sysdeps/nptl/libc-lock.h -@@ -22,6 +22,7 @@ - #include - #define __need_NULL - #include -+#include - - - /* Mutex type. */ -@@ -29,7 +30,12 @@ - # if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC - typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; - # else --typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t; -+typedef struct -+{ -+ int lock __LIBC_LOCK_ALIGNMENT; -+ int cnt; -+ void *owner; -+} __libc_lock_recursive_t; - # endif - #else - typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; -diff --git a/sysdeps/nptl/libc-lockP.h b/sysdeps/nptl/libc-lockP.h -index d3a6837fd2..425f514c5c 100644 ---- a/sysdeps/nptl/libc-lockP.h -+++ b/sysdeps/nptl/libc-lockP.h -@@ -32,9 +32,10 @@ - ld.so might be used on old kernels with a different libc.so. */ - #include - #include -+#include - - /* Mutex type. */ --typedef int __libc_lock_t; -+typedef int __libc_lock_t __LIBC_LOCK_ALIGNMENT; - typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t; - typedef pthread_rwlock_t __libc_rwlock_t; - -diff --git a/sysdeps/or1k/utmp-size.h b/sysdeps/or1k/utmp-size.h -new file mode 100644 -index 0000000000..6b3653aa4d ---- /dev/null -+++ b/sysdeps/or1k/utmp-size.h -@@ -0,0 +1,3 @@ -+/* or1k has less padding than other architectures with 64-bit time_t. */ -+#define UTMP_SIZE 392 -+#define LASTLOG_SIZE 296 -diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c -index bcff909b2f..f975dcd2bc 100644 ---- a/sysdeps/posix/getaddrinfo.c -+++ b/sysdeps/posix/getaddrinfo.c -@@ -120,6 +120,7 @@ struct gaih_result - { - struct gaih_addrtuple *at; - char *canon; -+ char *h_name; - bool free_at; - bool got_ipv6; - }; -@@ -165,6 +166,7 @@ gaih_result_reset (struct gaih_result *res) - if (res->free_at) - free (res->at); - free (res->canon); -+ free (res->h_name); - memset (res, 0, sizeof (*res)); - } - -@@ -203,9 +205,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, - return 0; - } - --/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name -- is not copied, and the struct hostent object must not be deallocated -- prematurely. The new addresses are appended to the tuple array in RES. */ -+/* Convert struct hostent to a list of struct gaih_addrtuple objects. The new -+ addresses are appended to the tuple array in RES. */ - static bool - convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, - struct hostent *h, struct gaih_result *res) -@@ -238,6 +239,15 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, - res->at = array; - res->free_at = true; - -+ /* Duplicate h_name because it may get reclaimed when the underlying storage -+ is freed. */ -+ if (res->h_name == NULL) -+ { -+ res->h_name = __strdup (h->h_name); -+ if (res->h_name == NULL) -+ return false; -+ } -+ - /* Update the next pointers on reallocation. */ - for (size_t i = 0; i < old; i++) - array[i].next = array + i + 1; -@@ -262,7 +272,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, - } - array[i].next = array + i + 1; - } -- array[0].name = h->h_name; - array[count - 1].next = NULL; - - return true; -@@ -324,15 +333,15 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name, - memory allocation failure. The returned string is allocated on the - heap; the caller has to free it. */ - static char * --getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name) -+getcanonname (nss_action_list nip, const char *hname, const char *name) - { - nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r"); - char *s = (char *) name; - if (cfct != NULL) - { - char buf[256]; -- if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf), -- &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS) -+ if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno, -+ &h_errno)) != NSS_STATUS_SUCCESS) - /* If the canonical name cannot be determined, use the passed - string. */ - s = (char *) name; -@@ -540,11 +549,11 @@ get_nscd_addresses (const char *name, const struct addrinfo *req, - at[count].addr[2] = htonl (0xffff); - } - else if (req->ai_family == AF_UNSPEC -- || air->family[count] == req->ai_family) -+ || air->family[i] == req->ai_family) - { -- at[count].family = air->family[count]; -+ at[count].family = air->family[i]; - memcpy (at[count].addr, addrs, size); -- if (air->family[count] == AF_INET6) -+ if (air->family[i] == AF_INET6) - res->got_ipv6 = true; - } - at[count].next = at + count + 1; -@@ -771,7 +780,7 @@ get_nss_addresses (const char *name, const struct addrinfo *req, - if ((req->ai_flags & AI_CANONNAME) != 0 - && res->canon == NULL) - { -- char *canonbuf = getcanonname (nip, res->at, name); -+ char *canonbuf = getcanonname (nip, res->h_name, name); - if (canonbuf == NULL) - { - __resolv_context_put (res_ctx); -@@ -1187,9 +1196,7 @@ free_and_return: - if (malloc_name) - free ((char *) name); - free (addrmem); -- if (res.free_at) -- free (res.at); -- free (res.canon); -+ gaih_result_reset (&res); - - return result; - } -diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c -index 8014f63355..20c9420dd4 100644 ---- a/sysdeps/posix/system.c -+++ b/sysdeps/posix/system.c -@@ -179,16 +179,16 @@ do_system (const char *line) - as if the shell had terminated using _exit(127). */ - status = W_EXITCODE (127, 0); - -+ /* sigaction can not fail with SIGINT/SIGQUIT used with old -+ disposition. Same applies for sigprocmask. */ - DO_LOCK (); - if (SUB_REF () == 0) - { -- /* sigaction can not fail with SIGINT/SIGQUIT used with old -- disposition. Same applies for sigprocmask. */ - __sigaction (SIGINT, &intr, NULL); - __sigaction (SIGQUIT, &quit, NULL); -- __sigprocmask (SIG_SETMASK, &omask, NULL); - } - DO_UNLOCK (); -+ __sigprocmask (SIG_SETMASK, &omask, NULL); - - if (ret != 0) - __set_errno (ret); -diff --git a/sysdeps/powerpc/mod-tlsopt-powerpc.c b/sysdeps/powerpc/mod-tlsopt-powerpc.c -index 2a82e53baf..d941024963 100644 ---- a/sysdeps/powerpc/mod-tlsopt-powerpc.c -+++ b/sysdeps/powerpc/mod-tlsopt-powerpc.c -@@ -22,7 +22,11 @@ tls_get_addr_opt_test (void) - tls_index *tls_arg; - #ifdef __powerpc64__ - register unsigned long thread_pointer __asm__ ("r13"); -- asm ("addi %0,2,foo@got@tlsgd" : "=r" (tls_arg)); -+# ifdef __PCREL__ -+ asm ("paddi %0,0,foo@got@tlsgd@pcrel,1" : "=b" (tls_arg)); -+# else -+ asm ("addi %0,2,foo@got@tlsgd" : "=b" (tls_arg)); -+# endif - #else - register unsigned long thread_pointer __asm__ ("r2"); - asm ("bcl 20,31,1f\n1:\t" -diff --git a/sysdeps/powerpc/powerpc32/bits/wordsize.h b/sysdeps/powerpc/powerpc32/bits/wordsize.h -index 04ca9debf0..6993fb6b29 100644 ---- a/sysdeps/powerpc/powerpc32/bits/wordsize.h -+++ b/sysdeps/powerpc/powerpc32/bits/wordsize.h -@@ -2,10 +2,9 @@ - - #if defined __powerpc64__ - # define __WORDSIZE 64 --# define __WORDSIZE_TIME64_COMPAT32 1 - #else - # define __WORDSIZE 32 --# define __WORDSIZE_TIME64_COMPAT32 0 - # define __WORDSIZE32_SIZE_ULONG 0 - # define __WORDSIZE32_PTRDIFF_LONG 0 - #endif -+#define __WORDSIZE_TIME64_COMPAT32 1 -diff --git a/sysdeps/powerpc/powerpc64/bits/wordsize.h b/sysdeps/powerpc/powerpc64/bits/wordsize.h -index 04ca9debf0..6993fb6b29 100644 ---- a/sysdeps/powerpc/powerpc64/bits/wordsize.h -+++ b/sysdeps/powerpc/powerpc64/bits/wordsize.h -@@ -2,10 +2,9 @@ - - #if defined __powerpc64__ - # define __WORDSIZE 64 --# define __WORDSIZE_TIME64_COMPAT32 1 - #else - # define __WORDSIZE 32 --# define __WORDSIZE_TIME64_COMPAT32 0 - # define __WORDSIZE32_SIZE_ULONG 0 - # define __WORDSIZE32_PTRDIFF_LONG 0 - #endif -+#define __WORDSIZE_TIME64_COMPAT32 1 -diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h -index bb0ccd0811..3868bcc2f7 100644 ---- a/sysdeps/powerpc/powerpc64/dl-machine.h -+++ b/sysdeps/powerpc/powerpc64/dl-machine.h -@@ -79,6 +79,7 @@ elf_host_tolerates_class (const Elf64_Ehdr *ehdr) - static inline Elf64_Addr - elf_machine_load_address (void) __attribute__ ((const)); - -+#ifndef __PCREL__ - static inline Elf64_Addr - elf_machine_load_address (void) - { -@@ -106,6 +107,24 @@ elf_machine_dynamic (void) - /* Then subtract off the load address offset. */ - return runtime_dynamic - elf_machine_load_address() ; - } -+#else /* __PCREL__ */ -+/* In PCREL mode, r2 may have been clobbered. Rely on relative -+ relocations instead. */ -+ -+static inline ElfW(Addr) -+elf_machine_load_address (void) -+{ -+ extern const ElfW(Ehdr) __ehdr_start attribute_hidden; -+ return (ElfW(Addr)) &__ehdr_start; -+} -+ -+static inline ElfW(Addr) -+elf_machine_dynamic (void) -+{ -+ extern ElfW(Dyn) _DYNAMIC[] attribute_hidden; -+ return (ElfW(Addr)) _DYNAMIC - elf_machine_load_address (); -+} -+#endif /* __PCREL__ */ - - /* The PLT uses Elf64_Rela relocs. */ - #define elf_machine_relplt elf_machine_rela -diff --git a/sysdeps/powerpc/utmp-size.h b/sysdeps/powerpc/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/powerpc/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/riscv/utmp-size.h b/sysdeps/riscv/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/riscv/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/sh/bits/wordsize.h b/sysdeps/sh/bits/wordsize.h -new file mode 100644 -index 0000000000..6ecbfe7c86 ---- /dev/null -+++ b/sysdeps/sh/bits/wordsize.h -@@ -0,0 +1,21 @@ -+/* Copyright (C) 1999-2024 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#define __WORDSIZE 32 -+#define __WORDSIZE_TIME64_COMPAT32 1 -+#define __WORDSIZE32_SIZE_ULONG 0 -+#define __WORDSIZE32_PTRDIFF_LONG 0 -diff --git a/sysdeps/sh/utmp-size.h b/sysdeps/sh/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/sh/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/sparc/sparc32/bits/wordsize.h b/sysdeps/sparc/sparc32/bits/wordsize.h -index 2f66f10d72..a2e79e0fa9 100644 ---- a/sysdeps/sparc/sparc32/bits/wordsize.h -+++ b/sysdeps/sparc/sparc32/bits/wordsize.h -@@ -1,11 +1,6 @@ - /* Determine the wordsize from the preprocessor defines. */ - --#if defined __arch64__ || defined __sparcv9 --# define __WORDSIZE 64 --# define __WORDSIZE_TIME64_COMPAT32 1 --#else --# define __WORDSIZE 32 --# define __WORDSIZE_TIME64_COMPAT32 0 --# define __WORDSIZE32_SIZE_ULONG 0 --# define __WORDSIZE32_PTRDIFF_LONG 0 --#endif -+#define __WORDSIZE 32 -+#define __WORDSIZE_TIME64_COMPAT32 1 -+#define __WORDSIZE32_SIZE_ULONG 0 -+#define __WORDSIZE32_PTRDIFF_LONG 0 -diff --git a/sysdeps/sparc/sparc32/memset.S b/sysdeps/sparc/sparc32/memset.S -index b1b67cb2d1..5154263317 100644 ---- a/sysdeps/sparc/sparc32/memset.S -+++ b/sysdeps/sparc/sparc32/memset.S -@@ -55,7 +55,7 @@ ENTRY(memset) - - andcc %o0, 3, %o2 - bne 3f --4: andcc %o0, 4, %g0 -+5: andcc %o0, 4, %g0 - - be 2f - mov %g3, %g2 -@@ -139,7 +139,7 @@ ENTRY(memset) - stb %g3, [%o0 + 0x02] - 2: sub %o2, 4, %o2 - add %o1, %o2, %o1 -- b 4b -+ b 5b - sub %o0, %o2, %o0 - END(memset) - libc_hidden_builtin_def (memset) -diff --git a/sysdeps/sparc/sparc64/bits/wordsize.h b/sysdeps/sparc/sparc64/bits/wordsize.h -index 2f66f10d72..ea103e5970 100644 ---- a/sysdeps/sparc/sparc64/bits/wordsize.h -+++ b/sysdeps/sparc/sparc64/bits/wordsize.h -@@ -2,10 +2,9 @@ - - #if defined __arch64__ || defined __sparcv9 - # define __WORDSIZE 64 --# define __WORDSIZE_TIME64_COMPAT32 1 - #else - # define __WORDSIZE 32 --# define __WORDSIZE_TIME64_COMPAT32 0 - # define __WORDSIZE32_SIZE_ULONG 0 - # define __WORDSIZE32_PTRDIFF_LONG 0 - #endif -+#define __WORDSIZE_TIME64_COMPAT32 1 -diff --git a/sysdeps/sparc/sparc64/memmove.S b/sysdeps/sparc/sparc64/memmove.S -index 8d46f2cd4e..7746684160 100644 ---- a/sysdeps/sparc/sparc64/memmove.S -+++ b/sysdeps/sparc/sparc64/memmove.S -@@ -38,7 +38,7 @@ ENTRY(memmove) - /* - * normal, copy forwards - */ --2: ble %XCC, .Ldbytecp -+2: bleu %XCC, .Ldbytecp - andcc %o1, 3, %o5 /* is src word aligned */ - bz,pn %icc, .Laldst - cmp %o5, 2 /* is src half-word aligned */ -diff --git a/sysdeps/sparc/sysdep.h b/sysdeps/sparc/sysdep.h -index 95068071cc..baab6817a6 100644 ---- a/sysdeps/sparc/sysdep.h -+++ b/sysdeps/sparc/sysdep.h -@@ -76,6 +76,15 @@ C_LABEL(name) \ - cfi_endproc; \ - .size name, . - name - -+#define ENTRY_NOCFI(name) \ -+ .align 4; \ -+ .global C_SYMBOL_NAME(name); \ -+ .type name, @function; \ -+C_LABEL(name) -+ -+#define END_NOCFI(name) \ -+ .size name, . - name -+ - #undef LOC - #define LOC(name) .L##name - -diff --git a/sysdeps/sparc/utmp-size.h b/sysdeps/sparc/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/sparc/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile -index a139a16532..d5d9af4de2 100644 ---- a/sysdeps/unix/sysv/linux/Makefile -+++ b/sysdeps/unix/sysv/linux/Makefile -@@ -265,6 +265,14 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py - < /dev/null > $@ 2>&1; $(evaluate-test) - $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps) - -+tests-special += $(objpfx)tst-mount-compile.out -+$(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py -+ $(sysdeps-linux-python) \ -+ ../sysdeps/unix/sysv/linux/tst-mount-compile.py \ -+ $(sysdeps-linux-python-cc) \ -+ < /dev/null > $@ 2>&1; $(evaluate-test) -+$(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps) -+ - tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0 - - endif # $(subdir) == misc -@@ -354,6 +362,8 @@ sysdep_headers += netinet/if_fddi.h netinet/if_tr.h \ - netrom/netrom.h netpacket/packet.h netrose/rose.h \ - neteconet/ec.h netiucv/iucv.h - sysdep_routines += netlink_assert_response -+ -+CFLAGS-check_pf.c += -fexceptions - endif - - # Don't compile the ctype glue code, since there is no old non-GNU C library. -diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h b/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h -index 616239bb84..b7ffea84e5 100644 ---- a/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h -+++ b/sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h -@@ -78,3 +78,24 @@ - #define HWCAP2_AFP (1 << 20) - #define HWCAP2_RPRES (1 << 21) - #define HWCAP2_MTE3 (1 << 22) -+#define HWCAP2_SME (1 << 23) -+#define HWCAP2_SME_I16I64 (1 << 24) -+#define HWCAP2_SME_F64F64 (1 << 25) -+#define HWCAP2_SME_I8I32 (1 << 26) -+#define HWCAP2_SME_F16F32 (1 << 27) -+#define HWCAP2_SME_B16F32 (1 << 28) -+#define HWCAP2_SME_F32F32 (1 << 29) -+#define HWCAP2_SME_FA64 (1 << 30) -+#define HWCAP2_WFXT (1UL << 31) -+#define HWCAP2_EBF16 (1UL << 32) -+#define HWCAP2_SVE_EBF16 (1UL << 33) -+#define HWCAP2_CSSC (1UL << 34) -+#define HWCAP2_RPRFM (1UL << 35) -+#define HWCAP2_SVE2P1 (1UL << 36) -+#define HWCAP2_SME2 (1UL << 37) -+#define HWCAP2_SME2P1 (1UL << 38) -+#define HWCAP2_SME_I16I32 (1UL << 39) -+#define HWCAP2_SME_BI32I32 (1UL << 40) -+#define HWCAP2_SME_B16B16 (1UL << 41) -+#define HWCAP2_SME_F16F16 (1UL << 42) -+#define HWCAP2_MOPS (1UL << 43) -diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c -index d14c0f4e1f..2543128352 100644 ---- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c -+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - - #define DCZID_DZP_MASK (1 << 4) - #define DCZID_BS_MASK (0xf) -@@ -38,11 +39,9 @@ struct cpu_list - }; - - static struct cpu_list cpu_list[] = { -- {"falkor", 0x510FC000}, - {"thunderxt88", 0x430F0A10}, - {"thunderx2t99", 0x431F0AF0}, - {"thunderx2t99p1", 0x420F5160}, -- {"phecda", 0x680F0000}, - {"ares", 0x411FD0C0}, - {"emag", 0x503F0001}, - {"kunpeng920", 0x481FD010}, -@@ -61,6 +60,46 @@ get_midr_from_mcpu (const char *mcpu) - } - #endif - -+#if __LINUX_KERNEL_VERSION < 0x060200 -+ -+/* Return true if we prefer using SVE in string ifuncs. Old kernels disable -+ SVE after every system call which results in unnecessary traps if memcpy -+ uses SVE. This is true for kernels between 4.15.0 and before 6.2.0, except -+ for 5.14.0 which was patched. For these versions return false to avoid using -+ SVE ifuncs. -+ Parse the kernel version into a 24-bit kernel.major.minor value without -+ calling any library functions. If uname() is not supported or if the version -+ format is not recognized, assume the kernel is modern and return true. */ -+ -+static inline bool -+prefer_sve_ifuncs (void) -+{ -+ struct utsname buf; -+ const char *p = &buf.release[0]; -+ int kernel = 0; -+ int val; -+ -+ if (__uname (&buf) < 0) -+ return true; -+ -+ for (int shift = 16; shift >= 0; shift -= 8) -+ { -+ for (val = 0; *p >= '0' && *p <= '9'; p++) -+ val = val * 10 + *p - '0'; -+ kernel |= (val & 255) << shift; -+ if (*p++ != '.') -+ break; -+ } -+ -+ if (kernel >= 0x060200 || kernel == 0x050e00) -+ return true; -+ if (kernel >= 0x040f00) -+ return false; -+ return true; -+} -+ -+#endif -+ - static inline void - init_cpu_features (struct cpu_features *cpu_features) - { -@@ -126,4 +165,14 @@ init_cpu_features (struct cpu_features *cpu_features) - - /* Check if SVE is supported. */ - cpu_features->sve = GLRO (dl_hwcap) & HWCAP_SVE; -+ -+ cpu_features->prefer_sve_ifuncs = cpu_features->sve; -+ -+#if __LINUX_KERNEL_VERSION < 0x060200 -+ if (cpu_features->sve) -+ cpu_features->prefer_sve_ifuncs = prefer_sve_ifuncs (); -+#endif -+ -+ /* Check if MOPS is supported. */ -+ cpu_features->mops = GLRO (dl_hwcap2) & HWCAP2_MOPS; - } -diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h -index 391165a99c..d51597b923 100644 ---- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h -+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h -@@ -47,11 +47,6 @@ - #define IS_THUNDERX2(midr) (MIDR_IMPLEMENTOR(midr) == 'C' \ - && MIDR_PARTNUM(midr) == 0xaf) - --#define IS_FALKOR(midr) (MIDR_IMPLEMENTOR(midr) == 'Q' \ -- && MIDR_PARTNUM(midr) == 0xc00) -- --#define IS_PHECDA(midr) (MIDR_IMPLEMENTOR(midr) == 'h' \ -- && 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' \ -@@ -76,6 +71,8 @@ struct cpu_features - /* Currently, the GLIBC memory tagging tunable only defines 8 bits. */ - uint8_t mte_state; - bool sve; -+ bool prefer_sve_ifuncs; -+ bool mops; - }; - - #endif /* _CPU_FEATURES_AARCH64_H */ -diff --git a/sysdeps/unix/sysv/linux/alpha/brk_call.h b/sysdeps/unix/sysv/linux/alpha/brk_call.h -index b8088cf13f..0b851b6c86 100644 ---- a/sysdeps/unix/sysv/linux/alpha/brk_call.h -+++ b/sysdeps/unix/sysv/linux/alpha/brk_call.h -@@ -21,8 +21,7 @@ __brk_call (void *addr) - { - unsigned long int result = INTERNAL_SYSCALL_CALL (brk, addr); - if (result == -ENOMEM) -- /* Mimic the default error reporting behavior. */ -- return addr; -- else -- return (void *) result; -+ /* Mimic the generic error reporting behavior. */ -+ result = INTERNAL_SYSCALL_CALL (brk, 0); -+ return (void *) result; - } -diff --git a/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h -new file mode 100644 -index 0000000000..30ee6279d2 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h -@@ -0,0 +1,139 @@ -+/* Definition for struct stat. Linux/arm version. -+ Copyright (C) 2020-2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#if !defined _SYS_STAT_H && !defined _FCNTL_H -+# error "Never include directly; use instead." -+#endif -+ -+#ifndef _BITS_STRUCT_STAT_H -+#define _BITS_STRUCT_STAT_H 1 -+ -+#include -+#include -+ -+struct stat -+ { -+#ifdef __USE_TIME_BITS64 -+# include -+#else -+ __dev_t st_dev; /* Device. */ -+ unsigned short int __pad1; -+# ifndef __USE_FILE_OFFSET64 -+ __ino_t st_ino; /* File serial number. */ -+# else -+ __ino_t __st_ino; /* 32bit file serial number. */ -+# 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 -+ __off_t st_size; /* Size of file, in bytes. */ -+# else -+ __off64_t st_size; /* Size of file, in bytes. */ -+# endif -+ __blksize_t st_blksize; /* Optimal block size for I/O. */ -+ -+# ifndef __USE_FILE_OFFSET64 -+ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ -+# else -+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -+# 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 -+ identifier 'timespec' to appear in the header. -+ Therefore we have to handle the use of this header in strictly -+ standard-compliant sources special. */ -+ 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 -+ __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 -+# ifndef __USE_FILE_OFFSET64 -+ unsigned long int __glibc_reserved4; -+ unsigned long int __glibc_reserved5; -+# else -+ __ino64_t st_ino; /* File serial number. */ -+# endif -+#endif /* __USE_TIME_BITS64 */ -+ }; -+ -+#ifdef __USE_LARGEFILE64 -+struct stat64 -+ { -+# ifdef __USE_TIME_BITS64 -+# include -+# else -+ __dev_t st_dev; /* Device. */ -+ unsigned int __pad1; -+ -+ __ino_t __st_ino; /* 32bit file serial number. */ -+ __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 int __pad2; -+ __off64_t st_size; /* Size of file, in bytes. */ -+ __blksize_t st_blksize; /* Optimal block size for I/O. */ -+ -+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -+# 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 -+ identifier 'timespec' to appear in the header. -+ Therefore we have to handle the use of this header in strictly -+ standard-compliant sources special. */ -+ 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. */ -+# 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 -+ __ino64_t st_ino; /* File serial number. */ -+# endif /* __USE_TIME_BITS64 */ -+ }; -+#endif -+ -+/* Tell code we have these members. */ -+#define _STATBUF_ST_BLKSIZE -+#define _STATBUF_ST_RDEV -+/* Nanosecond resolution time values are supported. */ -+#define _STATBUF_ST_NSEC -+ -+ -+#endif /* _BITS_STRUCT_STAT_H */ -diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h -index 33ff88ce59..bfc674235d 100644 ---- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h -+++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h -@@ -101,7 +101,7 @@ - #endif - - #ifndef F_GETLK --# ifndef __USE_FILE_OFFSET64 -+# if !defined __USE_FILE_OFFSET64 && __TIMESIZE != 64 - # define F_GETLK 5 /* Get record locking info. */ - # define F_SETLK 6 /* Set record locking info (non-blocking). */ - # define F_SETLKW 7 /* Set record locking info (blocking). */ -diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h -index 4f1f810ea1..539b8d7716 100644 ---- a/sysdeps/unix/sysv/linux/bits/socket.h -+++ b/sysdeps/unix/sysv/linux/bits/socket.h -@@ -307,6 +307,12 @@ struct cmsghdr - + CMSG_ALIGN (sizeof (struct cmsghdr))) - #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) - -+/* Given a length, return the additional padding necessary such that -+ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ -+#define __CMSG_PADDING(len) ((sizeof (size_t) \ -+ - ((len) & (sizeof (size_t) - 1))) \ -+ & (sizeof (size_t) - 1)) -+ - extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, - struct cmsghdr *__cmsg) __THROW; - #ifdef __USE_EXTERN_INLINES -@@ -316,18 +322,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, - _EXTERN_INLINE struct cmsghdr * - __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) - { -+ /* We may safely assume that __cmsg lies between __mhdr->msg_control and -+ __mhdr->msg_controllen because the user is required to obtain the first -+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs -+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet -+ trust the value of __cmsg->cmsg_len and therefore do not use it in any -+ pointer arithmetic until we check its value. */ -+ -+ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; -+ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; -+ -+ size_t __size_needed = sizeof (struct cmsghdr) -+ + __CMSG_PADDING (__cmsg->cmsg_len); -+ -+ /* The current header is malformed, too small to be a full header. */ - if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) -- /* The kernel header does this so there may be a reason. */ - return (struct cmsghdr *) 0; - -+ /* There isn't enough space between __cmsg and the end of the buffer to -+ hold the current cmsg *and* the next one. */ -+ if (((size_t) -+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) -+ < __size_needed) -+ || ((size_t) -+ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr -+ - __size_needed) -+ < __cmsg->cmsg_len)) -+ -+ return (struct cmsghdr *) 0; -+ -+ /* Now, we trust cmsg_len and can use it to find the next header. */ - __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg - + CMSG_ALIGN (__cmsg->cmsg_len)); -- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control -- + __mhdr->msg_controllen) -- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) -- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) -- /* No more entries. */ -- return (struct cmsghdr *) 0; - return __cmsg; - } - #endif /* Use `extern inline'. */ -diff --git a/sysdeps/unix/sysv/linux/bits/struct_stat.h b/sysdeps/unix/sysv/linux/bits/struct_stat.h -index 25bd6cb638..fb11a3fba4 100644 ---- a/sysdeps/unix/sysv/linux/bits/struct_stat.h -+++ b/sysdeps/unix/sysv/linux/bits/struct_stat.h -@@ -26,37 +26,36 @@ - #include - #include - --struct stat -- { --#ifdef __USE_TIME_BITS64 --# include --#else -- __dev_t st_dev; /* Device. */ -- unsigned short int __pad1; --# ifndef __USE_FILE_OFFSET64 -- __ino_t st_ino; /* File serial number. */ --# else -- __ino_t __st_ino; /* 32bit file serial number. */ -+#if defined __USE_FILE_OFFSET64 -+# define __field64(type, type64, name) type64 name -+#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T -+# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T -+# error "ino_t and off_t must both be the same type" - # 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 -- __off_t st_size; /* Size of file, in bytes. */ --# else -- __off64_t st_size; /* Size of file, in bytes. */ --# endif -- __blksize_t st_blksize; /* Optimal block size for I/O. */ -+# define __field64(type, type64, name) type name -+#elif __BYTE_ORDER == __LITTLE_ENDIAN -+# define __field64(type, type64, name) \ -+ type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad -+#else -+# define __field64(type, type64, name) \ -+ int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name -+#endif - --# ifndef __USE_FILE_OFFSET64 -- __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ --# else -- __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ --# endif --# ifdef __USE_XOPEN2K8 -+struct stat -+ { -+ __dev_t st_dev; /* Device. */ -+ __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ -+ __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. */ -+ __dev_t __pad1; -+ __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ -+ __blksize_t st_blksize; /* Optimal block size for I/O. */ -+ int __pad2; -+ __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ -+#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 -@@ -66,47 +65,38 @@ 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 --# ifndef __USE_FILE_OFFSET64 -- unsigned long int __glibc_reserved4; -- unsigned long int __glibc_reserved5; --# else -- __ino64_t st_ino; /* File serial number. */ --# endif --#endif /* __USE_TIME_BITS64 */ -+#endif -+ int __glibc_reserved[2]; - }; - -+#undef __field64 -+ - #ifdef __USE_LARGEFILE64 - struct stat64 - { --# ifdef __USE_TIME_BITS64 --# include --# else -- __dev_t st_dev; /* Device. */ -- unsigned int __pad1; -- -- __ino_t __st_ino; /* 32bit file serial number. */ -- __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 int __pad2; -- __off64_t st_size; /* Size of file, in bytes. */ -- __blksize_t st_blksize; /* Optimal block size for I/O. */ -- -- __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ --# ifdef __USE_XOPEN2K8 -+ __dev_t st_dev; /* Device. */ -+ __ino64_t st_ino; /* File serial number. */ -+ __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. */ -+ __dev_t __pad1; -+ __off64_t st_size; /* Size of file, in bytes. */ -+ __blksize_t st_blksize; /* Optimal block size for I/O. */ -+ int __pad2; -+ __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ -+#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 -@@ -116,16 +106,15 @@ 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. */ --# else -+#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 -- __ino64_t st_ino; /* File serial number. */ --# endif /* __USE_TIME_BITS64 */ -+#endif -+ int __glibc_reserved[2]; - }; - #endif - -@@ -135,5 +124,4 @@ struct stat64 - /* Nanosecond resolution time values are supported. */ - #define _STATBUF_ST_NSEC - -- - #endif /* _BITS_STRUCT_STAT_H */ -diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c -index fe73fe3ba8..ca20043408 100644 ---- a/sysdeps/unix/sysv/linux/check_pf.c -+++ b/sysdeps/unix/sysv/linux/check_pf.c -@@ -292,6 +292,14 @@ make_request (int fd, pid_t pid) - return NULL; - } - -+#ifdef __EXCEPTIONS -+static void -+cancel_handler (void *arg __attribute__((unused))) -+{ -+ /* Release the lock. */ -+ __libc_lock_unlock (lock); -+} -+#endif - - void - attribute_hidden -@@ -304,6 +312,10 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6, - struct cached_data *olddata = NULL; - struct cached_data *data = NULL; - -+#ifdef __EXCEPTIONS -+ /* Make sure that lock is released when the thread is cancelled. */ -+ __libc_cleanup_push (cancel_handler, NULL); -+#endif - __libc_lock_lock (lock); - - if (cache_valid_p ()) -@@ -338,6 +350,9 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6, - } - } - -+#ifdef __EXCEPTIONS -+ __libc_cleanup_pop (0); -+#endif - __libc_lock_unlock (lock); - - if (data != NULL) -diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c -index 15b7a3a925..24f72b797a 100644 ---- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c -+++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c -@@ -23,18 +23,38 @@ - struct cmsghdr * - __cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg) - { -+ /* We may safely assume that cmsg lies between mhdr->msg_control and -+ mhdr->msg_controllen because the user is required to obtain the first -+ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs -+ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet -+ trust the value of cmsg->cmsg_len and therefore do not use it in any -+ pointer arithmetic until we check its value. */ -+ -+ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control; -+ unsigned char * cmsg_ptr = (unsigned char *) cmsg; -+ -+ size_t size_needed = sizeof (struct cmsghdr) -+ + __CMSG_PADDING (cmsg->cmsg_len); -+ -+ /* The current header is malformed, too small to be a full header. */ - if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr)) -- /* The kernel header does this so there may be a reason. */ -- return NULL; -+ return (struct cmsghdr *) 0; -+ -+ /* There isn't enough space between cmsg and the end of the buffer to -+ hold the current cmsg *and* the next one. */ -+ if (((size_t) -+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr) -+ < size_needed) -+ || ((size_t) -+ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr -+ - size_needed) -+ < cmsg->cmsg_len)) -+ -+ return (struct cmsghdr *) 0; - -+ /* Now, we trust cmsg_len and can use it to find the next header. */ - cmsg = (struct cmsghdr *) ((unsigned char *) cmsg - + CMSG_ALIGN (cmsg->cmsg_len)); -- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control -- + mhdr->msg_controllen) -- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len) -- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen))) -- /* No more entries. */ -- return NULL; - return cmsg; - } - libc_hidden_def (__cmsg_nxthdr) -diff --git a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h -similarity index 92% -rename from sysdeps/unix/sysv/linux/generic/bits/struct_stat.h -rename to sysdeps/unix/sysv/linux/csky/bits/struct_stat.h -index fb11a3fba4..f0ee455748 100644 ---- a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h -+++ b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h -@@ -1,4 +1,4 @@ --/* Definition for struct stat. -+/* Definition for struct stat. Linux/csky version. - Copyright (C) 2020-2022 Free Software Foundation, Inc. - This file is part of the GNU C Library. - -@@ -43,6 +43,9 @@ - - struct stat - { -+#ifdef __USE_TIME_BITS64 -+# include -+#else - __dev_t st_dev; /* Device. */ - __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ - __mode_t st_mode; /* File mode. */ -@@ -55,7 +58,7 @@ struct stat - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ --#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 -@@ -65,18 +68,19 @@ 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 - int __glibc_reserved[2]; -+#endif - }; - - #undef __field64 -@@ -84,6 +88,9 @@ struct stat - #ifdef __USE_LARGEFILE64 - struct stat64 - { -+# ifdef __USE_TIME_BITS64 -+# include -+# else - __dev_t st_dev; /* Device. */ - __ino64_t st_ino; /* File serial number. */ - __mode_t st_mode; /* File mode. */ -@@ -96,7 +103,7 @@ struct stat64 - __blksize_t st_blksize; /* Optimal block size for I/O. */ - int __pad2; - __blkcnt64_t st_blocks; /* Nr. 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,15 +113,16 @@ 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. */ --#else -+# 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 - int __glibc_reserved[2]; -+# endif - }; - #endif - -diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c -index 064eaa08ae..4d01786120 100644 ---- a/sysdeps/unix/sysv/linux/getsysstats.c -+++ b/sysdeps/unix/sysv/linux/getsysstats.c -@@ -29,7 +29,7 @@ - #include - #include - --int -+static int - __get_nprocs_sched (void) - { - enum -diff --git a/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h -new file mode 100644 -index 0000000000..38b6e13e68 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h -@@ -0,0 +1,139 @@ -+/* Definition for struct stat. Linux/hppa version. -+ Copyright (C) 2020-2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#if !defined _SYS_STAT_H && !defined _FCNTL_H -+# error "Never include directly; use instead." -+#endif -+ -+#ifndef _BITS_STRUCT_STAT_H -+#define _BITS_STRUCT_STAT_H 1 -+ -+#include -+#include -+ -+struct stat -+ { -+#ifdef __USE_TIME_BITS64 -+# include -+#else -+ __dev_t st_dev; /* Device. */ -+ unsigned short int __pad1; -+# ifndef __USE_FILE_OFFSET64 -+ __ino_t st_ino; /* File serial number. */ -+# else -+ __ino_t __st_ino; /* 32bit file serial number. */ -+# 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 -+ __off_t st_size; /* Size of file, in bytes. */ -+# else -+ __off64_t st_size; /* Size of file, in bytes. */ -+# endif -+ __blksize_t st_blksize; /* Optimal block size for I/O. */ -+ -+# ifndef __USE_FILE_OFFSET64 -+ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ -+# else -+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -+# 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 -+ identifier 'timespec' to appear in the header. -+ Therefore we have to handle the use of this header in strictly -+ standard-compliant sources special. */ -+ 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 -+ __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 -+# ifndef __USE_FILE_OFFSET64 -+ unsigned long int __glibc_reserved4; -+ unsigned long int __glibc_reserved5; -+# else -+ __ino64_t st_ino; /* File serial number. */ -+# endif -+#endif /* __USE_TIME_BITS64 */ -+ }; -+ -+#ifdef __USE_LARGEFILE64 -+struct stat64 -+ { -+# ifdef __USE_TIME_BITS64 -+# include -+# else -+ __dev_t st_dev; /* Device. */ -+ unsigned int __pad1; -+ -+ __ino_t __st_ino; /* 32bit file serial number. */ -+ __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 int __pad2; -+ __off64_t st_size; /* Size of file, in bytes. */ -+ __blksize_t st_blksize; /* Optimal block size for I/O. */ -+ -+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -+# 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 -+ identifier 'timespec' to appear in the header. -+ Therefore we have to handle the use of this header in strictly -+ standard-compliant sources special. */ -+ 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. */ -+# 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 -+ __ino64_t st_ino; /* File serial number. */ -+# endif /* __USE_TIME_BITS64 */ -+ }; -+#endif -+ -+/* Tell code we have these members. */ -+#define _STATBUF_ST_BLKSIZE -+#define _STATBUF_ST_RDEV -+/* Nanosecond resolution time values are supported. */ -+#define _STATBUF_ST_NSEC -+ -+ -+#endif /* _BITS_STRUCT_STAT_H */ -diff --git a/sysdeps/unix/sysv/linux/hppa/bits/wordsize.h b/sysdeps/unix/sysv/linux/hppa/bits/wordsize.h -new file mode 100644 -index 0000000000..6ecbfe7c86 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/hppa/bits/wordsize.h -@@ -0,0 +1,21 @@ -+/* Copyright (C) 1999-2024 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#define __WORDSIZE 32 -+#define __WORDSIZE_TIME64_COMPAT32 1 -+#define __WORDSIZE32_SIZE_ULONG 0 -+#define __WORDSIZE32_PTRDIFF_LONG 0 -diff --git a/sysdeps/unix/sysv/linux/hppa/kernel-features.h b/sysdeps/unix/sysv/linux/hppa/kernel-features.h -index 0cd21ef0fa..079612e4aa 100644 ---- a/sysdeps/unix/sysv/linux/hppa/kernel-features.h -+++ b/sysdeps/unix/sysv/linux/hppa/kernel-features.h -@@ -30,3 +30,6 @@ - - #undef __ASSUME_CLONE_DEFAULT - #define __ASSUME_CLONE_BACKWARDS 1 -+ -+/* QEMU does not support set_robust_list. */ -+#undef __ASSUME_SET_ROBUST_LIST -diff --git a/sysdeps/unix/sysv/linux/ipc_priv.h b/sysdeps/unix/sysv/linux/ipc_priv.h -index 87893a6757..2f50c31a8e 100644 ---- a/sysdeps/unix/sysv/linux/ipc_priv.h -+++ b/sysdeps/unix/sysv/linux/ipc_priv.h -@@ -63,4 +63,10 @@ struct __old_ipc_perm - # define __IPC_TIME64 0 - #endif - -+#if __IPC_TIME64 || defined __ASSUME_SYSVIPC_BROKEN_MODE_T -+# define IPC_CTL_NEED_TRANSLATION 1 -+#else -+# define IPC_CTL_NEED_TRANSLATION 0 -+#endif -+ - #include -diff --git a/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h -new file mode 100644 -index 0000000000..1844bbaf6f ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h -@@ -0,0 +1,25 @@ -+/* Private libc-internal arch-specific definitions. m68k version. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public License as -+ published by the Free Software Foundation; either version 2.1 of the -+ License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; see the file COPYING.LIB. If -+ not, see . */ -+ -+#ifndef _LIBC_LOCK_ARCH_H -+#define _LIBC_LOCK_ARCH_H -+ -+/* Linux enforces 4-bytes alignment on futex inputs. */ -+#define __LIBC_LOCK_ALIGNMENT __attribute__ ((__aligned__ (4))) -+ -+#endif -diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c -new file mode 100644 -index 0000000000..fe6c3a0dda ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c -@@ -0,0 +1,51 @@ -+/* Get file status. Linux/MIPSn64 version. -+ Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+ -+/* Different than other ABIs, mips64 has different layouts for non-LFS -+ and LFS struct stat. */ -+int -+__fstatat (int fd, const char *file, struct stat *buf, int flag) -+{ -+ struct __stat64_t64 st64; -+ int r = __fstatat64_time64 (fd, file, &st64, flag); -+ if (r == 0) -+ { -+ /* Clear internal pad and reserved fields. */ -+ memset (buf, 0, sizeof (*buf)); -+ -+ buf->st_dev = st64.st_dev; -+ buf->st_ino = st64.st_ino; -+ buf->st_mode = st64.st_mode; -+ buf->st_nlink = st64.st_nlink; -+ buf->st_uid = st64.st_uid; -+ buf->st_gid = st64.st_gid; -+ buf->st_rdev = st64.st_rdev; -+ buf->st_size = st64.st_size; -+ buf->st_blksize = st64.st_blksize; -+ buf->st_blocks = st64.st_blocks; -+ buf->st_atim = st64.st_atim; -+ buf->st_mtim = st64.st_mtim; -+ buf->st_ctim = st64.st_ctim; -+ } -+ return r; -+} -+ -+weak_alias (__fstatat, fstatat) -diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c -index e824ebb095..2072205252 100644 ---- a/sysdeps/unix/sysv/linux/msgctl.c -+++ b/sysdeps/unix/sysv/linux/msgctl.c -@@ -85,11 +85,19 @@ msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf) - int - __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) - { --#if __IPC_TIME64 -+#if IPC_CTL_NEED_TRANSLATION -+# if __IPC_TIME64 - struct kernel_msqid64_ds ksemid, *arg = NULL; --#else -+# else - msgctl_arg_t *arg; --#endif -+# endif -+ -+ /* Some applications pass the __IPC_64 flag in cmd, to invoke -+ previously unsupported commands back when there was no EINVAL -+ error checking in glibc. Mask the flag for the switch statements -+ below. msgctl_syscall adds back the __IPC_64 flag for the actual -+ system call. */ -+ cmd &= ~__IPC_64; - - switch (cmd) - { -@@ -101,19 +109,19 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) - case IPC_STAT: - case MSG_STAT: - case MSG_STAT_ANY: --#if __IPC_TIME64 -+# if __IPC_TIME64 - if (buf != NULL) - { - msqid64_to_kmsqid64 (buf, &ksemid); - arg = &ksemid; - } --# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T -+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T - if (cmd == IPC_SET) - arg->msg_perm.mode *= 0x10000U; --# endif --#else -+# endif -+# else - arg = buf; --#endif -+# endif - break; - - case IPC_INFO: -@@ -137,21 +145,25 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) - case IPC_STAT: - case MSG_STAT: - case MSG_STAT_ANY: --#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T -+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T - arg->msg_perm.mode >>= 16; --#else -+# else - /* Old Linux kernel versions might not clear the mode padding. */ - if (sizeof ((struct msqid_ds){0}.msg_perm.mode) - != sizeof (__kernel_mode_t)) - arg->msg_perm.mode &= 0xFFFF; --#endif -+# endif - --#if __IPC_TIME64 -+# if __IPC_TIME64 - kmsqid64_to_msqid64 (arg, buf); --#endif -+# endif - } - - return ret; -+ -+#else /* !IPC_CTL_NEED_TRANSLATION */ -+ return msgctl_syscall (msqid, cmd, buf); -+#endif - } - #if __TIMESIZE != 64 - libc_hidden_def (__msgctl64) -diff --git a/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h -new file mode 100644 -index 0000000000..e00e71173e ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h -@@ -0,0 +1,135 @@ -+/* Definition for struct stat. Linux/nios2 version. -+ Copyright (C) 2020-2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#if !defined _SYS_STAT_H && !defined _FCNTL_H -+# error "Never include directly; use instead." -+#endif -+ -+#ifndef _BITS_STRUCT_STAT_H -+#define _BITS_STRUCT_STAT_H 1 -+ -+#include -+#include -+ -+#if defined __USE_FILE_OFFSET64 -+# define __field64(type, type64, name) type64 name -+#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T -+# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T -+# error "ino_t and off_t must both be the same type" -+# endif -+# define __field64(type, type64, name) type name -+#elif __BYTE_ORDER == __LITTLE_ENDIAN -+# define __field64(type, type64, name) \ -+ type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad -+#else -+# define __field64(type, type64, name) \ -+ int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name -+#endif -+ -+struct stat -+ { -+#ifdef __USE_TIME_BITS64 -+# include -+#else -+ __dev_t st_dev; /* Device. */ -+ __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ -+ __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. */ -+ __dev_t __pad1; -+ __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ -+ __blksize_t st_blksize; /* Optimal block size for I/O. */ -+ int __pad2; -+ __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ -+# 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 -+ identifier 'timespec' to appear in the header. -+ Therefore we have to handle the use of this header in strictly -+ standard-compliant sources special. */ -+ 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 -+ __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 -+ int __glibc_reserved[2]; -+#endif -+ }; -+ -+#undef __field64 -+ -+#ifdef __USE_LARGEFILE64 -+struct stat64 -+ { -+# ifdef __USE_TIME_BITS64 -+# include -+# else -+ __dev_t st_dev; /* Device. */ -+ __ino64_t st_ino; /* File serial number. */ -+ __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. */ -+ __dev_t __pad1; -+ __off64_t st_size; /* Size of file, in bytes. */ -+ __blksize_t st_blksize; /* Optimal block size for I/O. */ -+ int __pad2; -+ __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ -+# 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 -+ identifier 'timespec' to appear in the header. -+ Therefore we have to handle the use of this header in strictly -+ standard-compliant sources special. */ -+ 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. */ -+# 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 -+ int __glibc_reserved[2]; -+# endif -+ }; -+#endif -+ -+/* Tell code we have these members. */ -+#define _STATBUF_ST_BLKSIZE -+#define _STATBUF_ST_RDEV -+/* Nanosecond resolution time values are supported. */ -+#define _STATBUF_ST_NSEC -+ -+#endif /* _BITS_STRUCT_STAT_H */ -diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h -index a263d294b1..cf35c8bfc9 100644 ---- a/sysdeps/unix/sysv/linux/not-cancel.h -+++ b/sysdeps/unix/sysv/linux/not-cancel.h -@@ -68,7 +68,7 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt) - INTERNAL_SYSCALL_CALL (writev, fd, iov, iovcnt); - } - --static inline int -+static inline ssize_t - __getrandom_nocancel (void *buf, size_t buflen, unsigned int flags) - { - return INLINE_SYSCALL_CALL (getrandom, buf, buflen, flags); -diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h -index d7cf158b33..0ca6e69ee9 100644 ---- a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h -+++ b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h -@@ -33,6 +33,12 @@ - # define __O_LARGEFILE 0200000 - #endif - -+#if __WORDSIZE == 64 && !defined __USE_FILE_OFFSET64 -+# define F_GETLK 5 -+# define F_SETLK 6 -+# define F_SETLKW 7 -+#endif -+ - struct flock - { - short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */ -diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h b/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h -index 04ca9debf0..6993fb6b29 100644 ---- a/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h -+++ b/sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h -@@ -2,10 +2,9 @@ - - #if defined __powerpc64__ - # define __WORDSIZE 64 --# define __WORDSIZE_TIME64_COMPAT32 1 - #else - # define __WORDSIZE 32 --# define __WORDSIZE_TIME64_COMPAT32 0 - # define __WORDSIZE32_SIZE_ULONG 0 - # define __WORDSIZE32_PTRDIFF_LONG 0 - #endif -+#define __WORDSIZE_TIME64_COMPAT32 1 -diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h -index bf4be80f8d..202520ee25 100644 ---- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h -+++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h -@@ -122,6 +122,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 -diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h -index d656aedcc2..4e65f337d4 100644 ---- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h -+++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h -@@ -127,6 +127,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 -diff --git a/sysdeps/unix/sysv/linux/sched_getcpu.c b/sysdeps/unix/sysv/linux/sched_getcpu.c -index 5c3301004c..3a2f712386 100644 ---- a/sysdeps/unix/sysv/linux/sched_getcpu.c -+++ b/sysdeps/unix/sysv/linux/sched_getcpu.c -@@ -33,17 +33,9 @@ vsyscall_sched_getcpu (void) - return r == -1 ? r : cpu; - } - --#ifdef RSEQ_SIG - int - sched_getcpu (void) - { - int cpu_id = THREAD_GETMEM_VOLATILE (THREAD_SELF, rseq_area.cpu_id); - return __glibc_likely (cpu_id >= 0) ? cpu_id : vsyscall_sched_getcpu (); - } --#else /* RSEQ_SIG */ --int --sched_getcpu (void) --{ -- return vsyscall_sched_getcpu (); --} --#endif /* RSEQ_SIG */ -diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c -index 77a8130c18..3458b018bc 100644 ---- a/sysdeps/unix/sysv/linux/semctl.c -+++ b/sysdeps/unix/sysv/linux/semctl.c -@@ -140,6 +140,13 @@ __semctl64 (int semid, int semnum, int cmd, ...) - union semun64 arg64 = { 0 }; - va_list ap; - -+ /* Some applications pass the __IPC_64 flag in cmd, to invoke -+ previously unsupported commands back when there was no EINVAL -+ error checking in glibc. Mask the flag for the switch statements -+ below. semctl_syscall adds back the __IPC_64 flag for the actual -+ system call. */ -+ cmd &= ~__IPC_64; -+ - /* Get the argument only if required. */ - switch (cmd) - { -diff --git a/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h -new file mode 100644 -index 0000000000..0f7c9cdc89 ---- /dev/null -+++ b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h -@@ -0,0 +1,139 @@ -+/* Definition for struct stat. Linux/sh version. -+ Copyright (C) 2020-2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library. If not, see -+ . */ -+ -+#if !defined _SYS_STAT_H && !defined _FCNTL_H -+# error "Never include directly; use instead." -+#endif -+ -+#ifndef _BITS_STRUCT_STAT_H -+#define _BITS_STRUCT_STAT_H 1 -+ -+#include -+#include -+ -+struct stat -+ { -+#ifdef __USE_TIME_BITS64 -+# include -+#else -+ __dev_t st_dev; /* Device. */ -+ unsigned short int __pad1; -+# ifndef __USE_FILE_OFFSET64 -+ __ino_t st_ino; /* File serial number. */ -+# else -+ __ino_t __st_ino; /* 32bit file serial number. */ -+# 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 -+ __off_t st_size; /* Size of file, in bytes. */ -+# else -+ __off64_t st_size; /* Size of file, in bytes. */ -+# endif -+ __blksize_t st_blksize; /* Optimal block size for I/O. */ -+ -+# ifndef __USE_FILE_OFFSET64 -+ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ -+# else -+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -+# 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 -+ identifier 'timespec' to appear in the header. -+ Therefore we have to handle the use of this header in strictly -+ standard-compliant sources special. */ -+ 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 -+ __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 -+# ifndef __USE_FILE_OFFSET64 -+ unsigned long int __glibc_reserved4; -+ unsigned long int __glibc_reserved5; -+# else -+ __ino64_t st_ino; /* File serial number. */ -+# endif -+#endif /* __USE_TIME_BITS64 */ -+ }; -+ -+#ifdef __USE_LARGEFILE64 -+struct stat64 -+ { -+# ifdef __USE_TIME_BITS64 -+# include -+# else -+ __dev_t st_dev; /* Device. */ -+ unsigned int __pad1; -+ -+ __ino_t __st_ino; /* 32bit file serial number. */ -+ __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 int __pad2; -+ __off64_t st_size; /* Size of file, in bytes. */ -+ __blksize_t st_blksize; /* Optimal block size for I/O. */ -+ -+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ -+# 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 -+ identifier 'timespec' to appear in the header. -+ Therefore we have to handle the use of this header in strictly -+ standard-compliant sources special. */ -+ 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. */ -+# 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 -+ __ino64_t st_ino; /* File serial number. */ -+# endif /* __USE_TIME_BITS64 */ -+ }; -+#endif -+ -+/* Tell code we have these members. */ -+#define _STATBUF_ST_BLKSIZE -+#define _STATBUF_ST_RDEV -+/* Nanosecond resolution time values are supported. */ -+#define _STATBUF_ST_NSEC -+ -+ -+#endif /* _BITS_STRUCT_STAT_H */ -diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c -index ea38935497..f00817a6f6 100644 ---- a/sysdeps/unix/sysv/linux/shmctl.c -+++ b/sysdeps/unix/sysv/linux/shmctl.c -@@ -85,11 +85,19 @@ shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf) - int - __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) - { --#if __IPC_TIME64 -+#if IPC_CTL_NEED_TRANSLATION -+# if __IPC_TIME64 - struct kernel_shmid64_ds kshmid, *arg = NULL; --#else -+# else - shmctl_arg_t *arg; --#endif -+# endif -+ -+ /* Some applications pass the __IPC_64 flag in cmd, to invoke -+ previously unsupported commands back when there was no EINVAL -+ error checking in glibc. Mask the flag for the switch statements -+ below. shmctl_syscall adds back the __IPC_64 flag for the actual -+ system call. */ -+ cmd &= ~__IPC_64; - - switch (cmd) - { -@@ -103,19 +111,19 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) - case IPC_STAT: - case SHM_STAT: - case SHM_STAT_ANY: --#if __IPC_TIME64 -+# if __IPC_TIME64 - if (buf != NULL) - { - shmid64_to_kshmid64 (buf, &kshmid); - arg = &kshmid; - } --# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T -+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T - if (cmd == IPC_SET) - arg->shm_perm.mode *= 0x10000U; --# endif --#else -+# endif -+# else - arg = buf; --#endif -+# endif - break; - - case IPC_INFO: -@@ -140,21 +148,25 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) - case IPC_STAT: - case SHM_STAT: - case SHM_STAT_ANY: --#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T -+# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T - arg->shm_perm.mode >>= 16; --#else -+# else - /* Old Linux kernel versions might not clear the mode padding. */ - if (sizeof ((struct shmid_ds){0}.shm_perm.mode) - != sizeof (__kernel_mode_t)) - arg->shm_perm.mode &= 0xFFFF; --#endif -+# endif - --#if __IPC_TIME64 -+# if __IPC_TIME64 - kshmid64_to_shmid64 (arg, buf); --#endif -+# endif - } - - return ret; -+ -+#else /* !IPC_CTL_NEED_TRANSLATION */ -+ return shmctl_syscall (shmid, cmd, buf); -+#endif - } - #if __TIMESIZE != 64 - libc_hidden_def (__shmctl64) -diff --git a/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h b/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h -index 7562875ee2..ea103e5970 100644 ---- a/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h -+++ b/sysdeps/unix/sysv/linux/sparc/bits/wordsize.h -@@ -2,10 +2,9 @@ - - #if defined __arch64__ || defined __sparcv9 - # define __WORDSIZE 64 --# define __WORDSIZE_TIME64_COMPAT32 1 - #else - # define __WORDSIZE 32 - # define __WORDSIZE32_SIZE_ULONG 0 - # define __WORDSIZE32_PTRDIFF_LONG 0 --# define __WORDSIZE_TIME64_COMPAT32 0 - #endif -+#define __WORDSIZE_TIME64_COMPAT32 1 -diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S b/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S -index 2829e881eb..a1492ea59e 100644 ---- a/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S -+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S -@@ -23,12 +23,15 @@ - - [1] https://lkml.org/lkml/2016/5/27/465 */ - --ENTRY (__rt_sigreturn_stub) -+ nop -+ nop -+ -+ENTRY_NOCFI (__rt_sigreturn_stub) - mov __NR_rt_sigreturn, %g1 - ta 0x10 --END (__rt_sigreturn_stub) -+END_NOCFI (__rt_sigreturn_stub) - --ENTRY (__sigreturn_stub) -+ENTRY_NOCFI (__sigreturn_stub) - mov __NR_sigreturn, %g1 - ta 0x10 --END (__sigreturn_stub) -+END_NOCFI (__sigreturn_stub) -diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S b/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S -index ac6af95e36..23b8b93f56 100644 ---- a/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S -+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S -@@ -23,7 +23,10 @@ - - [1] https://lkml.org/lkml/2016/5/27/465 */ - --ENTRY (__rt_sigreturn_stub) -+ nop -+ nop -+ -+ENTRY_NOCFI (__rt_sigreturn_stub) - mov __NR_rt_sigreturn, %g1 - ta 0x6d --END (__rt_sigreturn_stub) -+END_NOCFI (__rt_sigreturn_stub) -diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h -index f965986ba8..19841d0738 100644 ---- a/sysdeps/unix/sysv/linux/sys/mount.h -+++ b/sysdeps/unix/sysv/linux/sys/mount.h -@@ -27,77 +27,113 @@ - #include - #include - --#define BLOCK_SIZE 1024 -+#ifdef __has_include -+# if __has_include ("linux/mount.h") -+# include "linux/mount.h" -+# endif -+#endif -+ -+ - #define BLOCK_SIZE_BITS 10 -+#define BLOCK_SIZE (1<. -+ -+import argparse -+import sys -+ -+import glibcextract -+ -+ -+def main(): -+ """The main entry point.""" -+ parser = argparse.ArgumentParser( -+ description='Check if glibc provided sys/mount.h can be ' -+ ' used along related kernel headers.') -+ parser.add_argument('--cc', metavar='CC', -+ help='C compiler (including options) to use') -+ args = parser.parse_args() -+ -+ if glibcextract.compile_c_snippet( -+ '#include ', -+ args.cc).returncode != 0: -+ sys.exit (77) -+ -+ def check(testname, snippet): -+ # Add -Werror to catch macro redefinitions and _ISOMAC to avoid -+ # internal glibc definitions. -+ r = glibcextract.compile_c_snippet(snippet, args.cc, -+ '-Werror -D_ISOMAC') -+ if r.returncode != 0: -+ print('error: test {}:\n{}'.format(testname, r.output.decode())) -+ return r.returncode -+ -+ status = max( -+ check("sys/mount.h + linux/mount.h", -+ "#include \n" -+ "#include "), -+ check("sys/mount.h + linux/fs.h", -+ "#include \n" -+ "#include "), -+ check("linux/mount.h + sys/mount.h", -+ "#include \n" -+ "#include "), -+ check("linux/fs.h + sys/mount.h", -+ "#include \n" -+ "#include ")) -+ sys.exit(status) -+ -+if __name__ == '__main__': -+ main() -diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py -index a62f803123..be2ef2daf1 100755 ---- a/sysdeps/unix/sysv/linux/tst-mount-consts.py -+++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py -@@ -33,6 +33,11 @@ def main(): - help='C compiler (including options) to use') - args = parser.parse_args() - -+ if glibcextract.compile_c_snippet( -+ '#include ', -+ args.cc).returncode != 0: -+ sys.exit (77) -+ - linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) - # Constants in glibc were updated to match Linux v5.16. When glibc - # constants are updated this value should be updated to match the -diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py -index 90cbb9be64..d732173abd 100644 ---- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py -+++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py -@@ -33,11 +33,13 @@ def main(): - help='C compiler (including options) to use') - args = parser.parse_args() - -- linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) -- # Linux started to provide pidfd.h with 5.10. -- if linux_version_headers < (5, 10): -+ if glibcextract.compile_c_snippet( -+ '#include ', -+ args.cc).returncode != 0: - sys.exit (77) -- linux_version_glibc = (5, 18) -+ -+ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) -+ linux_version_glibc = (5, 19) - sys.exit(glibcextract.compare_macro_consts( - '#include \n', - '#include \n' -diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c -index 037af22290..5711d1c312 100644 ---- a/sysdeps/unix/sysv/linux/tst-pidfd.c -+++ b/sysdeps/unix/sysv/linux/tst-pidfd.c -@@ -147,8 +147,11 @@ do_test (void) - may be denied if the process doesn't have CAP_SYS_PTRACE or - if a LSM security_ptrace_access_check denies access. */ - if (fd == -1 && errno == EPERM) -- FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, " -- "skipping test"); -+ { -+ TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0); -+ FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, " -+ "skipping test"); -+ } - TEST_VERIFY (fd > 0); - - char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd); -diff --git a/sysdeps/unix/sysv/linux/tst-rseq-disable.c b/sysdeps/unix/sysv/linux/tst-rseq-disable.c -index e1a2c02f78..a46b0d0562 100644 ---- a/sysdeps/unix/sysv/linux/tst-rseq-disable.c -+++ b/sysdeps/unix/sysv/linux/tst-rseq-disable.c -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - #include - - #ifdef RSEQ_SIG -diff --git a/sysdeps/x86/bits/wordsize.h b/sysdeps/x86/bits/wordsize.h -index 70f652bca1..3f40aa76f9 100644 ---- a/sysdeps/x86/bits/wordsize.h -+++ b/sysdeps/x86/bits/wordsize.h -@@ -8,10 +8,9 @@ - #define __WORDSIZE32_PTRDIFF_LONG 0 - #endif - -+#define __WORDSIZE_TIME64_COMPAT32 1 -+ - #ifdef __x86_64__ --# define __WORDSIZE_TIME64_COMPAT32 1 - /* Both x86-64 and x32 use the 64-bit system call interface. */ - # define __SYSCALL_WORDSIZE 64 --#else --# define __WORDSIZE_TIME64_COMPAT32 0 - #endif -diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h -index e9f3382108..d95c1efa2c 100644 ---- a/sysdeps/x86/dl-cacheinfo.h -+++ b/sysdeps/x86/dl-cacheinfo.h -@@ -478,7 +478,7 @@ handle_zhaoxin (int name) - } - - static void --get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, -+get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, unsigned int *threads_ptr, - long int core) - { - unsigned int eax; -@@ -497,6 +497,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, - unsigned int family = cpu_features->basic.family; - unsigned int model = cpu_features->basic.model; - long int shared = *shared_ptr; -+ long int shared_per_thread = *shared_per_thread_ptr; - unsigned int threads = *threads_ptr; - bool inclusive_cache = true; - bool support_count_mask = true; -@@ -512,6 +513,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, - /* Try L2 otherwise. */ - level = 2; - shared = core; -+ shared_per_thread = core; - threads_l2 = 0; - threads_l3 = -1; - } -@@ -668,29 +670,27 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, - } - else - { --intel_bug_no_cache_info: -- /* Assume that all logical threads share the highest cache -- level. */ -- threads -- = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16) -- & 0xff); -- } -- -- /* Cap usage of highest cache level to the number of supported -- threads. */ -- if (shared > 0 && threads > 0) -- shared /= threads; -+ intel_bug_no_cache_info: -+ /* Assume that all logical threads share the highest cache -+ level. */ -+ threads = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16) -+ & 0xff); -+ } -+ /* Get per-thread size of highest level cache. */ -+ if (shared_per_thread > 0 && threads > 0) -+ shared_per_thread /= threads; - } - - /* Account for non-inclusive L2 and L3 caches. */ - if (!inclusive_cache) - { -- if (threads_l2 > 0) -- core /= threads_l2; -+ long int core_per_thread = threads_l2 > 0 ? (core / threads_l2) : core; -+ shared_per_thread += core_per_thread; - shared += core; - } - - *shared_ptr = shared; -+ *shared_per_thread_ptr = shared_per_thread; - *threads_ptr = threads; - } - -@@ -704,6 +704,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) - int max_cpuid_ex; - long int data = -1; - long int shared = -1; -+ long int shared_per_thread = -1; - long int core = -1; - unsigned int threads = 0; - unsigned long int level1_icache_size = -1; -@@ -724,6 +725,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) - data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); - core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); - shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); -+ shared_per_thread = shared; - - level1_icache_size - = handle_intel (_SC_LEVEL1_ICACHE_SIZE, cpu_features); -@@ -747,13 +749,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) - level4_cache_size - = handle_intel (_SC_LEVEL4_CACHE_SIZE, cpu_features); - -- get_common_cache_info (&shared, &threads, core); -+ get_common_cache_info (&shared, &shared_per_thread, &threads, core); - } - else if (cpu_features->basic.kind == arch_kind_zhaoxin) - { - data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); - core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); - shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); -+ shared_per_thread = shared; - - level1_icache_size = handle_zhaoxin (_SC_LEVEL1_ICACHE_SIZE); - level1_icache_linesize = handle_zhaoxin (_SC_LEVEL1_ICACHE_LINESIZE); -@@ -767,13 +770,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) - level3_cache_assoc = handle_zhaoxin (_SC_LEVEL3_CACHE_ASSOC); - level3_cache_linesize = handle_zhaoxin (_SC_LEVEL3_CACHE_LINESIZE); - -- get_common_cache_info (&shared, &threads, core); -+ get_common_cache_info (&shared, &shared_per_thread, &threads, core); - } - else if (cpu_features->basic.kind == arch_kind_amd) - { - data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); - core = handle_amd (_SC_LEVEL2_CACHE_SIZE); - shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); -+ shared_per_thread = shared; - - level1_icache_size = handle_amd (_SC_LEVEL1_ICACHE_SIZE); - level1_icache_linesize = handle_amd (_SC_LEVEL1_ICACHE_LINESIZE); -@@ -791,8 +795,11 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) - __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx); - - if (shared <= 0) -- /* No shared L3 cache. All we have is the L2 cache. */ -- shared = core; -+ { -+ /* No shared L3 cache. All we have is the L2 cache. */ -+ shared = core; -+ shared_per_thread = core; -+ } - else - { - /* Figure out the number of logical threads that share L3. */ -@@ -816,7 +823,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) - /* Cap usage of highest cache level to the number of - supported threads. */ - if (threads > 0) -- shared /= threads; -+ shared_per_thread /= threads; - - /* Get shared cache per ccx for Zen architectures. */ - if (cpu_features->basic.family >= 0x17) -@@ -827,12 +834,13 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) - __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); - - unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; -- shared *= threads_per_ccx; -+ shared_per_thread *= threads_per_ccx; - } - else - { - /* Account for exclusive L2 and L3 caches. */ - shared += core; -+ shared_per_thread += core; - } - } - } -@@ -850,17 +858,46 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) - cpu_features->level3_cache_linesize = level3_cache_linesize; - cpu_features->level4_cache_size = level4_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. */ -- unsigned long int non_temporal_threshold = shared * 3 / 4; -+ /* The default setting for the non_temporal threshold is 1/4 of size -+ of the chip's cache. For most Intel and AMD processors with an -+ initial release date between 2017 and 2023, a thread's typical -+ share of the cache is from 18-64MB. Using the 1/4 L3 is meant to -+ estimate the point where non-temporal stores begin out-competing -+ REP MOVSB. As well the point where the fact that non-temporal -+ stores are forced back to main memory would already occurred to the -+ majority of the lines in the copy. Note, concerns about the -+ entire L3 cache being evicted by the copy are mostly alleviated -+ by the fact that modern HW detects streaming patterns and -+ provides proper LRU hints so that the maximum thrashing -+ capped at 1/associativity. */ -+ unsigned long int non_temporal_threshold = shared / 4; -+ -+ /* If the computed non_temporal_threshold <= 3/4 * per-thread L3, we most -+ likely have incorrect/incomplete cache info in which case, default to -+ 3/4 * per-thread L3 to avoid regressions. */ -+ unsigned long int non_temporal_threshold_lowbound -+ = shared_per_thread * 3 / 4; -+ if (non_temporal_threshold < non_temporal_threshold_lowbound) -+ non_temporal_threshold = non_temporal_threshold_lowbound; -+ -+ /* If no ERMS, we use the per-thread L3 chunking. Normal cacheable stores run -+ a higher risk of actually thrashing the cache as they don't have a HW LRU -+ hint. As well, their performance in highly parallel situations is -+ noticeably worse. */ -+ if (!CPU_FEATURE_USABLE_P (cpu_features, ERMS)) -+ non_temporal_threshold = non_temporal_threshold_lowbound; -+ /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of -+ 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best -+ if that operation cannot overflow. Minimum of 0x4040 (16448) because the -+ L(large_memset_4x) loops need 64-byte to cache align and enough space for -+ at least 1 iteration of 4x PAGE_SIZE unrolled loop. Both values are -+ reflected in the manual. */ -+ unsigned long int maximum_non_temporal_threshold = SIZE_MAX >> 4; -+ unsigned long int minimum_non_temporal_threshold = 0x4040; -+ if (non_temporal_threshold < minimum_non_temporal_threshold) -+ non_temporal_threshold = minimum_non_temporal_threshold; -+ else if (non_temporal_threshold > maximum_non_temporal_threshold) -+ non_temporal_threshold = maximum_non_temporal_threshold; - - #if HAVE_TUNABLES - /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ -@@ -915,8 +952,8 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) - shared = tunable_size; - - tunable_size = TUNABLE_GET (x86_non_temporal_threshold, long int, NULL); -- /* NB: Ignore the default value 0. */ -- if (tunable_size != 0) -+ if (tunable_size > minimum_non_temporal_threshold -+ && tunable_size <= maximum_non_temporal_threshold) - non_temporal_threshold = tunable_size; - - tunable_size = TUNABLE_GET (x86_rep_movsb_threshold, long int, NULL); -@@ -931,14 +968,9 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) - - TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, data, 0, SIZE_MAX); - TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, shared, 0, SIZE_MAX); -- /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of -- 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best -- if that operation cannot overflow. Minimum of 0x4040 (16448) because the -- L(large_memset_4x) loops need 64-byte to cache align and enough space for -- at least 1 iteration of 4x PAGE_SIZE unrolled loop. Both values are -- reflected in the manual. */ - TUNABLE_SET_WITH_BOUNDS (x86_non_temporal_threshold, non_temporal_threshold, -- 0x4040, SIZE_MAX >> 4); -+ minimum_non_temporal_threshold, -+ maximum_non_temporal_threshold); - TUNABLE_SET_WITH_BOUNDS (x86_rep_movsb_threshold, rep_movsb_threshold, - minimum_rep_movsb_threshold, SIZE_MAX); - TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1, -diff --git a/sysdeps/x86/get-isa-level.h b/sysdeps/x86/get-isa-level.h -index 1ade78ab73..5b4dd5f062 100644 ---- a/sysdeps/x86/get-isa-level.h -+++ b/sysdeps/x86/get-isa-level.h -@@ -47,6 +47,8 @@ get_isa_level (const struct cpu_features *cpu_features) - isa_level |= GNU_PROPERTY_X86_ISA_1_V2; - if (CPU_FEATURE_USABLE_P (cpu_features, AVX) - && CPU_FEATURE_USABLE_P (cpu_features, AVX2) -+ && CPU_FEATURE_USABLE_P (cpu_features, BMI1) -+ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) - && CPU_FEATURE_USABLE_P (cpu_features, F16C) - && CPU_FEATURE_USABLE_P (cpu_features, FMA) - && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) -diff --git a/sysdeps/x86/isa-level.h b/sysdeps/x86/isa-level.h -index 3c4480aba7..06f6c9663e 100644 ---- a/sysdeps/x86/isa-level.h -+++ b/sysdeps/x86/isa-level.h -@@ -79,7 +79,9 @@ - /* ISA level >= 3 guaranteed includes. */ - #define AVX_X86_ISA_LEVEL 3 - #define AVX2_X86_ISA_LEVEL 3 -+#define BMI1_X86_ISA_LEVEL 3 - #define BMI2_X86_ISA_LEVEL 3 -+#define LZCNT_X86_ISA_LEVEL 3 - #define MOVBE_X86_ISA_LEVEL 3 - - /* ISA level >= 2 guaranteed includes. */ -diff --git a/sysdeps/x86/utmp-size.h b/sysdeps/x86/utmp-size.h -new file mode 100644 -index 0000000000..8f21ebe1b6 ---- /dev/null -+++ b/sysdeps/x86/utmp-size.h -@@ -0,0 +1,2 @@ -+#define UTMP_SIZE 384 -+#define LASTLOG_SIZE 292 -diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S -index 0db2cb4152..7619e743e1 100644 ---- a/sysdeps/x86_64/dl-tlsdesc.S -+++ b/sysdeps/x86_64/dl-tlsdesc.S -@@ -61,7 +61,7 @@ _dl_tlsdesc_return: - _dl_tlsdesc_undefweak: - _CET_ENDBR - movq 8(%rax), %rax -- subq %fs:0, %rax -+ sub %fs:0, %RAX_LP - ret - cfi_endproc - .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak -@@ -102,7 +102,7 @@ _dl_tlsdesc_dynamic: - /* Preserve call-clobbered registers that we modify. - We need two scratch regs anyway. */ - movq %rsi, -16(%rsp) -- movq %fs:DTV_OFFSET, %rsi -+ mov %fs:DTV_OFFSET, %RSI_LP - movq %rdi, -8(%rsp) - movq TLSDESC_ARG(%rax), %rdi - movq (%rsi), %rax -@@ -116,7 +116,7 @@ _dl_tlsdesc_dynamic: - addq TLSDESC_MODOFF(%rdi), %rax - .Lret: - movq -16(%rsp), %rsi -- subq %fs:0, %rax -+ sub %fs:0, %RAX_LP - movq -8(%rsp), %rdi - ret - .Lslow: -diff --git a/sysdeps/x86_64/ffsll.c b/sysdeps/x86_64/ffsll.c -index 842ebaeb4c..d352866d9f 100644 ---- a/sysdeps/x86_64/ffsll.c -+++ b/sysdeps/x86_64/ffsll.c -@@ -26,13 +26,13 @@ int - ffsll (long long int x) - { - long long int cnt; -- long long int tmp; - -- asm ("bsfq %2,%0\n" /* Count low bits in X and store in %1. */ -- "cmoveq %1,%0\n" /* If number was zero, use -1 as result. */ -- : "=&r" (cnt), "=r" (tmp) : "rm" (x), "1" (-1)); -+ asm ("mov $-1,%k0\n" /* Initialize cnt to -1. */ -+ "bsf %1,%0\n" /* Count low bits in x and store in cnt. */ -+ "inc %k0\n" /* Increment cnt by 1. */ -+ : "=&r" (cnt) : "r" (x)); - -- return cnt + 1; -+ return cnt; - } - - #ifndef __ILP32__ -diff --git a/sysdeps/x86_64/fpu/fraiseexcpt.c b/sysdeps/x86_64/fpu/fraiseexcpt.c -index 864f4777a2..23446ff4ac 100644 ---- a/sysdeps/x86_64/fpu/fraiseexcpt.c -+++ b/sysdeps/x86_64/fpu/fraiseexcpt.c -@@ -33,7 +33,7 @@ __feraiseexcept (int excepts) - /* One example of an invalid operation is 0.0 / 0.0. */ - float f = 0.0; - -- __asm__ __volatile__ ("divss %0, %0 " : : "x" (f)); -+ __asm__ __volatile__ ("divss %0, %0 " : "+x" (f)); - (void) &f; - } - -@@ -43,7 +43,7 @@ __feraiseexcept (int excepts) - float f = 1.0; - float g = 0.0; - -- __asm__ __volatile__ ("divss %1, %0" : : "x" (f), "x" (g)); -+ __asm__ __volatile__ ("divss %1, %0" : "+x" (f) : "x" (g)); - (void) &f; - } - -diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h -index a57a9952f3..f2f5e8a211 100644 ---- a/sysdeps/x86_64/multiarch/ifunc-avx2.h -+++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h -@@ -36,7 +36,9 @@ IFUNC_SELECTOR (void) - const struct cpu_features *cpu_features = __get_cpu_features (); - - if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) -+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI1) - && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) -+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, LZCNT) - && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, - AVX_Fast_Unaligned_Load, )) - { -diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c -index a71444eccb..00a91123d3 100644 ---- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c -+++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c -@@ -69,10 +69,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - && CPU_FEATURE_USABLE (BMI2)), - __memchr_evex_rtm) - X86_IFUNC_IMPL_ADD_V3 (array, i, memchr, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __memchr_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, memchr, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __memchr_avx2_rtm) - /* ISA V2 wrapper for SSE2 implementation because the SSE2 -@@ -207,13 +209,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - IFUNC_IMPL (i, name, memrchr, - X86_IFUNC_IMPL_ADD_V4 (array, i, memrchr, - (CPU_FEATURE_USABLE (AVX512VL) -- && CPU_FEATURE_USABLE (AVX512BW)), -+ && CPU_FEATURE_USABLE (AVX512BW) -+ && CPU_FEATURE_USABLE (BMI2) -+ && CPU_FEATURE_USABLE (LZCNT)), - __memrchr_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) -+ && CPU_FEATURE_USABLE (LZCNT)), - __memrchr_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) -+ && CPU_FEATURE_USABLE (LZCNT) - && CPU_FEATURE_USABLE (RTM)), - __memrchr_avx2_rtm) - /* ISA V2 wrapper for SSE2 implementation because the SSE2 -@@ -335,10 +343,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - && CPU_FEATURE_USABLE (BMI2)), - __rawmemchr_evex_rtm) - X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __rawmemchr_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __rawmemchr_avx2_rtm) - /* ISA V2 wrapper for SSE2 implementation because the SSE2 -@@ -448,13 +458,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - IFUNC_IMPL (i, name, strcasecmp, - X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp, - (CPU_FEATURE_USABLE (AVX512VL) -- && CPU_FEATURE_USABLE (AVX512BW)), -+ && CPU_FEATURE_USABLE (AVX512BW) -+ && CPU_FEATURE_USABLE (BMI2)), - __strcasecmp_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __strcasecmp_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __strcasecmp_avx2_rtm) - X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp, -@@ -470,13 +483,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - IFUNC_IMPL (i, name, strcasecmp_l, - X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp, - (CPU_FEATURE_USABLE (AVX512VL) -- && CPU_FEATURE_USABLE (AVX512BW)), -+ && CPU_FEATURE_USABLE (AVX512BW) -+ && CPU_FEATURE_USABLE (BMI2)), - __strcasecmp_l_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __strcasecmp_l_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __strcasecmp_l_avx2_rtm) - X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp_l, -@@ -562,13 +578,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - IFUNC_IMPL (i, name, strrchr, - X86_IFUNC_IMPL_ADD_V4 (array, i, strrchr, - (CPU_FEATURE_USABLE (AVX512VL) -- && CPU_FEATURE_USABLE (AVX512BW)), -+ && CPU_FEATURE_USABLE (AVX512BW) -+ && CPU_FEATURE_USABLE (BMI1) -+ && CPU_FEATURE_USABLE (BMI2)), - __strrchr_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI1) -+ && CPU_FEATURE_USABLE (BMI2)), - __strrchr_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI1) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __strrchr_avx2_rtm) - /* ISA V2 wrapper for SSE2 implementation because the SSE2 -@@ -585,10 +607,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - && CPU_FEATURE_USABLE (BMI2)), - __strcmp_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __strcmp_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __strcmp_avx2_rtm) - X86_IFUNC_IMPL_ADD_V2 (array, i, strcmp, -@@ -638,13 +662,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - IFUNC_IMPL (i, name, strncasecmp, - X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp, - (CPU_FEATURE_USABLE (AVX512VL) -- && CPU_FEATURE_USABLE (AVX512BW)), -+ && CPU_FEATURE_USABLE (AVX512BW) -+ && CPU_FEATURE_USABLE (BMI2)), - __strncasecmp_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __strncasecmp_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __strncasecmp_avx2_rtm) - X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp, -@@ -660,13 +687,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - IFUNC_IMPL (i, name, strncasecmp_l, - X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp, - (CPU_FEATURE_USABLE (AVX512VL) -- && CPU_FEATURE_USABLE (AVX512BW)), -+ & CPU_FEATURE_USABLE (AVX512BW) -+ && CPU_FEATURE_USABLE (BMI2)), - __strncasecmp_l_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __strncasecmp_l_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __strncasecmp_l_avx2_rtm) - X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp_l, -@@ -773,13 +803,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - X86_IFUNC_IMPL_ADD_V4 (array, i, wcsrchr, - (CPU_FEATURE_USABLE (AVX512VL) - && CPU_FEATURE_USABLE (AVX512BW) -+ && CPU_FEATURE_USABLE (BMI1) - && CPU_FEATURE_USABLE (BMI2)), - __wcsrchr_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI1) -+ && CPU_FEATURE_USABLE (BMI2)), - __wcsrchr_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI1) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __wcsrchr_avx2_rtm) - /* ISA V2 wrapper for SSE2 implementation because the SSE2 -@@ -796,10 +831,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - && CPU_FEATURE_USABLE (BMI2)), - __wcscmp_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __wcscmp_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __wcscmp_avx2_rtm) - /* ISA V2 wrapper for SSE2 implementation because the SSE2 -@@ -816,10 +853,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - && CPU_FEATURE_USABLE (BMI2)), - __wcsncmp_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __wcsncmp_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __wcsncmp_avx2_rtm) - /* ISA V2 wrapper for GENERIC implementation because the -@@ -909,10 +948,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - && CPU_FEATURE_USABLE (BMI2)), - __wmemchr_evex_rtm) - X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __wmemchr_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __wmemchr_avx2_rtm) - /* ISA V2 wrapper for SSE2 implementation because the SSE2 -@@ -1162,13 +1203,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, - IFUNC_IMPL (i, name, strncmp, - X86_IFUNC_IMPL_ADD_V4 (array, i, strncmp, - (CPU_FEATURE_USABLE (AVX512VL) -- && CPU_FEATURE_USABLE (AVX512BW)), -+ && CPU_FEATURE_USABLE (AVX512BW) -+ && CPU_FEATURE_USABLE (BMI2)), - __strncmp_evex) - X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp, -- CPU_FEATURE_USABLE (AVX2), -+ (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2)), - __strncmp_avx2) - X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp, - (CPU_FEATURE_USABLE (AVX2) -+ && CPU_FEATURE_USABLE (BMI2) - && CPU_FEATURE_USABLE (RTM)), - __strncmp_avx2_rtm) - X86_IFUNC_IMPL_ADD_V2 (array, i, strncmp, -diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h -index 68646ef199..7622af259c 100644 ---- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h -+++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h -@@ -34,6 +34,7 @@ IFUNC_SELECTOR (void) - const struct cpu_features *cpu_features = __get_cpu_features (); - - if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) -+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) - && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, - AVX_Fast_Unaligned_Load, )) - { -diff --git a/sysdeps/x86_64/multiarch/memcmp-sse2.S b/sysdeps/x86_64/multiarch/memcmp-sse2.S -index afd450d020..51bc9344f0 100644 ---- a/sysdeps/x86_64/multiarch/memcmp-sse2.S -+++ b/sysdeps/x86_64/multiarch/memcmp-sse2.S -@@ -308,7 +308,17 @@ L(ret_nonzero_vec_end_0): - setg %dl - leal -1(%rdx, %rdx), %eax - # else -- addl %edx, %eax -+ /* Use `addq` instead of `addl` here so that even if `rax` + `rdx` -+ is negative value of the sum will be usable as a 64-bit offset -+ (negative 32-bit numbers zero-extend to a large and often -+ out-of-bounds 64-bit offsets). Note that `rax` + `rdx` >= 0 is -+ an invariant when `memcmp` is used correctly, but if the input -+ strings `rsi`/`rdi` are concurrently modified as the function -+ runs (there is a Data-Race) it is possible for `rax` + `rdx` to -+ be negative. Given that there is virtually no extra to cost -+ using `addq` instead of `addl` we may as well protect the -+ data-race case. */ -+ addq %rdx, %rax - movzbl (VEC_SIZE * -1 + SIZE_OFFSET)(%rsi, %rax), %ecx - movzbl (VEC_SIZE * -1 + SIZE_OFFSET)(%rdi, %rax), %eax - subl %ecx, %eax -diff --git a/sysdeps/x86_64/multiarch/rtld-strcpy.S b/sysdeps/x86_64/multiarch/rtld-strcpy.S -new file mode 100644 -index 0000000000..19439c553d ---- /dev/null -+++ b/sysdeps/x86_64/multiarch/rtld-strcpy.S -@@ -0,0 +1,18 @@ -+/* Copyright (C) 2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include "../strcpy.S" -diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c -index fdd5afe3af..9d6c9f66ba 100644 ---- a/sysdeps/x86_64/multiarch/strcmp.c -+++ b/sysdeps/x86_64/multiarch/strcmp.c -@@ -45,12 +45,12 @@ IFUNC_SELECTOR (void) - const struct cpu_features *cpu_features = __get_cpu_features (); - - if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) -+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) - && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, - AVX_Fast_Unaligned_Load, )) - { - if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) -- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) -- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)) -+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) - return OPTIMIZE (evex); - - if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) -diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S -index 0593fb303b..b9b58ef599 100644 ---- a/sysdeps/x86_64/multiarch/strlen-avx2.S -+++ b/sysdeps/x86_64/multiarch/strlen-avx2.S -@@ -544,14 +544,11 @@ L(return_vzeroupper): - L(cross_page_less_vec): - tzcntl %eax, %eax - # ifdef USE_AS_WCSLEN -- /* NB: Multiply length by 4 to get byte count. */ -- sall $2, %esi -+ /* NB: Divide by 4 to convert from byte-count to length. */ -+ shrl $2, %eax - # endif - cmpq %rax, %rsi - cmovb %esi, %eax --# ifdef USE_AS_WCSLEN -- shrl $2, %eax --# endif - VZEROUPPER_RETURN - # endif - -diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c -index 4ebe4bde30..c4f8b6bbb5 100644 ---- a/sysdeps/x86_64/multiarch/strncmp.c -+++ b/sysdeps/x86_64/multiarch/strncmp.c -@@ -41,12 +41,12 @@ IFUNC_SELECTOR (void) - const struct cpu_features *cpu_features = __get_cpu_features (); - - if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) -+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) - && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, - AVX_Fast_Unaligned_Load, )) - { - if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) -- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) -- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)) -+ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) - return OPTIMIZE (evex); - - if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) -diff --git a/time/Makefile b/time/Makefile -index 470275b90c..2f4aa2d528 100644 ---- a/time/Makefile -+++ b/time/Makefile -@@ -50,7 +50,7 @@ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \ - tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 \ - tst-adjtime tst-ctime tst-difftime tst-mktime4 tst-clock_settime \ - tst-settimeofday tst-itimer tst-gmtime tst-timegm \ -- tst-timespec_get tst-timespec_getres -+ tst-timespec_get tst-timespec_getres tst-strftime4 - - tests-time64 := \ - tst-adjtime-time64 \ -@@ -65,6 +65,7 @@ tests-time64 := \ - tst-itimer-time64 \ - tst-mktime4-time64 \ - tst-settimeofday-time64 \ -+ tst-strftime4-time64 \ - tst-timegm-time64 \ - tst-timespec_get-time64 \ - tst-timespec_getres-time64 \ -diff --git a/time/mktime.c b/time/mktime.c -index 494c89bf54..e9a6006710 100644 ---- a/time/mktime.c -+++ b/time/mktime.c -@@ -429,8 +429,13 @@ __mktime_internal (struct tm *tp, - time with the right value, and use its UTC offset. - - Heuristic: probe the adjacent timestamps in both directions, -- looking for the desired isdst. This should work for all real -- time zone histories in the tz database. */ -+ looking for the desired isdst. If none is found within a -+ reasonable duration bound, assume a one-hour DST difference. -+ This should work for all real time zone histories in the tz -+ database. */ -+ -+ /* +1 if we wanted standard time but got DST, -1 if the reverse. */ -+ int dst_difference = (isdst == 0) - (tm.tm_isdst == 0); - - /* Distance between probes when looking for a DST boundary. In - tzdata2003a, the shortest period of DST is 601200 seconds -@@ -441,12 +446,14 @@ __mktime_internal (struct tm *tp, - periods when probing. */ - int stride = 601200; - -- /* The longest period of DST in tzdata2003a is 536454000 seconds -- (e.g., America/Jujuy starting 1946-10-01 01:00). The longest -- period of non-DST is much longer, but it makes no real sense -- to search for more than a year of non-DST, so use the DST -- max. */ -- int duration_max = 536454000; -+ /* In TZDB 2021e, the longest period of DST (or of non-DST), in -+ which the DST (or adjacent DST) difference is not one hour, -+ is 457243209 seconds: e.g., America/Cambridge_Bay with leap -+ seconds, starting 1965-10-31 00:00 in a switch from -+ double-daylight time (-05) to standard time (-07), and -+ continuing to 1980-04-27 02:00 in a switch from standard time -+ (-07) to daylight time (-06). */ -+ int duration_max = 457243209; - - /* Search in both directions, so the maximum distance is half - the duration; add the stride to avoid off-by-1 problems. */ -@@ -483,6 +490,11 @@ __mktime_internal (struct tm *tp, - } - } - -+ /* No unusual DST offset was found nearby. Assume one-hour DST. */ -+ t += 60 * 60 * dst_difference; -+ if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm)) -+ goto offset_found; -+ - __set_errno (EOVERFLOW); - return -1; - } -diff --git a/time/strftime_l.c b/time/strftime_l.c -index 75554fee7c..4d7c4ea828 100644 ---- a/time/strftime_l.c -+++ b/time/strftime_l.c -@@ -159,6 +159,10 @@ extern char *tzname[]; - #ifdef _LIBC - # define tzname __tzname - # define tzset __tzset -+ -+# define time_t __time64_t -+# define __gmtime_r(t, tp) __gmtime64_r (t, tp) -+# define mktime(tp) __mktime64 (tp) - #endif - - #if !HAVE_TM_GMTOFF -diff --git a/time/strptime_l.c b/time/strptime_l.c -index a3c5681fc2..f927448204 100644 ---- a/time/strptime_l.c -+++ b/time/strptime_l.c -@@ -30,8 +30,10 @@ - #ifdef _LIBC - # define HAVE_LOCALTIME_R 0 - # include "../locale/localeinfo.h" --#endif - -+# define time_t __time64_t -+# define __localtime_r(t, tp) __localtime64_r (t, tp) -+#endif - - #if ! HAVE_LOCALTIME_R && ! defined localtime_r - # ifdef _LIBC -diff --git a/time/tst-strftime4-time64.c b/time/tst-strftime4-time64.c -new file mode 100644 -index 0000000000..4d47ee7d79 ---- /dev/null -+++ b/time/tst-strftime4-time64.c -@@ -0,0 +1 @@ -+#include "tst-strftime4.c" -diff --git a/time/tst-strftime4.c b/time/tst-strftime4.c -new file mode 100644 -index 0000000000..659716d0fa ---- /dev/null -+++ b/time/tst-strftime4.c -@@ -0,0 +1,52 @@ -+/* Test strftime and strptime after 2038-01-19 03:14:07 UTC (bug 30053). -+ Copyright (C) 2023 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+static int -+do_test (void) -+{ -+ TEST_VERIFY_EXIT (setenv ("TZ", "UTC0", 1) == 0); -+ tzset (); -+ if (sizeof (time_t) > 4) -+ { -+ time_t wrap = (time_t) 2147483648LL; -+ char buf[80]; -+ struct tm *tm = gmtime (&wrap); -+ TEST_VERIFY_EXIT (tm != NULL); -+ TEST_VERIFY_EXIT (strftime (buf, sizeof buf, "%s", tm) > 0); -+ puts (buf); -+ TEST_VERIFY (strcmp (buf, "2147483648") == 0); -+ -+ struct tm tm2; -+ char *p = strptime (buf, "%s", &tm2); -+ TEST_VERIFY_EXIT (p != NULL && *p == '\0'); -+ time_t t = mktime (&tm2); -+ printf ("%lld\n", (long long) t); -+ TEST_VERIFY (t == wrap); -+ } -+ else -+ FAIL_UNSUPPORTED ("32-bit time_t"); -+ return 0; -+} -+ -+#include -diff --git a/time/tzfile.c b/time/tzfile.c -index dd75848ba9..8bba4e5b8d 100644 ---- a/time/tzfile.c -+++ b/time/tzfile.c -@@ -32,7 +32,7 @@ - int __use_tzfile; - static dev_t tzfile_dev; - static ino64_t tzfile_ino; --static time_t tzfile_mtime; -+static __time64_t tzfile_mtime; - - struct ttinfo - { -@@ -61,6 +61,10 @@ static size_t num_leaps; - static struct leap *leaps; - static char *tzspec; - -+/* Used to restore the daylight variable during time conversion, as if -+ tzset had been called. */ -+static int daylight_saved; -+ - #include - #include - -@@ -438,36 +442,35 @@ __tzfile_read (const char *file, size_t extra, char **extrap) - if (__tzname[1] == NULL) - __tzname[1] = __tzname[0]; - -+ daylight_saved = 0; - if (num_transitions == 0) - /* Use the first rule (which should also be the only one). */ - rule_stdoff = rule_dstoff = types[0].offset; - else - { -- int stdoff_set = 0, dstoff_set = 0; -- rule_stdoff = rule_dstoff = 0; -+ rule_stdoff = 0; -+ -+ /* Search for the last rule with a standard time offset. This -+ will be used for the global timezone variable. */ - i = num_transitions - 1; - do -- { -- if (!stdoff_set && !types[type_idxs[i]].isdst) -- { -- stdoff_set = 1; -- rule_stdoff = types[type_idxs[i]].offset; -- } -- else if (!dstoff_set && types[type_idxs[i]].isdst) -- { -- dstoff_set = 1; -- rule_dstoff = types[type_idxs[i]].offset; -- } -- if (stdoff_set && dstoff_set) -+ if (!types[type_idxs[i]].isdst) -+ { -+ rule_stdoff = types[type_idxs[i]].offset; - break; -- } -+ } -+ else -+ daylight_saved = 1; - while (i-- > 0); - -- if (!dstoff_set) -- rule_dstoff = rule_stdoff; -+ /* Keep searching to see if there is a DST rule. This -+ information will be used to set the global daylight -+ variable. */ -+ while (i-- > 0 && !daylight_saved) -+ daylight_saved = types[type_idxs[i]].isdst; - } - -- __daylight = rule_stdoff != rule_dstoff; -+ __daylight = daylight_saved; - __timezone = -rule_stdoff; - - done: -@@ -731,7 +734,7 @@ __tzfile_compute (__time64_t timer, int use_localtime, - } - - struct ttinfo *info = &types[i]; -- __daylight = rule_stdoff != rule_dstoff; -+ __daylight = daylight_saved; - __timezone = -rule_stdoff; - - if (__tzname[0] == NULL) -diff --git a/timezone/Makefile b/timezone/Makefile -index a789c22d26..5002de39ad 100644 ---- a/timezone/Makefile -+++ b/timezone/Makefile -@@ -23,7 +23,7 @@ subdir := timezone - include ../Makeconfig - - others := zdump zic --tests := test-tz tst-timezone tst-tzset tst-bz28707 -+tests := test-tz tst-timezone tst-tzset tst-bz28707 tst-bz29951 - - generated-dirs += testdata - -@@ -86,11 +86,13 @@ $(objpfx)tst-timezone.out: $(addprefix $(testdata)/, \ - Europe/London) - $(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4) - $(objpfx)tst-bz28707.out: $(testdata)/XT5 -+$(objpfx)tst-bz29951.out: $(testdata)/XT6 - - test-tz-ENV = TZDIR=$(testdata) - tst-timezone-ENV = TZDIR=$(testdata) - tst-tzset-ENV = TZDIR=$(testdata) - tst-bz28707-ENV = TZDIR=$(testdata) -+tst-bz29951-ENV = TZDIR=$(testdata) - - # Note this must come second in the deps list for $(built-program-cmd) to work. - zic-deps = $(objpfx)zic $(leapseconds) yearistype -diff --git a/timezone/testdata/XT6 b/timezone/testdata/XT6 -new file mode 100644 -index 0000000000..07b393bb7d -Binary files /dev/null and b/timezone/testdata/XT6 differ -diff --git a/timezone/tst-bz29951.c b/timezone/tst-bz29951.c -new file mode 100644 -index 0000000000..abd334683b ---- /dev/null -+++ b/timezone/tst-bz29951.c -@@ -0,0 +1,68 @@ -+/* Check that daylight is set if the last DST transition did not change offset. -+ Copyright (C) 2023 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#include -+#include -+#include -+#include -+ -+/* Set the specified time zone with error checking. */ -+static void -+set_timezone (const char *name) -+{ -+ TEST_VERIFY (setenv ("TZ", name, 1) == 0); -+ errno = 0; -+ tzset (); -+ TEST_COMPARE (errno, 0); -+} -+ -+static int -+do_test (void) -+{ -+ /* Test zone based on tz-2022g version of Africa/Tripoli. The last -+ DST transition coincided with a change in the standard time -+ offset, effectively making it a no-op. -+ -+ Africa/Tripoli Thu Oct 24 23:59:59 2013 UT -+ = Fri Oct 25 01:59:59 2013 CEST isdst=1 gmtoff=7200 -+ Africa/Tripoli Fri Oct 25 00:00:00 2013 UT -+ = Fri Oct 25 02:00:00 2013 EET isdst=0 gmtoff=7200 -+ */ -+ set_timezone ("XT6"); -+ TEST_VERIFY (daylight != 0); -+ TEST_COMPARE (timezone, -7200); -+ -+ /* Check that localtime re-initializes the two variables. */ -+ daylight = timezone = 17; -+ time_t t = 844034401; -+ struct tm *tm = localtime (&t); -+ TEST_VERIFY (daylight != 0); -+ TEST_COMPARE (timezone, -7200); -+ TEST_COMPARE (tm->tm_year, 96); -+ TEST_COMPARE (tm->tm_mon, 8); -+ TEST_COMPARE (tm->tm_mday, 29); -+ TEST_COMPARE (tm->tm_hour, 23); -+ TEST_COMPARE (tm->tm_min, 0); -+ TEST_COMPARE (tm->tm_sec, 1); -+ TEST_COMPARE (tm->tm_gmtoff, 3600); -+ TEST_COMPARE (tm->tm_isdst, 0); -+ -+ return 0; -+} -+ -+#include -diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile -index e6b9e8743a..4af102a3f6 100644 ---- a/wcsmbs/Makefile -+++ b/wcsmbs/Makefile -@@ -22,8 +22,9 @@ subdir := wcsmbs - - include ../Makeconfig - --headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h \ -- bits/types/__mbstate_t.h bits/types/mbstate_t.h bits/types/wint_t.h -+headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar2-decl.h \ -+ bits/wchar-ldbl.h uchar.h bits/types/__mbstate_t.h \ -+ bits/types/mbstate_t.h bits/types/wint_t.h - - routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ - wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \ -@@ -73,6 +74,8 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales) - $(objpfx)tst-wcstod-nan-locale.out: $(gen-locales) - $(objpfx)tst-c16-surrogate.out: $(gen-locales) - $(objpfx)tst-c32-state.out: $(gen-locales) -+$(objpfx)test-c8rtomb.out: $(gen-locales) -+$(objpfx)test-mbrtoc8.out: $(gen-locales) - endif - - $(objpfx)tst-wcstod-round: $(libm) -diff --git a/wcsmbs/bits/wchar2-decl.h b/wcsmbs/bits/wchar2-decl.h -new file mode 100644 -index 0000000000..8e1735c33b ---- /dev/null -+++ b/wcsmbs/bits/wchar2-decl.h -@@ -0,0 +1,124 @@ -+/* Checking macros for wchar functions. Declarations only. -+ Copyright (C) 2004-2022 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+#ifndef _BITS_WCHAR2_DECL_H -+#define _BITS_WCHAR2_DECL_H 1 -+ -+#ifndef _WCHAR_H -+# error "Never include directly; use instead." -+#endif -+ -+ -+extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1, -+ const wchar_t *__restrict __s2, size_t __n, -+ size_t __ns1) __THROW; -+extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2, -+ size_t __n, size_t __ns1) __THROW; -+ -+ -+#ifdef __USE_GNU -+ -+extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1, -+ const wchar_t *__restrict __s2, size_t __n, -+ size_t __ns1) __THROW; -+ -+#endif -+ -+ -+extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n, -+ size_t __ns) __THROW; -+extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest, -+ const wchar_t *__restrict __src, -+ size_t __n) __THROW; -+extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest, -+ const wchar_t *__restrict __src, -+ size_t __destlen) __THROW; -+extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest, -+ const wchar_t *__restrict __src, size_t __n, -+ size_t __destlen) __THROW; -+extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest, -+ const wchar_t *__restrict __src, size_t __n, -+ size_t __destlen) __THROW; -+extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest, -+ const wchar_t *__restrict __src, -+ size_t __destlen) __THROW; -+extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest, -+ const wchar_t *__restrict __src, -+ size_t __n, size_t __destlen) __THROW; -+extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n, -+ int __flag, size_t __s_len, -+ const wchar_t *__restrict __format, ...) -+ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */; -+extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, -+ int __flag, size_t __s_len, -+ const wchar_t *__restrict __format, -+ __gnuc_va_list __arg) -+ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; -+ -+#if __USE_FORTIFY_LEVEL > 1 -+ -+extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag, -+ const wchar_t *__restrict __format, ...); -+extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format, -+ ...); -+extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag, -+ const wchar_t *__restrict __format, -+ __gnuc_va_list __ap); -+extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format, -+ __gnuc_va_list __ap); -+ -+#endif -+ -+extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n, -+ __FILE *__restrict __stream) __wur; -+ -+#ifdef __USE_GNU -+ -+extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size, -+ int __n, __FILE *__restrict __stream) -+ __wur; -+ -+#endif -+ -+extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar, -+ mbstate_t *__restrict __p, -+ size_t __buflen) __THROW __wur; -+extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst, -+ const char **__restrict __src, -+ size_t __len, mbstate_t *__restrict __ps, -+ size_t __dstlen) __THROW; -+extern size_t __wcsrtombs_chk (char *__restrict __dst, -+ const wchar_t **__restrict __src, -+ size_t __len, mbstate_t *__restrict __ps, -+ size_t __dstlen) __THROW; -+ -+#ifdef __USE_XOPEN2K8 -+ -+extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, -+ const char **__restrict __src, size_t __nmc, -+ size_t __len, mbstate_t *__restrict __ps, -+ size_t __dstlen) __THROW; -+extern size_t __wcsnrtombs_chk (char *__restrict __dst, -+ const wchar_t **__restrict __src, -+ size_t __nwc, size_t __len, -+ mbstate_t *__restrict __ps, size_t __dstlen) -+ __THROW; -+ -+#endif -+ -+#endif /* bits/wchar2-decl.h. */ -diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h -index 0e017f458b..3f110efe57 100644 ---- a/wcsmbs/bits/wchar2.h -+++ b/wcsmbs/bits/wchar2.h -@@ -21,9 +21,6 @@ - #endif - - --extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1, -- const wchar_t *__restrict __s2, size_t __n, -- size_t __ns1) __THROW; - extern wchar_t *__REDIRECT_NTH (__wmemcpy_alias, - (wchar_t *__restrict __s1, - const wchar_t *__restrict __s2, size_t __n), -@@ -45,8 +42,6 @@ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, - } - - --extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2, -- size_t __n, size_t __ns1) __THROW; - extern wchar_t *__REDIRECT_NTH (__wmemmove_alias, (wchar_t *__s1, - const wchar_t *__s2, - size_t __n), wmemmove); -@@ -66,9 +61,6 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n)) - - - #ifdef __USE_GNU --extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1, -- const wchar_t *__restrict __s2, size_t __n, -- size_t __ns1) __THROW; - extern wchar_t *__REDIRECT_NTH (__wmempcpy_alias, - (wchar_t *__restrict __s1, - const wchar_t *__restrict __s2, -@@ -91,8 +83,6 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, - #endif - - --extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n, -- size_t __ns) __THROW; - extern wchar_t *__REDIRECT_NTH (__wmemset_alias, (wchar_t *__s, wchar_t __c, - size_t __n), wmemset); - extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn, -@@ -110,9 +100,6 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n)) - } - - --extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest, -- const wchar_t *__restrict __src, -- size_t __n) __THROW; - extern wchar_t *__REDIRECT_NTH (__wcscpy_alias, - (wchar_t *__restrict __dest, - const wchar_t *__restrict __src), wcscpy); -@@ -127,9 +114,6 @@ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) - } - - --extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest, -- const wchar_t *__restrict __src, -- size_t __destlen) __THROW; - extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias, - (wchar_t *__restrict __dest, - const wchar_t *__restrict __src), wcpcpy); -@@ -144,9 +128,6 @@ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) - } - - --extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest, -- const wchar_t *__restrict __src, size_t __n, -- size_t __destlen) __THROW; - extern wchar_t *__REDIRECT_NTH (__wcsncpy_alias, - (wchar_t *__restrict __dest, - const wchar_t *__restrict __src, -@@ -168,9 +149,6 @@ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, - } - - --extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest, -- const wchar_t *__restrict __src, size_t __n, -- size_t __destlen) __THROW; - extern wchar_t *__REDIRECT_NTH (__wcpncpy_alias, - (wchar_t *__restrict __dest, - const wchar_t *__restrict __src, -@@ -192,9 +170,6 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, - } - - --extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest, -- const wchar_t *__restrict __src, -- size_t __destlen) __THROW; - extern wchar_t *__REDIRECT_NTH (__wcscat_alias, - (wchar_t *__restrict __dest, - const wchar_t *__restrict __src), wcscat); -@@ -209,9 +184,6 @@ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) - } - - --extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest, -- const wchar_t *__restrict __src, -- size_t __n, size_t __destlen) __THROW; - extern wchar_t *__REDIRECT_NTH (__wcsncat_alias, - (wchar_t *__restrict __dest, - const wchar_t *__restrict __src, -@@ -228,10 +200,6 @@ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src, - } - - --extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n, -- int __flag, size_t __s_len, -- const wchar_t *__restrict __format, ...) -- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */; - - extern int __REDIRECT_NTH_LDBL (__swprintf_alias, - (wchar_t *__restrict __s, size_t __n, -@@ -258,11 +226,6 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n, - : swprintf (s, n, __VA_ARGS__)) - #endif - --extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, -- int __flag, size_t __s_len, -- const wchar_t *__restrict __format, -- __gnuc_va_list __arg) -- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; - - extern int __REDIRECT_NTH_LDBL (__vswprintf_alias, - (wchar_t *__restrict __s, size_t __n, -@@ -283,16 +246,6 @@ __NTH (vswprintf (wchar_t *__restrict __s, size_t __n, - - #if __USE_FORTIFY_LEVEL > 1 - --extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag, -- const wchar_t *__restrict __format, ...); --extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format, -- ...); --extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag, -- const wchar_t *__restrict __format, -- __gnuc_va_list __ap); --extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format, -- __gnuc_va_list __ap); -- - # ifdef __va_arg_pack - __fortify_function int - wprintf (const wchar_t *__restrict __fmt, ...) -@@ -328,8 +281,6 @@ vfwprintf (__FILE *__restrict __stream, - - #endif - --extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n, -- __FILE *__restrict __stream) __wur; - extern wchar_t *__REDIRECT (__fgetws_alias, - (wchar_t *__restrict __s, int __n, - __FILE *__restrict __stream), fgetws) __wur; -@@ -351,9 +302,6 @@ fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) - } - - #ifdef __USE_GNU --extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size, -- int __n, __FILE *__restrict __stream) -- __wur; - extern wchar_t *__REDIRECT (__fgetws_unlocked_alias, - (wchar_t *__restrict __s, int __n, - __FILE *__restrict __stream), fgetws_unlocked) -@@ -379,9 +327,6 @@ fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) - #endif - - --extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar, -- mbstate_t *__restrict __p, -- size_t __buflen) __THROW __wur; - extern size_t __REDIRECT_NTH (__wcrtomb_alias, - (char *__restrict __s, wchar_t __wchar, - mbstate_t *__restrict __ps), wcrtomb) __wur; -@@ -404,10 +349,6 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar, - } - - --extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst, -- const char **__restrict __src, -- size_t __len, mbstate_t *__restrict __ps, -- size_t __dstlen) __THROW; - extern size_t __REDIRECT_NTH (__mbsrtowcs_alias, - (wchar_t *__restrict __dst, - const char **__restrict __src, -@@ -431,10 +372,6 @@ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, - } - - --extern size_t __wcsrtombs_chk (char *__restrict __dst, -- const wchar_t **__restrict __src, -- size_t __len, mbstate_t *__restrict __ps, -- size_t __dstlen) __THROW; - extern size_t __REDIRECT_NTH (__wcsrtombs_alias, - (char *__restrict __dst, - const wchar_t **__restrict __src, -@@ -458,10 +395,6 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src, - - - #ifdef __USE_XOPEN2K8 --extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, -- const char **__restrict __src, size_t __nmc, -- size_t __len, mbstate_t *__restrict __ps, -- size_t __dstlen) __THROW; - extern size_t __REDIRECT_NTH (__mbsnrtowcs_alias, - (wchar_t *__restrict __dst, - const char **__restrict __src, size_t __nmc, -@@ -485,11 +418,6 @@ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, - } - - --extern size_t __wcsnrtombs_chk (char *__restrict __dst, -- const wchar_t **__restrict __src, -- size_t __nwc, size_t __len, -- mbstate_t *__restrict __ps, size_t __dstlen) -- __THROW; - extern size_t __REDIRECT_NTH (__wcsnrtombs_alias, - (char *__restrict __dst, - const wchar_t **__restrict __src, -diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h -index c37e8619a0..5f7139f279 100644 ---- a/wcsmbs/uchar.h -+++ b/wcsmbs/uchar.h -@@ -34,8 +34,16 @@ - /* Declare the C2x char8_t typedef in C2x modes, but only if the C++ - __cpp_char8_t feature test macro is not defined. */ - #if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t -+#if __GNUC_PREREQ (10, 0) && defined __cplusplus -+/* Suppress the diagnostic regarding char8_t being a keyword in C++20. */ -+# pragma GCC diagnostic push -+# pragma GCC diagnostic ignored "-Wc++20-compat" -+#endif - /* Define the 8-bit character type. */ - typedef unsigned char char8_t; -+#if __GNUC_PREREQ (10, 0) && defined __cplusplus -+# pragma GCC diagnostic pop -+#endif - #endif - - #ifndef __USE_ISOCXX11 -diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h -index 5d6a40853d..c1321c7518 100644 ---- a/wcsmbs/wchar.h -+++ b/wcsmbs/wchar.h -@@ -864,14 +864,21 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize, - - /* Define some macros helping to catch buffer overflows. */ - #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function --# include -+/* Declare all functions from bits/wchar2-decl.h first. */ -+# include - #endif - --#include -+/* The following headers provide asm redirections. These redirections must -+ appear before the first usage of these functions, e.g. in bits/wchar.h. */ - #if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 - # include - #endif - -+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function -+/* Now include the function definitions and redirects too. */ -+# include -+#endif -+ - __END_DECLS - - #endif /* wchar.h */ diff --git a/glibc/linux-headers-cp-insteadof-rsync.patch b/glibc/linux-headers-cp-insteadof-rsync.patch deleted file mode 100644 index 5f97583..0000000 --- a/glibc/linux-headers-cp-insteadof-rsync.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- linux-5.15.55/Makefile.orig 2022-10-06 02:40:50.437097642 +0200 -+++ linux-5.15.55/Makefile 2022-10-06 03:19:33.637096756 +0200 -@@ -1306,8 +1306,9 @@ - quiet_cmd_headers_install = INSTALL $(INSTALL_HDR_PATH)/include - cmd_headers_install = \ - mkdir -p $(INSTALL_HDR_PATH); \ -- rsync -mrl --include='*/' --include='*\.h' --exclude='*' \ -- usr/include $(INSTALL_HDR_PATH) -+ cp -a usr/include $(INSTALL_HDR_PATH); \ -+ find $(INSTALL_HDR_PATH) -type f ! -name '*.h' -delete; \ -+ find $(INSTALL_HDR_PATH) -type d -empty -delete - - PHONY += headers_install - headers_install: headers