git-updates
authorGNU Libc Maintainers <debian-glibc@lists.debian.org>
Thu, 6 Mar 2025 22:46:53 +0000 (23:46 +0100)
committerAurelien Jarno <aurel32@debian.org>
Thu, 6 Mar 2025 22:46:53 +0000 (23:46 +0100)
GIT update of https://sourceware.org/git/glibc.git/release/2.36/master from glibc-2.36

GIT update of https://sourceware.org/git/glibc.git/release/2.36/master from glibc-2.36

Gbp-Pq: Name git-updates.diff

346 files changed:
Makeconfig
Makerules
NEWS
assert/Makefile
assert/assert.c
assert/tst-assert-sa-2025-0001.c [new file with mode: 0644]
bits/socket.h
bits/wordsize.h
csu/libc-start.c
csu/libc-tls.c
dlfcn/dlopen.c
elf/Makefile
elf/cache.c
elf/dl-cache.c
elf/dl-call_fini.c [new file with mode: 0644]
elf/dl-close.c
elf/dl-find_object.c
elf/dl-fini.c
elf/dl-hwcaps.c
elf/dl-init.c
elf/dl-lookup.c
elf/dl-open.c
elf/dl-reloc.c
elf/dl-sort-maps.c
elf/dl-support.c
elf/dl-tls.c
elf/dl-tunables.c
elf/dl-tunables.list
elf/dso-sort-tests-1.def
elf/elf.h
elf/ifuncmain1.c
elf/ifuncmain5.c
elf/rtld-Rules
elf/rtld.c
elf/tst-auditmod28.c
elf/tst-dlmopen-twice-mod1.c [new file with mode: 0644]
elf/tst-dlmopen-twice-mod2.c [new file with mode: 0644]
elf/tst-dlmopen-twice.c [new file with mode: 0644]
elf/tst-env-setuid-tunables.c
elf/tst-ldconfig-p.sh [new file with mode: 0644]
elf/tst-recursive-tls.c [new file with mode: 0644]
elf/tst-recursive-tlsmallocmod.c [new file with mode: 0644]
elf/tst-recursive-tlsmodN.c [new file with mode: 0644]
elf/tst-stackguard1.c
gmon/Makefile
gmon/gmon.c
gmon/mcount.c
gmon/sys/gmon.h
gmon/tst-mcleanup.c [new file with mode: 0644]
gmon/tst-mcount-overflow-check.sh [new file with mode: 0644]
gmon/tst-mcount-overflow.c [new file with mode: 0644]
gshadow/Makefile
gshadow/sgetsgent_r.c
gshadow/tst-sgetsgent.c [new file with mode: 0644]
iconv/gconv_parseconfdir.h
iconvdata/Makefile
iconvdata/iso-2022-cn-ext.c
iconvdata/tst-iconv-iso-2022-cn-ext.c [new file with mode: 0644]
include/arpa/nameser.h
include/bits/wchar2-decl.h [new file with mode: 0644]
include/link.h
include/resolv.h
include/sys/sysinfo.h
io/Makefile
io/tst-fcntl-lock-lfs.c [new file with mode: 0644]
io/tst-fcntl-lock.c [new file with mode: 0644]
io/tst-lockf.c
libio/bits/stdio2.h
libio/bug-mmap-fflush.c
libio/genops.c
libio/libioP.h
locale/weight.h
localedata/tst-ctype.c
login/Makefile
login/tst-utmp-size-64.c [new file with mode: 0644]
login/tst-utmp-size.c [new file with mode: 0644]
malloc/arena.c
math/test-tgmath2.c
misc/Makefile
misc/bits/syslog.h
misc/getsysstats.c
misc/sys/cdefs.h
misc/sys/syslog.h
misc/syslog.c
misc/tst-mremap1.c [new file with mode: 0644]
misc/tst-mremap2.c [new file with mode: 0644]
misc/tst-preadvwritev2-common.c
misc/tst-syslog-long-progname.c [new file with mode: 0644]
misc/tst-syslog.c
nis/nis_call.c
nptl/descr.h
nptl/tst-cancel7.c
nptl/tst-setuid2.c
nptl/tst-stackguard1.c
nscd/aicache.c
nscd/connections.c
nscd/netgroupcache.c
nscd/nscd.h
nscd/nscd_gethst_r.c
nss/Makefile
nss/getent.c
nss/nss_test_gai_hv2_canonname.c [new file with mode: 0644]
nss/tst-nss-db-endpwent.c
nss/tst-nss-files-hosts-long.c
nss/tst-nss-gai-hv2-canonname.c [new file with mode: 0644]
nss/tst-nss-gai-hv2-canonname.h [new file with mode: 0644]
nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script [new file with mode: 0644]
nss/tst-reload1.c
posix/tst-truncate-common.c
resolv/Makefile
resolv/README
resolv/mapv4v6addr.h [deleted file]
resolv/mapv4v6hostent.h [deleted file]
resolv/ns_name_length_uncompressed.c [new file with mode: 0644]
resolv/ns_rr_cursor_init.c [new file with mode: 0644]
resolv/ns_rr_cursor_next.c [new file with mode: 0644]
resolv/ns_samebinaryname.c [new file with mode: 0644]
resolv/nss_dns/dns-host.c
resolv/res-name-checking.c
resolv/res_send.c
resolv/resolv-internal.h
resolv/tst-ns_name_length_uncompressed.c [new file with mode: 0644]
resolv/tst-ns_rr_cursor.c [new file with mode: 0644]
resolv/tst-ns_samebinaryname.c [new file with mode: 0644]
resolv/tst-resolv-aliases.c [new file with mode: 0644]
resolv/tst-resolv-byaddr.c [new file with mode: 0644]
resolv/tst-resolv-invalid-cname.c [new file with mode: 0644]
resolv/tst-resolv-maybe_insert_sig.h [new file with mode: 0644]
resolv/tst-resolv-noaaaa-vc.c [new file with mode: 0644]
resolv/tst-resolv-semi-failure.c [new file with mode: 0644]
resolv/tst-resolv-short-response.c [new file with mode: 0644]
rt/aio_misc.c
scripts/dso-ordering-test.py
scripts/glibcextract.py
socket/Makefile
socket/bits/socket2.h
socket/tst-cmsghdr-skeleton.c [new file with mode: 0644]
socket/tst-cmsghdr.c [new file with mode: 0644]
stdio-common/Makefile
stdio-common/tst-scanf-bz27650.c [new file with mode: 0644]
stdio-common/tst-ungetc-leak.c [new file with mode: 0644]
stdio-common/tst-ungetc.c
stdlib/Makefile
stdlib/arc4random.c
stdlib/bits/stdlib.h
stdlib/exit.c
stdlib/longlong.h
stdlib/test-atexit-recursive.c [new file with mode: 0644]
stdlib/tst-setenv-environ.c [new file with mode: 0644]
stdlib/tst-system.c
string/test-strnlen.c
sunrpc/netname.c
support/Makefile
support/check.h
support/dtotimespec-time64.c [new file with mode: 0644]
support/dtotimespec.c [new file with mode: 0644]
support/shell-container.c
support/support_can_chroot.c
support/support_copy_file.c
support/support_descriptor_supports_holes.c
support/test-container.c
support/timespec.h
support/xpthread_cond_signal.c [new file with mode: 0644]
support/xstdlib.h [new file with mode: 0644]
support/xsystem.c [new file with mode: 0644]
support/xthread.h
sysdeps/aarch64/configure [changed mode: 0644->0755]
sysdeps/aarch64/configure.ac
sysdeps/aarch64/dl-trampoline.S
sysdeps/aarch64/memchr.S
sysdeps/aarch64/memcpy.S
sysdeps/aarch64/memrchr.S
sysdeps/aarch64/memset.S
sysdeps/aarch64/multiarch/Makefile
sysdeps/aarch64/multiarch/ifunc-impl-list.c
sysdeps/aarch64/multiarch/init-arch.h
sysdeps/aarch64/multiarch/memchr_nosimd.S
sysdeps/aarch64/multiarch/memcpy.c
sysdeps/aarch64/multiarch/memcpy_a64fx.S
sysdeps/aarch64/multiarch/memcpy_advsimd.S [deleted file]
sysdeps/aarch64/multiarch/memcpy_falkor.S [deleted file]
sysdeps/aarch64/multiarch/memcpy_mops.S [new file with mode: 0644]
sysdeps/aarch64/multiarch/memcpy_sve.S
sysdeps/aarch64/multiarch/memcpy_thunderx.S
sysdeps/aarch64/multiarch/memcpy_thunderx2.S
sysdeps/aarch64/multiarch/memmove.c
sysdeps/aarch64/multiarch/memmove_mops.S [new file with mode: 0644]
sysdeps/aarch64/multiarch/memset.c
sysdeps/aarch64/multiarch/memset_a64fx.S
sysdeps/aarch64/multiarch/memset_base64.S [deleted file]
sysdeps/aarch64/multiarch/memset_emag.S
sysdeps/aarch64/multiarch/memset_falkor.S [deleted file]
sysdeps/aarch64/multiarch/memset_generic.S
sysdeps/aarch64/multiarch/memset_kunpeng.S
sysdeps/aarch64/multiarch/memset_mops.S [new file with mode: 0644]
sysdeps/aarch64/multiarch/memset_zva64.S [new file with mode: 0644]
sysdeps/aarch64/multiarch/rtld-memset.S [deleted file]
sysdeps/aarch64/multiarch/strlen.c
sysdeps/aarch64/multiarch/strlen_asimd.S
sysdeps/aarch64/multiarch/strlen_generic.S [new file with mode: 0644]
sysdeps/aarch64/multiarch/strlen_mte.S [deleted file]
sysdeps/aarch64/rawmemchr.S
sysdeps/aarch64/strchr.S
sysdeps/aarch64/strchrnul.S
sysdeps/aarch64/strcpy.S
sysdeps/aarch64/strlen.S
sysdeps/aarch64/strnlen.S
sysdeps/aarch64/strrchr.S
sysdeps/arc/utmp-size.h [new file with mode: 0644]
sysdeps/arm/bits/wordsize.h [new file with mode: 0644]
sysdeps/arm/dl-machine.h
sysdeps/arm/utmp-size.h [new file with mode: 0644]
sysdeps/csky/bits/wordsize.h [new file with mode: 0644]
sysdeps/csky/utmp-size.h [new file with mode: 0644]
sysdeps/generic/ldsodefs.h
sysdeps/generic/libc-lock-arch.h [new file with mode: 0644]
sysdeps/generic/mremap-failure.h [new file with mode: 0644]
sysdeps/generic/utmp-size.h [new file with mode: 0644]
sysdeps/hppa/dl-machine.h
sysdeps/hppa/utmp-size.h [new file with mode: 0644]
sysdeps/ieee754/dbl-64/s_expm1.c
sysdeps/ieee754/dbl-64/s_log1p.c
sysdeps/ieee754/ldbl-128/e_j1l.c
sysdeps/ieee754/ldbl-128ibm/e_j1l.c
sysdeps/ieee754/ldbl-128ibm/s_llroundl.c
sysdeps/m68k/bits/wordsize.h [new file with mode: 0644]
sysdeps/m68k/utmp-size.h [new file with mode: 0644]
sysdeps/mach/getsysstats.c
sysdeps/mach/hurd/bits/socket.h
sysdeps/microblaze/bits/wordsize.h [new file with mode: 0644]
sysdeps/microblaze/utmp-size.h [new file with mode: 0644]
sysdeps/mips/bits/wordsize.h
sysdeps/mips/utmp-size.h [new file with mode: 0644]
sysdeps/nios2/bits/wordsize.h [new file with mode: 0644]
sysdeps/nios2/utmp-size.h [new file with mode: 0644]
sysdeps/nptl/dl-tls_init_tp.c
sysdeps/nptl/libc-lock.h
sysdeps/nptl/libc-lockP.h
sysdeps/or1k/utmp-size.h [new file with mode: 0644]
sysdeps/posix/getaddrinfo.c
sysdeps/posix/libc_fatal.c
sysdeps/posix/system.c
sysdeps/powerpc/mod-tlsopt-powerpc.c
sysdeps/powerpc/powerpc32/bits/wordsize.h
sysdeps/powerpc/powerpc64/bits/wordsize.h
sysdeps/powerpc/powerpc64/dl-machine.h
sysdeps/powerpc/utmp-size.h [new file with mode: 0644]
sysdeps/pthread/tst-setuid3.c
sysdeps/riscv/utmp-size.h [new file with mode: 0644]
sysdeps/s390/wcsncmp-vx.S
sysdeps/sh/bits/wordsize.h [new file with mode: 0644]
sysdeps/sh/utmp-size.h [new file with mode: 0644]
sysdeps/sparc/sparc32/bits/wordsize.h
sysdeps/sparc/sparc32/memset.S
sysdeps/sparc/sparc64/bits/wordsize.h
sysdeps/sparc/sparc64/memmove.S
sysdeps/sparc/sysdep.h
sysdeps/sparc/utmp-size.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/Makefile
sysdeps/unix/sysv/linux/aarch64/bits/hwcap.h
sysdeps/unix/sysv/linux/aarch64/cpu-features.c
sysdeps/unix/sysv/linux/aarch64/cpu-features.h
sysdeps/unix/sysv/linux/alpha/brk_call.h
sysdeps/unix/sysv/linux/arm/bits/struct_stat.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/bits/fcntl-linux.h
sysdeps/unix/sysv/linux/bits/socket.h
sysdeps/unix/sysv/linux/bits/struct_stat.h
sysdeps/unix/sysv/linux/bits/uio-ext.h
sysdeps/unix/sysv/linux/check_pf.c
sysdeps/unix/sysv/linux/cmsg_nxthdr.c
sysdeps/unix/sysv/linux/csky/bits/struct_stat.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/dl-rseq-symbols.S [new file with mode: 0644]
sysdeps/unix/sysv/linux/generic/bits/struct_stat.h [deleted file]
sysdeps/unix/sysv/linux/getsysstats.c
sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/hppa/bits/wordsize.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/hppa/kernel-features.h
sysdeps/unix/sysv/linux/ipc_priv.h
sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/mremap-failure.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/mremap.c
sysdeps/unix/sysv/linux/msgctl.c
sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/not-cancel.h
sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h
sysdeps/unix/sysv/linux/powerpc/bits/wordsize.h
sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
sysdeps/unix/sysv/linux/rseq-internal.h
sysdeps/unix/sysv/linux/sched_getcpu.c
sysdeps/unix/sysv/linux/semctl.c
sysdeps/unix/sysv/linux/sh/bits/struct_stat.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/shmctl.c
sysdeps/unix/sysv/linux/sparc/bits/wordsize.h
sysdeps/unix/sysv/linux/sparc/sparc32/sigreturn_stub.S
sysdeps/unix/sysv/linux/sparc/sparc64/sigreturn_stub.S
sysdeps/unix/sysv/linux/sys/mount.h
sysdeps/unix/sysv/linux/syscall-names.list
sysdeps/unix/sysv/linux/tst-linux-mremap1.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-mount-compile.py [new file with mode: 0755]
sysdeps/unix/sysv/linux/tst-mount-consts.py
sysdeps/unix/sysv/linux/tst-pidfd-consts.py
sysdeps/unix/sysv/linux/tst-pidfd.c
sysdeps/unix/sysv/linux/tst-rseq-disable.c
sysdeps/unix/sysv/linux/tst-rseq.c
sysdeps/x86/Makefile
sysdeps/x86/bits/wordsize.h
sysdeps/x86/dl-cacheinfo.h
sysdeps/x86/get-isa-level.h
sysdeps/x86/isa-level.h
sysdeps/x86/utmp-size.h [new file with mode: 0644]
sysdeps/x86_64/dl-tls.c
sysdeps/x86_64/dl-tlsdesc.S
sysdeps/x86_64/ffsll.c
sysdeps/x86_64/fpu/fraiseexcpt.c
sysdeps/x86_64/fpu/multiarch/Makefile
sysdeps/x86_64/fpu/multiarch/e_log2-fma.c [new file with mode: 0644]
sysdeps/x86_64/fpu/multiarch/e_log2.c [new file with mode: 0644]
sysdeps/x86_64/fpu/multiarch/s_expm1-fma.c [new file with mode: 0644]
sysdeps/x86_64/fpu/multiarch/s_expm1.c [new file with mode: 0644]
sysdeps/x86_64/fpu/multiarch/s_log1p-fma.c [new file with mode: 0644]
sysdeps/x86_64/fpu/multiarch/s_log1p.c [new file with mode: 0644]
sysdeps/x86_64/multiarch/ifunc-avx2.h
sysdeps/x86_64/multiarch/ifunc-impl-list.c
sysdeps/x86_64/multiarch/ifunc-strcasecmp.h
sysdeps/x86_64/multiarch/memcmp-sse2.S
sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S
sysdeps/x86_64/multiarch/rtld-strcpy.S [new file with mode: 0644]
sysdeps/x86_64/multiarch/strcmp.c
sysdeps/x86_64/multiarch/strlen-avx2.S
sysdeps/x86_64/multiarch/strncmp.c
time/Makefile
time/mktime.c
time/strftime_l.c
time/strptime_l.c
time/tst-strftime4-time64.c [new file with mode: 0644]
time/tst-strftime4.c [new file with mode: 0644]
time/tzfile.c
timezone/Makefile
timezone/tst-bz29951.c [new file with mode: 0644]
wcsmbs/Makefile
wcsmbs/bits/wchar2-decl.h [new file with mode: 0644]
wcsmbs/bits/wchar2.h
wcsmbs/uchar.h
wcsmbs/wchar.h

index ba70321af1d239edb7088ca12bc2ab28cb9684ad..151f542c278fa71bfb627f9ac78045ef2739b6d6 100644 (file)
@@ -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)
@@ -569,10 +585,13 @@ link-libc-rpath-link = -Wl,-rpath-link=$(rpath-link)
 # before the expansion of LDLIBS-* variables).
 
 # Tests use -Wl,-rpath instead of -Wl,-rpath-link for
-# build-hardcoded-path-in-tests.
+# build-hardcoded-path-in-tests.  Add -Wl,--disable-new-dtags to force
+# DT_RPATH instead of DT_RUNPATH which only applies to DT_NEEDED entries
+# in the executable and doesn't applies to DT_NEEDED entries in shared
+# libraries which are loaded via DT_NEEDED entries in the executable.
 ifeq (yes,$(build-hardcoded-path-in-tests))
-link-libc-tests-rpath-link = $(link-libc-rpath)
-link-test-modules-rpath-link = $(link-libc-rpath)
+link-libc-tests-rpath-link = $(link-libc-rpath) -Wl,--disable-new-dtags
+link-test-modules-rpath-link = $(link-libc-rpath) -Wl,--disable-new-dtags
 else
 link-libc-tests-rpath-link = $(link-libc-rpath-link)
 link-test-modules-rpath-link =
@@ -868,7 +887,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 +936,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
index d1e139d03c1c448e14aee35af3e54ee7abe2180c..09c0cf8357310896c050234902025fa7da2566e1 100644 (file)
--- 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))
 \f
 # 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 f61e521fc88316f739f844ac18cfc580e6154feb..96ff2c8a2059f6762f5e189c60d139b3eec565a2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,115 @@ See the end for copying conditions.
 Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
 using `glibc' in the "product" field.
 \f
+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.
+
+Deprecated and removed features, and other changes affecting compatibility:
+
+* __rseq_size now denotes the size of the active rseq area (20 bytes
+  initially), not the size of struct rseq (32 bytes initially).
+
+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.
+
+  CVE-2025-0395: When the assert() function fails, it does not allocate
+  enough space for the assertion failure message string and size
+  information, which may lead to a buffer overflow if the message string
+  size aligns to page size.
+
+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
+  [27821] ungetc: Fix backup buffer leak on program exit
+  [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
+  [30081] resolv: Do not wait for non-existing second DNS response after error
+  [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
+  [31476] resolv: Track single-request fallback via _res._flags
+  [31890] resolv: Allow short error responses to match any DNS query
+  [31965] rseq extension mechanism does not work as intended
+  [31968] mremap implementation in C does not handle arguments correctly
+  [32052] Name space violation in fortify wrappers
+  [32137] libio: Attempt wide backup free only for non-legacy code
+  [32231] elf: Change ldconfig auxcache magic number
+  [32470] x86: Avoid integer truncation with large cache sizes
+  [32582] Fix underallocation of abort_msg_s struct (CVE-2025-0395)
+\f
 Version 2.36
 
 Major new features:
index f7cf8e9b77939aefbd399a5615de4c1f9f4ca535..df5a8e6f10a0477993506c4a0d4d96adc3ef30c1 100644 (file)
@@ -22,10 +22,23 @@ subdir      := assert
 
 include ../Makeconfig
 
-headers        := assert.h
-
-routines := assert assert-perr __assert
-tests := test-assert test-assert-perr tst-assert-c++ tst-assert-g++
+headers := \
+  assert.h
+  # headers
+
+routines := \
+  __assert \
+  assert \
+  assert-perr \
+  # routines
+
+tests := \
+  test-assert \
+  test-assert-perr \
+  tst-assert-c++ \
+  tst-assert-g++ \
+  tst-assert-sa-2025-0001 \
+  # tests
 
 ifeq ($(have-cxx-thread_local),yes)
 CFLAGS-tst-assert-c++.o = -std=c++11
@@ -33,7 +46,10 @@ LDLIBS-tst-assert-c++ = -lstdc++
 CFLAGS-tst-assert-g++.o = -std=gnu++11
 LDLIBS-tst-assert-g++ = -lstdc++
 else
-tests-unsupported += tst-assert-c++ tst-assert-g++
+tests-unsupported += \
+  tst-assert-c++ \
+  tst-assert-g++ \
+  # tests-unsupported
 endif
 
 include ../Rules
index 133a183bc337075e06447e4c8e5cfba180aaf7bf..9e55eeb473399bd8e9c9490275f1cd5249af772f 100644 (file)
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <atomic.h>
 #include <ldsodefs.h>
+#include <libc-pointer-arith.h>
 #include <libintl.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -64,7 +65,8 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file,
       (void) __fxprintf (NULL, "%s", str);
       (void) fflush (stderr);
 
-      total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
+      total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
+                       GLRO(dl_pagesize));
       struct abort_msg_s *buf = __mmap (NULL, total, PROT_READ | PROT_WRITE,
                                        MAP_ANON | MAP_PRIVATE, -1, 0);
       if (__glibc_likely (buf != MAP_FAILED))
diff --git a/assert/tst-assert-sa-2025-0001.c b/assert/tst-assert-sa-2025-0001.c
new file mode 100644 (file)
index 0000000..102cb00
--- /dev/null
@@ -0,0 +1,92 @@
+/* Test for CVE-2025-0395.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+/* Test that a large enough __progname does not result in a buffer overflow
+   when printing an assertion failure.  This was CVE-2025-0395.  */
+#include <assert.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
+
+extern const char *__progname;
+
+int
+do_test (int argc, char **argv)
+{
+
+  support_need_proc ("Reads /proc/self/maps to add guards to writable maps.");
+  ignore_stderr ();
+
+  /* XXX assumes that the assert is on a 2 digit line number.  */
+  const char *prompt = ": %s:99: do_test: Assertion `argc < 1' failed.\n";
+
+  int ret = fprintf (stderr, prompt, __FILE__);
+  if (ret < 0)
+    FAIL_EXIT1 ("fprintf failed: %m\n");
+
+  size_t pagesize = getpagesize ();
+  size_t namesize = pagesize - 1 - ret;
+
+  /* Alter the progname so that the assert message fills the entire page.  */
+  char progname[namesize];
+  memset (progname, 'A', namesize - 1);
+  progname[namesize - 1] = '\0';
+  __progname = progname;
+
+  FILE *f = xfopen ("/proc/self/maps", "r");
+  char *line = NULL;
+  size_t len = 0;
+  uintptr_t prev_to = 0;
+
+  /* Pad the beginning of every writable mapping with a PROT_NONE map.  This
+     ensures that the mmap in the assert_fail path never ends up below a
+     writable map and will terminate immediately in case of a buffer
+     overflow.  */
+  while (xgetline (&line, &len, f))
+    {
+      uintptr_t from, to;
+      char perm[4];
+
+      sscanf (line, "%" SCNxPTR "-%" SCNxPTR " %c%c%c%c ",
+             &from, &to,
+             &perm[0], &perm[1], &perm[2], &perm[3]);
+
+      bool writable = (memchr (perm, 'w', 4) != NULL);
+
+      if (prev_to != 0 && from - prev_to > pagesize && writable)
+       xmmap ((void *) from - pagesize, pagesize, PROT_NONE,
+              MAP_ANONYMOUS | MAP_PRIVATE, 0);
+
+      prev_to = to;
+    }
+
+  xfclose (f);
+
+  assert (argc < 1);
+  return 0;
+}
+
+#define EXPECTED_SIGNAL SIGABRT
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
index 2b99dea33bfe0c2fa2d43fa6f08d578b2e07c89e..aac8c49b008f1b606fa1596222d6d1ac211a07f4 100644 (file)
@@ -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'.  */
index 14edae3a11d01c9714172d9dd6b78b38b086c36c..53013a9275c7c81eccb0356ab956eb2688bcf512 100644 (file)
@@ -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
index 543560f36c33b07a1fbe1b7e4578374fe8007b1f..bfeee6d8513fba6fb283be2d9082fe5b6f94eb44 100644 (file)
@@ -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);
 
index 0a216c550289058ecd408ec71bbcee3322e4f12a..7fdf7cd7a84da140fb45326bd1b1cae4b09ac16e 100644 (file)
@@ -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);
index 2696dde4b1cdf510b78f173e8b69155890ddae66..9b07b4e132f2e73d00339d8702ff34c1d455ac23 100644 (file)
@@ -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 *
index fd77d0c7c8799c336c65278f6f8e939ed8707633..eb77ff641dd2eadbb58f3205c687b5421e2b55f1 100644 (file)
@@ -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 \
@@ -435,6 +440,7 @@ tests += \
   tst-p_align1 \
   tst-p_align2 \
   tst-p_align3 \
+  tst-recursive-tls \
   tst-relsort1 \
   tst-ro-dynamic \
   tst-rtld-run-static \
@@ -631,6 +637,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 +772,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 +807,7 @@ modules-names += \
   tst-auditmanymod7 \
   tst-auditmanymod8 \
   tst-auditmanymod9 \
+  tst-auditmod-tlsdesc  \
   tst-auditmod1 \
   tst-auditmod9a \
   tst-auditmod9b \
@@ -834,6 +844,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 \
@@ -866,6 +878,23 @@ modules-names += \
   tst-null-argv-lib \
   tst-p_alignmod-base \
   tst-p_alignmod3 \
+  tst-recursive-tlsmallocmod \
+  tst-recursive-tlsmod0 \
+  tst-recursive-tlsmod1 \
+  tst-recursive-tlsmod2 \
+  tst-recursive-tlsmod3 \
+  tst-recursive-tlsmod4 \
+  tst-recursive-tlsmod5 \
+  tst-recursive-tlsmod6 \
+  tst-recursive-tlsmod7 \
+  tst-recursive-tlsmod8 \
+  tst-recursive-tlsmod9 \
+  tst-recursive-tlsmod10 \
+  tst-recursive-tlsmod11 \
+  tst-recursive-tlsmod12 \
+  tst-recursive-tlsmod13 \
+  tst-recursive-tlsmod14 \
+  tst-recursive-tlsmod15 \
   tst-relsort1mod1 \
   tst-relsort1mod2 \
   tst-ro-dynamic-mod \
@@ -990,23 +1019,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 +2424,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 +2986,33 @@ $(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
+
+$(objpfx)tst-recursive-tls: $(objpfx)tst-recursive-tlsmallocmod.so
+# More objects than DTV_SURPLUS, to trigger DTV reallocation.
+$(objpfx)tst-recursive-tls.out: \
+  $(patsubst %,$(objpfx)tst-recursive-tlsmod%.so, \
+    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
+$(objpfx)tst-recursive-tlsmod%.os: tst-recursive-tlsmodN.c
+       $(compile-command.c) -DVAR=thread_$* -DFUNC=get_threadvar_$*
index 3d7d3a67bf4e6d2d171f985951f5874cd47f362d..528a8ba6948ce062c13bbd13207c8bdb74aebbf7 100644 (file)
@@ -845,7 +845,7 @@ struct aux_cache_entry
   struct aux_cache_entry *next;
 };
 
-#define AUX_CACHEMAGIC         "glibc-ld.so.auxcache-1.0"
+#define AUX_CACHEMAGIC         "glibc-ld.so.auxcache-2.0"
 
 struct aux_cache_file_entry
 {
index 8bbf110d02c832df53924faf6b86a09df656c308..b97c17b3a9c5e750a673f6d1e3ed39022304652d 100644 (file)
@@ -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 (file)
index 0000000..9e7ba10
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ldsodefs.h>
+#include <sysdep.h>
+
+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));
+}
index bcd6e206e94b1c67cbe0b884f82eed847ccd228e..ef909d8c66b43c76483992439e770ca57fd3080c 100644 (file)
 
 #include <dl-unmap-segments.h>
 
-
-/* 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.  */
@@ -743,7 +703,7 @@ _dl_close_worker (struct link_map *map, bool force)
       if (__glibc_unlikely (newgen == 0))
        _dl_fatal_printf ("TLS generation counter wrapped!  Please report as described in "REPORT_BUGS_TO".\n");
       /* Can be read concurrently.  */
-      atomic_store_relaxed (&GL(dl_tls_generation), newgen);
+      atomic_store_release (&GL(dl_tls_generation), newgen);
 
       if (tls_free_end == GL(dl_tls_static_used))
        GL(dl_tls_static_used) = tls_free_start;
index 4d5831b6f4f0a755fbddd6fad09329cb316b068f..2e5b456c11347226a955fc59203416e9f6f9462a 100644 (file)
@@ -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.  */
index 030b1fcbcdc3018d7874ca4760eacbfb5fa66760..50ff94db16308aaa28a6604b742a600b617d3579 100644 (file)
 #include <ldsodefs.h>
 #include <elf-initfini.h>
 
-
-/* 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);
index 6f161f6ad528661f6b577d7d5d8a1f6ec6825363..92eb53790ef8d32005c0da5e28804bc5843a94d3 100644 (file)
@@ -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)
index deefeb099a856d1f590626f6c5fb5727b94e11d8..fca8e3a05ebdc705152784dbb3a0f2dc98c3f83e 100644 (file)
 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.  */
index 4c86dc694e0eebb23421e08103ee7f3c0adaadf9..67fb2e31e2612a0ec8b1002efa7a3eb6ad3b84a7 100644 (file)
@@ -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);
 }
index a23e65926bcfe797f06f8b4175f65040f4547a05..734a0bee4eaf15dc6cfc59c415ac54e283e57f96 100644 (file)
@@ -405,7 +405,7 @@ update_tls_slotinfo (struct link_map *new)
     _dl_fatal_printf (N_("\
 TLS generation counter wrapped!  Please report this."));
   /* Can be read concurrently.  */
-  atomic_store_relaxed (&GL(dl_tls_generation), newgen);
+  atomic_store_release (&GL(dl_tls_generation), newgen);
 
   /* We need a second pass for static tls data, because
      _dl_update_slotinfo must not be run while calls to
@@ -422,8 +422,8 @@ TLS generation counter wrapped!  Please report this."));
             now, but we can delay updating the DTV.  */
          imap->l_need_tls_init = 0;
 #ifdef SHARED
-         /* Update the slot information data for at least the
-            generation of the DSO we are allocating data for.  */
+         /* Update the slot information data for the current
+            generation.  */
 
          /* FIXME: This can terminate the process on memory
             allocation failure.  It is not possible to raise
@@ -431,7 +431,7 @@ TLS generation counter wrapped!  Please report this."));
             _dl_update_slotinfo would have to be split into two
             operations, similar to resize_scopes and update_scopes
             above.  This is related to bug 16134.  */
-         _dl_update_slotinfo (imap->l_tls_modid);
+         _dl_update_slotinfo (imap->l_tls_modid, newgen);
 #endif
 
          dl_init_static_tls (imap);
@@ -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
index 756bf950f6f98aa04e4ee23d202f27c26775584e..88816a715f65897bee33527aaf9822abce414d00 100644 (file)
@@ -112,11 +112,11 @@ _dl_try_allocate_static_tls (struct link_map *map, bool optional)
   if (map->l_real->l_relocated)
     {
 #ifdef SHARED
+      /* Update the DTV of the current thread.  Note: GL(dl_load_tls_lock)
+        is held here so normal load of the generation counter is valid.  */
       if (__builtin_expect (THREAD_DTV()[0].counter != GL(dl_tls_generation),
                            0))
-       /* Update the slot information data for at least the generation of
-          the DSO we are allocating data for.  */
-       (void) _dl_update_slotinfo (map->l_tls_modid);
+       (void) _dl_update_slotinfo (map->l_tls_modid, GL(dl_tls_generation));
 #endif
 
       dl_init_static_tls (map);
index 96638d7ed1a2df2faf62caf035b636ed870514b5..3e2a6a584ec46f802a775ff088fdedb009014f0d 100644 (file)
    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.  */
index 4af0b5b2ce23a762bd78d29747f50b0e1210680d..f45b630ba5cf9146a841005c1410dc2d0f3a06e7 100644 (file)
@@ -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);
 
index 093cdddb7ed8ff53cf721a1290afe7138d22005e..c6c213709214191b023dfa71d795a98872ae9d1a 100644 (file)
 /* Default for dl_tls_static_optional.  */
 #define OPTIONAL_TLS 512
 
+/* Used to count the number of threads currently executing dynamic TLS
+   updates.  Used to avoid recursive malloc calls in __tls_get_addr
+   for an interposed malloc that uses global-dynamic TLS (which is not
+   recommended); see _dl_tls_allocate_active checks.  This could be a
+   per-thread flag, but would need TLS access in the dynamic linker.  */
+unsigned int _dl_tls_threads_in_update;
+
+static inline void
+_dl_tls_allocate_begin (void)
+{
+  atomic_fetch_add_relaxed (&_dl_tls_threads_in_update, 1);
+}
+
+static inline void
+_dl_tls_allocate_end (void)
+{
+  atomic_fetch_add_relaxed (&_dl_tls_threads_in_update, -1);
+}
+
+static inline bool
+_dl_tls_allocate_active (void)
+{
+  return atomic_load_relaxed (&_dl_tls_threads_in_update) > 0;
+}
+
 /* Compute the static TLS surplus based on the namespace count and the
    TLS space that can be used for optimizations.  */
 static inline int
@@ -160,6 +185,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;
              }
 
@@ -430,12 +456,18 @@ _dl_allocate_tls_storage (void)
   size += TLS_PRE_TCB_SIZE;
 #endif
 
-  /* Perform the allocation.  Reserve space for the required alignment
-     and the pointer to the original allocation.  */
+  /* Reserve space for the required alignment and the pointer to the
+     original allocation.  */
   size_t alignment = GLRO (dl_tls_static_align);
+
+  /* Perform the allocation.  */
+  _dl_tls_allocate_begin ();
   void *allocated = malloc (size + alignment + sizeof (void *));
   if (__glibc_unlikely (allocated == NULL))
-    return NULL;
+    {
+      _dl_tls_allocate_end ();
+      return NULL;
+    }
 
   /* Perform alignment and allocate the DTV.  */
 #if TLS_TCB_AT_TP
@@ -471,6 +503,8 @@ _dl_allocate_tls_storage (void)
   result = allocate_dtv (result);
   if (result == NULL)
     free (allocated);
+
+  _dl_tls_allocate_end ();
   return result;
 }
 
@@ -488,6 +522,7 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
   size_t newsize = max_modid + DTV_SURPLUS;
   size_t oldsize = dtv[-1].counter;
 
+  _dl_tls_allocate_begin ();
   if (dtv == GL(dl_initial_dtv))
     {
       /* This is the initial dtv that was either statically allocated in
@@ -507,6 +542,7 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
       if (newp == NULL)
        oom ();
     }
+  _dl_tls_allocate_end ();
 
   newp[0].counter = newsize;
 
@@ -681,7 +717,9 @@ allocate_dtv_entry (size_t alignment, size_t size)
   if (powerof2 (alignment) && alignment <= _Alignof (max_align_t))
     {
       /* The alignment is supported by malloc.  */
+      _dl_tls_allocate_begin ();
       void *ptr = malloc (size);
+      _dl_tls_allocate_end ();
       return (struct dtv_pointer) { ptr, ptr };
     }
 
@@ -693,7 +731,10 @@ allocate_dtv_entry (size_t alignment, size_t size)
 
   /* Perform the allocation.  This is the pointer we need to free
      later.  */
+  _dl_tls_allocate_begin ();
   void *start = malloc (alloc_size);
+  _dl_tls_allocate_end ();
+
   if (start == NULL)
     return (struct dtv_pointer) {};
 
@@ -721,57 +762,57 @@ allocate_and_init (struct link_map *map)
 
 
 struct link_map *
-_dl_update_slotinfo (unsigned long int req_modid)
+_dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)
 {
   struct link_map *the_map = NULL;
   dtv_t *dtv = THREAD_DTV ();
 
-  /* The global dl_tls_dtv_slotinfo array contains for each module
-     index the generation counter current when the entry was created.
+  /* CONCURRENCY NOTES:
+
+     The global dl_tls_dtv_slotinfo_list array contains for each module
+     index the generation counter current when that entry was updated.
      This array never shrinks so that all module indices which were
-     valid at some time can be used to access it.  Before the first
-     use of a new module index in this function the array was extended
-     appropriately.  Access also does not have to be guarded against
-     modifications of the array.  It is assumed that pointer-size
-     values can be read atomically even in SMP environments.  It is
-     possible that other threads at the same time dynamically load
-     code and therefore add to the slotinfo list.  This is a problem
-     since we must not pick up any information about incomplete work.
-     The solution to this is to ignore all dtv slots which were
-     created after the one we are currently interested.  We know that
-     dynamic loading for this module is completed and this is the last
-     load operation we know finished.  */
-  unsigned long int idx = req_modid;
+     valid at some time can be used to access it.  Concurrent loading
+     and unloading of modules can update slotinfo entries or extend
+     the array.  The updates happen under the GL(dl_load_tls_lock) and
+     finish with the release store of the generation counter to
+     GL(dl_tls_generation) which is synchronized with the load of
+     new_gen in the caller.  So updates up to new_gen are synchronized
+     but updates for later generations may not be.
+
+     Here we update the thread dtv from old_gen (== dtv[0].counter) to
+     new_gen generation.  For this, each dtv[i] entry is either set to
+     an unallocated state (set), or left unmodified (nop).  Where (set)
+     may resize the dtv first if modid i >= dtv[-1].counter. The rules
+     for the decision between (set) and (nop) are
+
+     (1) If slotinfo entry i is concurrently updated then either (set)
+         or (nop) is valid: TLS access cannot use dtv[i] unless it is
+         synchronized with a generation > new_gen.
+
+     Otherwise, if the generation of slotinfo entry i is gen and the
+     loaded module for this entry is map then
+
+     (2) If gen <= old_gen then do (nop).
+
+     (3) If old_gen < gen <= new_gen then
+         (3.1) if map != 0 then (set)
+         (3.2) if map == 0 then either (set) or (nop).
+
+     Note that (1) cannot be reliably detected, but since both actions
+     are valid it does not have to be.  Only (2) and (3.1) cases need
+     to be distinguished for which relaxed mo access of gen and map is
+     enough: their value is synchronized when it matters.
+
+     Note that a relaxed mo load may give an out-of-thin-air value since
+     it is used in decisions that can affect concurrent stores.  But this
+     should only happen if the OOTA value causes UB that justifies the
+     concurrent store of the value.  This is not expected to be an issue
+     in practice.  */
   struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
 
-  while (idx >= listp->len)
-    {
-      idx -= listp->len;
-      listp = listp->next;
-    }
-
-  if (dtv[0].counter < listp->slotinfo[idx].gen)
+  if (dtv[0].counter < new_gen)
     {
-      /* CONCURRENCY NOTES:
-
-        Here the dtv needs to be updated to new_gen generation count.
-
-        This code may be called during TLS access when GL(dl_load_tls_lock)
-        is not held.  In that case the user code has to synchronize with
-        dlopen and dlclose calls of relevant modules.  A module m is
-        relevant if the generation of m <= new_gen and dlclose of m is
-        synchronized: a memory access here happens after the dlopen and
-        before the dlclose of relevant modules.  The dtv entries for
-        relevant modules need to be updated, other entries can be
-        arbitrary.
-
-        This e.g. means that the first part of the slotinfo list can be
-        accessed race free, but the tail may be concurrently extended.
-        Similarly relevant slotinfo entries can be read race free, but
-        other entries are racy.  However updating a non-relevant dtv
-        entry does not affect correctness.  For a relevant module m,
-        max_modid >= modid of m.  */
-      size_t new_gen = listp->slotinfo[idx].gen;
       size_t total = 0;
       size_t max_modid  = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx));
       assert (max_modid >= req_modid);
@@ -784,31 +825,33 @@ _dl_update_slotinfo (unsigned long int req_modid)
            {
              size_t modid = total + cnt;
 
-             /* Later entries are not relevant.  */
+             /* Case (1) for all later modids.  */
              if (modid > max_modid)
                break;
 
              size_t gen = atomic_load_relaxed (&listp->slotinfo[cnt].gen);
 
+             /* Case (1).  */
              if (gen > new_gen)
-               /* Not relevant.  */
                continue;
 
-             /* If the entry is older than the current dtv layout we
-                know we don't have to handle it.  */
+             /* Case (2) or (1).  */
              if (gen <= dtv[0].counter)
                continue;
 
+             /* Case (3) or (1).  */
+
              /* If there is no map this means the entry is empty.  */
              struct link_map *map
                = atomic_load_relaxed (&listp->slotinfo[cnt].map);
              /* Check whether the current dtv array is large enough.  */
              if (dtv[-1].counter < modid)
                {
+                 /* Case (3.2) or (1).  */
                  if (map == NULL)
                    continue;
 
-                 /* Resize the dtv.  */
+                 /* Resizing the dtv aborts on failure: bug 16134.  */
                  dtv = _dl_resize_dtv (dtv, max_modid);
 
                  assert (modid <= dtv[-1].counter);
@@ -819,10 +862,21 @@ _dl_update_slotinfo (unsigned long int req_modid)
                }
 
              /* If there is currently memory allocate for this
-                dtv entry free it.  */
+                dtv entry free it.  Note: this is not AS-safe.  */
              /* XXX Ideally we will at some point create a memory
                 pool.  */
-             free (dtv[modid].pointer.to_free);
+             /* Avoid calling free on a null pointer.  Some mallocs
+                incorrectly use dynamic TLS, and depending on how the
+                free function was compiled, it could call
+                __tls_get_addr before the null pointer check in the
+                free implementation.  Checking here papers over at
+                least some dynamic TLS usage by interposed mallocs.  */
+             if (dtv[modid].pointer.to_free != NULL)
+               {
+                 _dl_tls_allocate_begin ();
+                 free (dtv[modid].pointer.to_free);
+                 _dl_tls_allocate_end ();
+               }
              dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
              dtv[modid].pointer.to_free = NULL;
 
@@ -914,9 +968,9 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
 
 static struct link_map *
 __attribute_noinline__
-update_get_addr (GET_ADDR_ARGS)
+update_get_addr (GET_ADDR_ARGS, size_t gen)
 {
-  struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
+  struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE, gen);
   dtv_t *dtv = THREAD_DTV ();
 
   void *p = dtv[GET_ADDR_MODULE].pointer.val;
@@ -946,12 +1000,29 @@ __tls_get_addr (GET_ADDR_ARGS)
   dtv_t *dtv = THREAD_DTV ();
 
   /* Update is needed if dtv[0].counter < the generation of the accessed
-     module.  The global generation counter is used here as it is easier
-     to check.  Synchronization for the relaxed MO access is guaranteed
-     by user code, see CONCURRENCY NOTES in _dl_update_slotinfo.  */
+     module, but the global generation counter is easier to check (which
+     must be synchronized up to the generation of the accessed module by
+     user code doing the TLS access so relaxed mo read is enough).  */
   size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
   if (__glibc_unlikely (dtv[0].counter != gen))
-    return update_get_addr (GET_ADDR_PARAM);
+    {
+      if (_dl_tls_allocate_active ()
+         && GET_ADDR_MODULE < _dl_tls_initial_modid_limit)
+         /* This is a reentrant __tls_get_addr call, but we can
+            satisfy it because it's an initially-loaded module ID.
+            These TLS slotinfo slots do not change, so the
+            out-of-date generation counter does not matter.  However,
+            if not in a TLS update, still update_get_addr below, to
+            get off the slow path eventually.  */
+       ;
+      else
+       {
+         /* Update DTV up to the global generation, see CONCURRENCY NOTES
+            in _dl_update_slotinfo.  */
+         gen = atomic_load_acquire (&GL(dl_tls_generation));
+         return update_get_addr (GET_ADDR_PARAM, gen);
+       }
+    }
 
   void *p = dtv[GET_ADDR_MODULE].pointer.val;
 
@@ -960,7 +1031,7 @@ __tls_get_addr (GET_ADDR_ARGS)
 
   return (char *) p + GET_ADDR_OFFSET;
 }
-#endif
+#endif /* SHARED */
 
 
 /* Look up the module's TLS block as for __tls_get_addr,
@@ -1009,6 +1080,25 @@ _dl_tls_get_addr_soft (struct link_map *l)
   return data;
 }
 
+size_t _dl_tls_initial_modid_limit;
+
+void
+_dl_tls_initial_modid_limit_setup (void)
+{
+  struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+  size_t idx;
+  for (idx = 0; idx < listp->len; ++idx)
+    {
+      struct link_map *l = listp->slotinfo[idx].map;
+      if (l == NULL
+         /* The object can be unloaded, so its modid can be
+            reassociated.  */
+         || !(l->l_type == lt_executable || l->l_type == lt_library))
+       break;
+    }
+  _dl_tls_initial_modid_limit = idx;
+}
+
 
 void
 _dl_add_to_slotinfo (struct link_map *l, bool do_add)
@@ -1041,9 +1131,11 @@ _dl_add_to_slotinfo (struct link_map *l, bool do_add)
         the first slot.  */
       assert (idx == 0);
 
+      _dl_tls_allocate_begin ();
       listp = (struct dtv_slotinfo_list *)
        malloc (sizeof (struct dtv_slotinfo_list)
                + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
+      _dl_tls_allocate_end ();
       if (listp == NULL)
        {
          /* We ran out of memory while resizing the dtv slotinfo list.  */
index 8e7ee9df1049576f4c379d7955106e7811bfc216..76cf8b9da3cdf9c3fcbcff92b377b4934e3d5512 100644 (file)
@@ -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
 
index e6a56b307053a5f9e443f6cebf6c50c25cb559cc..9fa3b484cfc8d4c28027c4d62d54ecf6d2fa3311 100644 (file)
@@ -169,4 +169,17 @@ glibc {
       default: 2
     }
   }
+
+  gmon {
+    minarcs {
+      type: INT_32
+      minval: 50
+      default: 50
+    }
+    maxarcs {
+      type: INT_32
+      minval: 50
+      default: 1048576
+    }
+  }
 }
index 5f7f18ef270bc12d8ef848f62c35b84bb1ddb41c..4bf9052db16fb3522375afad055f1ca0ba9f32f6 100644 (file)
@@ -64,3 +64,10 @@ output: b>a>{}<a<b
 tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};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[<a<c<d<g<f<b<e];}
 output(glibc.rtld.dynamic_sort=2): {+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[<g<f<a<b<c<d<e];}
+
+# Test that even in the presence of dependency loops involving dlopen'ed
+# object, that object is initialized last (and not unloaded prematurely).
+# Final destructor order is indeterminate due to the cycle.
+tst-bz28937: {+a;+b;-b;+c;%c};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[<b<b1];+c[c>];%c(a1());}<a<a2<c<a1
+output(glibc.rtld.dynamic_sort=2): {+a[a2>a1>a>];+b[b1>b>];-b[<b<b1];+c[c>];%c(a1());}<a2<a<c<a1
index 02a1b3f52fdfa3d8d92fd4e3008316ab0a23f26d..f34d4ef7f498ed93faeb80e621d3ab609b56ce8c 100644 (file)
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1215,6 +1215,9 @@ typedef struct
 #define AT_HWCAP2      26              /* More machine-dependent hints about
                                           processor capabilities.  */
 
+#define AT_RSEQ_FEATURE_SIZE   27      /* rseq supported feature size.  */
+#define AT_RSEQ_ALIGN  28              /* rseq allocation alignment.  */
+
 #define AT_EXECFN      31              /* Filename of executable.  */
 
 /* Pointer to the global system page used for system calls and other
@@ -4085,8 +4088,11 @@ enum
 #define R_NDS32_TLS_DESC       119
 
 /* LoongArch ELF Flags */
-#define EF_LARCH_ABI           0x07
-#define EF_LARCH_ABI_LP64D     0x03
+#define EF_LARCH_ABI_MODIFIER_MASK  0x07
+#define EF_LARCH_ABI_SOFT_FLOAT     0x01
+#define EF_LARCH_ABI_SINGLE_FLOAT   0x02
+#define EF_LARCH_ABI_DOUBLE_FLOAT   0x03
+#define EF_LARCH_OBJABI_V1          0x40
 
 /* LoongArch specific dynamic relocations */
 #define R_LARCH_NONE           0
index 747fc02648a5493eb6a8b0f21cfc96e4aaa55c41..6effce3d77b1f7067f07045bf0af898dcdcce508 100644 (file)
@@ -19,7 +19,14 @@ typedef int (*foo_p) (void);
 #endif
 
 foo_p foo_ptr = foo;
+
+/* Address-significant access to protected symbols is not supported in
+   position-dependent mode on several architectures because GCC
+   generates relocations that assume that the address is local to the
+   main program.  */
+#ifdef __PIE__
 foo_p foo_procted_ptr = foo_protected;
+#endif
 
 extern foo_p get_foo_p (void);
 extern foo_p get_foo_hidden_p (void);
@@ -37,12 +44,16 @@ main (void)
   if ((*foo_ptr) () != -1)
     abort ();
 
+#ifdef __PIE__
   if (foo_procted_ptr != foo_protected)
     abort ();
+#endif
   if (foo_protected () != 0)
     abort ();
+#ifdef __PIE__
   if ((*foo_procted_ptr) () != 0)
     abort ();
+#endif
 
   p = get_foo_p ();
   if (p != foo)
@@ -55,8 +66,10 @@ main (void)
     abort ();
 
   p = get_foo_protected_p ();
+#ifdef __PIE__
   if (p != foo_protected)
     abort ();
+#endif
   if (ret_foo_protected != 0 || (*p) () != ret_foo_protected)
     abort ();
 
index f398085cb46719d18950533e3178de578face344..6fda768fb6908aed552e3150a478ad2c60c06cdf 100644 (file)
@@ -14,12 +14,19 @@ get_foo (void)
   return foo;
 }
 
+
+/* Address-significant access to protected symbols is not supported in
+   position-dependent mode on several architectures because GCC
+   generates relocations that assume that the address is local to the
+   main program.  */
+#ifdef __PIE__
 foo_p
 __attribute__ ((noinline))
 get_foo_protected (void)
 {
   return foo_protected;
 }
+#endif
 
 int
 main (void)
@@ -30,9 +37,11 @@ main (void)
   if ((*p) () != -1)
     abort ();
 
+#ifdef __PIE__
   p = get_foo_protected ();
   if ((*p) () != 0)
     abort ();
+#endif
 
   return 0;
 }
index ca00dd1fe23eda1196b9ae602b67eb1a3a7d9660..3c5e273f2b8faf3e38c987c61ab6637ce295e4fb 100644 (file)
@@ -52,7 +52,7 @@ $(objpfx)rtld-libc.a: $(foreach dir,$(rtld-subdirs),\
        mv -f $@T $@
 
 # 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        :=
index cbbaf4a33196512c92ad4b2f7657a850b411d8b4..6e40893e5298bd47476b37273b4cef2e22782c73 100644 (file)
@@ -791,6 +791,8 @@ init_tls (size_t naudit)
     _dl_fatal_printf ("\
 cannot allocate TLS data structures for initial thread\n");
 
+  _dl_tls_initial_modid_limit_setup ();
+
   /* Store for detection of the special case by __tls_get_addr
      so it knows not to pass this dtv to the normal realloc.  */
   GL(dl_initial_dtv) = GET_DTV (tcbp);
@@ -2122,6 +2124,12 @@ dl_main (const ElfW(Phdr) *phdr,
            if (l->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),
index db7ba95abec20f534f9cee3d2f64bc3fb8c1c4ca..9e0a122c389535d0580f2b020e29604643f045be 100644 (file)
@@ -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 (file)
index 0000000..0eaf049
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+
+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 (file)
index 0000000..40c6c01
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <ctype.h>
+#include <stdio.h>
+
+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 (file)
index 0000000..70c71fe
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+/* 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 <support/test-driver.c>
index 88182b7b254f1ce919974f1e677c673539028d12..5e9e4c57561437e9b4f27bec5672f56db1b64138 100644 (file)
@@ -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 (file)
index 0000000..ec937bf
--- /dev/null
@@ -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
+# <https://www.gnu.org/licenses/>.
+
+# 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/elf/tst-recursive-tls.c b/elf/tst-recursive-tls.c
new file mode 100644 (file)
index 0000000..716d1f7
--- /dev/null
@@ -0,0 +1,60 @@
+/* Test with interposed malloc with dynamic TLS.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <array_length.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+/* Defined in tst-recursive-tlsmallocmod.so.  */
+extern __thread unsigned int malloc_subsytem_counter;
+
+static int
+do_test (void)
+{
+  /* 16 is large enough to exercise the DTV resizing case.  */
+  void *handles[16];
+
+  for (unsigned int i = 0; i < array_length (handles); ++i)
+    {
+      /* Re-use the TLS slot for module 0.  */
+      if (i > 0)
+        xdlclose (handles[0]);
+
+      char soname[30];
+      snprintf (soname, sizeof (soname), "tst-recursive-tlsmod%u.so", i);
+      handles[i] = xdlopen (soname, RTLD_NOW);
+
+      if (i > 0)
+        {
+          handles[0] = xdlopen ("tst-recursive-tlsmod0.so", RTLD_NOW);
+          int (*fptr) (void) = xdlsym (handles[0], "get_threadvar_0");
+          /* May trigger TLS storage allocation using malloc.  */
+          TEST_COMPARE (fptr (), 0);
+        }
+    }
+
+  for (unsigned int i = 0; i < array_length (handles); ++i)
+    xdlclose (handles[i]);
+
+  printf ("info: malloc subsystem calls: %u\n", malloc_subsytem_counter);
+  TEST_VERIFY (malloc_subsytem_counter > 0);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-recursive-tlsmallocmod.c b/elf/tst-recursive-tlsmallocmod.c
new file mode 100644 (file)
index 0000000..c24e994
--- /dev/null
@@ -0,0 +1,64 @@
+/* Interposed malloc with dynamic TLS.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <dlfcn.h>
+
+__thread unsigned int malloc_subsytem_counter;
+
+static __typeof (malloc) *malloc_fptr;
+static __typeof (free) *free_fptr;
+static __typeof (calloc) *calloc_fptr;
+static __typeof (realloc) *realloc_fptr;
+
+static void __attribute__ ((constructor))
+init (void)
+{
+  malloc_fptr = dlsym (RTLD_NEXT, "malloc");
+  free_fptr = dlsym (RTLD_NEXT, "free");
+  calloc_fptr = dlsym (RTLD_NEXT, "calloc");
+  realloc_fptr = dlsym (RTLD_NEXT, "realloc");
+}
+
+void *
+malloc (size_t size)
+{
+  ++malloc_subsytem_counter;
+  return malloc_fptr (size);
+}
+
+void
+free (void *ptr)
+{
+  ++malloc_subsytem_counter;
+  return free_fptr (ptr);
+}
+
+void *
+calloc (size_t a, size_t b)
+{
+  ++malloc_subsytem_counter;
+  return calloc_fptr (a, b);
+}
+
+void *
+realloc (void *ptr, size_t size)
+{
+  ++malloc_subsytem_counter;
+  return realloc_fptr (ptr, size);
+}
diff --git a/elf/tst-recursive-tlsmodN.c b/elf/tst-recursive-tlsmodN.c
new file mode 100644 (file)
index 0000000..bb7592a
--- /dev/null
@@ -0,0 +1,28 @@
+/* Test module with global-dynamic TLS.  Used to trigger DTV reallocation.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* Compiled with VAR and FUNC set via -D.  FUNC requires some
+   relocation against TLS variable VAR.  */
+
+__thread int VAR;
+
+int
+FUNC (void)
+{
+  return VAR;
+}
index 050784319a24853747f8093d53ae3b8e3565cbc1..98625632dc932d04ef556222921277da9055c08e 100644 (file)
@@ -26,6 +26,8 @@
 #include <tls.h>
 #include <unistd.h>
 
+#include <support/xstdlib.h>
+
 static const char *command;
 static bool child;
 static uintptr_t stack_chk_guard_copy;
@@ -108,7 +110,8 @@ do_test (void)
          dup2 (fds[1], 2);
          close (fds[1]);
 
-         system (command);
+         xsystem (command);
+
          exit (0);
        }
 
index 552b7d77512be975921bdb959e1ea27885d56c46..fbe2b0ba5c5787e9f90a1799477cd916da294481 100644 (file)
@@ -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)
index dee64803ada583d79ca9adc281beffce4300255f..97be1f72caa163e10e8c0df39426f5870ff3fd92 100644 (file)
@@ -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;
 }
index 9d4a1a50fa6ab21af97293c4ec59a199c06f0a5d..f7180fdb83399a1426b64fbe23b385d4f10255b9 100644 (file)
@@ -41,6 +41,10 @@ static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93";
 
 #include <atomic.h>
 
+#include <not-cancel.h>
+#include <unistd.h>
+#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;
 }
 
index b4cc3b043a2aec77d55d4bb819cf24ae6c9a0ed0..af0582a3717085b531954ef1b94587f79acb3e66 100644 (file)
@@ -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 (file)
index 0000000..b259653
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+/* 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 <sys/gmon.h>
+
+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 (file)
index 0000000..27eb553
--- /dev/null
@@ -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
+# <https://www.gnu.org/licenses/>.
+
+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 (file)
index 0000000..06cc93e
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+/* 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;
+}
index eff303f5386b1fe101102fb3c58ad0e03bad54ae..5b3fa7e387b69855185463f9b7976377f58c8ef8 100644 (file)
@@ -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
index 28c826c9b5decdc025806479fb904e839f2e73f3..a767a643d489c35247b23c7ab52f490d9d69d250 100644 (file)
@@ -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 (file)
index 0000000..0370c10
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <gshadow.h>
+#include <stddef.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+#include <stdlib.h>
+
+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 <support/test-driver.c>
index debb96b322b0ceee27b203871a0e4a7b25c79993..b72933b526d0363ef829e1571c7ad49d0ea62b83 100644 (file)
 # 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);
index f4c089ed5d0eefbe9400ec3ebf63c996dcb61efd..d01b3fcab642b529e08c8da76bc945d593376dc0 100644 (file)
@@ -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)) \
index e09f358cad5553027fc3e80c95372acb5303919c..2cc478a8c6cded0a04c0296eea49673581a1bd4f 100644 (file)
@@ -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 (file)
index 0000000..96a8765
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <errno.h>
+#include <iconv.h>
+#include <sys/mman.h>
+
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <support/support.h>
+
+/* 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 <support/test-driver.c>
index 53f1dbc7c3f659e930fee72f5fd36595f7104e84..c27e7886b7891997cbd4f8797595917a0e13de30 100644 (file)
@@ -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 (file)
index 0000000..00b1b93
--- /dev/null
@@ -0,0 +1 @@
+#include <wcsmbs/bits/wchar2-decl.h>
index 0ac82d7c774f0975bbc9eaae4792e881eab67aeb..87966e839701095e753e1aec0a9d395041cc6f06 100644 (file)
@@ -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
       {
index 3590b6f496d47710d08e0a8e37bb597853097f6f..4dbbac3800b7ef302c8c93eb1cb3855c5a1c3d83 100644 (file)
@@ -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
index c490561581733038fa4ac0377143125bb133a8be..65742b10366590f053a97b77310316012d54d588 100644 (file)
@@ -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)
index b1710407d0be683a29dae4b8b3dc90e65e0b7710..b896484320d35c00cc2816203404886dbe454888 100644 (file)
@@ -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 (file)
index 0000000..f2a909f
--- /dev/null
@@ -0,0 +1,2 @@
+#define _FILE_OFFSET_BITS 64
+#include <io/tst-fcntl-lock.c>
diff --git a/io/tst-fcntl-lock.c b/io/tst-fcntl-lock.c
new file mode 100644 (file)
index 0000000..357c4b7
--- /dev/null
@@ -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 <https://www.gnu.org/licenses/>.
+*/
+
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+/* 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"
index be92f33fd1bbcca6f8dffece4e6881be18923b75..5e41dc19df7ce6f50c21ff677079e326a476b59d 100644 (file)
 #include <support/capture_subprocess.h>
 #include <support/check.h>
 
+#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);
       }
     }
 
index b1e200e7164bfd7a56479a2b1333b3154d575bbf..0fa261257c1af4942f7a05f8ebd186ff7f62f548 100644 (file)
@@ -208,12 +208,12 @@ extern char *__REDIRECT (__fgets_chk_warn,
 __fortify_function __wur __fortified_attr_access (__write_only__, 1, 2) char *
 fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize (__s);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+  size_t __sz = __glibc_objsize (__s);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
     return __fgets_alias (__s, __n, __stream);
-  if (__glibc_unsafe_len (__n, sizeof (char), sz))
-    return __fgets_chk_warn (__s, sz, __n, __stream);
-  return __fgets_chk (__s, sz, __n, __stream);
+  if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+    return __fgets_chk_warn (__s, __sz, __n, __stream);
+  return __fgets_chk (__s, __sz, __n, __stream);
 }
 
 extern size_t __REDIRECT (__fread_alias,
@@ -232,12 +232,12 @@ __fortify_function __wur size_t
 fread (void *__restrict __ptr, size_t __size, size_t __n,
        FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize0 (__ptr);
-  if (__glibc_safe_or_unknown_len (__n, __size, sz))
+  size_t __sz = __glibc_objsize0 (__ptr);
+  if (__glibc_safe_or_unknown_len (__n, __size, __sz))
     return __fread_alias (__ptr, __size, __n, __stream);
-  if (__glibc_unsafe_len (__n, __size, sz))
-    return __fread_chk_warn (__ptr, sz, __size, __n, __stream);
-  return __fread_chk (__ptr, sz, __size, __n, __stream);
+  if (__glibc_unsafe_len (__n, __size, __sz))
+    return __fread_chk_warn (__ptr, __sz, __size, __n, __stream);
+  return __fread_chk (__ptr, __sz, __size, __n, __stream);
 }
 
 #ifdef __USE_GNU
@@ -254,12 +254,12 @@ extern char *__REDIRECT (__fgets_unlocked_chk_warn,
 __fortify_function __wur __fortified_attr_access (__write_only__, 1, 2) char *
 fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize (__s);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+  size_t __sz = __glibc_objsize (__s);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
     return __fgets_unlocked_alias (__s, __n, __stream);
-  if (__glibc_unsafe_len (__n, sizeof (char), sz))
-    return __fgets_unlocked_chk_warn (__s, sz, __n, __stream);
-  return __fgets_unlocked_chk (__s, sz, __n, __stream);
+  if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+    return __fgets_unlocked_chk_warn (__s, __sz, __n, __stream);
+  return __fgets_unlocked_chk (__s, __sz, __n, __stream);
 }
 #endif
 
@@ -281,8 +281,8 @@ __fortify_function __wur size_t
 fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
                FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize0 (__ptr);
-  if (__glibc_safe_or_unknown_len (__n, __size, sz))
+  size_t __sz = __glibc_objsize0 (__ptr);
+  if (__glibc_safe_or_unknown_len (__n, __size, __sz))
     {
 # ifdef __USE_EXTERN_INLINES
       if (__builtin_constant_p (__size)
@@ -307,9 +307,9 @@ fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
 # endif
       return __fread_unlocked_alias (__ptr, __size, __n, __stream);
     }
-  if (__glibc_unsafe_len (__n, __size, sz))
-    return __fread_unlocked_chk_warn (__ptr, sz, __size, __n, __stream);
-  return __fread_unlocked_chk (__ptr, sz, __size, __n, __stream);
+  if (__glibc_unsafe_len (__n, __size, __sz))
+    return __fread_unlocked_chk_warn (__ptr, __sz, __size, __n, __stream);
+  return __fread_unlocked_chk (__ptr, __sz, __size, __n, __stream);
 
 }
 #endif
index d8aa58985aa0790c1267e7b00a281eec0238da6e..3f99222eefa7d4c3a925e887ee53d495f9a9402d 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <support/xstdlib.h>
 
 static char *fname;
 
@@ -35,14 +36,16 @@ do_test (void)
   char buffer[1024];
 
   snprintf (buffer, sizeof (buffer), "echo 'From foo@bar.com' > %s", fname);
-  system (buffer);
+  xsystem (buffer);
+
   f = fopen (fname, "r");
   fseek (f, 0, SEEK_END);
   o = ftello (f);
   fseek (f, 0, SEEK_SET);
   fflush (f);
   snprintf (buffer, sizeof (buffer), "echo 'From bar@baz.edu' >> %s", fname);
-  system (buffer);
+  xsystem (buffer);
+
   fseek (f, o, SEEK_SET);
   if (fgets (buffer, 1024, f) == NULL)
     exit (1);
index 1b629eb6954743829a1a77fb676ec3c53888c92e..1be964ef774d5ce67768634dc69e84d5b4162092 100644 (file)
@@ -635,7 +635,7 @@ _IO_sputbackc (FILE *fp, int c)
 {
   int result;
 
-  if (fp->_IO_read_ptr > fp->_IO_read_base
+  if (fp->_IO_read_ptr > fp->_IO_read_base && !_IO_in_backup (fp)
       && (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
     {
       fp->_IO_read_ptr--;
@@ -796,6 +796,12 @@ _IO_unbuffer_all (void)
        legacy = 1;
 #endif
 
+      /* Free up the backup area if it was ever allocated.  */
+      if (_IO_have_backup (fp))
+       _IO_free_backup_area (fp);
+      if (!legacy && fp->_mode > 0 && _IO_have_wbackup (fp))
+       _IO_free_wbackup_area (fp);
+
       if (! (fp->_flags & _IO_UNBUFFERED)
          /* Iff stream is un-orientated, it wasn't used. */
          && (legacy || fp->_mode != 0))
index ba4fdbd200c2692d32fca55c992ca7155fb14718..bef3324ffb39f3ae67a45cc879f177516bb20673 100644 (file)
@@ -529,8 +529,8 @@ extern void _IO_old_init (FILE *fp, int flags) __THROW;
        ((__fp)->_wide_data->_IO_write_base \
        = (__fp)->_wide_data->_IO_write_ptr = __p, \
        (__fp)->_wide_data->_IO_write_end = (__ep))
-#define _IO_have_backup(fp) ((fp)->_IO_save_base != NULL)
-#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_save_base != NULL)
+#define _IO_have_backup(fp) ((fp)->_IO_backup_base != NULL)
+#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_backup_base != NULL)
 #define _IO_in_backup(fp) ((fp)->_flags & _IO_IN_BACKUP)
 #define _IO_have_markers(fp) ((fp)->_markers != NULL)
 #define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base)
index 8be2d220f814fbbcb85c506a0911d4215324203c..4a4d5aa6b261ab4e3bc116efc85ce0e49721a38b 100644 (file)
@@ -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;
 
index d77a684b41d294b8e5eb01839bdce89b3ff0bb2c..ae7426eadbda67649ee676f6b6e7d146f98be156 100644 (file)
@@ -21,6 +21,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <support/check.h>
+
 
 static const char lower[] = "abcdefghijklmnopqrstuvwxyz";
 static const char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -53,19 +55,11 @@ static struct classes
 #define nclasses (sizeof (classes) / sizeof (classes[0]))
 
 
-#define FAIL(str, args...) \
-  {                                                                          \
-    printf ("      " str "\n", ##args);                                              \
-    ++errors;                                                                \
-  }
-
-
 static int
 do_test (void)
 {
   const char *cp;
   const char *cp2;
-  int errors = 0;
   char *inpline = NULL;
   size_t inplinelen = 0;
   char *resline = NULL;
@@ -394,11 +388,8 @@ punct = %04x  alnum = %04x\n",
            {
              if (((__ctype_b[(unsigned int) *inp] & classes[n].mask) != 0)
                  != (*resp != '0'))
-               {
-                 printf ("    is%s('%c' = '\\x%02x') %s true\n", inpline,
-                         *inp, *inp, *resp == '1' ? "not" : "is");
-                 ++errors;
-               }
+               FAIL ("    is%s('%c' = '\\x%02x') %s true\n", inpline,
+                     *inp, *inp, *resp == '1' ? "not" : "is");
              ++inp;
              ++resp;
            }
@@ -408,11 +399,8 @@ punct = %04x  alnum = %04x\n",
          while (*inp != '\0')
            {
              if (tolower (*inp) != *resp)
-               {
-                 printf ("    tolower('%c' = '\\x%02x') != '%c'\n",
-                         *inp, *inp, *resp);
-                 ++errors;
-               }
+               FAIL ("    tolower('%c' = '\\x%02x') != '%c'\n",
+                     *inp, *inp, *resp);
              ++inp;
              ++resp;
            }
@@ -422,11 +410,8 @@ punct = %04x  alnum = %04x\n",
          while (*inp != '\0')
            {
              if (toupper (*inp) != *resp)
-               {
-                 printf ("    toupper('%c' = '\\x%02x') != '%c'\n",
-                         *inp, *inp, *resp);
-                 ++errors;
-               }
+               FAIL ("    toupper('%c' = '\\x%02x') != '%c'\n",
+                     *inp, *inp, *resp);
              ++inp;
              ++resp;
            }
@@ -436,14 +421,7 @@ punct = %04x  alnum = %04x\n",
     }
 
 
-  if (errors != 0)
-    {
-      printf ("  %d error%s for `%s' locale\n\n\n", errors,
-             errors == 1 ? "" : "s", setlocale (LC_ALL, NULL));
-      return 1;
-    }
-
-  printf ("  No errors for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
+  printf ("Completed testing for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
   return 0;
 }
 
index 62440499bcaeaa17dae31b04bb25cac6dcc3c675..0b6b962c06fa68ebc8096785cd41c18b4a789c50 100644 (file)
@@ -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 (file)
index 0000000..7a581a4
--- /dev/null
@@ -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 (file)
index 0000000..1b7f7ff
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <utmp.h>
+#include <utmpx.h>
+#include <utmp-size.h>
+
+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 <support/test-driver.c>
index 0a684a720d9648953073bd7d35faca100762c031..a1ee7928d381b7ebb32267569875f8293e8d3344 100644 (file)
@@ -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);
index d758231a89adbe788778e666f6c20bc7dc25189f..95897948fbe1b8a927ceb236fd8396ae44a73942 100644 (file)
@@ -24,6 +24,8 @@
 #include <string.h>
 #include <tgmath.h>
 
+#include <support/check.h>
+
 //#define DEBUG
 
 typedef complex float cfloat;
@@ -87,13 +89,6 @@ enum
 int count;
 int counts[Tlast][C_last];
 
-#define FAIL(str) \
-  do                                                           \
-    {                                                          \
-      printf ("%s failure on line %d\n", (str), __LINE__);     \
-      result = 1;                                              \
-    }                                                          \
-  while (0)
 #define TEST_TYPE_ONLY(expr, rettype) \
   do                                                           \
     {                                                          \
@@ -133,8 +128,6 @@ int counts[Tlast][C_last];
 int
 test_cos (const int Vint4, const long long int Vllong4)
 {
-  int result = 0;
-
   TEST (cos (vfloat1), float, cos);
   TEST (cos (vdouble1), double, cos);
   TEST (cos (vldouble1), ldouble, cos);
@@ -152,7 +145,7 @@ test_cos (const int Vint4, const long long int Vllong4)
   TEST (cos (Vcdouble1), cdouble, cos);
   TEST (cos (Vcldouble1), cldouble, cos);
 
-  return result;
+  return 0;
 }
 
 int
index ba8232a0e9515241b768d47929bb2d5eef03d0f4..e77cdd8c1b5c13131fe269ff8afea3900465f1d9 100644 (file)
@@ -90,7 +90,7 @@ tests := tst-dirname tst-tsearch tst-fdset tst-mntent tst-hsearch \
         tst-preadvwritev2 tst-preadvwritev64v2 tst-warn-wide \
         tst-ldbl-warn tst-ldbl-error tst-dbl-efgcvt tst-ldbl-efgcvt \
         tst-mntent-autofs tst-syscalls tst-mntent-escape tst-select \
-        tst-ioctl
+        tst-ioctl tst-mremap1 tst-mremap2
 
 tests-time64 := \
   tst-select-time64 \
@@ -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)
index fd30dd31149ca79e0da433ea9e2a2abea3bb98b0..916d2b6f1230607baa5102655845536ff9121799 100644 (file)
 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 <bits/floatn.h>
+#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
+# include <bits/syslog-ldbl.h>
+#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)
 {
index e56aff0f375e6bf151610a9506fc2c591f3be13f..660f64eb8070c4bfd528687aa72b09b7d02c0647 100644 (file)
@@ -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)
 {
index f525f67547f0c81902a591c8fc1f23b2cf38072e..294e633335998cad5dda2cf55f26fcba64d2b45a 100644 (file)
 # 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.  */
    ? __ ## 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.  */
    ? __ ## 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)))
index d933fea1041338e76c9e721513e38cb181e179c8..3888153ed2ee7cfc5ba464b2c892879fb841c17c 100644 (file)
@@ -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 <bits/syslog.h>
-#endif
-
-#include <bits/floatn.h>
-#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
-# include <bits/syslog-ldbl.h>
+#else
+# include <bits/floatn.h>
+# if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1
+#  include <bits/syslog-ldbl.h>
+# endif
 #endif
 
 __END_DECLS
index 554089bfc45244e87c08eb0482e61c35dd0fa3ca..9336036666aada3d65b7fdca4e5b68b275e2f3b7 100644 (file)
@@ -41,6 +41,7 @@ static char sccsid[] = "@(#)syslog.c  8.4 (Berkeley) 3/18/94";
 #include <sys/uio.h>
 #include <sys/un.h>
 #include <syslog.h>
+#include <limits.h>
 
 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-mremap1.c b/misc/tst-mremap1.c
new file mode 100644 (file)
index 0000000..0469991
--- /dev/null
@@ -0,0 +1,46 @@
+/* Test mremap with MREMAP_MAYMOVE.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <support/xstdlib.h>
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+
+static int
+do_test (void)
+{
+  size_t old_size = getpagesize ();
+  char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE,
+                         MAP_PRIVATE | MAP_ANONYMOUS, -1);
+  old_addr[0] = 1;
+  old_addr[old_size - 1] = 2;
+
+  /* Test MREMAP_MAYMOVE.  */
+  size_t new_size = old_size + old_size;
+  char *new_addr = mremap (old_addr, old_size, new_size, MREMAP_MAYMOVE);
+  TEST_VERIFY_EXIT (new_addr != MAP_FAILED);
+  new_addr[0] = 1;
+  new_addr[new_size - 1] = 2;
+  xmunmap (new_addr, new_size);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/misc/tst-mremap2.c b/misc/tst-mremap2.c
new file mode 100644 (file)
index 0000000..45be7f0
--- /dev/null
@@ -0,0 +1,54 @@
+/* Test mremap with MREMAP_FIXED.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <support/xstdlib.h>
+#include <support/xunistd.h>
+#include <support/test-driver.h>
+#include <mremap-failure.h>
+
+static int
+do_test (void)
+{
+  size_t old_size = getpagesize ();
+  size_t new_size = old_size + old_size;
+  char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE,
+                         MAP_PRIVATE | MAP_ANONYMOUS, -1);
+  old_addr[0] = 1;
+  old_addr[old_size - 1] = 2;
+
+  char *fixed_addr = xmmap (NULL, new_size, PROT_READ | PROT_WRITE,
+                           MAP_PRIVATE | MAP_ANONYMOUS, -1);
+  fixed_addr[0] = 1;
+  fixed_addr[new_size - 1] = 2;
+
+  /* Test MREMAP_FIXED.  */
+  char *new_addr = mremap (old_addr, old_size, new_size,
+                          MREMAP_FIXED | MREMAP_MAYMOVE,
+                          fixed_addr);
+  if (new_addr == MAP_FAILED)
+    return mremap_failure_exit (errno);
+  new_addr[0] = 1;
+  new_addr[new_size - 1] = 2;
+  xmunmap (new_addr, new_size);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
index 40b527bdcbe045a523edf5fcc7076665a7687f62..ed3dc04eeb5101da0448332dd4c32c928a1344c9 100644 (file)
 #ifndef RWF_APPEND
 # define RWF_APPEND 0
 #endif
+#ifndef RWF_NOAPPEND
+# define RWF_NOAPPEND 0
+#endif
 #define RWF_SUPPORTED  (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \
-                        | RWF_APPEND)
+                        | RWF_APPEND | RWF_NOAPPEND)
 
 /* Generic uio_lim.h does not define IOV_MAX.  */
 #ifndef IOV_MAX
diff --git a/misc/tst-syslog-long-progname.c b/misc/tst-syslog-long-progname.c
new file mode 100644 (file)
index 0000000..88f37a8
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <syslog.h>
+#include <string.h>
+
+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 <support/test-driver.c>
index e550d157967d2c57dfa57cd555582c81286996dc..3560b518a25d1ee1bb96f19db32a7d9ecb6ba091 100644 (file)
@@ -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;
 }
index 90187e30b13b1a349ac20ba7c734103116e610f1..5b9dd50151299d60463d8fa9a7772be6ad2024f6 100644 (file)
@@ -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,
index 5cacb286f35da5d2e252b6fd4e0fa0bf166d126d..bbb26607ef4632a5b6fcceb1f8ce79c53b6f799c 100644 (file)
@@ -34,7 +34,6 @@
 #include <bits/types/res_state.h>
 #include <kernel-features.h>
 #include <tls-internal-struct.h>
-#include <sys/rseq.h>
 #include <internal-sigset.h>
 
 #ifndef TCB_ALIGNMENT
@@ -402,14 +401,27 @@ 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;
+      uint64_t rseq_cs;
+      uint32_t flags;
+    };
+    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
index 903457db76312890ed5ece4f0d96832edc1acd7a..1c80457553bdbbb0f04ebcaf5d34880b6d8d75f0 100644 (file)
@@ -43,7 +43,8 @@ tf (void *arg)
 {
   char *cmd = xasprintf ("%s --direct --sem %s --pidfile %s",
                         command, semfilename, pidfilename);
-  system (cmd);
+  if (system (cmd))
+    FAIL_EXIT1("system call unexpectedly returned");
   /* This call should never return.  */
   return NULL;
 }
index aff3b1a97dba3aa14f9060678ba7cbb8663296af..9b7799991ca374cc9e4e8a3dc8c6c34e777ffff5 100644 (file)
@@ -20,6 +20,7 @@
 #include <signal.h>
 #include <stdbool.h>
 #include <stdio.h>
+#include <support/xthread.h>
 #include <sys/syscall.h>
 #include <unistd.h>
 
@@ -36,30 +37,21 @@ static pthread_cond_t cond_recv;
 static void *
 thread_func (void *ctx __attribute__ ((unused)))
 {
-  int ret = pthread_mutex_lock (&mutex);
-  if (ret != 0)
-    FAIL ("pthread_mutex_lock (thread): %d", ret);
-
+  xpthread_mutex_lock (&mutex);
   while (true)
     {
       if (func_sent != NULL)
        {
          void (*func) (void) = func_sent;
-         ret = pthread_mutex_unlock (&mutex);
-         if (ret != 0)
-           FAIL ("pthread_mutex_unlock (thread): %d", ret);
+         xpthread_mutex_unlock (&mutex);
+
          func ();
-         ret = pthread_mutex_lock (&mutex);
-         if (ret != 0)
-           FAIL ("pthread_mutex_lock (thread): %d", ret);
+
+         xpthread_mutex_lock (&mutex);
          func_sent = NULL;
-         ret = pthread_cond_signal (&cond_recv);
-         if (ret != 0)
-           FAIL ("pthread_cond_signal (recv): %d", ret);
+         xpthread_cond_signal (&cond_recv);
        }
-      ret = pthread_cond_wait (&cond_send, &mutex);
-      if (ret != 0)
-       FAIL ("pthread_cond_wait (send): %d", ret);
+      xpthread_cond_wait (&cond_send, &mutex);
     }
   return NULL;
 }
@@ -67,31 +59,18 @@ thread_func (void *ctx __attribute__ ((unused)))
 static void
 run_on_thread (void (*func) (void))
 {
-  int ret = pthread_mutex_lock (&mutex);
-  if (ret != 0)
-    FAIL ("pthread_mutex_lock (%s): %d", __func__, ret);
+  xpthread_mutex_lock (&mutex);
   func_sent = func;
-  ret = pthread_mutex_unlock (&mutex);
-  if (ret != 0)
-    FAIL ("pthread_mutex_unlock (%s): %d", __func__, ret);
+  xpthread_mutex_unlock (&mutex);
 
-  ret = pthread_cond_signal (&cond_send);
-  if (ret != 0)
-    FAIL ("pthread_mutex_lock (%s): %d", __func__, ret);
-
-  ret = pthread_mutex_lock (&mutex);
-  if (ret != 0)
-    FAIL ("pthread_mutex_lock (%s): %d", __func__, ret);
+  xpthread_cond_signal (&cond_send);
 
+  xpthread_mutex_lock (&mutex);
   while (func_sent != NULL)
     {
-      ret = pthread_cond_wait (&cond_recv, &mutex);
-      if (ret != 0)
-       FAIL ("pthread_mutex_wait (%s): %d", __func__, ret);
+      xpthread_cond_wait (&cond_recv, &mutex);
     }
-  ret = pthread_mutex_unlock (&mutex);
-  if (ret != 0)
-    FAIL ("pthread_mutex_unlock (%s): %d", __func__, ret);
+  xpthread_mutex_unlock (&mutex);
 }
 
 static void
@@ -141,5 +120,4 @@ do_test (void)
   return 0;
 }
 
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
index 3460c01819ee8dfe588b990daeac6fdfa8d0ea15..bc8900ce2287b2740d98441e1c209ca45a4ac14a 100644 (file)
@@ -27,6 +27,8 @@
 #include <tls.h>
 #include <unistd.h>
 
+#include <support/xstdlib.h>
+
 static const char *command;
 static bool child;
 static uintptr_t stack_chk_guard_copy;
@@ -138,7 +140,8 @@ do_test (void)
          dup2 (fds[1], 2);
          close (fds[1]);
 
-         system (command);
+         xsystem (command);
+
          exit (0);
        }
 
index 51e793199fff83137548501949b553bc2cad2f37..e0baed170b36d6d1ca2ca6c3f758e50c131d5e97 100644 (file)
@@ -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;
index 61d1674eb49a2eb48e3534662e675ff5b1936f6a..531d2e83df4fa417ff26a3cf14144f30895927f2 100644 (file)
@@ -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
index 85977521a64715d61bc760e3268286910e0fb8c8..adc34ba6b4ba6816fc8027f41566dff976c32a75 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <scratch_buffer.h>
 
 #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, &notfound, 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, &notfound, 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;
 }
index 368091aef8ec14392138f6ba87dc5e1aebc679fc..f15321585b379b1c494b5688578f22d11761408a 100644 (file)
@@ -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;
index 9becb620335d14d7becebe6c29ad96cc4e7463ee..31c64275f0833d17e59afa9066f1b115fdf6af7a 100644 (file)
@@ -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)
index a978e3927a78c36ef8a83d15e07655cdc0a6deeb..7a52c6879143e46d0ec7ed98edc98d02736abeac 100644 (file)
@@ -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
index 8178b4b470063f27dc1975c7f186c3fbdb8b9c10..d2d2524b0cbef18b912f4de412e6bb37daa789eb 100644 (file)
@@ -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 (file)
index 0000000..4439c83
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <nss.h>
+#include <stdlib.h>
+#include <string.h>
+#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;
+}
index da4ab643e770f5371603762c5a59516135c33145..c2417b2505aa6e01ce331de029758c35a8f7c645 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <support/support.h>
 #include <support/check.h>
+#include <support/xstdlib.h>
 
 /* It is entirely allowed to start with a getpwent call without
    resetting the state of the service via a call to setpwent.
@@ -55,7 +56,7 @@ do_test (void)
 
   cmd = xasprintf ("%s/makedb -o /var/db/passwd.db /var/db/passwd.in",
                   support_bindir_prefix);
-  system (cmd);
+  xsystem (cmd);
   free (cmd);
 
   try_it ();
index 3942cf5fca5d4961e26657df3e9e2305e43f11df..a7697e31431fc77cb41e8b1e92a73c5d6117b229 100644 (file)
@@ -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 (file)
index 0000000..7db53cf
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <nss.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mcheck.h>
+#include <support/check.h>
+#include <support/xstdio.h>
+#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 <support/test-driver.c>
diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h
new file mode 100644 (file)
index 0000000..14f2a9c
--- /dev/null
@@ -0,0 +1 @@
+#define QUERYNAME "test.example.com"
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 (file)
index 0000000..31848b4
--- /dev/null
@@ -0,0 +1,2 @@
+cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2
+su
index fdc5bdd65b24bc3c7e485eee20f8855837236e7e..bc32bb132aa0a8da9d850ac8e10259c3038ef85f 100644 (file)
@@ -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[] = {
index c8093c5473068ac6454433cfc28e88a3ffb6ff65..39061ce6c5425f1ba7994bacfb474fa1efe4519e 100644 (file)
@@ -21,6 +21,8 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <support/check.h>
+
 static void do_prepare (void);
 #define PREPARE(argc, argv)     do_prepare ()
 static int do_test (void);
@@ -42,9 +44,6 @@ do_prepare (void)
     }
 }
 
-#define FAIL(str) \
-  do { printf ("error: %s (line %d)\n", str, __LINE__); return 1; } while (0)
-
 static int
 do_test_with_offset (off_t offset)
 {
@@ -54,35 +53,35 @@ do_test_with_offset (off_t offset)
   memset (buf, 0xcf, sizeof (buf));
 
   if (pwrite (temp_fd, buf, sizeof (buf), offset) != sizeof (buf))
-    FAIL ("write failed");
+    FAIL_RET ("write failed");
   if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + sizeof (buf)))
-    FAIL ("initial size wrong");
+    FAIL_RET ("initial size wrong");
 
   if (ftruncate (temp_fd, offset + 800) < 0)
-    FAIL ("size reduction with ftruncate failed");
+    FAIL_RET ("size reduction with ftruncate failed");
   if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800))
-    FAIL ("size after reduction with ftruncate is incorrect");
+    FAIL_RET ("size after reduction with ftruncate is incorrect");
 
   /* The following test covers more than POSIX.  POSIX does not require
      that ftruncate() can increase the file size.  But we are testing
      Unix systems.  */
   if (ftruncate (temp_fd, offset + 1200) < 0)
-    FAIL ("size increate with ftruncate failed");
+    FAIL_RET ("size increate with ftruncate failed");
   if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200))
-    FAIL ("size after increase is incorrect");
+    FAIL_RET ("size after increase is incorrect");
 
   if (truncate (temp_filename, offset + 800) < 0)
-    FAIL ("size reduction with truncate failed");
+    FAIL_RET ("size reduction with truncate failed");
   if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800))
-    FAIL ("size after reduction with truncate incorrect");
+    FAIL_RET ("size after reduction with truncate incorrect");
 
   /* The following test covers more than POSIX.  POSIX does not require
      that truncate() can increase the file size.  But we are testing
      Unix systems.  */
   if (truncate (temp_filename, (offset + 1200)) < 0)
-    FAIL ("size increase with truncate failed");
+    FAIL_RET ("size increase with truncate failed");
   if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200))
-    FAIL ("size increase with truncate is incorrect");
+    FAIL_RET ("size increase with truncate is incorrect");
 
   return 0;
 }
index 5b15321f9b4a093846da0b49cd94dba8d5ef7acb..e5165fb34b25e62f832f281e83e10a97eecc946e 100644 (file)
@@ -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,14 +93,20 @@ 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 \
+  tst-resolv-semi-failure \
+  tst-resolv-short-response \
   tst-resolv-trailing \
 
 # This test calls __res_context_send directly, which is not exported
@@ -104,6 +114,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 +280,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,11 +291,18 @@ $(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)
 $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-semi-failure: $(objpfx)libresolv.so \
+  $(shared-thread-library)
+$(objpfx)tst-resolv-short-response: $(objpfx)libresolv.so \
+  $(shared-thread-library)
 $(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-threads: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-txnid-collision: $(objpfx)libresolv.a \
index 514e9bb617e710f16126c1474561965a2b35653d..2146bc3b27a6dc5688958ac31d561bb4202098c0 100644 (file)
@@ -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 (file)
index 7f85f7d..0000000
+++ /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 <string.h>
-#include <arpa/nameser.h>
-
-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 (file)
index c11038a..0000000
+++ /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 <arpa/nameser.h>
-#include <sys/socket.h>
-
-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 (file)
index 0000000..51296b4
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arpa/nameser.h>
+#include <errno.h>
+#include <stdbool.h>
+
+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 (file)
index 0000000..6ee80b3
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arpa/nameser.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+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 (file)
index 0000000..33652fc
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arpa/nameser.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+
+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 (file)
index 0000000..9a47d8e
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arpa/nameser.h>
+#include <stdbool.h>
+
+/* 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;
+}
index 544cffbecd1a1e9949d7cb7805fc0a1e14fad4f3..227734da5c075d71841f22ec0f967e396c0b627e 100644 (file)
@@ -69,6 +69,7 @@
  * --Copyright--
  */
 
+#include <alloc_buffer.h>
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <resolv/resolv-internal.h>
 #include <resolv/resolv_context.h>
 
-/* Get implementations of some internal functions.  */
-#include <resolv/mapv4v6addr.h>
-#include <resolv/mapv4v6hostent.h>
-
 #define RESOLVSORT
 
 #if PACKETSZ > 65536
 #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 <malloc/dynarray-skeleton.c>
+
+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;
 }
index 07a412d8ff4da7423393325cc4627a9b2398d8bc..213edceaf3dc677bcfe56dd33d95fe8aa72a7152 100644 (file)
@@ -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);
index 6a08e729a473f20c46a021a3382f6dd32f574cc0..1bcc98ed21d5a9ece7a9477a6a20aff253eeb97b 100644 (file)
@@ -947,9 +947,11 @@ send_dg(res_state statp,
                seconds /= statp->nscount;
        if (seconds <= 0)
                seconds = 1;
-       bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0;
-       bool single_request = (((statp->options & RES_SNGLKUP) != 0)
-                              | single_request_reopen);
+       bool single_request_reopen = ((statp->options & RES_SNGLKUPREOP)
+                                     || (statp->_flags & RES_F_SNGLKUPREOP));
+       bool single_request = ((statp->options & RES_SNGLKUP)
+                              || (statp->_flags & RES_F_SNGLKUP)
+                              || single_request_reopen);
        int save_gotsomewhere = *gotsomewhere;
 
        int retval;
@@ -1006,14 +1008,14 @@ send_dg(res_state statp,
                       have received the first answer.  */
                    if (!single_request)
                      {
-                       statp->options |= RES_SNGLKUP;
+                       statp->_flags |= RES_F_SNGLKUP;
                        single_request = true;
                        *gotsomewhere = save_gotsomewhere;
                        goto retry;
                      }
                    else if (!single_request_reopen)
                      {
-                       statp->options |= RES_SNGLKUPREOP;
+                       statp->_flags |= RES_F_SNGLKUPREOP;
                        single_request_reopen = true;
                        *gotsomewhere = save_gotsomewhere;
                        __res_iclose (statp, false);
@@ -1197,19 +1199,30 @@ send_dg(res_state statp,
                }
 
                /* Check for the correct header layout and a matching
-                  question.  */
+                  question.  Some recursive resolvers send REFUSED
+                  without copying back the question section
+                  (producing a response that is only HFIXEDSZ bytes
+                  long).  Skip query matching in this case.  */
+               bool thisansp_error = (anhp->rcode == SERVFAIL ||
+                                      anhp->rcode == NOTIMP ||
+                                      anhp->rcode == REFUSED);
+               bool skip_query_match = (*thisresplenp == HFIXEDSZ
+                                        && ntohs (anhp->qdcount) == 0
+                                        && thisansp_error);
                int matching_query = 0; /* Default to no matching query.  */
                if (!recvresp1
                    && anhp->id == hp->id
-                   && __libc_res_queriesmatch (buf, buf + buflen,
-                                               *thisansp,
-                                               *thisansp + *thisanssizp))
+                   && (skip_query_match
+                       || __libc_res_queriesmatch (buf, buf + buflen,
+                                                   *thisansp,
+                                                   *thisansp + *thisanssizp)))
                  matching_query = 1;
                if (!recvresp2
                    && anhp->id == hp2->id
-                   && __libc_res_queriesmatch (buf2, buf2 + buflen2,
-                                               *thisansp,
-                                               *thisansp + *thisanssizp))
+                   && (skip_query_match
+                       || __libc_res_queriesmatch (buf2, buf2 + buflen2,
+                                                   *thisansp,
+                                                   *thisansp + *thisanssizp)))
                  matching_query = 2;
                if (matching_query == 0)
                  /* Spurious UDP packet.  Drop it and continue
@@ -1219,15 +1232,13 @@ send_dg(res_state statp,
                    goto wait;
                  }
 
-               if (anhp->rcode == SERVFAIL ||
-                   anhp->rcode == NOTIMP ||
-                   anhp->rcode == REFUSED) {
+               if (thisansp_error) {
                next_ns:
                        if (recvresp1 || (buf2 != NULL && recvresp2)) {
                          *resplen2 = 0;
                          return resplen;
                        }
-                       if (buf2 != NULL)
+                       if (buf2 != NULL && !single_request)
                          {
                            /* No data from the first reply.  */
                            resplen = 0;
index bb12f474d266e451404ab550d8de733bd5992e34..170a4b9101b721dcbbcc21805e081ba32a0f2012 100644 (file)
@@ -26,6 +26,8 @@
 #define RES_F_VC        0x00000001 /* Socket is TCP.  */
 #define RES_F_CONN      0x00000002 /* Socket is connected.  */
 #define RES_F_EDNS0ERR  0x00000004 /* EDNS0 caused errors.  */
+#define RES_F_SNGLKUP  0x00200000 /* Private version of RES_SNGLKUP.  */
+#define RES_F_SNGLKUPREOP 0x00400000 /* Private version of RES_SNGLKUPREOP.  */
 
 /* The structure HEADER is normally aligned on a word boundary.  In
    some code, we need to access this structure when it may be aligned
diff --git a/resolv/tst-ns_name_length_uncompressed.c b/resolv/tst-ns_name_length_uncompressed.c
new file mode 100644 (file)
index 0000000..c4a2904
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arpa/nameser.h>
+#include <array_length.h>
+#include <errno.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/next_to_fault.h>
+
+/* 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 <support/test-driver.c>
diff --git a/resolv/tst-ns_rr_cursor.c b/resolv/tst-ns_rr_cursor.c
new file mode 100644 (file)
index 0000000..c3c0908
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arpa/nameser.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/next_to_fault.h>
+
+/* 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 <support/test-driver.c>
diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c
new file mode 100644 (file)
index 0000000..b06ac61
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arpa/nameser.h>
+#include <array_length.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <support/check.h>
+
+/* 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 <support/test-driver.c>
diff --git a/resolv/tst-resolv-aliases.c b/resolv/tst-resolv-aliases.c
new file mode 100644 (file)
index 0000000..b212823
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <array_length.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+
+#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 <support/test-driver.c>
diff --git a/resolv/tst-resolv-byaddr.c b/resolv/tst-resolv-byaddr.c
new file mode 100644 (file)
index 0000000..6299e89
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/next_to_fault.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+
+#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 <support/test-driver.c>
diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c
new file mode 100644 (file)
index 0000000..63dac90
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+/* 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 <support/test-driver.c>
diff --git a/resolv/tst-resolv-maybe_insert_sig.h b/resolv/tst-resolv-maybe_insert_sig.h
new file mode 100644 (file)
index 0000000..0572522
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+/* 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 (file)
index 0000000..9f5aebd
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+/* 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 <support/test-driver.c>
diff --git a/resolv/tst-resolv-semi-failure.c b/resolv/tst-resolv-semi-failure.c
new file mode 100644 (file)
index 0000000..aa9798b
--- /dev/null
@@ -0,0 +1,133 @@
+/* Test parallel failure/success responses (bug 30081).
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <resolv.h>
+#include <support/check.h>
+#include <support/resolv_test.h>
+#include <support/check_nss.h>
+
+/* The rcode in the initial response.  */
+static volatile int rcode;
+
+/* Whether to fail the initial A query (!fail_aaaa) or the initial
+   AAAA query (fail_aaaa).  */
+static volatile bool fail_aaaa;
+
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  /* Handle the failing query.  */
+  if ((fail_aaaa && qtype == T_AAAA) && ctx->server_index == 0)
+    {
+      struct resolv_response_flags flags = {.rcode = rcode};
+      resolv_response_init (b, flags);
+      return;
+    }
+
+  /* Otherwise produce a response.  */
+  resolv_response_init (b, (struct resolv_response_flags) {});
+  resolv_response_add_question (b, qname, qclass, qtype);
+  resolv_response_section (b, ns_s_an);
+  resolv_response_open_record (b, qname, qclass, qtype, 0);
+  switch (qtype)
+    {
+    case T_A:
+      {
+        char ipv4[4] = {192, 0, 2, 17};
+        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, 0, 1};
+        resolv_response_add_data (b, &ipv6, sizeof (ipv6));
+      }
+      break;
+    default:
+      FAIL_EXIT1 ("unexpected TYPE%d query", qtype);
+    }
+  resolv_response_close_record (b);
+}
+
+static void
+check_one (void)
+{
+
+  /* The buggy 1-second query timeout results in 30 seconds of delay,
+     which triggers are test timeout failure.  */
+  for (int i = 0;  i < 30; ++i)
+    {
+      static const struct addrinfo hints =
+        {
+          .ai_family = AF_UNSPEC,
+          .ai_socktype = SOCK_STREAM,
+        };
+      struct addrinfo *ai;
+      int ret = getaddrinfo ("www.example", "80", &hints, &ai);
+      const char *expected;
+      if (ret == 0 && ai->ai_next != NULL)
+        expected = ("address: STREAM/TCP 192.0.2.17 80\n"
+                    "address: STREAM/TCP 2001:db8::1 80\n");
+      else
+        /* Only one response because the AAAA lookup failure is
+           treated as an ignoreable error.  */
+        expected = "address: STREAM/TCP 192.0.2.17 80\n";
+      check_addrinfo ("www.example", ai, ret, expected);
+      if (ret == 0)
+        freeaddrinfo (ai);
+    }
+}
+
+static int
+do_test (void)
+{
+  for (int do_single_lookup = 0; do_single_lookup < 2; ++do_single_lookup)
+    {
+      struct resolv_test *aux = resolv_test_start
+        ((struct resolv_redirect_config)
+         {
+           .response_callback = response,
+         });
+
+      if (do_single_lookup)
+        _res.options |= RES_SNGLKUP;
+
+      for (int do_fail_aaaa = 0; do_fail_aaaa < 2; ++do_fail_aaaa)
+        {
+          fail_aaaa = do_fail_aaaa;
+
+          rcode = 2; /* SERVFAIL.  */
+          check_one ();
+
+          rcode = 4; /* NOTIMP.  */
+          check_one ();
+
+          rcode = 5; /* REFUSED.  */
+          check_one ();
+        }
+
+      resolv_test_end (aux);
+    }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c
new file mode 100644 (file)
index 0000000..9b06b0c
--- /dev/null
@@ -0,0 +1,126 @@
+/* Test for spurious timeouts with short 12-byte responses (bug 31890).
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <resolv.h>
+#include <support/check.h>
+#include <support/resolv_test.h>
+#include <support/check_nss.h>
+
+/* The rcode in the initial response.  */
+static volatile int rcode;
+
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  switch (ctx->server_index)
+    {
+    case 0:
+      /* First server times out.  */
+      {
+        struct resolv_response_flags flags = {.rcode = rcode};
+        resolv_response_init (b, flags);
+      }
+      break;
+    case 1:
+      /* Second server sends reply.  */
+      resolv_response_init (b, (struct resolv_response_flags) {});
+      resolv_response_add_question (b, qname, qclass, qtype);
+      resolv_response_section (b, ns_s_an);
+      resolv_response_open_record (b, qname, qclass, qtype, 0);
+      switch (qtype)
+        {
+        case T_A:
+          {
+            char ipv4[4] = {192, 0, 2, 17};
+            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, 0, 1};
+            resolv_response_add_data (b, &ipv6, sizeof (ipv6));
+          }
+          break;
+        default:
+          FAIL_EXIT1 ("unexpected TYPE%d query", qtype);
+        }
+      resolv_response_close_record (b);
+      break;
+    default:
+      FAIL_EXIT1 ("unexpected query to server %d", ctx->server_index);
+    }
+}
+
+static void
+check_one (void)
+{
+
+  /* The buggy 1-second query timeout results in 30 seconds of delay,
+     which triggers a test timeout failure.  */
+  for (int i = 0;  i < 10; ++i)
+    {
+      check_hostent ("www.example", gethostbyname ("www.example"),
+                     "name: www.example\n"
+                     "address: 192.0.2.17\n");
+      check_hostent ("www.example", gethostbyname2 ("www.example", AF_INET6),
+                     "name: www.example\n"
+                     "address: 2001:db8::1\n");
+      static const struct addrinfo hints =
+        {
+          .ai_family = AF_UNSPEC,
+          .ai_socktype = SOCK_STREAM,
+        };
+      struct addrinfo *ai;
+      int ret = getaddrinfo ("www.example", "80", &hints, &ai);
+      check_addrinfo ("www.example", ai, ret,
+                      "address: STREAM/TCP 192.0.2.17 80\n"
+                      "address: STREAM/TCP 2001:db8::1 80\n");
+      if (ret == 0)
+        freeaddrinfo (ai);
+    }
+}
+
+static int
+do_test (void)
+{
+  struct resolv_test *aux = resolv_test_start
+    ((struct resolv_redirect_config)
+     {
+       .response_callback = response,
+     });
+
+  _res.options |= RES_SNGLKUP;
+
+  rcode = 2; /* SERVFAIL.  */
+  check_one ();
+
+  rcode = 4; /* NOTIMP.  */
+  check_one ();
+
+  rcode = 5; /* REFUSED.  */
+  check_one ();
+
+  resolv_test_end (aux);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
index b4304d0a6f295e1649910565c4d2da63dc394279..5f9e52bcbaf620cdbcae2515a792cfcb93962aca 100644 (file)
@@ -698,7 +698,7 @@ libc_freeres_fn (free_res)
 {
   size_t row;
 
-  for (row = 0; row < pool_max_size; ++row)
+  for (row = 0; row < pool_size; ++row)
     free (pool[row]);
 
   free (pool);
index 2dd6bfda183257a8a4c7bad4862f6d3171c1eaca..b87cf2f80996de25ea4686704ec7b28cb5eaa8ba 100644 (file)
@@ -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))
index 43ab58ffe2a32c657b1f532ef552f515c673779e..36d204c9b0c9313c0335a32f00efb895de859aaf 100644 (file)
@@ -17,6 +17,7 @@
 # License along with the GNU C Library; if not, see
 # <https://www.gnu.org/licenses/>.
 
+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)
index 156eec6c85b5c62267b84ee59cc744766eb89933..2bde78387f2befe6af62b8f5d0f6ce0bee16b60e 100644 (file)
@@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt    \
 tests := \
   tst-accept4 \
   tst-sockopt \
+  tst-cmsghdr \
   # tests
 
 tests-internal := \
index 0aface56398fdcf801a00d774e1d6a84aafa0457..0b1cb015ce2553afbf64947af27d91af92029ed0 100644 (file)
@@ -33,12 +33,12 @@ extern ssize_t __REDIRECT (__recv_chk_warn,
 __fortify_function ssize_t
 recv (int __fd, void *__buf, size_t __n, int __flags)
 {
-  size_t sz = __glibc_objsize0 (__buf);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+  size_t __sz = __glibc_objsize0 (__buf);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
     return __recv_alias (__fd, __buf, __n, __flags);
-  if (__glibc_unsafe_len (__n, sizeof (char), sz))
-    return __recv_chk_warn (__fd, __buf, __n, sz, __flags);
-  return __recv_chk (__fd, __buf, __n, sz, __flags);
+  if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+    return __recv_chk_warn (__fd, __buf, __n, __sz, __flags);
+  return __recv_chk (__fd, __buf, __n, __sz, __flags);
 }
 
 extern ssize_t __recvfrom_chk (int __fd, void *__restrict __buf, size_t __n,
@@ -61,11 +61,11 @@ __fortify_function ssize_t
 recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags,
          __SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)
 {
-  size_t sz = __glibc_objsize0 (__buf);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+  size_t __sz = __glibc_objsize0 (__buf);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
     return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len);
-  if (__glibc_unsafe_len (__n, sizeof (char), sz))
-    return __recvfrom_chk_warn (__fd, __buf, __n, sz, __flags, __addr,
+  if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+    return __recvfrom_chk_warn (__fd, __buf, __n, __sz, __flags, __addr,
                                __addr_len);
-  return __recvfrom_chk (__fd, __buf, __n, sz, __flags, __addr, __addr_len);
+  return __recvfrom_chk (__fd, __buf, __n, __sz, __flags, __addr, __addr_len);
 }
diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c
new file mode 100644 (file)
index 0000000..4c68985
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+/* 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 <stdint.h>
+
+#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 (file)
index 0000000..68c96d3
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/socket.h>
+#include <gnu/lib-names.h>
+#include <support/xdlfcn.h>
+#include <support/check.h>
+
+#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 <support/test-driver.c>
index b1e9144de07a4bc01d9f3f3952c43f8852740e2a..743e2611fa21c5817a5e347d70dc80ecaba13af0 100644 (file)
@@ -190,6 +190,7 @@ tests := \
   tst-put-error \
   tst-renameat2 \
   tst-rndseek \
+  tst-scanf-bz27650 \
   tst-scanf-round \
   tst-setvbuf1 \
   tst-sprintf \
@@ -201,6 +202,7 @@ tests := \
   tst-swscanf \
   tst-tmpnam \
   tst-ungetc \
+  tst-ungetc-leak \
   tst-unlockedio \
   tst-vfprintf-mbs-prec \
   tst-vfprintf-user-type \
@@ -233,6 +235,7 @@ tests-special += \
   $(objpfx)tst-printfsz-islongdouble.out \
   $(objpfx)tst-setvbuf1-cmp.out \
   $(objpfx)tst-unbputc.out \
+  $(objpfx)tst-ungetc-leak-mem.out \
   $(objpfx)tst-vfprintf-width-prec-mem.out \
   # tests-special
 
@@ -246,6 +249,9 @@ generated += \
   tst-printf-fp-free.mtrace \
   tst-printf-fp-leak-mem.out \
   tst-printf-fp-leak.mtrace \
+  tst-scanf-bz27650.mtrace \
+  tst-ungetc-leak-mem.out \
+  tst-ungetc-leak.mtrace \
   tst-vfprintf-width-prec-mem.out \
   tst-vfprintf-width-prec.mtrace \
   # generated
@@ -316,6 +322,12 @@ tst-printf-fp-free-ENV = \
 tst-printf-fp-leak-ENV = \
   MALLOC_TRACE=$(objpfx)tst-printf-fp-leak.mtrace \
   LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+tst-scanf-bz27650-ENV = \
+  MALLOC_TRACE=$(objpfx)tst-scanf-bz27650.mtrace \
+  LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-ungetc-leak-ENV = \
+  MALLOC_TRACE=$(objpfx)tst-ungetc-leak.mtrace \
+  LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
 
 $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
        $(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
diff --git a/stdio-common/tst-scanf-bz27650.c b/stdio-common/tst-scanf-bz27650.c
new file mode 100644 (file)
index 0000000..3a742bc
--- /dev/null
@@ -0,0 +1,108 @@
+/* Test for BZ #27650, formatted input matching beyond INT_MAX.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <error.h>
+#include <errno.h>
+#include <limits.h>
+#include <mcheck.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+
+#include <support/check.h>
+#include <support/test-driver.h>
+
+/* Produce a stream of more than INT_MAX characters via buffer BUF of
+   size SIZE according to bookkeeping in COOKIE and then return EOF.  */
+
+static ssize_t
+io_read (void *cookie, char *buf, size_t size)
+{
+  unsigned int *written = cookie;
+  unsigned int w = *written;
+
+  if (w > INT_MAX)
+    return 0;
+
+  memset (buf, 'a', size);
+  *written = w + size;
+  return size;
+}
+
+/* Consume a stream of more than INT_MAX characters from an artificial
+   input stream of which none is the new line character.  The call to
+   fscanf is supposed to complete upon the EOF condition of input,
+   however in the presence of BZ #27650 it will terminate prematurely
+   with characters still outstanding in input.  Diagnose the condition
+   and return status accordingly.  */
+
+int
+do_test (void)
+{
+  static cookie_io_functions_t io_funcs = { .read = io_read };
+  unsigned int written = 0;
+  FILE *in;
+  int v;
+
+  mtrace ();
+
+  in = fopencookie (&written, "r", io_funcs);
+  if (in == NULL)
+    {
+      FAIL ("fopencookie: %m");
+      goto out;
+    }
+
+  v = fscanf (in, "%*[^\n]");
+  if (ferror (in))
+    {
+      FAIL ("fscanf: input failure, at %u: %m", written);
+      goto out_close;
+    }
+  else if (v == EOF)
+    {
+      FAIL ("fscanf: unexpected end of file, at %u", written);
+      goto out_close;
+    }
+
+  if (!feof (in))
+    {
+      v = fgetc (in);
+      if (ferror (in))
+       FAIL ("fgetc: input failure: %m");
+      else if (v == EOF)
+       FAIL ("fgetc: unexpected end of file after missing end of file");
+      else if (v == '\n')
+       FAIL ("unexpected new line character received");
+      else
+       FAIL ("character received after end of file expected: \\x%02x", v);
+    }
+
+out_close:
+  if (fclose (in) != 0)
+    FAIL ("fclose: %m");
+
+out:
+  return EXIT_SUCCESS;
+}
+
+#define TIMEOUT (DEFAULT_TIMEOUT * 8)
+#include <support/test-driver.c>
diff --git a/stdio-common/tst-ungetc-leak.c b/stdio-common/tst-ungetc-leak.c
new file mode 100644 (file)
index 0000000..6c5152b
--- /dev/null
@@ -0,0 +1,32 @@
+/* Test for memory leak with ungetc when stream is unused.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <mcheck.h>
+#include <support/check.h>
+#include <support/support.h>
+
+static int
+do_test (void)
+{
+  mtrace ();
+  TEST_COMPARE (ungetc('y', stdin), 'y');
+  return 0;
+}
+
+#include <support/test-driver.c>
index 1344b2b591e3d6b12418d4c27bf930f783c7fcf6..388b202493ddd586b93870faec6e4be3a55c9b41 100644 (file)
@@ -1,70 +1,74 @@
-/* Test for ungetc bugs.  */
+/* Test for ungetc bugs.
+   Copyright (C) 1996-2024 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
+   <https://www.gnu.org/licenses/>.  */
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-
-#undef assert
-#define assert(x) \
-  if (!(x)) \
-    { \
-      fputs ("test failed: " #x "\n", stderr); \
-      retval = 1; \
-      goto the_end; \
-    }
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
 
-int
-main (int argc, char *argv[])
+static int
+do_test (void)
 {
-  char name[] = "/tmp/tst-ungetc.XXXXXX";
+  char *name = NULL;
   FILE *fp = NULL;
-  int retval = 0;
   int c;
   char buffer[64];
 
-  int fd = mkstemp (name);
+  int fd = create_temp_file ("tst-ungetc.", &name);
   if (fd == -1)
-    {
-      printf ("mkstemp failed: %m\n");
-      return 1;
-    }
-  close (fd);
-  fp = fopen (name, "w");
-  assert (fp != NULL)
-  fputs ("bla", fp);
-  fclose (fp);
-  fp = NULL;
+    FAIL_EXIT1 ("cannot create temporary file: %m");
+  xclose (fd);
 
-  fp = fopen (name, "r");
-  assert (fp != NULL);
-  assert (ungetc ('z', fp) == 'z');
-  assert (getc (fp) == 'z');
-  assert (getc (fp) == 'b');
-  assert (getc (fp) == 'l');
-  assert (ungetc ('m', fp) == 'm');
-  assert (getc (fp) == 'm');
-  assert ((c = getc (fp)) == 'a');
-  assert (getc (fp) == EOF);
-  assert (ungetc (c, fp) == c);
-  assert (feof (fp) == 0);
-  assert (getc (fp) == c);
-  assert (getc (fp) == EOF);
-  fclose (fp);
-  fp = NULL;
+  fp = xfopen (name, "w");
+  fputs ("bla", fp);
+  xfclose (fp);
 
-  fp = fopen (name, "r");
-  assert (fp != NULL);
-  assert (getc (fp) == 'b');
-  assert (getc (fp) == 'l');
-  assert (ungetc ('b', fp) == 'b');
-  assert (fread (buffer, 1, 64, fp) == 2);
-  assert (buffer[0] == 'b');
-  assert (buffer[1] == 'a');
+  fp = xfopen (name, "r");
+  TEST_VERIFY_EXIT (ungetc ('z', fp) == 'z');
+  TEST_VERIFY_EXIT (getc (fp) == 'z');
+  TEST_VERIFY_EXIT (getc (fp) == 'b');
+  TEST_VERIFY_EXIT (getc (fp) == 'l');
+  TEST_VERIFY_EXIT (ungetc ('m', fp) == 'm');
+  TEST_VERIFY_EXIT (ungetc ('n', fp) == 'n');
+  TEST_VERIFY_EXIT (getc (fp) == 'n');
+  TEST_VERIFY_EXIT (getc (fp) == 'm');
+  TEST_VERIFY_EXIT ((c = getc (fp)) == 'a');
+  TEST_VERIFY_EXIT (getc (fp) == EOF);
+  TEST_VERIFY_EXIT (ungetc (c, fp) == c);
+  TEST_VERIFY_EXIT (feof (fp) == 0);
+  TEST_VERIFY_EXIT (getc (fp) == c);
+  TEST_VERIFY_EXIT (getc (fp) == EOF);
+  xfclose (fp);
 
-the_end:
-  if (fp != NULL)
-    fclose (fp);
-  unlink (name);
+  fp = xfopen (name, "r");
+  TEST_VERIFY_EXIT (getc (fp) == 'b');
+  TEST_VERIFY_EXIT (getc (fp) == 'l');
+  TEST_VERIFY_EXIT (ungetc ('b', fp) == 'b');
+  TEST_VERIFY_EXIT (fread (buffer, 1, 64, fp) == 2);
+  TEST_VERIFY_EXIT (buffer[0] == 'b');
+  TEST_VERIFY_EXIT (buffer[1] == 'a');
+  xfclose (fp);
 
-  return retval;
+  return 0;
 }
+
+#include <support/test-driver.c>
index f7b25c1981f332d8a4a9a311c1ff6a555eebd59c..2da3030efc1c6bb74e7b35d5e7c78786df6f5a23 100644 (file)
@@ -171,6 +171,7 @@ tests := \
   test-a64l \
   test-at_quick_exit-race \
   test-atexit-race \
+  test-atexit-recursive \
   test-bz22786 \
   test-canon \
   test-canon2 \
@@ -221,6 +222,7 @@ tests := \
   tst-setcontext7 \
   tst-setcontext8 \
   tst-setcontext9 \
+  tst-setenv-environ \
   tst-strfmon_l \
   tst-strfrom \
   tst-strfrom-locale \
index e417ef624d72952ed1bf68fa9006773a6c8fdb3c..960a38f2954d84e0011793ff893deefd87443496 100644 (file)
@@ -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)
index de1c3b20f0ba84b6e7c86c0e5cc45994fed97398..19f8bd5b52e2866bbf1837e8db43e42f4cabb770 100644 (file)
@@ -36,16 +36,16 @@ extern char *__REDIRECT_NTH (__realpath_chk_warn,
 __fortify_function __wur char *
 __NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
 {
-  size_t sz = __glibc_objsize (__resolved);
+  size_t __sz = __glibc_objsize (__resolved);
 
-  if (sz == (size_t) -1)
+  if (__sz == (size_t) -1)
     return __realpath_alias (__name, __resolved);
 
 #if defined _LIBC_LIMITS_H_ && defined PATH_MAX
-  if (__glibc_unsafe_len (PATH_MAX, sizeof (char), sz))
-    return __realpath_chk_warn (__name, __resolved, sz);
+  if (__glibc_unsafe_len (PATH_MAX, sizeof (char), __sz))
+    return __realpath_chk_warn (__name, __resolved, __sz);
 #endif
-  return __realpath_chk (__name, __resolved, sz);
+  return __realpath_chk (__name, __resolved, __sz);
 }
 
 
index bc46109f3e36260a3eb2e9bd2ceafa1f3f247931..dc12e212bc862d1ee075b1f41a328e74212e7d4b 100644 (file)
@@ -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;
index 9b89469ac21ed70562d99a8d1436dfecaeebd577..d8f76a43b50ffd45b5e7489eaf637bafe93843b3 100644 (file)
@@ -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 (file)
index 0000000..0596b97
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+/* Check that atexit handler registed from another handler still called. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+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 <support/test-driver.c>
diff --git a/stdlib/tst-setenv-environ.c b/stdlib/tst-setenv-environ.c
new file mode 100644 (file)
index 0000000..02fcef9
--- /dev/null
@@ -0,0 +1,36 @@
+/* Test using setenv with updated environ.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <support/check.h>
+
+extern char **environ;
+
+int
+do_test (void)
+{
+  char *valp;
+  static char *dummy_environ[] = { NULL };
+  environ = dummy_environ;
+  setenv ("A", "1", 0);
+  valp = getenv ("A");
+  TEST_VERIFY_EXIT (valp[0] == '1' && valp[1] == '\0');
+  return 0;
+}
+
+#include <support/test-driver.c>
index f7fa74b2a6fb5374b1577a9927286fcf9b1a076c..5e0c79475f7672d0a86f350c702feec962ca0a78 100644 (file)
@@ -25,6 +25,7 @@
 #include <support/check.h>
 #include <support/temp_file.h>
 #include <support/support.h>
+#include <support/xthread.h>
 #include <support/xunistd.h>
 
 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;
index 4a9375112add204fa6466176ee18395ba42794ac..5cbaf4b73489f60b48150cb1a96c4c8fe62a93c2 100644 (file)
@@ -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);
+               }
+           }
+       }
     }
 }
 
index bf7f0b81c435f7dfb4d648e4f02ae2b0a74f082c..c1d1c43e502b7d65da7eb7f333aa24a17d9807c5 100644 (file)
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <rpc/rpc.h>
 #include <shlib-compat.h>
+#include <libc-diag.h>
 
 #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';
index 9b50eac11762fdfb63de3abdb0d50871758629fd..c8c1363b7684fa923c8fca32641cc767fc34a68f 100644 (file)
@@ -32,6 +32,8 @@ libsupport-routines = \
   check_hostent \
   check_netent \
   delayed_exit \
+  dtotimespec \
+  dtotimespec-time64 \
   ignore_stderr \
   next_to_fault \
   oom_error \
@@ -159,6 +161,7 @@ libsupport-routines = \
   xpthread_cancel \
   xpthread_check_return \
   xpthread_cond_wait \
+  xpthread_cond_signal \
   xpthread_create \
   xpthread_detach \
   xpthread_join \
@@ -205,6 +208,7 @@ libsupport-routines = \
   xstrndup \
   xsymlink \
   xsysconf \
+  xsystem \
   xunlink \
   xuselocale \
   xwaitpid \
@@ -237,6 +241,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
index fa080cf4805319b2583050937bc8d908f0a1ec1e..43f4208a0a40f64cc65eeff01c867dfc66138057 100644 (file)
 
 __BEGIN_DECLS
 
+/* Record a test failure, print the failure message to standard output
+   and pass the result of 1 through.  */
+#define FAIL(...) \
+  support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__)
+
 /* Record a test failure, print the failure message to standard output
    and return 1.  */
 #define FAIL_RET(...) \
diff --git a/support/dtotimespec-time64.c b/support/dtotimespec-time64.c
new file mode 100644 (file)
index 0000000..b3d5e35
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <time.h>
+
+#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 (file)
index 0000000..cde5b4d
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+/* Convert the double value SEC to a struct timespec.  Round toward
+   positive infinity.  On overflow, return an extremal value.  */
+
+#include <support/timespec.h>
+#include <intprops.h>
+
+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);
+    }
+}
index 1c73666f0a47d08689ed6d2f88c72c719ae4997f..019a6c47d1af210897069cd75b3e94ca6203e546 100644 (file)
@@ -16,8 +16,6 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#define _FILE_OFFSET_BITS 64
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -39,6 +37,7 @@
 #include <error.h>
 
 #include <support/support.h>
+#include <support/timespec.h>
 
 /* 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 }
 };
 
index ca0e5f7ef49c0804084dd53ab503fa8b844622a5..43979f7c3fb9f9eb251170e8f51a9c6254a12ed0 100644 (file)
@@ -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);
index 9a936b37c77f0515c4ee6ab51faba8b8d3a70764..52ed90fae021ef51d7ce97b2500357ba6cb0b559 100644 (file)
@@ -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;
index d9bcade1cfb640a2c571e922430ee6be64c8e3bd..83f02f7cf64ec38157e979f20f2e94ceb175c6a7 100644 (file)
@@ -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);
index b6a1158ae17bf934576358a5a60e59dcd87f6f7d..2033985a677890a4c43f995c21d99015a7dec731 100644 (file)
@@ -16,8 +16,6 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#define _FILE_OFFSET_BITS 64
-
 #include <array_length.h>
 #include <stdio.h>
 #include <stdlib.h>
index 4d2ac2737dd3912d6466847e8ed662c56a6f8901..1bba3a68370025322366fa32bed4afd204d1229e 100644 (file)
@@ -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/support/xpthread_cond_signal.c b/support/xpthread_cond_signal.c
new file mode 100644 (file)
index 0000000..ed0be1a
--- /dev/null
@@ -0,0 +1,26 @@
+/* pthread_cond_signal with error checking.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/xthread.h>
+
+void
+xpthread_cond_signal (pthread_cond_t *cond)
+{
+  xpthread_check_return
+    ("pthread_cond_signal", pthread_cond_signal (cond));
+}
diff --git a/support/xstdlib.h b/support/xstdlib.h
new file mode 100644 (file)
index 0000000..db5a5b9
--- /dev/null
@@ -0,0 +1,31 @@
+/* Error-checking wrappers for stdlib functions.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef SUPPORT_XSTDLIB_H
+#define SUPPORT_XSTDLIB_H
+
+#include <stdlib.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+void xsystem (const char *cmd);
+
+__END_DECLS
+
+#endif /* SUPPORT_XSTDLIB_H */
diff --git a/support/xsystem.c b/support/xsystem.c
new file mode 100644 (file)
index 0000000..1f55895
--- /dev/null
@@ -0,0 +1,37 @@
+/* Error-checking replacement for "system".
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/support.h>
+#include <support/check.h>
+
+#include <support/xstdlib.h>
+
+void
+xsystem (const char *cmd)
+{
+  int ret = system (cmd);
+
+  if (ret == 0 && cmd == NULL)
+    FAIL_EXIT1 ("Unable to spawn a shell for NULL command");
+
+  if (ret == 127)
+    FAIL_EXIT1 ("Child terminated with status 127");
+
+  if (ret < 0)
+    FAIL_EXIT1 ("system (\"%s\")", cmd);
+}
index af06715f469cc07e9a6f5838048938d5e1ed50d9..ae09649325d42a2ad4dc80f0c7cd0f4b0835b8d5 100644 (file)
@@ -62,6 +62,7 @@ void xpthread_mutex_consistent (pthread_mutex_t *);
 void xpthread_spin_lock (pthread_spinlock_t *lock);
 void xpthread_spin_unlock (pthread_spinlock_t *lock);
 void xpthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex);
+void xpthread_cond_signal (pthread_cond_t *cond);
 pthread_t xpthread_create (pthread_attr_t *attr,
                            void *(*thread_func) (void *), void *closure);
 void xpthread_detach (pthread_t thr);
old mode 100644 (file)
new mode 100755 (executable)
index bf97212..19d2b46
@@ -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
 
index 51253d98025b6f5956575558e459d72e0763c674..bb5adb17828c0d8f203478c7872fd4fbc84f265a 100644 (file)
@@ -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
index 909b208578225b22dd62a6d184809a9032e17ca9..d66f0b9c4579ef2fc95f9cb083ef3b87b8c56300 100644 (file)
@@ -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]
index 2053a977b686db1f15ef23d7cd7ca285fa0dc803..79aa910da49e4fb8b0c126bb775a3a460b2bfbff 100644 (file)
@@ -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
index 98d4e2c0e202eca13e1fd19ad8046cf61ad280ff..7b396b202fabf01b6ff2adc71a1038148e0b1054 100644 (file)
@@ -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.
  *
  */
 
 #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
    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)
index 5179320720485eeaa073ca47d8ab95ecf3d90842..428af51f70d9e0fa1d5c6de48b8cacb449007d21 100644 (file)
@@ -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
index 957996bd1903fa8d5d76f1f7754ae2be53f2ead7..b76d1c3e5ee650db7b7c2a927eefffc6a4543f79 100644 (file)
@@ -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.  */
index 16297192ee8375ea1470d7b1f7e728a6dd0fd704..e4720b746859f51502e070ba0c2f308072a49740 100644 (file)
@@ -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
index 4144615ab2198a97c76df40cec1056ea14300f56..1c712ce913fd8b948c21345bd6b06141a544defe 100644 (file)
@@ -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;
 }
index a4dcac0019204967c423092e975b27740ad640d3..5b2cf5cb127bb053ca817c6c69d68afec784d5fc 100644 (file)
@@ -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;
index ddf75339437c855ac18dfddde2dc182f6b103ff6..e39f39e6b3c917c75c90ae95904c7f6cfea4cfb4 100644 (file)
  * 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)
index 0486213f08db8ab08a903c4b9e6bdd19df6dccec..3de66c14d4509d03390198b4bd66ff0008fa1799 100644 (file)
 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;
 }
 
index c4eab06176d9ff67d3a2de2e2e168b00d8ce87b2..c254dc8b9f68e9afde3ae8533238056967d0df75 100644 (file)
@@ -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 (file)
index fe9beaf..0000000
+++ /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
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-
-/* 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 (file)
index 117edd9..0000000
+++ /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
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-
-/* 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 (file)
index 0000000..4685629
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+/* 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)
index a70907ec5595114e4da35c54e932279c22e53cc6..71d2f84f6308d95e4a1fc364dc3cf57e289e645b 100644 (file)
@@ -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
index 21e703dddd8c4f57ab193608f06b67880d243d04..2fb6be5c78bf4a6fefbd930dc16cd70ba461775e 100644 (file)
    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)
index 5e0a59ee5dc22091c85f8ba2ba393bce5ea1690f..3fceb1036d3838c882eb6d162bd916a99a737156 100644 (file)
 #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
index 261996ecc4b36bdaf3c50598d910e9c7dcace08b..fdcf4188209379b34162cb7cd89aede7a36585bb 100644 (file)
 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 (file)
index 0000000..c5ea66b
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+/* 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)
index c4008f346b34ec5b4b767a1433cf72692572a714..9ef9521fa6437221054e3d257aa6099ad1c18477 100644 (file)
 
 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);
index dc87190724b0050bfffa1e60a90d75d84ab906e1..4a4d4ed504ae1b80e3a3fa7ff014981dcc939f60 100644 (file)
@@ -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 (file)
index 32d20d7..0000000
+++ /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
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#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)
index 922c1ed57d9c533537a45cffa17a6a15926f0c5c..7ecf61dc59cc6768de639b1642f9441a7829fe1a 100644 (file)
    <https://www.gnu.org/licenses/>.  */
 
 #include <sysdep.h>
+#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 (file)
index 657f4c6..0000000
+++ /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
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-#include <memset-reg.h>
-
-/* 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 <sysdeps/aarch64/memset.S>
-#endif
index c879be93d5bd080b2ca87f73f2e2f58c35f4c00d..6efcb5f00d06d0badd08b815ef983de410eae8d8 100644 (file)
 
 #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 <sysdeps/aarch64/memset.S>
 #endif
+
+#include <../memset.S>
index a6d2c8c3bbe02d30182501d5ac12b44340ba9e83..8f2deddb7435c6d39210f0aea84a575a020e2b45 100644 (file)
 #include <sysdep.h>
 #include <sysdeps/aarch64/memset-reg.h>
 
-#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 (file)
index 0000000..ca820b8
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+/* 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/memset_zva64.S b/sysdeps/aarch64/multiarch/memset_zva64.S
new file mode 100644 (file)
index 0000000..13f45fd
--- /dev/null
@@ -0,0 +1,27 @@
+/* Optimized memset for zva size = 64.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+#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/rtld-memset.S b/sysdeps/aarch64/multiarch/rtld-memset.S
deleted file mode 100644 (file)
index 7968d25..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Memset for aarch64, for the dynamic linker.
-   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
-   <https://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-
-#if IS_IN (rtld)
-# define MEMSET memset
-# include <sysdeps/aarch64/memset.S>
-#endif
index 6d27c126b0384088a095d2e51c4f78468e5e7efe..a951967fcd2116c2452284da2377668f054dec84 100644 (file)
 
 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);
index 6faeb91361b67a7c8261c37dfd4eb88e416004ad..dcd4589d10794420355fc369584fdd221398e63b 100644 (file)
@@ -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_generic.S b/sysdeps/aarch64/multiarch/strlen_generic.S
new file mode 100644 (file)
index 0000000..014e376
--- /dev/null
@@ -0,0 +1,39 @@
+/* A Generic Optimized strlen implementation for AARCH64.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+/* The actual strlen code is in ../strlen.S.  If we are building libc this file
+   defines __strlen_generic.  Otherwise the include of ../strlen.S will define
+   the normal __strlen entry points.  */
+
+#include <sysdep.h>
+
+#if IS_IN (libc)
+
+# define STRLEN __strlen_generic
+
+/* Do not hide the generic version of strlen, we use it internally.  */
+# undef libc_hidden_builtin_def
+# define libc_hidden_builtin_def(name)
+
+# ifdef SHARED
+/* It doesn't make sense to send libc-internal strlen calls through a PLT. */
+       .globl __GI_strlen; __GI_strlen = __strlen_generic
+# endif
+#endif
+
+#include "../strlen.S"
diff --git a/sysdeps/aarch64/multiarch/strlen_mte.S b/sysdeps/aarch64/multiarch/strlen_mte.S
deleted file mode 100644 (file)
index bf03ac5..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* A Generic Optimized strlen implementation for AARCH64.
-   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
-   <https://www.gnu.org/licenses/>.  */
-
-/* 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.  */
-
-#include <sysdep.h>
-
-#if IS_IN (libc)
-
-# define STRLEN __strlen_mte
-
-/* Do not hide the generic version of strlen, we use it internally.  */
-# undef libc_hidden_builtin_def
-# define libc_hidden_builtin_def(name)
-
-# ifdef SHARED
-/* It doesn't make sense to send libc-internal strlen calls through a PLT. */
-       .globl __GI_strlen; __GI_strlen = __strlen_mte
-# endif
-#endif
-
-#include "../strlen.S"
index 55d9e34d4fa9f111fe41f926943a1e4b413e20a9..f90ce2bf8644b8c245a1290a4cb32da5596b8e87 100644 (file)
@@ -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
index 003bf4a4789f6f3d1676bb2601f6d04afc0945da..4781d45bd92d95cb5dc94d25ed09cb651da43fd7 100644 (file)
@@ -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
 #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
index ee154ab74bb8ea50274bd67a43e5e08f974565ef..94465fc088a018d7a6d0a991978c5bd2aee8bf90 100644 (file)
@@ -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
index 78d27b4aa616c9fdc579233bc9c680df1c508017..6eeda12df6da12f7cf98e64196de0b0380a9145d 100644 (file)
@@ -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)
index 3a5d0884077a97f0e7683a9f3618a3b51b550f3a..10b9ec07693bff0afd93b3c5bb324bc4bbf4ae7a 100644 (file)
 #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
index 282bddc9aa68f9678fca9f1ecb75af4008f619e9..a44a49a920eb9ab4448235b869008ed2ba588e0d 100644 (file)
 
 /*
    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)
index 596e77c43b4407bc35f71f7c58d814cc5a45c484..eda6fefb99dd9270f9a0709526135b5d09ccc6e2 100644 (file)
 
 /* 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
 
    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 (file)
index 0000000..a247fcd
--- /dev/null
@@ -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 (file)
index 0000000..6ecbfe7
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#define __WORDSIZE                     32
+#define __WORDSIZE_TIME64_COMPAT32     1
+#define __WORDSIZE32_SIZE_ULONG                0
+#define __WORDSIZE32_PTRDIFF_LONG      0
index 6a422713bdf008f19a9e2cfb5e7b00e108b14a97..659c6f16dad47155c38a4bfd98e747bccfb02632 100644 (file)
@@ -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 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -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 (file)
index 0000000..6ecbfe7
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#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 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
index 050a3032de8b0ed2879474dba3536fc9ea3be90f..17bd399888673f05c7570b076d9b571857d6b688 100644 (file)
@@ -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'
@@ -1257,9 +1267,24 @@ extern void _dl_add_to_slotinfo (struct link_map *l, bool do_add)
 
 /* Update slot information data for at least the generation of the
    module with the given index.  */
-extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid)
+extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid,
+                                            size_t gen)
      attribute_hidden;
 
+/* The last TLS module ID that is initially loaded, plus 1.  TLS
+   addresses for modules with IDs lower than that can be obtained from
+   the DTV even if its generation is outdated.  */
+extern size_t _dl_tls_initial_modid_limit attribute_hidden attribute_relro;
+
+/* Compute _dl_tls_initial_modid_limit.  To be called after initial
+   relocation.  */
+void _dl_tls_initial_modid_limit_setup (void) attribute_hidden;
+
+/* Number of threads currently in a TLS update.  This is used to
+   detect reentrant __tls_get_addr calls without a per-thread
+   flag.  */
+extern unsigned int _dl_tls_threads_in_update attribute_hidden;
+
 /* Look up the module's TLS block as for __tls_get_addr,
    but never touch anything.  Return null if it's not allocated yet.  */
 extern void *_dl_tls_get_addr_soft (struct link_map *l) attribute_hidden;
diff --git a/sysdeps/generic/libc-lock-arch.h b/sysdeps/generic/libc-lock-arch.h
new file mode 100644 (file)
index 0000000..4713b30
--- /dev/null
@@ -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 <https://www.gnu.org/licenses/>.  */
+
+#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/mremap-failure.h b/sysdeps/generic/mremap-failure.h
new file mode 100644 (file)
index 0000000..bc0d476
--- /dev/null
@@ -0,0 +1,25 @@
+/* mremap failure handling.  Generic 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
+   <https://www.gnu.org/licenses/>.  */
+
+/* Return exit value on mremap failure with errno ERR.  */
+
+static int
+mremap_failure_exit (int err)
+{
+  return EXIT_FAILURE;
+}
diff --git a/sysdeps/generic/utmp-size.h b/sysdeps/generic/utmp-size.h
new file mode 100644 (file)
index 0000000..89dbe87
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+/* 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
index c865713be1e3f8e0430bbb35c8db7ebe3e7a6abf..1d5194856601e025cb4355c94c2b49358fc81076 100644 (file)
@@ -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 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
index 8f1c95bd04bdb0bc44113c13b62c58c75c106a3f..1cafeca9c02381a1ef8bdce21b0f45dfe879ce9f 100644 (file)
@@ -130,6 +130,11 @@ static const double
          4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
          -2.01099218183624371326e-07 }; /* BE8AFDB7 6E09C32D */
 
+#ifndef SECTION
+# define SECTION
+#endif
+
+SECTION
 double
 __expm1 (double x)
 {
@@ -258,4 +263,6 @@ __expm1 (double x)
     }
   return y;
 }
+#ifndef __expm1
 libm_alias_double (__expm1, expm1)
+#endif
index e6476a826039ea8c8f2ac66133448b8c33c966c4..eeb0af859ffce7dacb14bf8fe82ff88ed11af23e 100644 (file)
@@ -99,6 +99,11 @@ static const double
 
 static const double zero = 0.0;
 
+#ifndef SECTION
+# define SECTION
+#endif
+
+SECTION
 double
 __log1p (double x)
 {
index 54c457681aecef079cb64d406ca89e05d2ce4fc5..9a9c5c6f00d7ca189d3068755c6be80dd80ff327 100644 (file)
@@ -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;
     }
 
index f85ba9446663d39d5fc6eaaea5a4a1f9a213c234..0a5fe68342fc974eec7ab3f528c7611d583cb391 100644 (file)
@@ -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;
     }
 
index d85154e73ac062e6c9ed403fe3cfc3889726ff72..d8c0de1faf29fd03180d6839e44818a8959cb045 100644 (file)
@@ -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 (file)
index 0000000..6ecbfe7
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#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 (file)
index 0000000..5946685
--- /dev/null
@@ -0,0 +1,3 @@
+/* m68k has 2-byte alignment.  */
+#define UTMP_SIZE 382
+#define LASTLOG_SIZE 292
index 37ea5e6a7a6405fdd5c0be003878ae27ede7d075..80ea7e17cb4e5ab15dcfd866f425018a41f10c62 100644 (file)
@@ -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)
index 5b35ea81ecd72696f53d25be5412b445d0f21545..70fce4fb276588a7f900b58483f3334052c7c7bf 100644 (file)
@@ -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 (file)
index 0000000..6ecbfe7
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#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 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
index e521dc589c5a3dd253b2ffbf54064c8a14de79f9..c6a4a4270be8c557d02d3baf24337934cdb6cf1e 100644 (file)
 
 #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 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -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 (file)
index 0000000..6ecbfe7
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#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 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
index 53fba774a55c5e76febbe549e30f06d7e4cba6bb..662bc0158da97c6b18b27ad86cd7eaec9b100625 100644 (file)
@@ -45,8 +45,6 @@ rtld_mutex_dummy (pthread_mutex_t *lock)
 #endif
 
 const unsigned int __rseq_flags;
-const unsigned int __rseq_size attribute_relro;
-const ptrdiff_t __rseq_offset attribute_relro;
 
 void
 __tls_pre_init_tp (void)
@@ -106,12 +104,7 @@ __tls_init_tp (void)
     do_rseq = TUNABLE_GET (rseq, int, NULL);
 #endif
     if (rseq_register_current_thread (pd, do_rseq))
-      {
-        /* We need a writable view of the variables.  They are in
-           .data.relro and are not yet write-protected.  */
-        extern unsigned int size __asm__ ("__rseq_size");
-        size = sizeof (pd->rseq_area);
-      }
+      _rseq_size = RSEQ_AREA_SIZE_INITIAL_USED;
 
 #ifdef RSEQ_SIG
     /* This should be a compile-time constant, but the current
@@ -119,8 +112,7 @@ __tls_init_tp (void)
        all targets support __thread_pointer, so set __rseq_offset only
        if thre rseq registration may have happened because RSEQ_SIG is
        defined.  */
-    extern ptrdiff_t offset __asm__ ("__rseq_offset");
-    offset = (char *) &pd->rseq_area - (char *) __thread_pointer ();
+    _rseq_offset = (char *) &pd->rseq_area - (char *) __thread_pointer ();
 #endif
   }
 
index 5af476c48b7f64fedd4cd9c29c45abe907b00f90..63b3f3d75ca16c890bc6bd29002ca562b07839ba 100644 (file)
@@ -22,6 +22,7 @@
 #include <pthread.h>
 #define __need_NULL
 #include <stddef.h>
+#include <libc-lock-arch.h>
 
 
 /* Mutex type.  */
 # 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;
index d3a6837fd212f3f5dfd80f46d0e9ce365042ae0c..425f514c5c47409c004a7044e28e27f2b235bf55 100644 (file)
    ld.so might be used on old kernels with a different libc.so.  */
 #include <lowlevellock.h>
 #include <tls.h>
+#include <libc-lock-arch.h>
 
 /* 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 (file)
index 0000000..6b3653a
--- /dev/null
@@ -0,0 +1,3 @@
+/* or1k has less padding than other architectures with 64-bit time_t.  */
+#define UTMP_SIZE 392
+#define LASTLOG_SIZE 296
index bcff909b2f3939d04b6ad33a78ae4f510504f96c..f975dcd2bcfaf585fad88e3f43a2ac7ea407f06d 100644 (file)
@@ -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;
 }
index 2ee0010b8dbee26dcc10d5cffab1b410c0446b31..dfa07805140cabc8d0332ae15153841f8d997f61 100644 (file)
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <ldsodefs.h>
+#include <libc-pointer-arith.h>
 #include <paths.h>
 #include <stdarg.h>
 #include <stdbool.h>
@@ -125,8 +126,8 @@ __libc_message (enum __libc_message_action action, const char *fmt, ...)
 
       if ((action & do_abort))
        {
-         total = ((total + 1 + GLRO(dl_pagesize) - 1)
-                  & ~(GLRO(dl_pagesize) - 1));
+         total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
+                           GLRO(dl_pagesize));
          struct abort_msg_s *buf = __mmap (NULL, total,
                                            PROT_READ | PROT_WRITE,
                                            MAP_ANON | MAP_PRIVATE, -1, 0);
index 8014f633550b031c72f9180e03d1ad5965f51977..20c9420dd424a6c3cde1bd368e39feaed7327c32 100644 (file)
@@ -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);
index 2a82e53bafe9d0eb3e8df7cdf5bc17fb3df7dd88..d941024963fc7e6a65cc6388185f3a596ba6fb2f 100644 (file)
@@ -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"
index 04ca9debf00d7ee97ddf83dcd2e66c139bcd9d7c..6993fb6b29ea3f743dedda57771ef9e4dce2169d 100644 (file)
@@ -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
index 04ca9debf00d7ee97ddf83dcd2e66c139bcd9d7c..6993fb6b29ea3f743dedda57771ef9e4dce2169d 100644 (file)
@@ -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
index bb0ccd0811b3c0bbc410ba60353ad6fee10273af..3868bcc2f778a2cfadd0b62397c3091400305fdf 100644 (file)
@@ -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 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
index 7dd360e32514e9e0e6db5b2caf6e02c18881ab4f..4a7779125348fc3279ef6f68b01b5bc350cd4e7d 100644 (file)
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <stdio.h>
 #include <errno.h>
 #include <pthread.h>
 #include <stdbool.h>
 #include <unistd.h>
 
+#include <support/check.h>
+
 /* The test must run under a non-privileged user ID.  */
 static const uid_t test_uid = 1;
 
 static pthread_barrier_t barrier1;
 static pthread_barrier_t barrier2;
 
-#define FAIL(fmt, ...) \
-  do { printf ("FAIL: " fmt "\n", __VA_ARGS__); _exit (1); } while (0)
-
-#define FAIL_ERR(fmt, ...) \
-  do { printf ("FAIL: " fmt ": %m\n", __VA_ARGS__); _exit (1); } while (0)
-
 /* True if x is not a successful return code from pthread_barrier_wait.  */
 static inline bool
 is_invalid_barrier_ret (int x)
@@ -45,10 +40,10 @@ thread_func (void *ctx __attribute__ ((unused)))
 {
   int ret = pthread_barrier_wait (&barrier1);
   if (is_invalid_barrier_ret (ret))
-    FAIL ("pthread_barrier_wait (barrier1) (on thread): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_wait (barrier1) (on thread): %d", ret);
   ret = pthread_barrier_wait (&barrier2);
   if (is_invalid_barrier_ret (ret))
-    FAIL ("pthread_barrier_wait (barrier2) (on thread): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_wait (barrier2) (on thread): %d", ret);
   return NULL;
 }
 
@@ -59,13 +54,13 @@ setuid_failure (int phase)
   switch (ret)
     {
     case 0:
-      FAIL ("setuid succeeded unexpectedly in phase %d", phase);
+      FAIL_EXIT1 ("setuid succeeded unexpectedly in phase %d", phase);
     case -1:
       if (errno != EPERM)
-       FAIL_ERR ("setuid phase %d", phase);
+       FAIL_EXIT1 ("setuid phase %d: %m", phase);
       break;
     default:
-      FAIL ("invalid setuid return value in phase %d: %d", phase, ret);
+      FAIL_EXIT1 ("invalid setuid return value in phase %d: %d", phase, ret);
     }
 }
 
@@ -74,42 +69,42 @@ do_test (void)
 {
   if (getuid () == 0)
     if (setuid (test_uid) != 0)
-      FAIL_ERR ("setuid (%u)", (unsigned) test_uid);
+      FAIL_EXIT1 ("setuid (%u): %m", (unsigned) test_uid);
   if (setuid (getuid ()))
-    FAIL_ERR ("setuid (%s)", "getuid ()");
+    FAIL_EXIT1 ("setuid (%s): %m", "getuid ()");
   setuid_failure (1);
 
   int ret = pthread_barrier_init (&barrier1, NULL, 2);
   if (ret != 0)
-    FAIL ("pthread_barrier_init (barrier1): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_init (barrier1): %d", ret);
   ret = pthread_barrier_init (&barrier2, NULL, 2);
   if (ret != 0)
-    FAIL ("pthread_barrier_init (barrier2): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_init (barrier2): %d", ret);
 
   pthread_t thread;
   ret = pthread_create (&thread, NULL, thread_func, NULL);
   if (ret != 0)
-    FAIL ("pthread_create: %d", ret);
+    FAIL_EXIT1 ("pthread_create: %d", ret);
 
   /* Ensure that the thread is running properly.  */
   ret = pthread_barrier_wait (&barrier1);
   if (is_invalid_barrier_ret (ret))
-    FAIL ("pthread_barrier_wait (barrier1): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_wait (barrier1): %d", ret);
 
   setuid_failure (2);
 
   /* Check success case. */
   if (setuid (getuid ()) != 0)
-    FAIL_ERR ("setuid (%s)", "getuid ()");
+    FAIL_EXIT1 ("setuid (%s): %m", "getuid ()");
 
   /* Shutdown.  */
   ret = pthread_barrier_wait (&barrier2);
   if (is_invalid_barrier_ret (ret))
-    FAIL ("pthread_barrier_wait (barrier2): %d", ret);
+    FAIL_EXIT1 ("pthread_barrier_wait (barrier2): %d", ret);
 
   ret = pthread_join (thread, NULL);
   if (ret != 0)
-    FAIL ("pthread_join: %d", ret);
+    FAIL_EXIT1 ("pthread_join: %d", ret);
 
   return 0;
 }
diff --git a/sysdeps/riscv/utmp-size.h b/sysdeps/riscv/utmp-size.h
new file mode 100644 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
index c518539bfae2bc30245adf6294761505a79a6487..5db0c707a10d5f3fa094466892123f7c0c3a3671 100644 (file)
@@ -59,14 +59,7 @@ ENTRY(WCSNCMP_Z13)
        sllg    %r4,%r4,2       /* Convert character-count to byte-count.  */
        locgrne %r4,%r1         /* Use max byte-count, if bit 0/1 was one.  */
 
-       /* Check first character without vector load.  */
-       lghi    %r5,4           /* current_len = 4 bytes.  */
-       /* Check s1/2[0].  */
-       lt      %r0,0(%r2)
-       l       %r1,0(%r3)
-       je      .Lend_cmp_one_char
-       crjne   %r0,%r1,.Lend_cmp_one_char
-
+       lghi    %r5,0           /* current_len = 0 bytes.  */
 .Lloop:
        vlbb    %v17,0(%r5,%r3),6 /* Load s2 to block boundary.  */
        vlbb    %v16,0(%r5,%r2),6 /* Load s1 to block boundary.  */
@@ -167,7 +160,6 @@ ENTRY(WCSNCMP_Z13)
        srl     %r4,2           /* And convert it to character-index.  */
        vlgvf   %r0,%v16,0(%r4) /* Load character-values.  */
        vlgvf   %r1,%v17,0(%r4)
-.Lend_cmp_one_char:
        cr      %r0,%r1
        je      .Lend_equal
        lghi    %r2,1
diff --git a/sysdeps/sh/bits/wordsize.h b/sysdeps/sh/bits/wordsize.h
new file mode 100644 (file)
index 0000000..6ecbfe7
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#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 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
index 2f66f10d7206731a2110721685d0ac6dc184ab14..a2e79e0fa9dc41d92fb8bd45e99a55f90ed816c5 100644 (file)
@@ -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
index b1b67cb2d109bca09d5a47037d66797d8ab92673..51542633171c4cb6dadd4d87dea7d1fa48a40156 100644 (file)
@@ -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)
index 2f66f10d7206731a2110721685d0ac6dc184ab14..ea103e5970829abc52731614b8835e1796606b4d 100644 (file)
@@ -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
index 8d46f2cd4ef4f3e9866291c69067674716bc5484..77466841602f1b95ca3b2bdec2c5a18e9500f36c 100644 (file)
@@ -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  */
index 95068071ccb50168f4e1ce69af728b3ea99076b0..baab6817a6a7adef6b6d8012873ae163cae08e18 100644 (file)
@@ -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 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
index a139a1653207df96bb22a471031ed885a7dd633d..d92ea7a1f303e96a13e0f2320de0fce752e599a7 100644 (file)
@@ -131,6 +131,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
   tst-pidfd \
   tst-process_mrelease \
   tst-mount \
+  tst-linux-mremap1 \
   # tests
 
 # process_madvise requires CAP_SYS_ADMIN.
@@ -265,6 +266,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 +363,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.
@@ -392,6 +403,7 @@ endif
 
 ifeq ($(subdir),elf)
 sysdep-rtld-routines += dl-brk dl-sbrk dl-getcwd dl-openat64 dl-opendir
+dl-routines += dl-rseq-symbols
 
 libof-lddlibc4 = lddlibc4
 
index 616239bb847e4d9b64fcff799b3e3e600e26ea23..b7ffea84e5c95c00c6fd18a89209eab3a8e82e06 100644 (file)
 #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)
index d14c0f4e1f2905148ac55a4569fd3e12f9a1d7fe..25431283527f844bfc059afb74cc1521de38ae65 100644 (file)
@@ -20,6 +20,7 @@
 #include <sys/auxv.h>
 #include <elf/dl-hwcaps.h>
 #include <sys/prctl.h>
+#include <sys/utsname.h>
 
 #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;
 }
index 391165a99c20adf82f10c5b07d559ab304a893e2..d51597b9237e44d1fbaebd86cbe1e11febb97cd8 100644 (file)
 #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  */
index b8088cf13f938c88b263f83efa1941e3c59a1a8a..0b851b6c8664e8d5dfcde26de9b8ef3b72bcfd1a 100644 (file)
@@ -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 (file)
index 0000000..30ee627
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H    1
+
+#include <bits/endian.h>
+#include <bits/wordsize.h>
+
+struct stat
+  {
+#ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+#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 <sys/stat.h> 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 <bits/struct_stat_time64_helper.h>
+# 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 <sys/stat.h> 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  */
index 33ff88ce59942945c63650598d29a3097b3f7010..bfc674235d60c423888eaa1bcc167eb40ef7a6bd 100644 (file)
 #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).  */
index 4f1f810ea1d9bf00ff428e4e7c49a52c71620775..539b8d771618b6219b36f8113ff36c3fbeb94ec7 100644 (file)
@@ -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'.  */
index 25bd6cb6386b578949c7fc9e529cdc81cbb0ef67..fb11a3fba45fa4dc4f2ea30282ed2371e1e18c80 100644 (file)
 #include <bits/endian.h>
 #include <bits/wordsize.h>
 
-struct stat
-  {
-#ifdef __USE_TIME_BITS64
-# include <bits/struct_stat_time64_helper.h>
-#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 <bits/struct_stat_time64_helper.h>
-# 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  */
index 5b0dba08c556b72ffe150fd44a524b9351c1af57..e49b66facde8bce6d78548c4adb1666aef20cf61 100644 (file)
@@ -47,6 +47,7 @@ extern ssize_t process_vm_writev (pid_t __pid, const struct iovec *__lvec,
 #define RWF_SYNC       0x00000004 /* per-IO O_SYNC.  */
 #define RWF_NOWAIT     0x00000008 /* per-IO nonblocking mode.  */
 #define RWF_APPEND     0x00000010 /* per-IO O_APPEND.  */
+#define RWF_NOAPPEND   0x00000020 /* per-IO negation of O_APPEND */
 
 __END_DECLS
 
index fe73fe3ba84db02b1d7188de8f29d55019a69ff3..ca20043408a9472762cde6b1eb3279df22f2fd17 100644 (file)
@@ -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)
index 15b7a3a9258083979ac46656f0267a8668b5075a..24f72b797a44b32dc8e18a1bb0371fc6a3846ce5 100644 (file)
 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/csky/bits/struct_stat.h b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h
new file mode 100644 (file)
index 0000000..f0ee455
--- /dev/null
@@ -0,0 +1,135 @@
+/* Definition for struct stat.  Linux/csky 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
+   <https://www.gnu.org/licenses/>.  */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H    1
+
+#include <bits/endian.h>
+#include <bits/wordsize.h>
+
+#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 <bits/struct_stat_time64_helper.h>
+#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 <sys/stat.h> 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 <bits/struct_stat_time64_helper.h>
+# 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 <sys/stat.h> 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/dl-rseq-symbols.S b/sysdeps/unix/sysv/linux/dl-rseq-symbols.S
new file mode 100644 (file)
index 0000000..b4bba06
--- /dev/null
@@ -0,0 +1,64 @@
+/* Define symbols used by rseq.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+#if __WORDSIZE == 64
+#define RSEQ_OFFSET_SIZE       8
+#else
+#define RSEQ_OFFSET_SIZE       4
+#endif
+
+/* Some targets define a macro to denote the zero register.  */
+#undef zero
+
+/* Define 2 symbols: '__rseq_size' is public const and '_rseq_size' (an
+   alias of '__rseq_size') is hidden and writable for internal use by the
+   dynamic linker which will initialize the value both symbols point to
+   before copy relocations take place. */
+
+       .globl  __rseq_size
+       .type   __rseq_size, %object
+       .size   __rseq_size, 4
+       .hidden _rseq_size
+       .globl  _rseq_size
+       .type   _rseq_size, %object
+       .size   _rseq_size, 4
+       .section .data.rel.ro
+       .balign 4
+__rseq_size:
+_rseq_size:
+       .zero   4
+
+/* Define 2 symbols: '__rseq_offset' is public const and '_rseq_offset' (an
+   alias of '__rseq_offset') is hidden and writable for internal use by the
+   dynamic linker which will initialize the value both symbols point to
+   before copy relocations take place. */
+
+       .globl  __rseq_offset
+       .type   __rseq_offset, %object
+       .size   __rseq_offset, RSEQ_OFFSET_SIZE
+       .hidden _rseq_offset
+       .globl  _rseq_offset
+       .type   _rseq_offset, %object
+       .size   _rseq_offset, RSEQ_OFFSET_SIZE
+       .section .data.rel.ro
+       .balign RSEQ_OFFSET_SIZE
+__rseq_offset:
+_rseq_offset:
+       .zero   RSEQ_OFFSET_SIZE
diff --git a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h b/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h
deleted file mode 100644 (file)
index fb11a3f..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* Definition for struct stat.
-   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
-   <https://www.gnu.org/licenses/>.  */
-
-#if !defined _SYS_STAT_H && !defined _FCNTL_H
-# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
-#endif
-
-#ifndef _BITS_STRUCT_STAT_H
-#define _BITS_STRUCT_STAT_H    1
-
-#include <bits/endian.h>
-#include <bits/wordsize.h>
-
-#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
-  {
-    __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 <sys/stat.h> 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];
-  };
-
-#undef __field64
-
-#ifdef __USE_LARGEFILE64
-struct stat64
-  {
-    __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 <sys/stat.h> 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
-
-/* 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  */
index 064eaa08ae2f79b6f5ffb580c7d77b318494a804..4d017861206798e9ac4bacb26a591c0349bf10f5 100644 (file)
@@ -29,7 +29,7 @@
 #include <sys/sysinfo.h>
 #include <sysdep.h>
 
-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 (file)
index 0000000..38b6e13
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H    1
+
+#include <bits/endian.h>
+#include <bits/wordsize.h>
+
+struct stat
+  {
+#ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+#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 <sys/stat.h> 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 <bits/struct_stat_time64_helper.h>
+# 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 <sys/stat.h> 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 (file)
index 0000000..6ecbfe7
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#define __WORDSIZE                     32
+#define __WORDSIZE_TIME64_COMPAT32     1
+#define __WORDSIZE32_SIZE_ULONG                0
+#define __WORDSIZE32_PTRDIFF_LONG      0
index 0cd21ef0fa8b4e140c45c7af48aca6424932521a..079612e4aad88002b14d59356a7bf1c9f059a80a 100644 (file)
@@ -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
index 87893a675749579b9886ada759ec1d5dcde99f28..2f50c31a8e92162563d67e6fa7723a47adc7c42e 100644 (file)
@@ -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 <ipc_ops.h>
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 (file)
index 0000000..1844bba
--- /dev/null
@@ -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 <https://www.gnu.org/licenses/>.  */
+
+#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 (file)
index 0000000..fe6c3a0
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sys/stat.h>
+#include <sysdep.h>
+
+/* 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/mremap-failure.h b/sysdeps/unix/sysv/linux/mremap-failure.h
new file mode 100644 (file)
index 0000000..c99ab30
--- /dev/null
@@ -0,0 +1,30 @@
+/* mremap failure handling.  Linux 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+
+/* Return exit value on mremap failure with errno ERR.  */
+
+static int
+mremap_failure_exit (int err)
+{
+  if (err != EINVAL)
+    return EXIT_FAILURE;
+
+  return EXIT_UNSUPPORTED;
+}
index e829a29dbdd233a7dd52c8221db13cf917cc2b2d..c48932e56937ef089389ca447c943ede3612fe77 100644 (file)
 #include <sysdep.h>
 #include <stdarg.h>
 #include <stddef.h>
+#include <errno.h>
+
+#define MREMAP_KNOWN_BITS \
+  (MREMAP_MAYMOVE \
+   | MREMAP_FIXED \
+   | MREMAP_DONTUNMAP)
 
 void *
 __mremap (void *addr, size_t old_len, size_t new_len, int flags, ...)
@@ -27,7 +33,13 @@ __mremap (void *addr, size_t old_len, size_t new_len, int flags, ...)
   va_list va;
   void *new_addr = NULL;
 
-  if (flags & MREMAP_FIXED)
+  if (flags & ~(MREMAP_KNOWN_BITS))
+    {
+      __set_errno (EINVAL);
+      return MAP_FAILED;
+    }
+
+  if (flags & (MREMAP_FIXED | MREMAP_DONTUNMAP))
     {
       va_start (va, flags);
       new_addr = va_arg (va, void *);
index e824ebb09584f7d613471a07f838093d35424560..2072205252def23d310c0ecd73364641f35dc5a2 100644 (file)
@@ -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 (file)
index 0000000..e00e711
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H    1
+
+#include <bits/endian.h>
+#include <bits/wordsize.h>
+
+#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 <bits/struct_stat_time64_helper.h>
+#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 <sys/stat.h> 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 <bits/struct_stat_time64_helper.h>
+# 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 <sys/stat.h> 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  */
index a263d294b1bbfd00726667ae872ed829133a78a6..cf35c8bfc9043ec99b368fa9362d585c16f59c9c 100644 (file)
@@ -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);
index d7cf158b338b4fe83b1af599154e4bfc38916c3b..0ca6e69ee90257b99d56c6524e55f9c202d88f29 100644 (file)
 # 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.  */
index 04ca9debf00d7ee97ddf83dcd2e66c139bcd9d7c..6993fb6b29ea3f743dedda57771ef9e4dce2169d 100644 (file)
@@ -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
index bf4be80f8d380963384dd022eea710f8c86bdfdb..202520ee254ec02f47b34413d825ce189fbdafd6 100644 (file)
 #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
index d656aedcc2be60098dafe60a663e6d0879ca8962..4e65f337d486de1f50019bf6fce2003c7792d8ae 100644 (file)
 #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
index 210f3ec566ec81a7a7d130957131bd973207c845..1aa63eca67504e2c66d459ffd61ead5bb2d31ba1 100644 (file)
 #include <stdio.h>
 #include <sys/rseq.h>
 
+/* 32 is the initially required value for the area size.  The
+   actually used rseq size may be less (20 bytes initially).  */
+#define RSEQ_AREA_SIZE_INITIAL 32
+#define RSEQ_AREA_SIZE_INITIAL_USED 20
+
+/* The variables are in .data.relro but are not yet write-protected.  */
+extern unsigned int _rseq_size attribute_hidden;
+extern ptrdiff_t _rseq_offset attribute_hidden;
+
 #ifdef RSEQ_SIG
 static inline bool
 rseq_register_current_thread (struct pthread *self, bool do_rseq)
 {
   if (do_rseq)
     {
+      unsigned int size;
+#if IS_IN (rtld)
+      /* Use the hidden symbol in ld.so.  */
+      size = _rseq_size;
+#else
+      size = __rseq_size;
+#endif
+      if (size < RSEQ_AREA_SIZE_INITIAL)
+        /* The initial implementation used only 20 bytes out of 32,
+           but still expected size 32.  */
+        size = RSEQ_AREA_SIZE_INITIAL;
+
+      /* Initialize the rseq fields that are read by the kernel on
+         registration, there is no guarantee that struct pthread is
+         cleared on all architectures.  */
+      THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_UNINITIALIZED);
+      THREAD_SETMEM (self, rseq_area.cpu_id_start, 0);
+      THREAD_SETMEM (self, rseq_area.rseq_cs, 0);
+      THREAD_SETMEM (self, rseq_area.flags, 0);
+
       int ret = INTERNAL_SYSCALL_CALL (rseq, &self->rseq_area,
-                                       sizeof (self->rseq_area),
-                                       0, RSEQ_SIG);
+                                       size, 0, RSEQ_SIG);
       if (!INTERNAL_SYSCALL_ERROR_P (ret))
         return true;
     }
+  /* When rseq is disabled by tunables or the registration fails, inform
+     userspace by setting 'cpu_id' to RSEQ_CPU_ID_REGISTRATION_FAILED.  */
   THREAD_SETMEM (self, rseq_area.cpu_id, RSEQ_CPU_ID_REGISTRATION_FAILED);
   return false;
 }
index 5c3301004cc9f39db8a4c838dcb8bf3e5c7beeb0..3a2f71238622864c07112b3da062034bc6190e92 100644 (file)
@@ -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 */
index 77a8130c18b2cf76e8457791ce232db489f2ea9f..3458b018bc5b58f207df4b797e1130759745e62b 100644 (file)
@@ -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 (file)
index 0000000..0f7c9cd
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include <bits/struct_stat.h> directly; use <sys/stat.h> instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H    1
+
+#include <bits/endian.h>
+#include <bits/wordsize.h>
+
+struct stat
+  {
+#ifdef __USE_TIME_BITS64
+# include <bits/struct_stat_time64_helper.h>
+#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 <sys/stat.h> 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 <bits/struct_stat_time64_helper.h>
+# 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 <sys/stat.h> 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  */
index ea389354973edbe13533370eb7b766e9029fc965..f00817a6f62de8402a1c14320e326bd0dbd94b90 100644 (file)
@@ -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)
index 7562875ee23ba8c52156e7e0fa1f4457ae15286e..ea103e5970829abc52731614b8835e1796606b4d 100644 (file)
@@ -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
index 2829e881eb6f0e6d7120a8ddcbc6631d61dd7ffc..a1492ea59eddd1aeff0e50889adc2e7054304b5b 100644 (file)
 
    [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)
index ac6af95e3688aa675026748e2446c0cf0d102f1d..23b8b93f56a5ae36616bbea380eaa5dfb2b25138 100644 (file)
 
    [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)
index f965986ba8771af5441ee83b618831873f504340..19841d07385244813e3773d872348d37dcc8c97d 100644 (file)
 #include <stddef.h>
 #include <sys/ioctl.h>
 
-#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<<BLOCK_SIZE_BITS)
 
 
 /* These are the fs-independent mount-flags: up to 16 flags are
    supported  */
 enum
 {
+#undef MS_RDONLY
   MS_RDONLY = 1,               /* Mount read-only.  */
 #define MS_RDONLY      MS_RDONLY
+#undef MS_NOSUID
   MS_NOSUID = 2,               /* Ignore suid and sgid bits.  */
 #define MS_NOSUID      MS_NOSUID
+#undef MS_NODEV
   MS_NODEV = 4,                        /* Disallow access to device special files.  */
 #define MS_NODEV       MS_NODEV
+#undef MS_NOEXEC
   MS_NOEXEC = 8,               /* Disallow program execution.  */
 #define MS_NOEXEC      MS_NOEXEC
+#undef MS_SYNCHRONOUS
   MS_SYNCHRONOUS = 16,         /* Writes are synced at once.  */
 #define MS_SYNCHRONOUS MS_SYNCHRONOUS
+#undef MS_REMOUNT
   MS_REMOUNT = 32,             /* Alter flags of a mounted FS.  */
 #define MS_REMOUNT     MS_REMOUNT
+#undef MS_MANDLOCK
   MS_MANDLOCK = 64,            /* Allow mandatory locks on an FS.  */
 #define MS_MANDLOCK    MS_MANDLOCK
+#undef MS_DIRSYNC
   MS_DIRSYNC = 128,            /* Directory modifications are synchronous.  */
 #define MS_DIRSYNC     MS_DIRSYNC
+#undef MS_NOSYMFOLLOW
   MS_NOSYMFOLLOW = 256,                /* Do not follow symlinks.  */
 #define MS_NOSYMFOLLOW MS_NOSYMFOLLOW
+#undef MS_NOATIME
   MS_NOATIME = 1024,           /* Do not update access times.  */
 #define MS_NOATIME     MS_NOATIME
+#undef MS_NODIRATIME
   MS_NODIRATIME = 2048,                /* Do not update directory access times.  */
 #define MS_NODIRATIME  MS_NODIRATIME
+#undef MS_BIND
   MS_BIND = 4096,              /* Bind directory at different place.  */
 #define MS_BIND                MS_BIND
+#undef MS_MOVE
   MS_MOVE = 8192,
 #define MS_MOVE                MS_MOVE
+#undef MS_REC
   MS_REC = 16384,
 #define MS_REC         MS_REC
+#undef MS_SILENT
   MS_SILENT = 32768,
 #define MS_SILENT      MS_SILENT
+#undef MS_POSIXACL
   MS_POSIXACL = 1 << 16,       /* VFS does not apply the umask.  */
 #define MS_POSIXACL    MS_POSIXACL
+#undef MS_UNBINDABLE
   MS_UNBINDABLE = 1 << 17,     /* Change to unbindable.  */
 #define MS_UNBINDABLE  MS_UNBINDABLE
+#undef MS_PRIVATE
   MS_PRIVATE = 1 << 18,                /* Change to private.  */
 #define MS_PRIVATE     MS_PRIVATE
+#undef MS_SLAVE
   MS_SLAVE = 1 << 19,          /* Change to slave.  */
 #define MS_SLAVE       MS_SLAVE
+#undef MS_SHARED
   MS_SHARED = 1 << 20,         /* Change to shared.  */
 #define MS_SHARED      MS_SHARED
+#undef MS_RELATIME
   MS_RELATIME = 1 << 21,       /* Update atime relative to mtime/ctime.  */
 #define MS_RELATIME    MS_RELATIME
+#undef MS_KERNMOUNT
   MS_KERNMOUNT = 1 << 22,      /* This is a kern_mount call.  */
 #define MS_KERNMOUNT   MS_KERNMOUNT
+#undef MS_I_VERSION
   MS_I_VERSION =  1 << 23,     /* Update inode I_version field.  */
 #define MS_I_VERSION   MS_I_VERSION
+#undef MS_STRICTATIME
   MS_STRICTATIME = 1 << 24,    /* Always perform atime updates.  */
 #define MS_STRICTATIME MS_STRICTATIME
+#undef MS_LAZYTIME
   MS_LAZYTIME = 1 << 25,       /* Update the on-disk [acm]times lazily.  */
 #define MS_LAZYTIME    MS_LAZYTIME
+#undef MS_ACTIVE
   MS_ACTIVE = 1 << 30,
 #define MS_ACTIVE      MS_ACTIVE
+#undef MS_NOUSER
   MS_NOUSER = 1 << 31
 #define MS_NOUSER      MS_NOUSER
 };
 
 /* Flags that can be altered by MS_REMOUNT  */
+#undef MS_RMT_MASK
 #define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_I_VERSION \
                     |MS_LAZYTIME)
 
 
 /* Magic mount flag number. Has to be or-ed to the flag values.  */
 
+#undef MS_MGC_VAL
 #define MS_MGC_VAL 0xc0ed0000  /* Magic flag number to indicate "new" flags */
 #define MS_MGC_MSK 0xffff0000  /* Magic flag number mask */
 
@@ -106,20 +142,35 @@ enum
    is probably as bad and I don't want to create yet another include
    file.  */
 
+#undef BLKROSET
 #define BLKROSET   _IO(0x12, 93) /* Set device read-only (0 = read-write).  */
+#undef BLKROGET
 #define BLKROGET   _IO(0x12, 94) /* Get read-only status (0 = read_write).  */
+#undef BLKRRPART
 #define BLKRRPART  _IO(0x12, 95) /* Re-read partition table.  */
+#undef BLKGETSIZE
 #define BLKGETSIZE _IO(0x12, 96) /* Return device size.  */
+#undef BLKFLSBUF
 #define BLKFLSBUF  _IO(0x12, 97) /* Flush buffer cache.  */
+#undef BLKRASET
 #define BLKRASET   _IO(0x12, 98) /* Set read ahead for block device.  */
+#undef BLKRAGET
 #define BLKRAGET   _IO(0x12, 99) /* Get current read ahead setting.  */
+#undef BLKFRASET
 #define BLKFRASET  _IO(0x12,100) /* Set filesystem read-ahead.  */
+#undef BLKFRAGET
 #define BLKFRAGET  _IO(0x12,101) /* Get filesystem read-ahead.  */
+#undef BLKSECTSET
 #define BLKSECTSET _IO(0x12,102) /* Set max sectors per request.  */
+#undef BLKSECTGET
 #define BLKSECTGET _IO(0x12,103) /* Get max sectors per request.  */
+#undef BLKSSZGET
 #define BLKSSZGET  _IO(0x12,104) /* Get block device sector size.  */
+#undef BLKBSZGET
 #define BLKBSZGET  _IOR(0x12,112,size_t)
+#undef BLKBSZSET
 #define BLKBSZSET  _IOW(0x12,113,size_t)
+#undef BLKGETSIZE64
 #define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size.  */
 
 
@@ -137,9 +188,6 @@ enum
 };
 
 
-/* fsopen flags.  */
-#define FSOPEN_CLOEXEC          0x00000001
-
 /* fsmount flags.  */
 #define FSMOUNT_CLOEXEC         0x00000001
 
@@ -157,6 +205,7 @@ enum
 #define MOUNT_ATTR_NOSYMFOLLOW  0x00200000 /* Do not follow symlinks.  */
 
 
+#ifndef MOUNT_ATTR_SIZE_VER0
 /* For mount_setattr.  */
 struct mount_attr
 {
@@ -165,6 +214,7 @@ struct mount_attr
   uint64_t propagation;
   uint64_t userns_fd;
 };
+#endif
 
 #define MOUNT_ATTR_SIZE_VER0    32 /* sizeof first published struct */
 
@@ -185,26 +235,31 @@ struct mount_attr
 #define FSPICK_EMPTY_PATH       0x00000008
 
 
+#ifndef FSOPEN_CLOEXEC
 /* The type of fsconfig call made.   */
 enum fsconfig_command
 {
   FSCONFIG_SET_FLAG       = 0,    /* Set parameter, supplying no value */
-#define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
+# define FSCONFIG_SET_FLAG FSCONFIG_SET_FLAG
   FSCONFIG_SET_STRING     = 1,    /* Set parameter, supplying a string value */
-#define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
+# define FSCONFIG_SET_STRING FSCONFIG_SET_STRING
   FSCONFIG_SET_BINARY     = 2,    /* Set parameter, supplying a binary blob value */
-#define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
+# define FSCONFIG_SET_BINARY FSCONFIG_SET_BINARY
   FSCONFIG_SET_PATH       = 3,    /* Set parameter, supplying an object by path */
-#define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
+# define FSCONFIG_SET_PATH FSCONFIG_SET_PATH
   FSCONFIG_SET_PATH_EMPTY = 4,    /* Set parameter, supplying an object by (empty) path */
-#define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
+# define FSCONFIG_SET_PATH_EMPTY FSCONFIG_SET_PATH_EMPTY
   FSCONFIG_SET_FD         = 5,    /* Set parameter, supplying an object by fd */
-#define FSCONFIG_SET_FD FSCONFIG_SET_FD
+# define FSCONFIG_SET_FD FSCONFIG_SET_FD
   FSCONFIG_CMD_CREATE     = 6,    /* Invoke superblock creation */
-#define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
+# define FSCONFIG_CMD_CREATE FSCONFIG_CMD_CREATE
   FSCONFIG_CMD_RECONFIGURE = 7,   /* Invoke superblock reconfiguration */
-#define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
+# define FSCONFIG_CMD_RECONFIGURE FSCONFIG_CMD_RECONFIGURE
 };
+#endif
+
+/* fsopen flags.  */
+#define FSOPEN_CLOEXEC          0x00000001
 
 /* open_tree flags.  */
 #define OPEN_TREE_CLONE    1         /* Clone the target tree and attach the clone */
index 6c7b2f70117757275e947855b310c313b38b0eb6..028ad3107a5116659ec00846310322c956f6bbe6 100644 (file)
@@ -21,8 +21,8 @@
 # This file can list all potential system calls.  The names are only
 # used if the installed kernel headers also provide them.
 
-# The list of system calls is current as of Linux 5.18.
-kernel 5.18
+# The list of system calls is current as of Linux 5.19.
+kernel 5.19
 
 FAST_atomic_update
 FAST_cmpxchg
diff --git a/sysdeps/unix/sysv/linux/tst-linux-mremap1.c b/sysdeps/unix/sysv/linux/tst-linux-mremap1.c
new file mode 100644 (file)
index 0000000..408e8af
--- /dev/null
@@ -0,0 +1,63 @@
+/* Test mremap with MREMAP_DONTUNMAP.
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/mman.h>
+#include <support/xstdlib.h>
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+#include <mremap-failure.h>
+
+static int
+do_test (void)
+{
+  size_t old_size = getpagesize ();
+  size_t new_size = old_size;
+  char *old_addr = xmmap (NULL, old_size, PROT_READ | PROT_WRITE,
+                         MAP_PRIVATE | MAP_ANONYMOUS, -1);
+  old_addr[0] = 1;
+  old_addr[old_size - 1] = 2;
+
+  /* Create an available 64-page mmap region.  */
+  size_t fixed_size = old_size * 64;
+  char *fixed_addr = xmmap (NULL, fixed_size, PROT_READ | PROT_WRITE,
+                           MAP_PRIVATE | MAP_ANONYMOUS, -1);
+  xmunmap (fixed_addr, fixed_size);
+
+  /* Add 3 * pagesize.  */
+  fixed_size += 3 * old_size;
+
+  /* Test MREMAP_DONTUNMAP.  It should return FIXED_ADDR created above.  */
+  char *new_addr = mremap (old_addr, old_size, new_size,
+                          MREMAP_DONTUNMAP | MREMAP_MAYMOVE,
+                          fixed_addr);
+  if (new_addr == MAP_FAILED)
+    return mremap_failure_exit (errno);
+  TEST_VERIFY_EXIT (fixed_addr == new_addr);
+  old_addr[0] = 3;
+  old_addr[old_size - 1] = 4;
+  new_addr[0] = 1;
+  new_addr[new_size - 1] = 2;
+  xmunmap (new_addr, new_size);
+  xmunmap (old_addr, old_size);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/tst-mount-compile.py b/sysdeps/unix/sysv/linux/tst-mount-compile.py
new file mode 100755 (executable)
index 0000000..0ec74d4
--- /dev/null
@@ -0,0 +1,66 @@
+#!/usr/bin/python3
+# Check if glibc provided sys/mount.h can be used along related kernel
+# headers.
+# 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
+# <https://www.gnu.org/licenses/>.
+
+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 <linux/mount.h>',
+            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 <sys/mount.h>\n"
+              "#include <linux/mount.h>"),
+        check("sys/mount.h + linux/fs.h",
+              "#include <sys/mount.h>\n"
+              "#include <linux/fs.h>"),
+        check("linux/mount.h + sys/mount.h",
+              "#include <linux/mount.h>\n"
+              "#include <sys/mount.h>"),
+        check("linux/fs.h + sys/mount.h",
+              "#include <linux/fs.h>\n"
+              "#include <sys/mount.h>"))
+    sys.exit(status)
+
+if __name__ == '__main__':
+    main()
index a62f803123706c9e2cd71cafcd62a5131f87b7bf..be2ef2daf10e8f07468f79ebd7febef47c1fb74b 100755 (executable)
@@ -33,6 +33,11 @@ def main():
                         help='C compiler (including options) to use')
     args = parser.parse_args()
 
+    if glibcextract.compile_c_snippet(
+            '#include <linux/mount.h>',
+            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
index 90cbb9be642f11d028fcef38c9673a3a57a8167e..d732173abda91332f6d586280cb776c3d047ba0d 100644 (file)
@@ -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 <linux/pidfd.h>',
+            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 <sys/pidfd.h>\n',
                 '#include <asm/fcntl.h>\n'
index 037af22290a76ac6eb75cc87d2aba5d7e214cb38..5711d1c312948ca0f1436bfb08bcc5e40cdcec09 100644 (file)
@@ -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);
index e1a2c02f784dd9cc7687fd86f39cb9ad101fd5da..a46b0d0562c405535788fc59818d5a8d4828a793 100644 (file)
@@ -22,6 +22,7 @@
 #include <support/xthread.h>
 #include <sysdep.h>
 #include <thread_pointer.h>
+#include <sys/rseq.h>
 #include <unistd.h>
 
 #ifdef RSEQ_SIG
index fa6a89541f972ec1771f38b11cfd645eaa39456d..613593f7f97f39acd1b2d2168c92f2a7e0971997 100644 (file)
@@ -29,6 +29,7 @@
 # include <stdlib.h>
 # include <string.h>
 # include <syscall.h>
+# include <sys/auxv.h>
 # include <thread_pointer.h>
 # include <tls.h>
 # include "tst-rseq.h"
@@ -42,7 +43,8 @@ do_rseq_main_test (void)
   TEST_COMPARE (__rseq_flags, 0);
   TEST_VERIFY ((char *) __thread_pointer () + __rseq_offset
                == (char *) &pd->rseq_area);
-  TEST_COMPARE (__rseq_size, sizeof (pd->rseq_area));
+  /* The current implementation only supports the initial size.  */
+  TEST_COMPARE (__rseq_size, 20);
 }
 
 static void
@@ -52,6 +54,12 @@ do_rseq_test (void)
     {
       FAIL_UNSUPPORTED ("kernel does not support rseq, skipping test");
     }
+  printf ("info: __rseq_size: %u\n", __rseq_size);
+  printf ("info: __rseq_offset: %td\n", __rseq_offset);
+  printf ("info: __rseq_flags: %u\n", __rseq_flags);
+  printf ("info: getauxval (AT_RSEQ_FEATURE_SIZE): %ld\n",
+          getauxval (AT_RSEQ_FEATURE_SIZE));
+  printf ("info: getauxval (AT_RSEQ_ALIGN): %ld\n", getauxval (AT_RSEQ_ALIGN));
   do_rseq_main_test ();
 }
 #else /* RSEQ_SIG */
index 56fd5fc805c41cede6e84472a53846bc3837ab3d..d680a9269570db5a297afc22c133c289cf39fc2c 100644 (file)
@@ -10,38 +10,53 @@ sysdep_headers += sys/platform/x86.h bits/platform/x86.h
 CFLAGS-dl-get-cpu-features.os += $(rtld-early-cflags)
 CFLAGS-get-cpuid-feature-leaf.o += $(no-stack-protector)
 
-tests += tst-get-cpu-features tst-get-cpu-features-static \
-        tst-cpu-features-cpuinfo tst-cpu-features-cpuinfo-static \
-        tst-cpu-features-supports tst-cpu-features-supports-static
-tests-static += tst-get-cpu-features-static \
-               tst-cpu-features-cpuinfo-static \
-               tst-cpu-features-supports-static
+tests += \
+  tst-get-cpu-features \
+  tst-get-cpu-features-static \
+  tst-cpu-features-cpuinfo \
+  tst-cpu-features-cpuinfo-static \
+  tst-cpu-features-supports \
+  tst-cpu-features-supports-static \
+# tests
+tests-static += \
+  tst-get-cpu-features-static \
+  tst-cpu-features-cpuinfo-static \
+  tst-cpu-features-supports-static \
+# tests-static
 ifeq (yes,$(have-ifunc))
 ifeq (yes,$(have-gcc-ifunc))
 tests += \
   tst-ifunc-isa-1 \
-  tst-ifunc-isa-1-static
+  tst-ifunc-isa-1-static \
+# tests
 tests-static += \
-  tst-ifunc-isa-1-static
+  tst-ifunc-isa-1-static \
+# tests-static
 test-xfail-tst-ifunc-isa-1 = $(with-lld)
 test-xfail-tst-ifunc-isa-1-static = $(with-lld)
 ifneq ($(have-tunables),no)
 tests += \
   tst-ifunc-isa-2 \
-  tst-ifunc-isa-2-static
+  tst-ifunc-isa-2-static \
+# tests
 tests-static += \
-  tst-ifunc-isa-2-static
+  tst-ifunc-isa-2-static \
+# tests-static
 test-xfail-tst-ifunc-isa-2 = $(with-lld)
 test-xfail-tst-ifunc-isa-2-static = $(with-lld)
 endif
 endif
 endif
 ifeq (yes,$(enable-x86-isa-level))
-tests += tst-isa-level-1
-modules-names += tst-isa-level-mod-1-baseline \
-                tst-isa-level-mod-1-v2 \
-                tst-isa-level-mod-1-v3 \
-                tst-isa-level-mod-1-v4 \
+tests += \
+  tst-isa-level-1 \
+# tests
+modules-names += \
+  tst-isa-level-mod-1-baseline \
+  tst-isa-level-mod-1-v2 \
+  tst-isa-level-mod-1-v3 \
+  tst-isa-level-mod-1-v4 \
+# modules-names
 
 # X86 ISA level baseline
 CFLAGS-tst-isa-level-mod-1-baseline.c += -DINCLUDE_X86_ISA_LEVEL \
@@ -72,7 +87,9 @@ endif
 endif
 
 ifeq ($(subdir),math)
-tests += tst-ldbl-nonnormal-printf
+tests += \
+ tst-ldbl-nonnormal-printf \
+# tests
 endif # $(subdir) == math
 
 ifeq ($(subdir),setjmp)
@@ -80,7 +97,9 @@ gen-as-const-headers += jmp_buf-ssp.sym
 sysdep_routines += __longjmp_cancel
 ifneq ($(enable-cet),no)
 ifneq ($(have-tunables),no)
-tests += tst-setjmp-cet
+tests += \
+  tst-setjmp-cet \
+# tests
 tst-setjmp-cet-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on
 endif
 endif
@@ -128,22 +147,47 @@ ifneq ($(enable-cet),no)
 ifeq ($(subdir),elf)
 sysdep-dl-routines += dl-cet
 
-tests += tst-cet-legacy-1 tst-cet-legacy-1a tst-cet-legacy-2 \
-        tst-cet-legacy-2a tst-cet-legacy-3 tst-cet-legacy-4 \
-        tst-cet-legacy-5a tst-cet-legacy-6a tst-cet-legacy-7 \
-        tst-cet-legacy-8 tst-cet-legacy-9 tst-cet-legacy-9-static \
-        tst-cet-legacy-10 tst-cet-legacy-10-static
-tests-static += tst-cet-legacy-9-static tst-cet-legacy-10-static
+tests += \
+  tst-cet-legacy-1 \
+  tst-cet-legacy-1a \
+  tst-cet-legacy-2 \
+  tst-cet-legacy-2a \
+  tst-cet-legacy-3 \
+  tst-cet-legacy-4 \
+  tst-cet-legacy-5a \
+  tst-cet-legacy-6a \
+  tst-cet-legacy-7 \
+  tst-cet-legacy-8 \
+  tst-cet-legacy-9 \
+  tst-cet-legacy-9-static \
+  tst-cet-legacy-10 \
+  tst-cet-legacy-10-static \
+# tests
+tests-static += \
+  tst-cet-legacy-9-static \
+  tst-cet-legacy-10-static \
+# tests-static
 tst-cet-legacy-1a-ARGS = -- $(host-test-program-cmd)
 ifneq (no,$(have-tunables))
-tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \
-        tst-cet-legacy-5b tst-cet-legacy-6b
+tests += \
+  tst-cet-legacy-4a \
+  tst-cet-legacy-4b \
+  tst-cet-legacy-4c \
+  tst-cet-legacy-5b \
+  tst-cet-legacy-6b \
+# tests
 endif
-modules-names += tst-cet-legacy-mod-1 tst-cet-legacy-mod-2 \
-                tst-cet-legacy-mod-4 tst-cet-legacy-mod-5a \
-                tst-cet-legacy-mod-5b tst-cet-legacy-mod-5c \
-                tst-cet-legacy-mod-6a tst-cet-legacy-mod-6b \
-                tst-cet-legacy-mod-6c
+modules-names += \
+  tst-cet-legacy-mod-1 \
+  tst-cet-legacy-mod-2 \
+  tst-cet-legacy-mod-4 \
+  tst-cet-legacy-mod-5a \
+  tst-cet-legacy-mod-5b \
+  tst-cet-legacy-mod-5c \
+  tst-cet-legacy-mod-6a \
+  tst-cet-legacy-mod-6b \
+  tst-cet-legacy-mod-6c \
+# modules-names
 
 CFLAGS-tst-cet-legacy-2.c += -fcf-protection=branch
 CFLAGS-tst-cet-legacy-2a.c += -fcf-protection
@@ -253,7 +297,9 @@ endif
 ifeq ($(subdir),posix)
 tests += \
   tst-sysconf-cache-linesize \
-  tst-sysconf-cache-linesize-static
+  tst-sysconf-cache-linesize-static \
+# tests
 tests-static += \
-  tst-sysconf-cache-linesize-static
+  tst-sysconf-cache-linesize-static \
+# tests-static
 endif
index 70f652bca14d65c1de5a21669e7c0ffb8ecfe5ea..3f40aa76f99c75e5aabc1390ab4a2ff4647e6035 100644 (file)
@@ -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
index e9f338210863b0a18226dfe0d43d677a27d58c51..16ee0f5b36e33db4558e3c2a020fa9c440f684dd 100644 (file)
@@ -187,7 +187,7 @@ intel_check_word (int name, unsigned int value, bool *has_level_2,
              ++round;
            }
          /* There is no other cache information anywhere else.  */
-         break;
+         return -1;
        }
       else
        {
@@ -257,28 +257,23 @@ handle_intel (int name, const struct cpu_features *cpu_features)
 
   /* OK, we can use the CPUID instruction to get all info about the
      caches.  */
-  unsigned int cnt = 0;
-  unsigned int max = 1;
   long int result = 0;
   bool no_level_2_or_3 = false;
   bool has_level_2 = false;
+  unsigned int eax;
+  unsigned int ebx;
+  unsigned int ecx;
+  unsigned int edx;
+  __cpuid (2, eax, ebx, ecx, edx);
 
-  while (cnt++ < max)
+  /* The low byte of EAX of CPUID leaf 2 should always return 1 and it
+     should be ignored.  If it isn't 1, use CPUID leaf 4 instead.  */
+  if ((eax & 0xff) != 1)
+    return intel_check_word (name, 0xff, &has_level_2, &no_level_2_or_3,
+                            cpu_features);
+  else
     {
-      unsigned int eax;
-      unsigned int ebx;
-      unsigned int ecx;
-      unsigned int edx;
-      __cpuid (2, eax, ebx, ecx, edx);
-
-      /* The low byte of EAX in the first round contain the number of
-        rounds we have to make.  At least one, the one we are already
-        doing.  */
-      if (cnt == 1)
-       {
-         max = eax & 0xff;
-         eax &= 0xffffff00;
-       }
+      eax &= 0xffffff00;
 
       /* Process the individual registers' value.  */
       result = intel_check_word (name, eax, &has_level_2,
@@ -478,7 +473,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 +492,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 +508,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 +665,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 +699,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 +720,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 +744,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 +765,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 +790,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 +818,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 +829,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,26 +853,55 @@ 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.  */
-  unsigned int minimum_rep_movsb_threshold;
+  unsigned long int minimum_rep_movsb_threshold;
 #endif
   /* NB: The default REP MOVSB threshold is 4096 * (VEC_SIZE / 16) for
      VEC_SIZE == 64 or 32.  For VEC_SIZE == 16, the default REP MOVSB
      threshold is 2048 * (VEC_SIZE / 16).  */
-  unsigned int rep_movsb_threshold;
+  unsigned long int rep_movsb_threshold;
   if (CPU_FEATURE_USABLE_P (cpu_features, AVX512F)
       && !CPU_FEATURE_PREFERRED_P (cpu_features, Prefer_No_AVX512))
     {
@@ -915,8 +947,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 +963,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,
index 1ade78ab73ed261fcaef776abe632c3bf755614e..5b4dd5f062283b12eab59ab173488170f9330291 100644 (file)
@@ -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)
index 3c4480aba70193a22cc07703a421a81dde82fd3c..06f6c9663e76d4a48efb8fbfdb707cc5045f47dc 100644 (file)
@@ -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 (file)
index 0000000..8f21ebe
--- /dev/null
@@ -0,0 +1,2 @@
+#define UTMP_SIZE 384
+#define LASTLOG_SIZE 292
index 24a6e643b08f54a0cd2d813003ab03fdb395584a..86517573dc665d7c0f01fec26b026e49f1f4d95a 100644 (file)
@@ -40,9 +40,12 @@ __tls_get_addr_slow (GET_ADDR_ARGS)
 {
   dtv_t *dtv = THREAD_DTV ();
 
-  size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
-  if (__glibc_unlikely (dtv[0].counter != gen))
-    return update_get_addr (GET_ADDR_PARAM);
+  size_t gen = atomic_load_acquire (&GL(dl_tls_generation));
+  if (__glibc_unlikely (dtv[0].counter != gen)
+      /* See comment in __tls_get_addr in elf/dl-tls.c.  */
+      && !(_dl_tls_allocate_active ()
+           && GET_ADDR_MODULE < _dl_tls_initial_modid_limit))
+    return update_get_addr (GET_ADDR_PARAM, gen);
 
   return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);
 }
index 0db2cb41526a1651982c5e52759426ff1754fe1d..7619e743e1be41bf5431081780e9ab58809b96cd 100644 (file)
@@ -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:
index 842ebaeb4cceb27bc23db4a52b43258c86c12d31..d352866d9fe36ecc9a6c3df9fd6a44a5889702ef 100644 (file)
@@ -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__
index 864f4777a26d740c6a33357c2227fd25c3770f85..23446ff4acd90aae828086688d621afde5aad303 100644 (file)
@@ -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;
     }
 
index 248162525bab14ee123f0f8b84f2dbaa697c3145..ea81753b708fcb8dacb17d49a4e3f58560d1dac2 100644 (file)
@@ -1,32 +1,78 @@
 ifeq ($(subdir),math)
-libm-sysdep_routines += s_floor-c s_ceil-c s_floorf-c s_ceilf-c \
-                       s_rint-c s_rintf-c s_nearbyint-c s_nearbyintf-c \
-                       s_roundeven-c s_roundevenf-c s_trunc-c s_truncf-c
+libm-sysdep_routines += \
+  s_ceil-c \
+  s_ceilf-c \
+  s_floor-c \
+  s_floorf-c \
+  s_rint-c \
+  s_rintf-c \
+  s_nearbyint-c \
+  s_nearbyintf-c \
+  s_roundeven-c \
+  s_roundevenf-c \
+  s_trunc-c \
+  s_truncf-c \
+# libm-sysdep_routines
 
-libm-sysdep_routines += s_ceil-sse4_1 s_ceilf-sse4_1 s_floor-sse4_1 \
-                       s_floorf-sse4_1 s_nearbyint-sse4_1 \
-                       s_nearbyintf-sse4_1 s_roundeven-sse4_1 \
-                       s_roundevenf-sse4_1 s_rint-sse4_1 s_rintf-sse4_1 \
-                       s_trunc-sse4_1 s_truncf-sse4_1
+libm-sysdep_routines += \
+  s_ceil-sse4_1 \
+  s_ceilf-sse4_1 \
+  s_floor-sse4_1 \
+  s_floorf-sse4_1 \
+  s_nearbyint-sse4_1 \
+  s_nearbyintf-sse4_1 \
+  s_roundeven-sse4_1 \
+  s_roundevenf-sse4_1 \
+  s_rint-sse4_1 \
+  s_rintf-sse4_1 \
+  s_trunc-sse4_1 \
+  s_truncf-sse4_1 \
+# libm-sysdep_routines
 
-libm-sysdep_routines += e_exp-fma e_log-fma e_pow-fma s_atan-fma \
-                       e_asin-fma e_atan2-fma s_sin-fma s_tan-fma \
-                       s_sincos-fma
+libm-sysdep_routines += \
+  e_asin-fma \
+  e_atan2-fma \
+  e_exp-fma \
+  e_log-fma \
+  e_log2-fma \
+  e_pow-fma \
+  s_atan-fma \
+  s_expm1-fma \
+  s_log1p-fma \
+  s_sin-fma \
+  s_sincos-fma \
+  s_tan-fma \
+# libm-sysdep_routines
 
 CFLAGS-e_asin-fma.c = -mfma -mavx2
 CFLAGS-e_atan2-fma.c = -mfma -mavx2
 CFLAGS-e_exp-fma.c = -mfma -mavx2
 CFLAGS-e_log-fma.c = -mfma -mavx2
+CFLAGS-e_log2-fma.c = -mfma -mavx2
 CFLAGS-e_pow-fma.c = -mfma -mavx2
 CFLAGS-s_atan-fma.c = -mfma -mavx2
+CFLAGS-s_expm1-fma.c = -mfma -mavx2
+CFLAGS-s_log1p-fma.c = -mfma -mavx2
 CFLAGS-s_sin-fma.c = -mfma -mavx2
 CFLAGS-s_tan-fma.c = -mfma -mavx2
 CFLAGS-s_sincos-fma.c = -mfma -mavx2
 
-libm-sysdep_routines += s_sinf-sse2 s_cosf-sse2 s_sincosf-sse2
+libm-sysdep_routines += \
+  s_cosf-sse2 \
+  s_sincosf-sse2 \
+  s_sinf-sse2 \
+# libm-sysdep_routines
 
-libm-sysdep_routines += e_exp2f-fma e_expf-fma e_log2f-fma e_logf-fma \
-                       e_powf-fma s_sinf-fma s_cosf-fma s_sincosf-fma
+libm-sysdep_routines += \
+  e_exp2f-fma \
+  e_expf-fma \
+  e_log2f-fma \
+  e_logf-fma \
+  e_powf-fma \
+  s_cosf-fma \
+  s_sincosf-fma \
+  s_sinf-fma \
+# libm-sysdep_routines
 
 CFLAGS-e_exp2f-fma.c = -mfma -mavx2
 CFLAGS-e_expf-fma.c = -mfma -mavx2
@@ -37,9 +83,17 @@ CFLAGS-s_sinf-fma.c = -mfma -mavx2
 CFLAGS-s_cosf-fma.c = -mfma -mavx2
 CFLAGS-s_sincosf-fma.c = -mfma -mavx2
 
-libm-sysdep_routines += e_exp-fma4 e_log-fma4 e_pow-fma4 s_atan-fma4 \
-                       e_asin-fma4 e_atan2-fma4 s_sin-fma4 s_tan-fma4 \
-                       s_sincos-fma4
+libm-sysdep_routines += \
+  e_exp-fma4 \
+  e_log-fma4 \
+  e_pow-fma4 \
+  e_asin-fma4 \
+  s_atan-fma4 \
+  e_atan2-fma4 \
+  s_sin-fma4 \
+  s_sincos-fma4 \
+  s_tan-fma4 \
+# libm-sysdep_routines
 
 CFLAGS-e_asin-fma4.c = -mfma4
 CFLAGS-e_atan2-fma4.c = -mfma4
@@ -51,9 +105,15 @@ CFLAGS-s_sin-fma4.c = -mfma4
 CFLAGS-s_tan-fma4.c = -mfma4
 CFLAGS-s_sincos-fma4.c = -mfma4
 
-libm-sysdep_routines += e_exp-avx e_log-avx s_atan-avx \
-                       e_atan2-avx s_sin-avx s_tan-avx \
-                       s_sincos-avx
+libm-sysdep_routines += \
+  e_exp-avx \
+  e_log-avx \
+  s_atan-avx \
+  e_atan2-avx \
+  s_sin-avx \
+  s_sincos-avx \
+  s_tan-avx \
+# libm-sysdep_routines
 
 CFLAGS-e_atan2-avx.c = -msse2avx -DSSE2AVX
 CFLAGS-e_exp-avx.c = -msse2avx -DSSE2AVX
diff --git a/sysdeps/x86_64/fpu/multiarch/e_log2-fma.c b/sysdeps/x86_64/fpu/multiarch/e_log2-fma.c
new file mode 100644 (file)
index 0000000..9fbebc1
--- /dev/null
@@ -0,0 +1,3 @@
+#define __log2 __log2_fma
+
+#include <sysdeps/ieee754/dbl-64/e_log2.c>
diff --git a/sysdeps/x86_64/fpu/multiarch/e_log2.c b/sysdeps/x86_64/fpu/multiarch/e_log2.c
new file mode 100644 (file)
index 0000000..c0320ca
--- /dev/null
@@ -0,0 +1,43 @@
+/* Multiple versions of log2.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <libm-alias-double.h>
+#include <libm-alias-finite.h>
+
+extern double __redirect_log2 (double);
+
+#define SYMBOL_NAME log2
+#include "ifunc-fma.h"
+
+libc_ifunc_redirected (__redirect_log2, __log2, IFUNC_SELECTOR ());
+
+#ifdef SHARED
+__hidden_ver1 (__log2, __GI___log2, __redirect_log2)
+  __attribute__ ((visibility ("hidden")));
+
+versioned_symbol (libm, __ieee754_log2, log2, GLIBC_2_29);
+libm_alias_double_other (__log2, log2)
+#else
+libm_alias_double (__log2, log2)
+#endif
+
+strong_alias (__log2, __ieee754_log2)
+libm_alias_finite (__log2, __log2)
+
+#define __log2 __log2_sse2
+#include <sysdeps/ieee754/dbl-64/e_log2.c>
diff --git a/sysdeps/x86_64/fpu/multiarch/s_expm1-fma.c b/sysdeps/x86_64/fpu/multiarch/s_expm1-fma.c
new file mode 100644 (file)
index 0000000..3ee2bd8
--- /dev/null
@@ -0,0 +1,10 @@
+#define __expm1 __expm1_fma
+
+/* NB: __expm1 may be expanded to __expm1_fma in the following
+   prototypes.  */
+extern long double __expm1l (long double);
+extern long double __expm1f128 (long double);
+
+#define SECTION __attribute__ ((section (".text.fma")))
+
+#include <sysdeps/ieee754/dbl-64/s_expm1.c>
diff --git a/sysdeps/x86_64/fpu/multiarch/s_expm1.c b/sysdeps/x86_64/fpu/multiarch/s_expm1.c
new file mode 100644 (file)
index 0000000..2cae83f
--- /dev/null
@@ -0,0 +1,36 @@
+/* Multiple versions of expm1.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <libm-alias-double.h>
+
+extern double __redirect_expm1 (double);
+
+#define SYMBOL_NAME expm1
+#include "ifunc-fma.h"
+
+libc_ifunc_redirected (__redirect_expm1, __expm1, IFUNC_SELECTOR ());
+libm_alias_double (__expm1, expm1)
+
+#define __expm1 __expm1_sse2
+
+/* NB: __expm1 may be expanded to __expm1_sse2 in the following
+   prototypes.  */
+extern long double __expm1l (long double);
+extern long double __expm1f128 (long double);
+
+#include <sysdeps/ieee754/dbl-64/s_expm1.c>
diff --git a/sysdeps/x86_64/fpu/multiarch/s_log1p-fma.c b/sysdeps/x86_64/fpu/multiarch/s_log1p-fma.c
new file mode 100644 (file)
index 0000000..8952df8
--- /dev/null
@@ -0,0 +1,4 @@
+#define __log1p __log1p_fma
+#define SECTION __attribute__ ((section (".text.fma")))
+
+#include <sysdeps/ieee754/dbl-64/s_log1p.c>
diff --git a/sysdeps/x86_64/fpu/multiarch/s_log1p.c b/sysdeps/x86_64/fpu/multiarch/s_log1p.c
new file mode 100644 (file)
index 0000000..6ce5198
--- /dev/null
@@ -0,0 +1,29 @@
+/* Multiple versions of log1p.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <libm-alias-double.h>
+
+extern double __redirect_log1p (double);
+
+#define SYMBOL_NAME log1p
+#include "ifunc-fma.h"
+
+libc_ifunc_redirected (__redirect_log1p, __log1p, IFUNC_SELECTOR ());
+
+#define __log1p __log1p_sse2
+#include <sysdeps/ieee754/dbl-64/s_log1p.c>
index a57a9952f31ff97cd64464565e11f284dfe9956b..f2f5e8a2119e8f060da125589daa90dd2dd008b3 100644 (file)
@@ -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, ))
     {
index a71444eccb3cb7cf59775408b3b2524397aaa2ec..00a91123d36743838728fed4599466ad27e23417 100644 (file)
@@ -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,
index 68646ef199ecb71ce93af9cdc98460c2c771437a..7622af259ca5c08fb0d7c0943d67c2cd5dc85cac 100644 (file)
@@ -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, ))
     {
index afd450d0206d6633da9fbc4607a7fa6aeb4e137c..51bc9344f0698b7c9c56b2fb8da3d5badd4ef0a6 100644 (file)
@@ -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
index 905d0fa4643d57684460bb0c0d8138aa89f02ff7..bc4053d1c508a34f502609dad882ff02b4eb7fae 100644 (file)
@@ -301,7 +301,7 @@ L(more_2x_vec):
        leaq    (VEC_SIZE * 4)(%rax), %LOOP_REG
 #endif
        /* Align dst for loop.  */
-       andq    $(VEC_SIZE * -2), %LOOP_REG
+       andq    $(VEC_SIZE * -1), %LOOP_REG
        .p2align 4
 L(loop):
        VMOVA   %VEC(0), LOOP_4X_OFFSET(%LOOP_REG)
diff --git a/sysdeps/x86_64/multiarch/rtld-strcpy.S b/sysdeps/x86_64/multiarch/rtld-strcpy.S
new file mode 100644 (file)
index 0000000..19439c5
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include "../strcpy.S"
index fdd5afe3af16eb473e3cfb7a39eb59836af3883a..9d6c9f66ba9254d8ab8c1062698bb611bc889055 100644 (file)
@@ -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))
index 0593fb303b3068115b3fba15b1c15b01d44a3a0e..b9b58ef599c19d2b13f9ff27c8af4bfbffecb735 100644 (file)
@@ -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
 
index 4ebe4bde30994e824b2a843033a7cc03d533537b..c4f8b6bbb5ee0f6a0ed70f070efb0690a000d8e6 100644 (file)
@@ -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))
index 470275b90c3519c96a4d66c3bc4dd7718d7cea32..2f4aa2d528e4f1e0373cfd9a837f6369dea7ed87 100644 (file)
@@ -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 \
index 494c89bf546e01072d6b939649d88c58174e2648..e9a60067107f0f78eabfb27a8ef932216475f001 100644 (file)
@@ -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;
     }
index 75554fee7ceff4606c81a724216e054a2cb47d44..4d7c4ea828db5f6762ec990ee1eab6ced6cbfa32 100644 (file)
@@ -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
index a3c5681fc2d154ea05caa041269faf4d91f5de5f..f92744820433f4729624bcdb897bfe085c39e3b6 100644 (file)
 #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 (file)
index 0000000..4d47ee7
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-strftime4.c"
diff --git a/time/tst-strftime4.c b/time/tst-strftime4.c
new file mode 100644 (file)
index 0000000..659716d
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+
+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 <support/test-driver.c>
index dd75848ba95d8f6c72fd9a6d54894804e5419c36..8bba4e5b8d3b3b5f0e62573d54a69eb47eae0e30 100644 (file)
@@ -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 <endian.h>
 #include <byteswap.h>
 
@@ -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)
index a789c22d269d356918b3b05d81b14dc222755c26..5002de39adfcdc944029d16f68af09362697935f 100644 (file)
@@ -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/tst-bz29951.c b/timezone/tst-bz29951.c
new file mode 100644 (file)
index 0000000..abd3346
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <time.h>
+
+/* 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 <support/test-driver.c>
index e6b9e8743a5c4475e955bcca3cee8b730e7b4883..4af102a3f6c4fb479b87894e60f7bb943bd8d9c4 100644 (file)
@@ -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 (file)
index 0000000..8e1735c
--- /dev/null
@@ -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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_WCHAR2_DECL_H
+#define _BITS_WCHAR2_DECL_H 1
+
+#ifndef _WCHAR_H
+# error "Never include <bits/wchar2-decl.h> directly; use <wchar.h> 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.  */
index 0e017f458be8c3f203bb8af96de29fa519d8c8b7..1181d36c24cfbdd10b5e1195d7679cbf6e48f48b 100644 (file)
@@ -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);
@@ -120,16 +107,13 @@ extern wchar_t *__REDIRECT_NTH (__wcscpy_alias,
 __fortify_function wchar_t *
 __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
 {
-  size_t sz = __glibc_objsize (__dest);
-  if (sz != (size_t) -1)
-    return __wcscpy_chk (__dest, __src, sz / sizeof (wchar_t));
+  size_t __sz = __glibc_objsize (__dest);
+  if (__sz != (size_t) -1)
+    return __wcscpy_chk (__dest, __src, __sz / sizeof (wchar_t));
   return __wcscpy_alias (__dest, __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);
@@ -137,16 +121,13 @@ extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias,
 __fortify_function wchar_t *
 __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
 {
-  size_t sz = __glibc_objsize (__dest);
-  if (sz != (size_t) -1)
-    return __wcpcpy_chk (__dest, __src, sz / sizeof (wchar_t));
+  size_t __sz = __glibc_objsize (__dest);
+  if (__sz != (size_t) -1)
+    return __wcpcpy_chk (__dest, __src, __sz / sizeof (wchar_t));
   return __wcpcpy_alias (__dest, __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);
@@ -202,16 +177,13 @@ extern wchar_t *__REDIRECT_NTH (__wcscat_alias,
 __fortify_function wchar_t *
 __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
 {
-  size_t sz = __glibc_objsize (__dest);
-  if (sz != (size_t) -1)
-    return __wcscat_chk (__dest, __src, sz / sizeof (wchar_t));
+  size_t __sz = __glibc_objsize (__dest);
+  if (__sz != (size_t) -1)
+    return __wcscat_chk (__dest, __src, __sz / sizeof (wchar_t));
   return __wcscat_alias (__dest, __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,
@@ -221,17 +193,13 @@ __fortify_function wchar_t *
 __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
                size_t __n))
 {
-  size_t sz = __glibc_objsize (__dest);
-  if (sz != (size_t) -1)
-    return __wcsncat_chk (__dest, __src, __n, sz / sizeof (wchar_t));
+  size_t __sz = __glibc_objsize (__dest);
+  if (__sz != (size_t) -1)
+    return __wcsncat_chk (__dest, __src, __n, __sz / sizeof (wchar_t));
   return __wcsncat_alias (__dest, __src, __n);
 }
 
 
-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,
@@ -243,10 +211,10 @@ __fortify_function int
 __NTH (swprintf (wchar_t *__restrict __s, size_t __n,
                 const wchar_t *__restrict __fmt, ...))
 {
-  size_t sz = __glibc_objsize (__s);
-  if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
+  size_t __sz = __glibc_objsize (__s);
+  if (__sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
     return __swprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
-                          sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
+                          __sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
   return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ());
 }
 #elif !defined __cplusplus
@@ -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,
@@ -273,26 +236,16 @@ __fortify_function int
 __NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
                  const wchar_t *__restrict __fmt, __gnuc_va_list __ap))
 {
-  size_t sz = __glibc_objsize (__s);
-  if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
+  size_t __sz = __glibc_objsize (__s);
+  if (__sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
     return __vswprintf_chk (__s, __n,  __USE_FORTIFY_LEVEL - 1,
-                           sz / sizeof (wchar_t), __fmt, __ap);
+                           __sz / sizeof (wchar_t), __fmt, __ap);
   return __vswprintf_alias (__s, __n, __fmt, __ap);
 }
 
 
 #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;
@@ -342,18 +293,15 @@ extern wchar_t *__REDIRECT (__fgetws_chk_warn,
 __fortify_function __wur wchar_t *
 fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize (__s);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
+  size_t __sz = __glibc_objsize (__s);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), __sz))
     return __fgetws_alias (__s, __n, __stream);
-  if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
-    return __fgetws_chk_warn (__s, sz / sizeof (wchar_t), __n, __stream);
-  return __fgetws_chk (__s, sz / sizeof (wchar_t), __n, __stream);
+  if (__glibc_unsafe_len (__n, sizeof (wchar_t), __sz))
+    return __fgetws_chk_warn (__s, __sz / sizeof (wchar_t), __n, __stream);
+  return __fgetws_chk (__s, __sz / sizeof (wchar_t), __n, __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)
@@ -368,20 +316,17 @@ extern wchar_t *__REDIRECT (__fgetws_unlocked_chk_warn,
 __fortify_function __wur wchar_t *
 fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
 {
-  size_t sz = __glibc_objsize (__s);
-  if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
+  size_t __sz = __glibc_objsize (__s);
+  if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), __sz))
     return __fgetws_unlocked_alias (__s, __n, __stream);
-  if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
-    return __fgetws_unlocked_chk_warn (__s, sz / sizeof (wchar_t), __n,
+  if (__glibc_unsafe_len (__n, sizeof (wchar_t), __sz))
+    return __fgetws_unlocked_chk_warn (__s, __sz / sizeof (wchar_t), __n,
                                       __stream);
-  return __fgetws_unlocked_chk (__s, sz / sizeof (wchar_t), __n, __stream);
+  return __fgetws_unlocked_chk (__s, __sz / sizeof (wchar_t), __n, __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,
index c37e8619a004fa04bfeb9b83b6f0f5aff09bc1fc..5f7139f2790ae878e7909aa708f0ffbd7dff9544 100644 (file)
 /* 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
index 5d6a40853d5eb176140324d3faab8f9244aa8da5..c1321c75186ad1ed8f4d148cfff27be2354310ea 100644 (file)
@@ -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 <bits/wchar2.h>
+/* Declare all functions from bits/wchar2-decl.h first.  */
+# include <bits/wchar2-decl.h>
 #endif
 
-#include <bits/floatn.h>
+/* 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 <bits/wchar-ldbl.h>
 #endif
 
+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
+/* Now include the function definitions and redirects too.  */
+# include <bits/wchar2.h>
+#endif
+
 __END_DECLS
 
 #endif /* wchar.h  */