diff --git a/acl/.footprint b/acl/.footprint index b24d6950..f00d1b2f 100644 --- a/acl/.footprint +++ b/acl/.footprint @@ -3,8 +3,8 @@ drwxr-xr-x root/root bin/ -rwxr-xr-x root/root bin/getfacl -rwxr-xr-x root/root bin/setfacl drwxr-xr-x root/root lib/ -lrwxrwxrwx root/root lib/libacl.so.1 -> libacl.so.1.1.2301 --rwxr-xr-x root/root lib/libacl.so.1.1.2301 +lrwxrwxrwx root/root lib/libacl.so.1 -> libacl.so.1.1.2302 +-rwxr-xr-x root/root lib/libacl.so.1.1.2302 drwxr-xr-x root/root usr/ drwxr-xr-x root/root usr/include/ drwxr-xr-x root/root usr/include/acl/ @@ -14,7 +14,7 @@ drwxr-xr-x root/root usr/include/sys/ drwxr-xr-x root/root usr/lib/ -rw-r--r-- root/root usr/lib/libacl.a -rwxr-xr-x root/root usr/lib/libacl.la -lrwxrwxrwx root/root usr/lib/libacl.so -> ../../lib/libacl.so.1.1.2301 +lrwxrwxrwx root/root usr/lib/libacl.so -> ../../lib/libacl.so.1.1.2302 drwxr-xr-x root/root usr/lib/pkgconfig/ -rw-r--r-- root/root usr/lib/pkgconfig/libacl.pc drwxr-xr-x root/root usr/share/ diff --git a/acl/.signature b/acl/.signature index 8f6e6ec0..097bee1b 100644 --- a/acl/.signature +++ b/acl/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqnUSS3xObEXDBCVvs54ntj07Z7Uu8N1STaoVmghrzkPynHIOdDFEXWSF+fpdEnGfEOqYcle/k/h35hkbW4MRvwM= -SHA256 (Pkgfile) = 863c2c69d1673e2f762cbe743b49918c8d86c0fd81dd9d21433bd72bad94237d -SHA256 (.footprint) = 20dc00826af98fa5597f6572c5f381843ce698a15f1a5d1fbafa97c169442a02 -SHA256 (acl-2.3.1.tar.xz) = c0234042e17f11306c23c038b08e5e070edb7be44bef6697fb8734dcff1c66b1 +RWRJc1FUaeVequ3HOtwxYHlBZU6HBtdh7UfvjVBt8kko9n9NgfmJoqkmoIsWlJH/Acbk90O4Zn/39i9s/HtGw/pt9NmQWSmK2QU= +SHA256 (Pkgfile) = 98274f0b01ffaa9c38a12c447d2313568ae81684ad863f6c7771f25b01c634ce +SHA256 (.footprint) = 0c6bde0698e79ace372b655fec6679e8da35371f3641b20b2fecd870aec82f04 +SHA256 (acl-2.3.2.tar.xz) = 97203a72cae99ab89a067fe2210c1cbf052bc492b479eca7d226d9830883b0bd diff --git a/acl/Pkgfile b/acl/Pkgfile index c8a76fdc..72eae20b 100644 --- a/acl/Pkgfile +++ b/acl/Pkgfile @@ -4,7 +4,7 @@ # Depends on: attr name=acl -version=2.3.1 +version=2.3.2 release=1 source=(https://download-mirror.savannah.gnu.org/releases/$name/$name-$version.tar.xz) diff --git a/attr/.footprint b/attr/.footprint index 20c3c55b..4098cfa5 100644 --- a/attr/.footprint +++ b/attr/.footprint @@ -5,8 +5,8 @@ drwxr-xr-x root/root bin/ drwxr-xr-x root/root etc/ -rw-r--r-- root/root etc/xattr.conf drwxr-xr-x root/root lib/ -lrwxrwxrwx root/root lib/libattr.so.1 -> libattr.so.1.1.2501 --rwxr-xr-x root/root lib/libattr.so.1.1.2501 +lrwxrwxrwx root/root lib/libattr.so.1 -> libattr.so.1.1.2502 +-rwxr-xr-x root/root lib/libattr.so.1.1.2502 drwxr-xr-x root/root usr/ drwxr-xr-x root/root usr/include/ drwxr-xr-x root/root usr/include/attr/ @@ -16,7 +16,7 @@ drwxr-xr-x root/root usr/include/attr/ drwxr-xr-x root/root usr/lib/ -rw-r--r-- root/root usr/lib/libattr.a -rwxr-xr-x root/root usr/lib/libattr.la -lrwxrwxrwx root/root usr/lib/libattr.so -> ../../lib/libattr.so.1.1.2501 +lrwxrwxrwx root/root usr/lib/libattr.so -> ../../lib/libattr.so.1.1.2502 drwxr-xr-x root/root usr/lib/pkgconfig/ -rw-r--r-- root/root usr/lib/pkgconfig/libattr.pc drwxr-xr-x root/root usr/share/ diff --git a/attr/.signature b/attr/.signature index 7ae8cfdb..2f352e6c 100644 --- a/attr/.signature +++ b/attr/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqobot4ovgn4CiW+w+goXyFf1koBC91Q7uKGh3O4TMCvN5gk2RdmwEx6FHQl6BA10DwuW/hWPS67BFC5qgrES0A8= -SHA256 (Pkgfile) = 25a803a86e7b7db13dbbd4ba8ecca5e4a80252b88b9ade939f79225a0fa5b4e2 -SHA256 (.footprint) = 8368c38477e91d036039def551b279f0a525d58a9ea7750fa3ee62f4b6a20475 -SHA256 (attr-2.5.1.tar.xz) = db448a626f9313a1a970d636767316a8da32aede70518b8050fa0de7947adc32 +RWRJc1FUaeVeqk53ekVTV+OXxXqJh/czOLGJXDpsSmal0b1zbEc3MzsDXmsbxqMzNh3dwn7fA5LWLoVih+kwODqefovA40MMAgM= +SHA256 (Pkgfile) = 3d15676c9c6a54573946b55ddd58ad7461fc29bfe614fec25a0a13fad7c6771e +SHA256 (.footprint) = 53d4c7f191d16554afcbb33287f508b1f85bd5d5d2c49acd7a9bcb07510ff42f +SHA256 (attr-2.5.2.tar.xz) = f2e97b0ab7ce293681ab701915766190d607a1dba7fae8a718138150b700a70b diff --git a/attr/Pkgfile b/attr/Pkgfile index 32811d69..821f253e 100644 --- a/attr/Pkgfile +++ b/attr/Pkgfile @@ -3,7 +3,7 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=attr -version=2.5.1 +version=2.5.2 release=1 source=(https://download-mirror.savannah.gnu.org/releases/$name/$name-$version.tar.xz) diff --git a/bash/.signature b/bash/.signature index 6849b23e..3887cb1d 100644 --- a/bash/.signature +++ b/bash/.signature @@ -1,7 +1,7 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqnVCN2VGEAw7Xwy+FVmja5Pl47S7Z8Mv/wp/uXASoGrRIfp9rYLM3xw4dgr6PRcgNBZ2iWmalMAVofgLcaQ1GQc= -SHA256 (Pkgfile) = e4f6b098dc701e4b0e83cd5c5ffb8f8086ca0060df6033075b6b2c73c3043cdf +RWRJc1FUaeVeqltELthg5AsBoMu0rWqatUKMVLZ0JASoRvzHGggcM8jDexMibZ54r1QA4CMRQ9qLyxcphd6IYZG+dEAedp6rLw0= +SHA256 (Pkgfile) = cf680bb551a68c329c28b5405caec807e8449059ccab07b1c0602307268802c8 SHA256 (.footprint) = 01ad0142672053f07bc5f2c5e481cb8cde032296c7eb3ff97334d626dce4f45c SHA256 (bash-5.2.tar.gz) = a139c166df7ff4471c5e0733051642ee5556c1cc8a4a78f145583c5c81ab32fb -SHA256 (bash-5.2.21.patch.gz) = da6d1a9d876500f1362cf9233fb2b7307cd6a5cedbb3c215e9ae01b8551bb076 +SHA256 (bash-5.2.26.patch.gz) = ff4d5dff871fa59437646e3de8fa53c6d0299bdb94561d6934dc338bd3b9072c SHA256 (profile) = 4f11de701adc2ab4e99d8cf28ab337dc1529de178e38337ae0f7f04840fddec6 diff --git a/bash/Pkgfile b/bash/Pkgfile index c1008586..b60059d9 100644 --- a/bash/Pkgfile +++ b/bash/Pkgfile @@ -4,8 +4,8 @@ # Depends on: readline name=bash -version=5.2.21 -release=1 +version=5.2.26 +release=2 source=(https://ftpmirror.gnu.org/gnu/$name/$name-${version:0:3}.tar.gz $name-$version.patch.gz profile) diff --git a/bash/bash-5.2.21.patch.gz b/bash/bash-5.2.21.patch.gz deleted file mode 100644 index 9e7aed60..00000000 Binary files a/bash/bash-5.2.21.patch.gz and /dev/null differ diff --git a/bash/bash-5.2.26.patch.gz b/bash/bash-5.2.26.patch.gz new file mode 100644 index 00000000..b5842b25 Binary files /dev/null and b/bash/bash-5.2.26.patch.gz differ diff --git a/cmake/.signature b/cmake/.signature index 0d07b9ca..e9f52476 100644 --- a/cmake/.signature +++ b/cmake/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqk7/8vOLmmqkj2jnpmZx9ceTGZ5WV/k1Ot/woCh3mXZ2z9jGsH6CVmJ87l9bpeEPqs4Fc/st8Gc/4n4VQD0KqAI= -SHA256 (Pkgfile) = dc20abf752d96bdae649cda77b0a6055ae4261bb5915d47df3e027ab02b63598 +RWRJc1FUaeVeqjZPTwkb8a5jE+F2mxZWUIdQFxoBsRzB5JSXH9IE2yD085e0yfqRDSYnFjzslqnU0QjX+sJRuDz0aenyJyhGXAg= +SHA256 (Pkgfile) = 0280b20476932bd2e34b8c79481240e55e685eb79375b9138da26249262b7777 SHA256 (.footprint) = 6ab7ef0b7738c4eebfc4b2491af5d910de1d1ce4d5633b8736977ec5b89b0c85 -SHA256 (cmake-3.28.1.tar.gz) = 15e94f83e647f7d620a140a7a5da76349fc47a1bfed66d0f5cdee8e7344079ad +SHA256 (cmake-3.28.2.tar.gz) = 1466f872dc1c226f373cf8fba4230ed216a8f108bd54b477b5ccdfd9ea2d124a diff --git a/cmake/Pkgfile b/cmake/Pkgfile index f1353d70..8872206a 100644 --- a/cmake/Pkgfile +++ b/cmake/Pkgfile @@ -5,7 +5,7 @@ # Optional: python3-sphinx name=cmake -version=3.28.1 +version=3.28.2 release=1 source=(https://cmake.org/files/v${version%.*}/$name-$version.tar.gz) diff --git a/cpio/.signature b/cpio/.signature index 921c8151..e2022295 100644 --- a/cpio/.signature +++ b/cpio/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqkHDGeLfHTdXMfg3pSawyigG9FpUjqWG07AbstHFPd3eFwRt01+6PNoDuASTgvGZrQPlsyxIKdR/6jeRnbm+rQQ= -SHA256 (Pkgfile) = 3dae32507d8aae5ee878d99bbc75cbae64a10e02be9ed814ab3662fe2c2e6123 +RWRJc1FUaeVeqvZRxvDSuLJ1kN6Qgp4PWUaZL3owScAEbdYjrWtjtO7vd7xyRBLuSspT9ZRE4X40uhjgmGaw1RdUk9pgCd7fYgg= +SHA256 (Pkgfile) = de01bb4fa740e0dd4c346cddadb0273b670e9aee6317eff2ad39b4ce42f5919a SHA256 (.footprint) = 26cfb1dd44c5356afcdba7aa054685d535b15b4ab96897ad7bd24a6c9a14b9fe -SHA256 (cpio-2.14.tar.bz2) = fcdc15d60f7267a6fc7efcd6b9db7b6c8966c4f2fbbb964c24d41336fd3f2c12 +SHA256 (cpio-2.15.tar.bz2) = 937610b97c329a1ec9268553fb780037bcfff0dcffe9725ebc4fd9c1aa9075db diff --git a/cpio/Pkgfile b/cpio/Pkgfile index 27320b78..6809968b 100644 --- a/cpio/Pkgfile +++ b/cpio/Pkgfile @@ -3,7 +3,7 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=cpio -version=2.14 +version=2.15 release=1 source=(https://ftpmirror.gnu.org/gnu/$name/$name-$version.tar.bz2) diff --git a/curl/.footprint b/curl/.footprint index 560bb2ac..763a0763 100644 --- a/curl/.footprint +++ b/curl/.footprint @@ -31,6 +31,7 @@ drwxr-xr-x root/root usr/share/man/ drwxr-xr-x root/root usr/share/man/man1/ -rw-r--r-- root/root usr/share/man/man1/curl-config.1.gz -rw-r--r-- root/root usr/share/man/man1/curl.1.gz +-rw-r--r-- root/root usr/share/man/man1/mk-ca-bundle.1.gz drwxr-xr-x root/root usr/share/man/man3/ -rw-r--r-- root/root usr/share/man/man3/CURLINFO_ACTIVESOCKET.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLINFO_APPCONNECT_TIME.3.gz @@ -73,6 +74,7 @@ drwxr-xr-x root/root usr/share/man/man3/ -rw-r--r-- root/root usr/share/man/man3/CURLINFO_PROXYAUTH_AVAIL.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLINFO_PROXY_ERROR.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLINFO_PROXY_SSL_VERIFYRESULT.3.gz +-rw-r--r-- root/root usr/share/man/man3/CURLINFO_QUEUE_TIME_T.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLINFO_REDIRECT_COUNT.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLINFO_REDIRECT_TIME.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLINFO_REDIRECT_TIME_T.3.gz @@ -340,6 +342,7 @@ drwxr-xr-x root/root usr/share/man/man3/ -rw-r--r-- root/root usr/share/man/man3/CURLOPT_SEEKDATA.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLOPT_SEEKFUNCTION.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLOPT_SERVER_RESPONSE_TIMEOUT.3.gz +-rw-r--r-- root/root usr/share/man/man3/CURLOPT_SERVER_RESPONSE_TIMEOUT_MS.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLOPT_SERVICE_NAME.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLOPT_SHARE.3.gz -rw-r--r-- root/root usr/share/man/man3/CURLOPT_SOCKOPTDATA.3.gz diff --git a/curl/.signature b/curl/.signature index af8aa6f8..510fc251 100644 --- a/curl/.signature +++ b/curl/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqj9jl6fgDS9l1BU8g7YurbFYgORqpm/YI5EJsfsRT00/zrKKSpZPbGWLKN5c8bxuEaPw44TfATJPkMapjumDSg0= -SHA256 (Pkgfile) = 1dfc6a6fe609ef80d7c81735cb86d8da6d89db767d5d5bf7e65abcfffe21f19f -SHA256 (.footprint) = c3470b7ba99683af6b8fe29f22eda2ab180e02b1e51ee4977dfa21755793ea81 -SHA256 (curl-8.5.0.tar.xz) = 42ab8db9e20d8290a3b633e7fbb3cec15db34df65fd1015ef8ac1e4723750eeb +RWRJc1FUaeVeqtNJVOYqAX0EF507iw/wLoI2s4Bo11li06bsxFc+ZSA/4hqBOg+Wfue/pdGA/bm6LgCRGYyS7X9ATuGKxdiM7w4= +SHA256 (Pkgfile) = 0d9be75a33942a0398fd9f6f56f9c62e9f2698ec4d824e815601cc982e77b4db +SHA256 (.footprint) = b93ccc07e39082f05d6a6485e1432f9b322edc85dc9d8861968bd505382e8b67 +SHA256 (curl-8.6.0.tar.xz) = 3ccd55d91af9516539df80625f818c734dc6f2ecf9bada33c76765e99121db15 diff --git a/curl/Pkgfile b/curl/Pkgfile index 2bdb91e2..ee5aa422 100644 --- a/curl/Pkgfile +++ b/curl/Pkgfile @@ -4,7 +4,7 @@ # Depends on: libnghttp2 openssl zstd name=curl -version=8.5.0 +version=8.6.0 release=1 source=(https://curl.haxx.se/download/$name-$version.tar.xz) diff --git a/ed/.signature b/ed/.signature index 090fc9fe..0aede43b 100644 --- a/ed/.signature +++ b/ed/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqn6KU3oOcljpTqgyvZG+B6pJC+4qTmBI5cfWe/dwL4SAlSN9rxOm+nlM6647qyi2XaSsJzNguJdRgi4GfLutngg= -SHA256 (Pkgfile) = d8cc25470ca6249d877931e528fab00a4462d6d091a5f5440a9ae5a01846c1a6 +RWRJc1FUaeVeqixiT4ML0Fx61N3Hloab4NbSVZhQ4WJyUgf9x9sYQIwttTe4V8KAbBOdG6bJQta2v64S/BpTUI8TC+erYQPNBwY= +SHA256 (Pkgfile) = b625c23308bd87ac2fc84d440d9f3ae8e243f125d28e8a00848bf0b7e5f4bb73 SHA256 (.footprint) = 50257280fd2c49c4fc30ff31c8fab89872b4fe65f98000c803c88dd3b57875b2 -SHA256 (ed-1.19.tar.lz) = ce2f2e5c424790aa96d09dacb93d9bbfdc0b7eb6249c9cb7538452e8ec77cd48 +SHA256 (ed-1.20.tar.lz) = c6030defe6ae172f1687906d7354054c75a6a9130af319d4e73c50a91959c5a6 diff --git a/ed/Pkgfile b/ed/Pkgfile index 4873b175..7b6e6c82 100644 --- a/ed/Pkgfile +++ b/ed/Pkgfile @@ -3,7 +3,7 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=ed -version=1.19 +version=1.20 release=1 source=(https://ftpmirror.gnu.org/gnu/$name/$name-$version.tar.lz) diff --git a/exim/.signature b/exim/.signature index 71287353..11f44b44 100644 --- a/exim/.signature +++ b/exim/.signature @@ -1,8 +1,8 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqktNwuCz1mI6FAhzJ+RDhle41g194J6bLbefyaWrxprJC3PkoAbqXVRQ4L0rXh4VDBT8a2xmnuCn+KMsqp8oDww= -SHA256 (Pkgfile) = 11b433b160e00014f32bfe5848b3b65a66e1eee9fe9721f0984348100a0243ff +RWRJc1FUaeVeqtS6OMxN2tl3oFVZhO7MnrYftg4LHh0a2XGlftxhEhtQUuuwWo9/66jpRUnYGgysCcHWmeTL1g0I/ebi4nvJeAg= +SHA256 (Pkgfile) = aeb85154010227706b86ad4d4e5a78d1650110c3864f4f087e302ecbd54cfe8c SHA256 (.footprint) = ea3802c2571c2652b12d43cfb5d843810d15f43a991c3b4a6e1e807c27bb6c78 -SHA256 (exim-4.97.tar.xz) = 428150e67c494fa14fe5195d81b972c1b23e651ee4f9f2ff1788250266d31e9c +SHA256 (exim-4.97.1.tar.xz) = bd782057509a793593508528590626d185ea160ce32cb34beda262e99cefdfa9 SHA256 (exim) = fcc6489769d9b4503f6435747dca79d9f8aca1da05628dc82de6a27335cd27a7 SHA256 (exim-config.patch) = 5b1843a12f62e830712cffcbc1fc585887e8fafcebc59cc47e299b2eefe54f96 SHA256 (disable-id_update.patch) = f0deb49dc795a4f3c8094e73f92b923fed517b549c24864086f0996059947c88 diff --git a/exim/Pkgfile b/exim/Pkgfile index a03a2fbd..48b2ac9c 100644 --- a/exim/Pkgfile +++ b/exim/Pkgfile @@ -4,8 +4,8 @@ # Depends on: db libpcre2 libxcrypt openssl name=exim -version=4.97 -release=2 +version=4.97.1 +release=1 source=(https://ftp.exim.org/pub/exim/exim4/$name-$version.tar.xz $name $name-config.patch disable-id_update.patch) diff --git a/exim/exim-4.96.1.tar.xz b/exim/exim-4.96.1.tar.xz new file mode 100644 index 00000000..432ec4d1 Binary files /dev/null and b/exim/exim-4.96.1.tar.xz differ diff --git a/glibc-32/glibc-2.36-8.patch b/glibc-32/glibc-2.36-8.patch new file mode 100644 index 00000000..df41fa4b --- /dev/null +++ b/glibc-32/glibc-2.36-8.patch @@ -0,0 +1,11330 @@ +diff --git a/Makeconfig b/Makeconfig +index ba70321af1..9dd058e04b 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -43,6 +43,22 @@ else + $(error objdir must be defined by the build-directory Makefile) + endif + ++# Did we request 'make -s' run? "yes" or "no". ++# Starting from make-4.4 MAKEFLAGS now contains long ++# options like '--shuffle'. To detect presence of 's' ++# we pick first word with short options. Long options ++# are guaranteed to come after whitespace. We use '-' ++# prefix to always have a word before long options ++# even if no short options were passed. ++# Typical MAKEFLAGS values to watch for: ++# "rs --shuffle=42" (silent) ++# " --shuffle" (not silent) ++ifeq ($(findstring s, $(firstword -$(MAKEFLAGS))),) ++silent-make := no ++else ++silent-make := yes ++endif ++ + # Root of the sysdeps tree. + sysdep_dir := $(..)sysdeps + export sysdep_dir := $(sysdep_dir) +@@ -868,7 +884,7 @@ endif + # Use 64 bit time_t support for installed programs + installed-modules = nonlib nscd lddlibc4 ldconfig locale_programs \ + iconvprogs libnss_files libnss_compat libnss_db libnss_hesiod \ +- libutil libpcprofile libSegFault ++ libutil libpcprofile libSegFault libnsl + +extra-time-flags = $(if $(filter $(installed-modules),\ + $(in-module)),-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64) + +@@ -917,7 +933,7 @@ endif + # umpteen zillion filenames along with it (we use `...' instead) + # but we don't want this echoing done when the user has said + # he doesn't want to see commands echoed by using -s. +-ifneq "$(findstring s,$(MAKEFLAGS))" "" # if -s ++ifeq ($(silent-make),yes) # if -s + +cmdecho := echo >/dev/null + else # not -s + +cmdecho := echo +diff --git a/Makerules b/Makerules +index d1e139d03c..09c0cf8357 100644 +--- a/Makerules ++++ b/Makerules +@@ -794,7 +794,7 @@ endif + # Maximize efficiency by minimizing the number of rules. + .SUFFIXES: # Clear the suffix list. We don't use suffix rules. + # Don't define any builtin rules. +-MAKEFLAGS := $(MAKEFLAGS)r ++MAKEFLAGS := $(MAKEFLAGS) -r + + # Generic rule for making directories. + %/: +@@ -811,7 +811,7 @@ MAKEFLAGS := $(MAKEFLAGS)r + .PRECIOUS: $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c)) + + # Use the verbose option of ar and tar when not running silently. +-ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s ++ifeq ($(silent-make),no) # if not -s + verbose := v + else # -s + verbose := +diff --git a/NEWS b/NEWS +index f61e521fc8..0f0ebce3f0 100644 +--- a/NEWS ++++ b/NEWS +@@ -5,6 +5,94 @@ See the end for copying conditions. + Please send GNU C library bug reports via + using `glibc' in the "product" field. + ++Version 2.36.1 ++ ++Major new features: ++ ++* The getent tool now supports the --no-addrconfig option. The output of ++ getent with --no-addrconfig may contain addresses of families not ++ configured on the current host i.e. as-if you had not passed ++ AI_ADDRCONFIG to getaddrinfo calls. ++ ++Security related changes: ++ ++ CVE-2022-39046: When the syslog function is passed a crafted input ++ string larger than 1024 bytes, it reads uninitialized memory from the ++ heap and prints it to the target log file, potentially revealing a ++ portion of the contents of the heap. ++ ++ CVE-2023-4527: If the system is configured in no-aaaa mode via ++ /etc/resolv.conf, getaddrinfo is called for the AF_UNSPEC address ++ family, and a DNS response is received over TCP that is larger than ++ 2048 bytes, getaddrinfo may potentially disclose stack contents via ++ the returned address data, or crash. ++ ++ CVE-2023-4806: When an NSS plugin only implements the ++ _gethostbyname2_r and _getcanonname_r callbacks, getaddrinfo could use ++ memory that was freed during buffer resizing, potentially causing a ++ crash or read or write to arbitrary memory. ++ ++ CVE-2023-5156: The fix for CVE-2023-4806 introduced a memory leak when ++ an application calls getaddrinfo for AF_INET6 with AI_CANONNAME, ++ AI_ALL and AI_V4MAPPED flags set. ++ ++ CVE-2023-4911: If a tunable of the form NAME=NAME=VAL is passed in the ++ environment of a setuid program and NAME is valid, it may result in a ++ buffer overflow, which could be exploited to achieve escalated ++ privileges. This flaw was introduced in glibc 2.34. ++ ++The following bugs are resolved with this release: ++ ++ [12154] Do not fail DNS resolution for CNAMEs which are not host names ++ [20975] Deferred cancellation triggers in __check_pf and looses lock leading to deadlock ++ [24816] Fix tst-nss-files-hosts-long on single-stack hosts ++ [27576] gmon: improve mcount overflow handling ++ [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning ++ [29039] Corrupt DTV after reuse of a TLS module ID following dlclose with unused TLS ++ [29444] gmon: Fix allocated buffer overflow (bug 29444) ++ [29864] libc: __libc_start_main() should obtain program headers ++ address (_dl_phdr) from the auxv, not the ELF header. ++ [29305] Conserve NSS buffer space during DNS packet parsing ++ [29402] nscd: nscd: No such file or directory ++ [29415] nscd: Fix netlink cache invalidation if epoll is used ++ [28937] New DSO dependency sorter does not put new map first if in a cycle ++ [29446] _dlopen now ignores dl_caller argument in static mode ++ [29485] Linux: Terminate subprocess on late failure in tst-pidfd ++ [29490] alpha: New __brk_call implementation is broken ++ [29463] math/test-float128-y1 fails on x86_64 ++ [29488] test-ibm128-llround fails on ppc64el when built with gcc-12 and -O2 ++ or higher ++ [29528] elf: Call __libc_early_init for reused namespaces ++ [29537] libc: [2.34 regression]: Alignment issue on m68k when using ++ [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are ++ [29576] build: librtld.os: in function `_dl_start_profile': ++ (.text+0x9444): undefined reference to `strcpy' ++ [29583] Use 64-bit interfaces in gconv_parseconfdir ++ [29600] Do not completely clear reused namespace in dlmopen ++ [29607] nscd repeatably crashes calling __strlen_avx2 when hosts cache is ++ enabled ++ [29638] libc: stdlib: arc4random fallback is never used ++ [29657] libc: Incorrect struct stat for 64-bit time on linux/generic ++ platforms ++ [29730] broken y2038 support in fstatat on MIPS N64 ++ [29771] Restore IPC_64 support in sysvipc *ctl functions ++ [29776] elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10 ++ [29951] time: Set daylight to 1 for matching DST/offset change ++ [30053] time: strftime %s returns -1 after 2038 on 32 bits systems ++ [30101] gmon: fix memory corruption issues ++ [30151] gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling ++ [30163] posix: Fix system blocks SIGCHLD erroneously ++ [30305] x86_64: Fix asm constraints in feraiseexcept ++ [30477] libc: [RISCV]: time64 does not work on riscv32 ++ [30515] _dl_find_object incorrectly returns 1 during early startup ++ [30745] Slight bug in cache info codes for x86 ++ [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with ++ -D_FILE_OFFSET_BITS=64 ++ [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) ++ [30843] potential use-after-free in getcanonname (CVE-2023-4806) ++ [31184] FAIL: elf/tst-tlsgap ++ [31185] Incorrect thread point access in _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic ++ + Version 2.36 + + Major new features: +diff --git a/bits/socket.h b/bits/socket.h +index 2b99dea33b..aac8c49b00 100644 +--- a/bits/socket.h ++++ b/bits/socket.h +@@ -245,6 +245,12 @@ struct cmsghdr + + CMSG_ALIGN (sizeof (struct cmsghdr))) + #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + ++/* Given a length, return the additional padding necessary such that ++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ ++#define __CMSG_PADDING(len) ((sizeof (size_t) \ ++ - ((len) & (sizeof (size_t) - 1))) \ ++ & (sizeof (size_t) - 1)) ++ + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + struct cmsghdr *__cmsg) __THROW; + #ifdef __USE_EXTERN_INLINES +@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + _EXTERN_INLINE struct cmsghdr * + __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) + { ++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and ++ __mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of __cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; ++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; ++ ++ size_t __size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (__cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ + return (struct cmsghdr *) 0; + ++ /* There isn't enough space between __cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) ++ < __size_needed) ++ || ((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr ++ - __size_needed) ++ < __cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; ++ ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); +- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control +- + __mhdr->msg_controllen) +- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) +- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) +- /* No more entries. */ +- return (struct cmsghdr *) 0; + return __cmsg; + } + #endif /* Use `extern inline'. */ +diff --git a/csu/libc-start.c b/csu/libc-start.c +index 543560f36c..bfeee6d851 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -262,28 +262,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + } + # endif + _dl_aux_init (auxvec); +- if (GL(dl_phdr) == NULL) + # endif +- { +- /* Starting from binutils-2.23, the linker will define the +- magic symbol __ehdr_start to point to our own ELF header +- if it is visible in a segment that also includes the phdrs. +- So we can set up _dl_phdr and _dl_phnum even without any +- information from auxv. */ +- +- extern const ElfW(Ehdr) __ehdr_start +-# if BUILD_PIE_DEFAULT +- __attribute__ ((visibility ("hidden"))); +-# else +- __attribute__ ((weak, visibility ("hidden"))); +- if (&__ehdr_start != NULL) +-# endif +- { +- assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr)); +- GL(dl_phdr) = (const void *) &__ehdr_start + __ehdr_start.e_phoff; +- GL(dl_phnum) = __ehdr_start.e_phnum; +- } +- } + + __tunables_init (__environ); + +diff --git a/csu/libc-tls.c b/csu/libc-tls.c +index 0a216c5502..7fdf7cd7a8 100644 +--- a/csu/libc-tls.c ++++ b/csu/libc-tls.c +@@ -118,19 +118,18 @@ __libc_setup_tls (void) + __tls_pre_init_tp (); + + /* Look through the TLS segment if there is any. */ +- if (_dl_phdr != NULL) +- for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) +- if (phdr->p_type == PT_TLS) +- { +- /* Remember the values we need. */ +- memsz = phdr->p_memsz; +- filesz = phdr->p_filesz; +- initimage = (void *) phdr->p_vaddr + main_map->l_addr; +- align = phdr->p_align; +- if (phdr->p_align > max_align) +- max_align = phdr->p_align; +- break; +- } ++ for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) ++ if (phdr->p_type == PT_TLS) ++ { ++ /* Remember the values we need. */ ++ memsz = phdr->p_memsz; ++ filesz = phdr->p_filesz; ++ initimage = (void *) phdr->p_vaddr + main_map->l_addr; ++ align = phdr->p_align; ++ if (phdr->p_align > max_align) ++ max_align = phdr->p_align; ++ break; ++ } + + /* Calculate the size of the static TLS surplus, with 0 auditors. */ + _dl_tls_static_surplus_init (0); +diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c +index 2696dde4b1..9b07b4e132 100644 +--- a/dlfcn/dlopen.c ++++ b/dlfcn/dlopen.c +@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1); + void * + __dlopen (const char *file, int mode, void *dl_caller) + { +- return dlopen_implementation (file, mode, RETURN_ADDRESS (0)); ++ return dlopen_implementation (file, mode, dl_caller); + } + + void * +diff --git a/elf/Makefile b/elf/Makefile +index fd77d0c7c8..30c9af1de9 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -53,6 +53,7 @@ routines = \ + # profiled libraries. + dl-routines = \ + dl-call-libc-early-init \ ++ dl-call_fini \ + dl-close \ + dl-debug \ + dl-debug-symbols \ +@@ -374,6 +375,8 @@ tests += \ + tst-align \ + tst-align2 \ + tst-align3 \ ++ tst-audit-tlsdesc \ ++ tst-audit-tlsdesc-dlopen \ + tst-audit1 \ + tst-audit2 \ + tst-audit8 \ +@@ -408,6 +411,7 @@ tests += \ + tst-dlmopen4 \ + tst-dlmopen-dlerror \ + tst-dlmopen-gethostbyname \ ++ tst-dlmopen-twice \ + tst-dlopenfail \ + tst-dlopenfail-2 \ + tst-dlopenrpath \ +@@ -631,6 +635,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 +770,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 +805,7 @@ modules-names += \ + tst-auditmanymod7 \ + tst-auditmanymod8 \ + tst-auditmanymod9 \ ++ tst-auditmod-tlsdesc \ + tst-auditmod1 \ + tst-auditmod9a \ + tst-auditmod9b \ +@@ -834,6 +842,8 @@ modules-names += \ + tst-dlmopen1mod \ + tst-dlmopen-dlerror-mod \ + tst-dlmopen-gethostbyname-mod \ ++ tst-dlmopen-twice-mod1 \ ++ tst-dlmopen-twice-mod2 \ + tst-dlopenfaillinkmod \ + tst-dlopenfailmod1 \ + tst-dlopenfailmod2 \ +@@ -990,23 +1000,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 +2405,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 +2967,25 @@ $(objpfx)tst-tls-allocation-failure-static-patched.out: \ + grep -q '^Fatal glibc error: Cannot allocate TLS block$$' $@ \ + && grep -q '^status: 127$$' $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ ++ $(objpfx)tst-audit-tlsdesc-mod2.so \ ++ $(shared-thread-library) ++ifeq (yes,$(have-mtls-dialect-gnu2)) ++# The test is valid for all TLS types, but we want to exercise GNU2 ++# TLS if possible. ++CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2 ++CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2 ++endif ++$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) ++$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \ ++ $(objpfx)tst-audit-tlsdesc-mod2.so ++$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so ++$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so ++tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so ++$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so ++tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so ++ ++$(objpfx)tst-dlmopen-twice.out: \ ++ $(objpfx)tst-dlmopen-twice-mod1.so \ ++ $(objpfx)tst-dlmopen-twice-mod2.so +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 8bbf110d02..b97c17b3a9 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name) + we are accessing. Therefore we must make the copy of the + mapping data without using malloc. */ + char *temp; +- temp = alloca (strlen (best) + 1); +- strcpy (temp, best); ++ size_t best_len = strlen (best) + 1; ++ temp = alloca (best_len); ++ memcpy (temp, best, best_len); + return __strdup (temp); + } + +diff --git a/elf/dl-call_fini.c b/elf/dl-call_fini.c +new file mode 100644 +index 0000000000..9e7ba10fa2 +--- /dev/null ++++ b/elf/dl-call_fini.c +@@ -0,0 +1,50 @@ ++/* Invoke DT_FINI and DT_FINI_ARRAY callbacks. ++ Copyright (C) 1996-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++void ++_dl_call_fini (void *closure_map) ++{ ++ struct link_map *map = closure_map; ++ ++ /* When debugging print a message first. */ ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS)) ++ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", map->l_name, map->l_ns); ++ ++ /* Make sure nothing happens if we are called twice. */ ++ map->l_init_called = 0; ++ ++ ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY]; ++ if (fini_array != NULL) ++ { ++ ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr ++ + fini_array->d_un.d_ptr); ++ size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val ++ / sizeof (ElfW(Addr))); ++ ++ while (sz-- > 0) ++ ((fini_t) array[sz]) (); ++ } ++ ++ /* Next try the old-style destructor. */ ++ ElfW(Dyn) *fini = map->l_info[DT_FINI]; ++ if (fini != NULL) ++ DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr)); ++} +diff --git a/elf/dl-close.c b/elf/dl-close.c +index bcd6e206e9..14deca2e2b 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -36,11 +36,6 @@ + + #include + +- +-/* Type of the constructor functions. */ +-typedef void (*fini_t) (void); +- +- + /* Special l_idx value used to indicate which objects remain loaded. */ + #define IDX_STILL_USED -1 + +@@ -110,31 +105,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, + return false; + } + +-/* Invoke dstructors for CLOSURE (a struct link_map *). Called with +- exception handling temporarily disabled, to make errors fatal. */ +-static void +-call_destructors (void *closure) +-{ +- struct link_map *map = closure; +- +- if (map->l_info[DT_FINI_ARRAY] != NULL) +- { +- ElfW(Addr) *array = +- (ElfW(Addr) *) (map->l_addr +- + map->l_info[DT_FINI_ARRAY]->d_un.d_ptr); +- unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val +- / sizeof (ElfW(Addr))); +- +- while (sz-- > 0) +- ((fini_t) array[sz]) (); +- } +- +- /* Next try the old-style destructor. */ +- if (map->l_info[DT_FINI] != NULL) +- DL_CALL_DT_FINI (map, ((void *) map->l_addr +- + map->l_info[DT_FINI]->d_un.d_ptr)); +-} +- + void + _dl_close_worker (struct link_map *map, bool force) + { +@@ -280,17 +250,7 @@ _dl_close_worker (struct link_map *map, bool force) + half-cooked objects. Temporarily disable exception + handling, so that errors are fatal. */ + if (imap->l_init_called) +- { +- /* When debugging print a message first. */ +- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, +- 0)) +- _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", +- imap->l_name, nsid); +- +- if (imap->l_info[DT_FINI_ARRAY] != NULL +- || imap->l_info[DT_FINI] != NULL) +- _dl_catch_exception (NULL, call_destructors, imap); +- } ++ _dl_catch_exception (NULL, _dl_call_fini, imap); + + #ifdef SHARED + /* Auditing checkpoint: we remove an object. */ +diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c +index 4d5831b6f4..2e5b456c11 100644 +--- a/elf/dl-find_object.c ++++ b/elf/dl-find_object.c +@@ -46,7 +46,7 @@ _dl_find_object_slow (void *pc, struct dl_find_object *result) + struct dl_find_object_internal internal; + _dl_find_object_from_map (l, &internal); + _dl_find_object_to_external (&internal, result); +- return 1; ++ return 0; + } + + /* Object not found. */ +diff --git a/elf/dl-fini.c b/elf/dl-fini.c +index 030b1fcbcd..50ff94db16 100644 +--- a/elf/dl-fini.c ++++ b/elf/dl-fini.c +@@ -21,11 +21,6 @@ + #include + #include + +- +-/* Type of the constructor functions. */ +-typedef void (*fini_t) (void); +- +- + void + _dl_fini (void) + { +@@ -116,38 +111,7 @@ _dl_fini (void) + + if (l->l_init_called) + { +- /* Make sure nothing happens if we are called twice. */ +- l->l_init_called = 0; +- +- /* Is there a destructor function? */ +- if (l->l_info[DT_FINI_ARRAY] != NULL +- || (ELF_INITFINI && l->l_info[DT_FINI] != NULL)) +- { +- /* When debugging print a message first. */ +- if (__builtin_expect (GLRO(dl_debug_mask) +- & DL_DEBUG_IMPCALLS, 0)) +- _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", +- DSO_FILENAME (l->l_name), +- ns); +- +- /* First see whether an array is given. */ +- if (l->l_info[DT_FINI_ARRAY] != NULL) +- { +- ElfW(Addr) *array = +- (ElfW(Addr) *) (l->l_addr +- + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); +- unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val +- / sizeof (ElfW(Addr))); +- while (i-- > 0) +- ((fini_t) array[i]) (); +- } +- +- /* Next try the old-style destructor. */ +- if (ELF_INITFINI && l->l_info[DT_FINI] != NULL) +- DL_CALL_DT_FINI +- (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr); +- } +- ++ _dl_call_fini (l); + #ifdef SHARED + /* Auditing checkpoint: another object closed. */ + _dl_audit_objclose (l); +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 6f161f6ad5..92eb53790e 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix + and a "/" suffix once stored in the result. */ + hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1; +- size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) ++ size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) + + hwcaps_counts.total_length); + + /* Count the number of bits set in the masked value. */ +@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + assert (m == cnt); + + /* Determine the total size of all strings together. */ ++ size_t total; + if (cnt == 1) +- total += temp[0].len + 1; ++ total = temp[0].len + 1; + else + { +- total += temp[0].len + temp[cnt - 1].len + 2; ++ total = temp[0].len + temp[cnt - 1].len + 2; + if (cnt > 2) + { + total <<= 1; +@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + /* This is the overall result, including both glibc-hwcaps + subdirectories and the legacy hwcaps subdirectories using the + power set construction. */ ++ total += hwcaps_sz; + struct r_strlenpair *overall_result + = malloc (*sz * sizeof (*result) + total); + if (overall_result == NULL) +diff --git a/elf/dl-init.c b/elf/dl-init.c +index deefeb099a..fca8e3a05e 100644 +--- a/elf/dl-init.c ++++ b/elf/dl-init.c +@@ -25,10 +25,14 @@ + static void + call_init (struct link_map *l, int argc, char **argv, char **env) + { ++ /* Do not run constructors for proxy objects. */ ++ if (l != l->l_real) ++ return; ++ + /* If the object has not been relocated, this is a bug. The + function pointers are invalid in this case. (Executables do not +- need relocation, and neither do proxy objects.) */ +- assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable); ++ need relocation.) */ ++ assert (l->l_relocated || l->l_type == lt_executable); + + if (l->l_init_called) + /* This object is all done. */ +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 4c86dc694e..67fb2e31e2 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -854,6 +854,23 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, + if (__glibc_unlikely (current_value.m->l_used == 0)) + current_value.m->l_used = 1; + ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)) ++ { ++ const char *reference_name = undef_map->l_name; ++ ++ _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'", ++ DSO_FILENAME (reference_name), ++ undef_map->l_ns, ++ DSO_FILENAME (current_value.m->l_name), ++ current_value.m->l_ns, ++ protected ? "protected" : "normal", undef_name); ++ if (version) ++ _dl_debug_printf_c (" [%s]\n", version->name); ++ else ++ _dl_debug_printf_c ("\n"); ++ } ++ ++ + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } +diff --git a/elf/dl-open.c b/elf/dl-open.c +index a23e65926b..e7db5e9642 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -850,6 +850,7 @@ no more namespaces available for dlmopen()")); + ++GL(dl_nns); + } + ++ GL(dl_ns)[nsid].libc_map = NULL; + _dl_debug_update (nsid)->r_state = RT_CONSISTENT; + } + /* Never allow loading a DSO in a namespace which is empty. Such +diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c +index 96638d7ed1..3e2a6a584e 100644 +--- a/elf/dl-sort-maps.c ++++ b/elf/dl-sort-maps.c +@@ -27,12 +27,12 @@ + If FOR_FINI is true, this is called for finishing an object. */ + static void + _dl_sort_maps_original (struct link_map **maps, unsigned int nmaps, +- unsigned int skip, bool for_fini) ++ bool force_first, bool for_fini) + { + /* Allows caller to do the common optimization of skipping the first map, + usually the main binary. */ +- maps += skip; +- nmaps -= skip; ++ maps += force_first; ++ nmaps -= force_first; + + /* A list of one element need not be sorted. */ + if (nmaps <= 1) +@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map, + + static void + _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, +- unsigned int skip __attribute__ ((unused)), bool for_fini) ++ bool force_first, bool for_fini) + { ++ struct link_map *first_map = maps[0]; + for (int i = nmaps - 1; i >= 0; i--) + maps[i]->l_visited = 0; + +@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, + Adjusting the order so that maps[0] is last traversed naturally avoids + this problem. + +- Further, the old "optimization" of skipping the main object at maps[0] +- from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general +- no longer valid, since traversing along object dependency-links +- may "find" the main object even when it is not included in the initial +- order (e.g. a dlopen()'ed shared object can have circular dependencies +- linked back to itself). In such a case, traversing N-1 objects will +- create a N-object result, and raise problems. +- + To summarize, just passing in the full list, and iterating from back + to front makes things much more straightforward. */ + +@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, + } + + memcpy (maps, rpo, sizeof (struct link_map *) * nmaps); ++ ++ /* Skipping the first object at maps[0] is not valid in general, ++ since traversing along object dependency-links may "find" that ++ first object even when it is not included in the initial order ++ (e.g., a dlopen'ed shared object can have circular dependencies ++ linked back to itself). In such a case, traversing N-1 objects ++ will create a N-object result, and raise problems. Instead, ++ force the object back into first place after sorting. This naive ++ approach may introduce further dependency ordering violations ++ compared to rotating the cycle until the first map is again in ++ the first position, but as there is a cycle, at least one ++ violation is already present. */ ++ if (force_first && maps[0] != first_map) ++ { ++ int i; ++ for (i = 0; maps[i] != first_map; ++i) ++ ; ++ assert (i < nmaps); ++ memmove (&maps[1], maps, i * sizeof (maps[0])); ++ maps[0] = first_map; ++ } + } + + void +@@ -286,7 +300,7 @@ _dl_sort_maps_init (void) + + void + _dl_sort_maps (struct link_map **maps, unsigned int nmaps, +- unsigned int skip, bool for_fini) ++ bool force_first, bool for_fini) + { + /* It can be tempting to use a static function pointer to store and call + the current selected sorting algorithm routine, but experimentation +@@ -296,9 +310,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, + input cases. A simple if-case with direct function calls appears to + be the fastest. */ + if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original)) +- _dl_sort_maps_original (maps, nmaps, skip, for_fini); ++ _dl_sort_maps_original (maps, nmaps, force_first, for_fini); + else +- _dl_sort_maps_dfs (maps, nmaps, skip, for_fini); ++ _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini); + } + + #endif /* HAVE_TUNABLES. */ +diff --git a/elf/dl-support.c b/elf/dl-support.c +index 4af0b5b2ce..f45b630ba5 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -255,6 +255,25 @@ _dl_aux_init (ElfW(auxv_t) *av) + for (int i = 0; i < array_length (auxv_values); ++i) + auxv_values[i] = 0; + _dl_parse_auxv (av, auxv_values); ++ ++ _dl_phdr = (void*) auxv_values[AT_PHDR]; ++ _dl_phnum = auxv_values[AT_PHNUM]; ++ ++ if (_dl_phdr == NULL) ++ { ++ /* Starting from binutils-2.23, the linker will define the ++ magic symbol __ehdr_start to point to our own ELF header ++ if it is visible in a segment that also includes the phdrs. ++ So we can set up _dl_phdr and _dl_phnum even without any ++ information from auxv. */ ++ ++ extern const ElfW(Ehdr) __ehdr_start attribute_hidden; ++ assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr)); ++ _dl_phdr = (const void *) &__ehdr_start + __ehdr_start.e_phoff; ++ _dl_phnum = __ehdr_start.e_phnum; ++ } ++ ++ assert (_dl_phdr != NULL); + } + #endif + +@@ -323,20 +342,19 @@ _dl_non_dynamic_init (void) + if (_dl_platform != NULL) + _dl_platformlen = strlen (_dl_platform); + +- if (_dl_phdr != NULL) +- for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph) +- switch (ph->p_type) +- { +- /* Check if the stack is nonexecutable. */ +- case PT_GNU_STACK: +- _dl_stack_flags = ph->p_flags; +- break; +- +- case PT_GNU_RELRO: +- _dl_main_map.l_relro_addr = ph->p_vaddr; +- _dl_main_map.l_relro_size = ph->p_memsz; +- break; +- } ++ for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph) ++ switch (ph->p_type) ++ { ++ /* Check if the stack is nonexecutable. */ ++ case PT_GNU_STACK: ++ _dl_stack_flags = ph->p_flags; ++ break; ++ ++ case PT_GNU_RELRO: ++ _dl_main_map.l_relro_addr = ph->p_vaddr; ++ _dl_main_map.l_relro_size = ph->p_memsz; ++ break; ++ } + + call_function_static_weak (_dl_find_object_init); + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 093cdddb7e..bf0ff0d9e8 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -160,6 +160,7 @@ _dl_assign_tls_modid (struct link_map *l) + { + /* Mark the entry as used, so any dependency see it. */ + atomic_store_relaxed (&runp->slotinfo[result - disp].map, l); ++ atomic_store_relaxed (&runp->slotinfo[result - disp].gen, 0); + break; + } + +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index 8e7ee9df10..76cf8b9da3 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -187,11 +187,7 @@ parse_tunables (char *tunestr, char *valstring) + /* If we reach the end of the string before getting a valid name-value + pair, bail out. */ + if (p[len] == '\0') +- { +- if (__libc_enable_secure) +- tunestr[off] = '\0'; +- return; +- } ++ break; + + /* We did not find a valid name-value pair before encountering the + colon. */ +@@ -251,9 +247,16 @@ parse_tunables (char *tunestr, char *valstring) + } + } + +- if (p[len] != '\0') +- p += len + 1; ++ /* We reached the end while processing the tunable string. */ ++ if (p[len] == '\0') ++ break; ++ ++ p += len + 1; + } ++ ++ /* Terminate tunestr before we leave. */ ++ if (__libc_enable_secure) ++ tunestr[off] = '\0'; + } + #endif + +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index e6a56b3070..9fa3b484cf 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -169,4 +169,17 @@ glibc { + default: 2 + } + } ++ ++ gmon { ++ minarcs { ++ type: INT_32 ++ minval: 50 ++ default: 50 ++ } ++ maxarcs { ++ type: INT_32 ++ minval: 50 ++ default: 1048576 ++ } ++ } + } +diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def +index 5f7f18ef27..4bf9052db1 100644 +--- a/elf/dso-sort-tests-1.def ++++ b/elf/dso-sort-tests-1.def +@@ -64,3 +64,10 @@ output: b>a>{}b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c + output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[a1;a->a2;a2->a;b->b1;c->a1;c=>a1 ++output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());}l_faked) + /* The library was not found. */ + _dl_printf ("\t%s => not found\n", l->l_libname->name); ++ else if (strcmp (l->l_libname->name, l->l_name) == 0) ++ /* Print vDSO like libraries without duplicate name. Some ++ consumers depend of this format. */ ++ _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name, ++ (int) sizeof l->l_map_start * 2, ++ (size_t) l->l_map_start); + else + _dl_printf ("\t%s => %s (0x%0*Zx)\n", + DSO_FILENAME (l->l_libname->name), +diff --git a/elf/tst-auditmod28.c b/elf/tst-auditmod28.c +index db7ba95abe..9e0a122c38 100644 +--- a/elf/tst-auditmod28.c ++++ b/elf/tst-auditmod28.c +@@ -71,6 +71,17 @@ la_version (unsigned int current) + TEST_VERIFY (dladdr1 (&_exit, &info, &extra_info, RTLD_DL_LINKMAP) != 0); + TEST_VERIFY (extra_info == handle); + ++ /* Check _dl_find_object. */ ++ struct dl_find_object dlfo; ++ TEST_COMPARE (_dl_find_object (__builtin_return_address (0), &dlfo), 0); ++ /* "ld.so" is seen with --enable-hardcoded-path-in-tests. */ ++ if (strcmp (basename (dlfo.dlfo_link_map->l_name), "ld.so") != 0) ++ TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LD_SO); ++ TEST_COMPARE (_dl_find_object (dlsym (handle, "environ"), &dlfo), 0); ++ TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LIBC_SO); ++ TEST_COMPARE (_dl_find_object ((void *) 1, &dlfo), -1); ++ TEST_COMPARE (_dl_find_object ((void *) -1, &dlfo), -1); ++ + /* Verify that dlmopen creates a new namespace. */ + void *dlmopen_handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); + TEST_VERIFY (dlmopen_handle != handle); +diff --git a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c +new file mode 100644 +index 0000000000..0eaf04948c +--- /dev/null ++++ b/elf/tst-dlmopen-twice-mod1.c +@@ -0,0 +1,37 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod1.so loaded"); ++ fflush (stdout); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded"); ++ fflush (stdout); ++} ++ ++/* Large allocation. The second module does not have this, so it ++ should load libc at a different address. */ ++char large_allocate[16 * 1024 * 1024]; +diff --git a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c +new file mode 100644 +index 0000000000..40c6c01f96 +--- /dev/null ++++ b/elf/tst-dlmopen-twice-mod2.c +@@ -0,0 +1,50 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod2.so loaded"); ++ fflush (stdout); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded"); ++ fflush (stdout); ++} ++ ++int ++run_check (void) ++{ ++ puts ("info: about to call isalpha"); ++ fflush (stdout); ++ ++ volatile char ch = 'a'; ++ if (!isalpha (ch)) ++ { ++ puts ("error: isalpha ('a') is not true"); ++ fflush (stdout); ++ return 1; ++ } ++ return 0; ++} +diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c +new file mode 100644 +index 0000000000..70c71fe19c +--- /dev/null ++++ b/elf/tst-dlmopen-twice.c +@@ -0,0 +1,54 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++/* Run the test multiple times, to check finding a new namespace while ++ another namespace is already in use. This used to trigger bug 29600. */ ++static void ++recurse (int depth) ++{ ++ if (depth == 0) ++ return; ++ ++ printf ("info: running at depth %d\n", depth); ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", ++ RTLD_NOW); ++ xdlclose (handle); ++ handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW); ++ int (*run_check) (void) = xdlsym (handle, "run_check"); ++ TEST_COMPARE (run_check (), 0); ++ recurse (depth - 1); ++ xdlclose (handle); ++} ++ ++static int ++do_test (void) ++{ ++ /* First run the test without nesting. */ ++ recurse (1); ++ ++ /* Then with nesting. The constant needs to be less than the ++ internal DL_NNS namespace constant. */ ++ recurse (10); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c +index 88182b7b25..5e9e4c5756 100644 +--- a/elf/tst-env-setuid-tunables.c ++++ b/elf/tst-env-setuid-tunables.c +@@ -52,6 +52,8 @@ const char *teststrings[] = + "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", + "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096", + "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.check=2", + "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2", + "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096", + ":glibc.malloc.garbage=2:glibc.malloc.check=1", +@@ -70,6 +72,8 @@ const char *resultstrings[] = + "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", ++ "", + "", + "", + "", +@@ -84,11 +88,18 @@ test_child (int off) + const char *val = getenv ("GLIBC_TUNABLES"); + + #if HAVE_TUNABLES ++ printf (" [%d] GLIBC_TUNABLES is %s\n", off, val); ++ fflush (stdout); + if (val != NULL && strcmp (val, resultstrings[off]) == 0) + return 0; + + if (val != NULL) +- printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val); ++ printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n", ++ off, val, resultstrings[off]); ++ else ++ printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off); ++ ++ fflush (stdout); + + return 1; + #else +@@ -117,21 +128,26 @@ do_test (int argc, char **argv) + if (ret != 0) + exit (1); + +- exit (EXIT_SUCCESS); ++ /* Special return code to make sure that the child executed all the way ++ through. */ ++ exit (42); + } + else + { +- int ret = 0; +- + /* Spawn tests. */ + for (int i = 0; i < array_length (teststrings); i++) + { + char buf[INT_BUFSIZE_BOUND (int)]; + +- printf ("Spawned test for %s (%d)\n", teststrings[i], i); ++ printf ("[%d] Spawned test for %s\n", i, teststrings[i]); + snprintf (buf, sizeof (buf), "%d\n", i); ++ fflush (stdout); + if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0) +- exit (1); ++ { ++ printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i); ++ support_record_failure (); ++ continue; ++ } + + int status = support_capture_subprogram_self_sgid (buf); + +@@ -139,9 +155,14 @@ do_test (int argc, char **argv) + if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) + return EXIT_UNSUPPORTED; + +- ret |= status; ++ if (WEXITSTATUS (status) != 42) ++ { ++ printf (" [%d] child failed with status %d\n", i, ++ WEXITSTATUS (status)); ++ support_record_failure (); ++ } + } +- return ret; ++ return 0; + } + } + +diff --git a/elf/tst-ldconfig-p.sh b/elf/tst-ldconfig-p.sh +new file mode 100644 +index 0000000000..ec937bf4ec +--- /dev/null ++++ b/elf/tst-ldconfig-p.sh +@@ -0,0 +1,77 @@ ++#!/bin/sh ++# Test that ldconfig -p prints something useful. ++# Copyright (C) 2023 Free Software Foundation, Inc. ++# This file is part of the GNU C Library. ++ ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++ ++# The GNU C Library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++ ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# . ++ ++# Check that the newly built ldconfig -p can dump the system ++# /etc/ld.so.cache file. This should always work even if the ABIs are ++# not compatible, except in a cross-endian build (that presumably ++# involves emulation when running ldconfig). ++ ++common_objpfx=$1 ++test_wrapper_env=$2 ++run_program_env=$3 ++ ++if ! test -r /etc/ld.so.cache; then ++ echo "warning: /etc/ld.so.cache does not exist, test skipped" ++ exit 77 ++fi ++ ++testout="${common_objpfx}elf/tst-ldconfig-p.out" ++# Truncate file. ++: > "$testout" ++ ++${test_wrapper_env} \ ++${run_program_env} \ ++${common_objpfx}elf/ldconfig -p \ ++ $testroot/lib >>"$testout" 2>>"$testout" ++status=$? ++echo "info: ldconfig exit status: $status" >>"$testout" ++ ++errors=0 ++case $status in ++ (0) ++ if head -n 1 "$testout" | \ ++ grep -q "libs found in cache \`/etc/ld.so.cache'\$" ; then ++ echo "info: initial string found" >>"$testout" ++ else ++ echo "error: initial string not found" >>"$testout" ++ errors=1 ++ fi ++ if grep -q "^ libc\.so\..* => " "$testout"; then ++ echo "info: libc.so.* string found" >>"$testout" ++ else ++ echo "error: libc.so.* string not found" >>"$testout" ++ errors=1 ++ fi ++ ;; ++ (1) ++ if head -n 1 "$testout" | \ ++ grep -q ": Cache file has wrong endianness\.$" ; then ++ echo "info: cache file has wrong endianess" >> "$testout" ++ else ++ echo "error: unexpected ldconfig error message" >> "$testout" ++ errors=1 ++ fi ++ ;; ++ (*) ++ echo "error: unexpected exit status" >> "$testout" ++ errors=1 ++ ;; ++esac ++ ++exit $errors +diff --git a/gmon/Makefile b/gmon/Makefile +index 552b7d7751..fbe2b0ba5c 100644 +--- a/gmon/Makefile ++++ b/gmon/Makefile +@@ -1,4 +1,5 @@ +-# Copyright (C) 1995-2022 Free Software Foundation, Inc. ++# Copyright (C) 1995-2023 Free Software Foundation, Inc. ++# Copyright The GNU Toolchain Authors. + # This file is part of the GNU C Library. + + # The GNU C Library is free software; you can redistribute it and/or +@@ -25,7 +26,7 @@ include ../Makeconfig + headers := sys/gmon.h sys/gmon_out.h sys/profil.h + routines := gmon mcount profil sprofil prof-freq + +-tests = tst-sprofil tst-gmon ++tests = tst-sprofil tst-gmon tst-mcleanup + ifeq ($(build-profile),yes) + tests += tst-profile-static + tests-static += tst-profile-static +@@ -56,6 +57,14 @@ ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)tst-gmon-gprof.out + endif + ++CFLAGS-tst-mcleanup.c := -fno-omit-frame-pointer -pg ++tst-mcleanup-no-pie = yes ++CRT-tst-mcleanup := $(csu-objpfx)g$(start-installed-name) ++tst-mcleanup-ENV := GMON_OUT_PREFIX=$(objpfx)tst-mcleanup.data ++ifeq ($(run-built-tests),yes) ++tests-special += $(objpfx)tst-mcleanup.out ++endif ++ + CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg + CRT-tst-gmon-static := $(csu-objpfx)g$(static-start-installed-name) + tst-gmon-static-no-pie = yes +@@ -103,6 +112,18 @@ $(objpfx)tst-gmon.out: clean-tst-gmon-data + clean-tst-gmon-data: + rm -f $(objpfx)tst-gmon.data.* + ++$(objpfx)tst-mcount-overflow.o: clean-tst-mcount-overflow-data ++clean-tst-mcount-overflow-data: ++ rm -f $(objpfx)tst-mcount-overflow.data.* ++ ++$(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)tst-mcount-overflow.out ++ $(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \ ++ $(evaluate-test) ++ ++$(objpfx)tst-mcleanup.out: clean-tst-mcleanup-data ++clean-tst-mcleanup-data: ++ rm -f $(objpfx)tst-mcleanup.data.* ++ + $(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out + $(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \ + $(evaluate-test) +diff --git a/gmon/gmon.c b/gmon/gmon.c +index dee64803ad..97be1f72ca 100644 +--- a/gmon/gmon.c ++++ b/gmon/gmon.c +@@ -97,11 +97,8 @@ __moncontrol (int mode) + { + struct gmonparam *p = &_gmonparam; + +- /* Don't change the state if we ran into an error. */ +- if (p->state == GMON_PROF_ERROR) +- return; +- +- if (mode) ++ /* Treat start request as stop if error or gmon not initialized. */ ++ if (mode && p->state != GMON_PROF_ERROR && p->tos != NULL) + { + /* start */ + __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale); +@@ -111,7 +108,9 @@ __moncontrol (int mode) + { + /* stop */ + __profil(NULL, 0, 0, 0); +- p->state = GMON_PROF_OFF; ++ /* Don't change the state if we ran into an error. */ ++ if (p->state != GMON_PROF_ERROR) ++ p->state = GMON_PROF_OFF; + } + } + libc_hidden_def (__moncontrol) +@@ -124,6 +123,19 @@ __monstartup (u_long lowpc, u_long highpc) + int o; + char *cp; + struct gmonparam *p = &_gmonparam; ++ long int minarcs, maxarcs; ++ ++ /* No tunables, we use hardcoded defaults */ ++ minarcs = MINARCS; ++ maxarcs = MAXARCS; ++ ++ /* ++ * If we are incorrectly called twice in a row (without an ++ * intervening call to _mcleanup), ignore the second call to ++ * prevent leaking memory. ++ */ ++ if (p->tos != NULL) ++ return; + + /* + * round lowpc and highpc to multiples of the density we're using +@@ -132,6 +144,8 @@ __monstartup (u_long lowpc, u_long highpc) + p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->textsize = p->highpc - p->lowpc; ++ /* This looks like a typo, but it's here to align the p->froms ++ section. */ + p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms)); + p->hashfraction = HASHFRACTION; + p->log_hashfraction = -1; +@@ -142,12 +156,12 @@ __monstartup (u_long lowpc, u_long highpc) + instead of integer division. Precompute shift amount. */ + p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1; + } +- p->fromssize = p->textsize / HASHFRACTION; ++ p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms)); + p->tolimit = p->textsize * ARCDENSITY / 100; +- if (p->tolimit < MINARCS) +- p->tolimit = MINARCS; +- else if (p->tolimit > MAXARCS) +- p->tolimit = MAXARCS; ++ if (p->tolimit < minarcs) ++ p->tolimit = minarcs; ++ else if (p->tolimit > maxarcs) ++ p->tolimit = maxarcs; + p->tossize = p->tolimit * sizeof(struct tostruct); + + cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1); +@@ -440,9 +454,14 @@ _mcleanup (void) + { + __moncontrol (0); + +- if (_gmonparam.state != GMON_PROF_ERROR) ++ if (_gmonparam.state != GMON_PROF_ERROR && _gmonparam.tos != NULL) + write_gmon (); + + /* free the memory. */ + free (_gmonparam.tos); ++ ++ /* reset buffer to initial state for safety */ ++ memset(&_gmonparam, 0, sizeof _gmonparam); ++ /* somewhat confusingly, ON=0, OFF=3 */ ++ _gmonparam.state = GMON_PROF_OFF; + } +diff --git a/gmon/mcount.c b/gmon/mcount.c +index 9d4a1a50fa..f7180fdb83 100644 +--- a/gmon/mcount.c ++++ b/gmon/mcount.c +@@ -41,6 +41,10 @@ static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; + + #include + ++#include ++#include ++#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1) ++ + /* + * mcount is called on entry to each function compiled with the profiling + * switch set. _mcount(), which is declared in a machine-dependent way +@@ -170,6 +174,7 @@ done: + return; + overflow: + p->state = GMON_PROF_ERROR; ++ ERR("mcount: call graph buffer size limit exceeded, gmon.out will not be generated\n"); + return; + } + +diff --git a/gmon/sys/gmon.h b/gmon/sys/gmon.h +index b4cc3b043a..af0582a371 100644 +--- a/gmon/sys/gmon.h ++++ b/gmon/sys/gmon.h +@@ -111,6 +111,8 @@ extern struct __bb *__bb_head; + * Always allocate at least this many tostructs. This + * hides the inadequacy of the ARCDENSITY heuristic, at least + * for small programs. ++ * ++ * Value can be overridden at runtime by glibc.gmon.minarcs tunable. + */ + #define MINARCS 50 + +@@ -124,8 +126,8 @@ extern struct __bb *__bb_head; + * Used to be max representable value of ARCINDEX minus 2, but now + * that ARCINDEX is a long, that's too large; we don't really want + * to allow a 48 gigabyte table. +- * The old value of 1<<16 wasn't high enough in practice for large C++ +- * programs; will 1<<20 be adequate for long? FIXME ++ * ++ * Value can be overridden at runtime by glibc.gmon.maxarcs tunable. + */ + #define MAXARCS (1 << 20) + +diff --git a/gmon/tst-mcleanup.c b/gmon/tst-mcleanup.c +new file mode 100644 +index 0000000000..b259653ec8 +--- /dev/null ++++ b/gmon/tst-mcleanup.c +@@ -0,0 +1,31 @@ ++/* Test program for repeated invocation of _mcleanup ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Intentionally calls _mcleanup() twice: once manually, it will be ++ called again as an atexit handler. This is incorrect use of the API, ++ but the point of the test is to make sure we don't crash when the ++ API is misused in this way. */ ++ ++#include ++ ++int ++main (void) ++{ ++ _mcleanup(); ++ return 0; ++} +diff --git a/gmon/tst-mcount-overflow-check.sh b/gmon/tst-mcount-overflow-check.sh +new file mode 100644 +index 0000000000..27eb5538fd +--- /dev/null ++++ b/gmon/tst-mcount-overflow-check.sh +@@ -0,0 +1,45 @@ ++#!/bin/sh ++# Test expected messages generated when mcount overflows ++# Copyright (C) 2017-2023 Free Software Foundation, Inc. ++# Copyright The GNU Toolchain Authors. ++# This file is part of the GNU C Library. ++ ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++ ++# The GNU C Library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++ ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# . ++ ++LC_ALL=C ++export LC_ALL ++set -e ++exec 2>&1 ++ ++program="$1" ++ ++check_msg() { ++ if ! grep -q "$1" "$program.out"; then ++ echo "FAIL: expected message not in output: $1" ++ exit 1 ++ fi ++} ++ ++check_msg 'monstartup: maxarcs < minarcs, setting maxarcs = minarcs' ++check_msg 'mcount: call graph buffer size limit exceeded, gmon.out will not be generated' ++ ++for data_file in $1.data.*; do ++ if [ -f "$data_file" ]; then ++ echo "FAIL: expected no data files, but found $data_file" ++ exit 1 ++ fi ++done ++ ++echo PASS +diff --git a/gmon/tst-mcount-overflow.c b/gmon/tst-mcount-overflow.c +new file mode 100644 +index 0000000000..06cc93ef87 +--- /dev/null ++++ b/gmon/tst-mcount-overflow.c +@@ -0,0 +1,72 @@ ++/* Test program to trigger mcount overflow in profiling collection. ++ Copyright (C) 2017-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Program with sufficiently complex, yet pointless, call graph ++ that it will trigger an mcount overflow, when you set the ++ minarcs/maxarcs tunables to very low values. */ ++ ++#define PREVENT_TAIL_CALL asm volatile ("") ++ ++/* Calls REP(n) macro 16 times, for n=0..15. ++ * You need to define REP(n) before using this. ++ */ ++#define REPS \ ++ REP(0) REP(1) REP(2) REP(3) REP(4) REP(5) REP(6) REP(7) \ ++ REP(8) REP(9) REP(10) REP(11) REP(12) REP(13) REP(14) REP(15) ++ ++/* Defines 16 leaf functions named f1_0 to f1_15 */ ++#define REP(n) \ ++ __attribute__ ((noinline, noclone, weak)) void f1_##n (void) {}; ++REPS ++#undef REP ++ ++/* Calls all 16 leaf functions f1_* in succession */ ++__attribute__ ((noinline, noclone, weak)) void ++f2 (void) ++{ ++# define REP(n) f1_##n(); ++ REPS ++# undef REP ++ PREVENT_TAIL_CALL; ++} ++ ++/* Defines 16 functions named f2_0 to f2_15, which all just call f2 */ ++#define REP(n) \ ++ __attribute__ ((noinline, noclone, weak)) void \ ++ f2_##n (void) { f2(); PREVENT_TAIL_CALL; }; ++REPS ++#undef REP ++ ++__attribute__ ((noinline, noclone, weak)) void ++f3 (int count) ++{ ++ for (int i = 0; i < count; ++i) ++ { ++ /* Calls f1_0(), f2_0(), f1_1(), f2_1(), f3_0(), etc */ ++# define REP(n) f1_##n(); f2_##n(); ++ REPS ++# undef REP ++ } ++} ++ ++int ++main (void) ++{ ++ f3 (1000); ++ return 0; ++} +diff --git a/gshadow/Makefile b/gshadow/Makefile +index eff303f538..5b3fa7e387 100644 +--- a/gshadow/Makefile ++++ b/gshadow/Makefile +@@ -26,7 +26,7 @@ headers = gshadow.h + routines = getsgent getsgnam sgetsgent fgetsgent putsgent \ + getsgent_r getsgnam_r sgetsgent_r fgetsgent_r + +-tests = tst-gshadow tst-putsgent tst-fgetsgent_r ++tests = tst-gshadow tst-putsgent tst-fgetsgent_r tst-sgetsgent + + CFLAGS-getsgent_r.c += -fexceptions + CFLAGS-getsgent.c += -fexceptions +diff --git a/gshadow/sgetsgent_r.c b/gshadow/sgetsgent_r.c +index 28c826c9b5..a767a643d4 100644 +--- a/gshadow/sgetsgent_r.c ++++ b/gshadow/sgetsgent_r.c +@@ -61,7 +61,10 @@ __sgetsgent_r (const char *string, struct sgrp *resbuf, char *buffer, + buffer[buflen - 1] = '\0'; + sp = strncpy (buffer, string, buflen); + if (buffer[buflen - 1] != '\0') +- return ERANGE; ++ { ++ __set_errno (ERANGE); ++ return ERANGE; ++ } + } + else + sp = (char *) string; +diff --git a/gshadow/tst-sgetsgent.c b/gshadow/tst-sgetsgent.c +new file mode 100644 +index 0000000000..0370c10fd0 +--- /dev/null ++++ b/gshadow/tst-sgetsgent.c +@@ -0,0 +1,69 @@ ++/* Test large input for sgetsgent (bug 30151). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Create a shadow group with 1000 members. */ ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ const char *passwd = "k+zD0nucwfxAo3sw1NXUj6K5vt5M16+X0TVGdE1uFvq5R8V7efJ"; ++ fprintf (mem.out, "group-name:%s::m0", passwd); ++ for (int i = 1; i < 1000; ++i) ++ fprintf (mem.out, ",m%d", i); ++ xfclose_memstream (&mem); ++ ++ /* Call sgetsgent. */ ++ char *input = mem.buffer; ++ struct sgrp *e = sgetsgent (input); ++ TEST_VERIFY_EXIT (e != NULL); ++ TEST_COMPARE_STRING (e->sg_namp, "group-name"); ++ TEST_COMPARE_STRING (e->sg_passwd, passwd); ++ /* No administrators. */ ++ TEST_COMPARE_STRING (e->sg_adm[0], NULL); ++ /* Check the members list. */ ++ for (int i = 0; i < 1000; ++i) ++ { ++ char *member = xasprintf ("m%d", i); ++ TEST_COMPARE_STRING (e->sg_mem[i], member); ++ free (member); ++ } ++ TEST_COMPARE_STRING (e->sg_mem[1000], NULL); ++ ++ /* Check that putsgent brings back the input string. */ ++ xopen_memstream (&mem); ++ TEST_COMPARE (putsgent (e, mem.out), 0); ++ xfclose_memstream (&mem); ++ /* Compare without the trailing '\n' that putsgent added. */ ++ TEST_COMPARE (mem.buffer[mem.length - 1], '\n'); ++ mem.buffer[mem.length - 1] = '\0'; ++ TEST_COMPARE_STRING (mem.buffer, input); ++ ++ free (mem.buffer); ++ free (input); ++ return 0; ++} ++ ++#include +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +index debb96b322..b72933b526 100644 +--- a/iconv/gconv_parseconfdir.h ++++ b/iconv/gconv_parseconfdir.h +@@ -29,14 +29,14 @@ + # define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr) + # define asprintf __asprintf + # define opendir __opendir +-# define readdir __readdir ++# define readdir64 __readdir64 + # define closedir __closedir + # define mempcpy __mempcpy +-# define struct_stat struct __stat64_t64 +-# define lstat __lstat64_time64 ++# define struct_stat64 struct __stat64_t64 ++# define lstat64 __lstat64_time64 + # define feof_unlocked __feof_unlocked + #else +-# define struct_stat struct stat ++# define struct_stat64 struct stat64 + #endif + + /* Name of the file containing the module information in the directories +@@ -148,8 +148,8 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) + DIR *confdir = opendir (buf); + if (confdir != NULL) + { +- struct dirent *ent; +- while ((ent = readdir (confdir)) != NULL) ++ struct dirent64 *ent; ++ while ((ent = readdir64 (confdir)) != NULL) + { + if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN) + continue; +@@ -161,12 +161,12 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) + && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) + { + char *conf; +- struct_stat st; ++ struct_stat64 st; + if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) + continue; + + if (ent->d_type != DT_UNKNOWN +- || (lstat (conf, &st) != -1 && S_ISREG (st.st_mode))) ++ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode))) + found |= read_conf_file (conf, dir, dir_len); + + free (conf); +diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h +index 53f1dbc7c3..c27e7886b7 100644 +--- a/include/arpa/nameser.h ++++ b/include/arpa/nameser.h +@@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW; + int __ns_name_unpack (const unsigned char *, const unsigned char *, + const unsigned char *, unsigned char *, size_t) __THROW; + ++/* Like ns_samename, but for uncompressed binary names. Return true ++ if the two arguments compare are equal as case-insensitive domain ++ names. */ ++_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *) ++ attribute_hidden; ++ + #define ns_msg_getflag(handle, flag) \ + (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift) + +@@ -89,5 +95,105 @@ libc_hidden_proto (__ns_name_unpack) + extern __typeof (ns_samename) __libc_ns_samename; + libc_hidden_proto (__libc_ns_samename) + ++/* Packet parser helper functions. */ ++ ++/* Verify that P points to an uncompressed domain name in wire format. ++ On success, return the length of the encoded name, including the ++ terminating null byte. On failure, return -1 and set errno. EOM ++ must point one past the last byte in the packet. */ ++int __ns_name_length_uncompressed (const unsigned char *p, ++ const unsigned char *eom) attribute_hidden; ++ ++/* Iterator over the resource records in a DNS packet. */ ++struct ns_rr_cursor ++{ ++ /* These members are not changed after initialization. */ ++ const unsigned char *begin; /* First byte of packet. */ ++ const unsigned char *end; /* One past the last byte of the packet. */ ++ const unsigned char *first_rr; /* First resource record (or packet end). */ ++ ++ /* Advanced towards the end while reading the packet. */ ++ const unsigned char *current; ++}; ++ ++/* Returns the RCODE field from the DNS header. */ ++static inline int ++ns_rr_cursor_rcode (const struct ns_rr_cursor *c) ++{ ++ return c->begin[3] & 0x0f; /* Lower 4 bits at offset 3. */ ++} ++ ++/* Returns the length of the answer section according to the DNS header. */ ++static inline int ++ns_rr_cursor_ancount (const struct ns_rr_cursor *c) ++{ ++ return c->begin[6] * 256 + c->begin[7]; /* 16 bits at offset 6. */ ++} ++ ++/* Returns the length of the authority (name server) section according ++ to the DNS header. */ ++static inline int ++ns_rr_cursor_nscount (const struct ns_rr_cursor *c) ++{ ++ return c->begin[8] * 256 + c->begin[9]; /* 16 bits at offset 8. */ ++} ++ ++/* Returns the length of the additional data section according to the ++ DNS header. */ ++static inline int ++ns_rr_cursor_adcount (const struct ns_rr_cursor *c) ++{ ++ return c->begin[10] * 256 + c->begin[11]; /* 16 bits at offset 10. */ ++} ++ ++/* Returns a pointer to the uncompressed question name in wire ++ format. */ ++static inline const unsigned char * ++ns_rr_cursor_qname (const struct ns_rr_cursor *c) ++{ ++ return c->begin + 12; /* QNAME starts right after the header. */ ++} ++ ++/* Returns the question type of the first and only question. */ ++static inline const int ++ns_rr_cursor_qtype (const struct ns_rr_cursor *c) ++{ ++ /* 16 bits 4 bytes back from the first RR header start. */ ++ return c->first_rr[-4] * 256 + c->first_rr[-3]; ++} ++ ++/* Returns the clss of the first and only question (usally C_IN). */ ++static inline const int ++ns_rr_cursor_qclass (const struct ns_rr_cursor *c) ++{ ++ /* 16 bits 2 bytes back from the first RR header start. */ ++ return c->first_rr[-2] * 256 + c->first_rr[-1]; ++} ++ ++/* Initializes *C to cover the packet [BUF, BUF+LEN). Returns false ++ if LEN is less than sizeof (*HD), if the packet does not contain a ++ full (uncompressed) question, or if the question count is not 1. */ ++_Bool __ns_rr_cursor_init (struct ns_rr_cursor *c, ++ const unsigned char *buf, size_t len) ++ attribute_hidden; ++ ++/* Like ns_rr, but the record owner name is not decoded into text format. */ ++struct ns_rr_wire ++{ ++ unsigned char rname[NS_MAXCDNAME]; /* Owner name of the record. */ ++ uint16_t rtype; /* Resource record type (T_*). */ ++ uint16_t rclass; /* Resource record class (C_*). */ ++ uint32_t ttl; /* Time-to-live field. */ ++ const unsigned char *rdata; /* Start of resource record data. */ ++ uint16_t rdlength; /* Length of the data at rdata, in bytes. */ ++}; ++ ++/* Attempts to parse the record at C into *RR. On success, return ++ true, and C is advanced past the record, and RR->rdata points to ++ the record data. On failure, errno is set to EMSGSIZE, and false ++ is returned. */ ++_Bool __ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr) ++ attribute_hidden; ++ + # endif /* !_ISOMAC */ + #endif +diff --git a/include/bits/wchar2-decl.h b/include/bits/wchar2-decl.h +new file mode 100644 +index 0000000000..00b1b93342 +--- /dev/null ++++ b/include/bits/wchar2-decl.h +@@ -0,0 +1 @@ ++#include +diff --git a/include/link.h b/include/link.h +index 0ac82d7c77..87966e8397 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -278,6 +278,10 @@ struct link_map + /* List of object in order of the init and fini calls. */ + struct link_map **l_initfini; + ++ /* Linked list of objects in reverse ELF constructor execution ++ order. Head of list is stored in _dl_init_called_list. */ ++ struct link_map *l_init_called_next; ++ + /* List of the dependencies introduced through symbol binding. */ + struct link_map_reldeps + { +diff --git a/include/resolv.h b/include/resolv.h +index 3590b6f496..4dbbac3800 100644 +--- a/include/resolv.h ++++ b/include/resolv.h +@@ -70,5 +70,8 @@ libc_hidden_proto (__libc_res_nameinquery) + extern __typeof (__res_queriesmatch) __libc_res_queriesmatch; + libc_hidden_proto (__libc_res_queriesmatch) + ++/* Variant of res_hnok which operates on binary (but uncompressed) names. */ ++bool __res_binary_hnok (const unsigned char *dn) attribute_hidden; ++ + # endif /* _RESOLV_H_ && !_ISOMAC */ + #endif +diff --git a/io/Makefile b/io/Makefile +index b1710407d0..b896484320 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -59,6 +59,7 @@ routines := \ + ftw64-time64 \ + closefrom close_range + ++ + others := pwd + test-srcs := ftwtest ftwtest-time64 + tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ +@@ -80,7 +81,9 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ + tst-utimensat \ + tst-closefrom \ + tst-close_range \ +- tst-ftw-bz28126 ++ tst-ftw-bz28126 \ ++ tst-fcntl-lock \ ++ tst-fcntl-lock-lfs + + tests-time64 := \ + tst-fcntl-time64 \ +diff --git a/io/tst-fcntl-lock-lfs.c b/io/tst-fcntl-lock-lfs.c +new file mode 100644 +index 0000000000..f2a909fb02 +--- /dev/null ++++ b/io/tst-fcntl-lock-lfs.c +@@ -0,0 +1,2 @@ ++#define _FILE_OFFSET_BITS 64 ++#include +diff --git a/io/tst-fcntl-lock.c b/io/tst-fcntl-lock.c +new file mode 100644 +index 0000000000..357c4b7b56 +--- /dev/null ++++ b/io/tst-fcntl-lock.c +@@ -0,0 +1,97 @@ ++/* Test for advisory record locking. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License ++ as published by the Free Software Foundation; either version 2 ++ of the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . ++*/ ++ ++#include ++#include ++#include ++ ++/* This is essentially the POSIX lockf. */ ++ ++static int ++fcntl_lockf (int fd, int cmd, off_t len) ++{ ++ struct flock fl = { ++ .l_type = F_WRLCK, ++ .l_whence = SEEK_CUR, ++ .l_len = len ++ }; ++ ++ switch (cmd) ++ { ++ case F_TEST: ++ fl.l_type = F_RDLCK; ++ if (fcntl (fd, F_GETLK, &fl) < 0) ++ return -1; ++ if (fl.l_type == F_UNLCK || fl.l_pid == getpid ()) ++ return 0; ++ errno = EACCES; ++ return -1; ++ ++ case F_ULOCK: ++ fl.l_type = F_UNLCK; ++ return fcntl (fd, F_SETLK, &fl); ++ ++ case F_LOCK: ++ return fcntl (fd, F_SETLKW, &fl); ++ ++ case F_TLOCK: ++ return fcntl (fd, F_SETLK, &fl); ++ } ++ ++ errno = EINVAL; ++ return -1; ++} ++ ++static int ++fcntl64_lockf (int fd, int cmd, off64_t len64) ++ { ++ struct flock64 fl64 = { ++ .l_type = F_WRLCK, ++ .l_whence = SEEK_CUR, ++ .l_len = len64 ++ }; ++ ++ switch (cmd) ++ { ++ case F_TEST: ++ fl64.l_type = F_RDLCK; ++ if (fcntl64 (fd, F_GETLK64, &fl64) < 0) ++ return -1; ++ if (fl64.l_type == F_UNLCK || fl64.l_pid == getpid ()) ++ return 0; ++ errno = EACCES; ++ return -1; ++ ++ case F_ULOCK: ++ fl64.l_type = F_UNLCK; ++ return fcntl64 (fd, F_SETLK64, &fl64); ++ ++ case F_LOCK: ++ return fcntl64 (fd, F_SETLKW64, &fl64); ++ ++ case F_TLOCK: ++ return fcntl64 (fd, F_SETLK64, &fl64); ++ } ++ ++ errno = EINVAL; ++ return -1; ++} ++ ++#define TST_LOCKFD "tst-fcntl-lock." ++#define LOCKF fcntl_lockf ++#define LOCKF64 fcntl64_lockf ++#include "tst-lockf.c" +diff --git a/io/tst-lockf.c b/io/tst-lockf.c +index be92f33fd1..5e41dc19df 100644 +--- a/io/tst-lockf.c ++++ b/io/tst-lockf.c +@@ -24,13 +24,23 @@ + #include + #include + ++#ifndef TST_LOCKFD ++# define TST_LOCKFD "tst-lockfd." ++#endif ++#ifndef LOCKF ++# define LOCKF lockf ++#endif ++#ifndef LOCKF64 ++# define LOCKF64 lockf64 ++#endif ++ + static char *temp_filename; + static int temp_fd; + + static void + do_prepare (int argc, char **argv) + { +- temp_fd = create_temp_file ("tst-lockfd.", &temp_filename); ++ temp_fd = create_temp_file (TST_LOCKFD, &temp_filename); + TEST_VERIFY_EXIT (temp_fd != -1); + } + #define PREPARE do_prepare +@@ -40,22 +50,22 @@ do_test_child_lockf (void *closure) + { + /* Check if parent has [0, 1024) locked. */ + TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0); +- TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), -1); ++ TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), -1); + TEST_COMPARE (errno, EAGAIN); +- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1); ++ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (errno, EACCES); + /* Also Check if parent has last 1024 bytes locked. */ + TEST_COMPARE (lseek (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024); +- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1); ++ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1); + + /* And try to lock [1024, 2048). */ + TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024); +- TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0); + + /* Check if non-LFS interface cap access to 32-bif off_t. */ + TEST_COMPARE (lseek64 (temp_fd, (off64_t)INT32_MAX, SEEK_SET), + (off64_t)INT32_MAX); +- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0); + } + + static void +@@ -63,32 +73,32 @@ do_test_child_lockf64 (void *closure) + { + /* Check if parent has [0, 1024) locked. */ + TEST_COMPARE (lseek64 (temp_fd, 0, SEEK_SET), 0); +- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1); + TEST_COMPARE (errno, EAGAIN); +- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (errno, EACCES); + /* Also Check if parent has last 1024 bytes locked. */ + TEST_COMPARE (lseek64 (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024); +- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); + + /* And try to lock [1024, 2048). */ + TEST_COMPARE (lseek64 (temp_fd, 1024, SEEK_SET), 1024); +- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); + + /* And also [INT32_MAX, INT32_MAX+1024). */ + { + off64_t off = (off64_t)INT32_MAX; + TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); +- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); + } + + /* Check if [INT32_MAX+1024, INT64_MAX) is locked. */ + { + off64_t off = (off64_t)INT32_MAX+1024; + TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); +- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1); + TEST_COMPARE (errno, EAGAIN); +- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (errno, EACCES); + } + } +@@ -97,38 +107,38 @@ static int + do_test (void) + { + /* Basic tests to check if a lock can be obtained and checked. */ +- TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0); +- TEST_COMPARE (lockf (temp_fd, F_LOCK, INT32_MAX), 0); +- TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), 0); +- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, INT32_MAX), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), 0); + TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024); +- TEST_COMPARE (lockf (temp_fd, F_ULOCK, 1024), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_ULOCK, 1024), 0); + /* Parent process should have ([0, 1024), [2048, INT32_MAX)) ranges locked. */ + + { + struct support_capture_subprocess result; + result = support_capture_subprocess (do_test_child_lockf, NULL); +- support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none); ++ support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none); + } + + if (sizeof (off_t) != sizeof (off64_t)) + { + /* Check if previously locked regions with LFS symbol. */ + TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0); +- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); +- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), 0); +- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0); + /* Lock region [INT32_MAX+1024, INT64_MAX). */ + off64_t off = (off64_t)INT32_MAX + 1024; + TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); +- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); + /* Parent process should have ([0, 1024), [2048, INT32_MAX), + [INT32_MAX+1024, INT64_MAX)) ranges locked. */ + + { + struct support_capture_subprocess result; + result = support_capture_subprocess (do_test_child_lockf64, NULL); +- support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none); ++ support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none); + } + } + +diff --git a/locale/weight.h b/locale/weight.h +index 8be2d220f8..4a4d5aa6b2 100644 +--- a/locale/weight.h ++++ b/locale/weight.h +@@ -27,7 +27,14 @@ findidx (const int32_t *table, + const unsigned char *extra, + const unsigned char **cpp, size_t len) + { ++ /* With GCC 8 when compiling with -Os the compiler warns that ++ seq1.back_us and seq2.back_us might be used uninitialized. ++ This uninitialized use is impossible for the same reason ++ as described in comments in locale/weightwc.h. */ ++ DIAG_PUSH_NEEDS_COMMENT; ++ DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized"); + int32_t i = table[*(*cpp)++]; ++ DIAG_POP_NEEDS_COMMENT; + const unsigned char *cp; + const unsigned char *usrc; + +diff --git a/misc/bits/syslog.h b/misc/bits/syslog.h +index fd30dd3114..916d2b6f12 100644 +--- a/misc/bits/syslog.h ++++ b/misc/bits/syslog.h +@@ -24,6 +24,20 @@ + extern void __syslog_chk (int __pri, int __flag, const char *__fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + ++#ifdef __USE_MISC ++extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt, ++ __gnuc_va_list __ap) ++ __attribute__ ((__format__ (__printf__, 3, 0))); ++#endif ++ ++#include ++#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 ++# include ++#endif ++ ++/* The following functions must be used only after applying all asm ++ redirections, e.g. long double asm redirections. */ ++ + #ifdef __va_arg_pack + __fortify_function void + syslog (int __pri, const char *__fmt, ...) +@@ -37,10 +51,6 @@ syslog (int __pri, const char *__fmt, ...) + + + #ifdef __USE_MISC +-extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt, +- __gnuc_va_list __ap) +- __attribute__ ((__format__ (__printf__, 3, 0))); +- + __fortify_function void + vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap) + { +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index f525f67547..294e633335 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -152,6 +152,7 @@ + # define __glibc_objsize(__o) __bos (__o) + #endif + ++#if __USE_FORTIFY_LEVEL > 0 + /* Compile time conditions to choose between the regular, _chk and _chk_warn + variants. These conditions should get evaluated to constant and optimized + away. */ +@@ -187,7 +188,7 @@ + ? __ ## f ## _alias (__VA_ARGS__) \ + : (__glibc_unsafe_len (__l, __s, __osz) \ + ? __ ## f ## _chk_warn (__VA_ARGS__, __osz) \ +- : __ ## f ## _chk (__VA_ARGS__, __osz))) \ ++ : __ ## f ## _chk (__VA_ARGS__, __osz))) + + /* Fortify function f, where object size argument passed to f is the number of + elements and not total size. */ +@@ -197,7 +198,8 @@ + ? __ ## f ## _alias (__VA_ARGS__) \ + : (__glibc_unsafe_len (__l, __s, __osz) \ + ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s)) \ +- : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) \ ++ : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) ++#endif + + #if __GNUC_PREREQ (4,3) + # define __warnattr(msg) __attribute__((__warning__ (msg))) +diff --git a/misc/sys/syslog.h b/misc/sys/syslog.h +index d933fea104..3888153ed2 100644 +--- a/misc/sys/syslog.h ++++ b/misc/sys/syslog.h +@@ -205,11 +205,11 @@ extern void vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap) + /* Define some macros helping to catch buffer overflows. */ + #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function + # include +-#endif +- +-#include +-#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 +-# include ++#else ++# include ++# if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 ++# include ++# endif + #endif + + __END_DECLS +diff --git a/misc/syslog.c b/misc/syslog.c +index 554089bfc4..f67d4b58a4 100644 +--- a/misc/syslog.c ++++ b/misc/syslog.c +@@ -167,7 +167,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) +@@ -193,28 +193,32 @@ __vsyslog_internal (int pri, const char *fmt, va_list 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; +- } ++ buf = bufs; ++ bufsize = l + vl; + + va_end (apc); + } + + 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; + + if (has_ts) +- __snprintf (bufs, sizeof bufs, ++ __snprintf (buf, l + 1, + SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); + else +- __snprintf (bufs, sizeof bufs, ++ __snprintf (buf, l + 1, + SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); ++ ++ va_list apc; ++ va_copy (apc, ap); ++ __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, ++ mode_flags); ++ va_end (apc); + } + else + { +diff --git a/misc/tst-syslog.c b/misc/tst-syslog.c +index e550d15796..3560b518a2 100644 +--- a/misc/tst-syslog.c ++++ b/misc/tst-syslog.c +@@ -68,21 +68,19 @@ static const int priorities[] = + LOG_DEBUG + }; + +-enum +- { +- ident_length = 64, +- msg_length = 64 +- }; ++#define IDENT_LENGTH 64 ++#define MSG_LENGTH 1024 + + #define SYSLOG_MSG_BASE "syslog_message" + #define OPENLOG_IDENT "openlog_ident" ++static char large_message[MSG_LENGTH]; + + struct msg_t + { + int priority; + int facility; +- char ident[ident_length]; +- char msg[msg_length]; ++ char ident[IDENT_LENGTH]; ++ char msg[MSG_LENGTH]; + pid_t pid; + }; + +@@ -147,6 +145,37 @@ check_syslog_message (const struct msg_t *msg, int msgnum, int options, + return true; + } + ++static void ++send_syslog_large (int options) ++{ ++ int facility = LOG_USER; ++ int priority = LOG_INFO; ++ ++ syslog (facility | priority, "%s %d %d", large_message, facility, ++ priority); ++} ++ ++static void ++send_vsyslog_large (int options) ++{ ++ int facility = LOG_USER; ++ int priority = LOG_INFO; ++ ++ call_vsyslog (facility | priority, "%s %d %d", large_message, facility, ++ priority); ++} ++ ++static bool ++check_syslog_message_large (const struct msg_t *msg, int msgnum, int options, ++ pid_t pid) ++{ ++ TEST_COMPARE (msg->facility, LOG_USER); ++ TEST_COMPARE (msg->priority, LOG_INFO); ++ TEST_COMPARE_STRING (msg->msg, large_message); ++ ++ return false; ++} ++ + static void + send_openlog (int options) + { +@@ -179,6 +208,17 @@ send_openlog (int options) + closelog (); + } + ++static void ++send_openlog_large (int options) ++{ ++ /* Define a non-default IDENT and a not default facility. */ ++ openlog (OPENLOG_IDENT, options, LOG_LOCAL0); ++ ++ syslog (LOG_INFO, "%s %d %d", large_message, LOG_LOCAL0, LOG_INFO); ++ ++ closelog (); ++} ++ + static bool + check_openlog_message (const struct msg_t *msg, int msgnum, + int options, pid_t pid) +@@ -189,7 +229,7 @@ check_openlog_message (const struct msg_t *msg, int msgnum, + int expected_priority = priorities[msgnum % array_length (priorities)]; + TEST_COMPARE (msg->priority, expected_priority); + +- char expected_ident[ident_length]; ++ char expected_ident[IDENT_LENGTH]; + snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:", + OPENLOG_IDENT, + options & LOG_PID ? "[" : "", +@@ -211,17 +251,43 @@ check_openlog_message (const struct msg_t *msg, int msgnum, + return true; + } + ++static bool ++check_openlog_message_large (const struct msg_t *msg, int msgnum, ++ int options, pid_t pid) ++{ ++ char expected_ident[IDENT_LENGTH]; ++ snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:", ++ OPENLOG_IDENT, ++ options & LOG_PID ? "[" : "", ++ options & LOG_PID ? pid : 0, ++ options & LOG_PID ? "]" : ""); ++ ++ TEST_COMPARE_STRING (msg->ident, expected_ident); ++ TEST_COMPARE_STRING (msg->msg, large_message); ++ TEST_COMPARE (msg->priority, LOG_INFO); ++ TEST_COMPARE (msg->facility, LOG_LOCAL0); ++ ++ return false; ++} ++ + static struct msg_t + parse_syslog_msg (const char *msg) + { + struct msg_t r = { .pid = -1 }; + int number; ++ int wsb, wsa; ++ ++#define STRINPUT(size) XSTRINPUT(size) ++#define XSTRINPUT(size) "%" # size "s" + + /* The message in the form: +- <179>Apr 8 14:51:19 tst-syslog: syslog message 176 3 */ +- int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d %32s %64s %*d %*d", +- &number, r.ident, r.msg); ++ <179>Apr 8 14:51:19 tst-syslog: message 176 3 */ ++ int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d%n %n" STRINPUT(IDENT_LENGTH) ++ " " STRINPUT(MSG_LENGTH) " %*d %*d", ++ &number, &wsb, &wsa, r.ident, r.msg); + TEST_COMPARE (n, 3); ++ /* It should only one space between timestamp and message. */ ++ TEST_COMPARE (wsa - wsb, 1); + + r.facility = number & LOG_FACMASK; + r.priority = number & LOG_PRIMASK; +@@ -246,7 +312,7 @@ parse_syslog_console (const char *msg) + + /* The message in the form: + openlog_ident: syslog_message 128 0 */ +- int n = sscanf (msg, "%32s %64s %d %d", ++ int n = sscanf (msg, STRINPUT(IDENT_LENGTH) " " STRINPUT(MSG_LENGTH) " %d %d", + r.ident, r.msg, &facility, &priority); + TEST_COMPARE (n, 4); + +@@ -281,7 +347,7 @@ check_syslog_udp (void (*syslog_send)(int), int options, + int msgnum = 0; + while (1) + { +- char buf[512]; ++ char buf[2048]; + size_t l = xrecvfrom (server_udp, buf, sizeof (buf), 0, + (struct sockaddr *) &addr, &addrlen); + buf[l] = '\0'; +@@ -325,7 +391,7 @@ check_syslog_tcp (void (*syslog_send)(int), int options, + + int client_tcp = xaccept (server_tcp, NULL, NULL); + +- char buf[512], *rb = buf; ++ char buf[2048], *rb = buf; + size_t rbl = sizeof (buf); + size_t prl = 0; /* Track the size of the partial record. */ + int msgnum = 0; +@@ -393,20 +459,34 @@ check_syslog_console_read (FILE *fp) + } + + static void +-check_syslog_console (void) ++check_syslog_console_read_large (FILE *fp) ++{ ++ char buf[2048]; ++ TEST_VERIFY (fgets (buf, sizeof (buf), fp) != NULL); ++ struct msg_t msg = parse_syslog_console (buf); ++ ++ TEST_COMPARE_STRING (msg.ident, OPENLOG_IDENT ":"); ++ TEST_COMPARE_STRING (msg.msg, large_message); ++ TEST_COMPARE (msg.priority, LOG_INFO); ++ TEST_COMPARE (msg.facility, LOG_LOCAL0); ++} ++ ++static void ++check_syslog_console (void (*syslog_send)(int), ++ void (*syslog_check)(FILE *fp)) + { + xmkfifo (_PATH_CONSOLE, 0666); + + pid_t sender_pid = xfork (); + if (sender_pid == 0) + { +- send_openlog (LOG_CONS); ++ syslog_send (LOG_CONS); + _exit (0); + } + + { + FILE *fp = xfopen (_PATH_CONSOLE, "r+"); +- check_syslog_console_read (fp); ++ syslog_check (fp); + xfclose (fp); + } + +@@ -425,16 +505,28 @@ send_openlog_callback (void *clousure) + } + + static void +-check_syslog_perror (void) ++send_openlog_callback_large (void *clousure) ++{ ++ int options = *(int *) clousure; ++ send_openlog_large (options); ++} ++ ++static void ++check_syslog_perror (bool large) + { + struct support_capture_subprocess result; +- result = support_capture_subprocess (send_openlog_callback, ++ result = support_capture_subprocess (large ++ ? send_openlog_callback_large ++ : send_openlog_callback, + &(int){LOG_PERROR}); + + FILE *mfp = fmemopen (result.err.buffer, result.err.length, "r"); + if (mfp == NULL) + FAIL_EXIT1 ("fmemopen: %m"); +- check_syslog_console_read (mfp); ++ if (large) ++ check_syslog_console_read_large (mfp); ++ else ++ check_syslog_console_read (mfp); + xfclose (mfp); + + support_capture_subprocess_check (&result, "tst-openlog-child", 0, +@@ -462,10 +554,31 @@ do_test (void) + check_syslog_tcp (send_openlog, LOG_PID, check_openlog_message); + + /* Check the LOG_CONS option. */ +- check_syslog_console (); ++ check_syslog_console (send_openlog, check_syslog_console_read); + + /* Check the LOG_PERROR option. */ +- check_syslog_perror (); ++ check_syslog_perror (false); ++ ++ /* Similar tests as before, but with a large message to trigger the ++ syslog path that uses dynamically allocated memory. */ ++ memset (large_message, 'a', sizeof large_message - 1); ++ large_message[sizeof large_message - 1] = '\0'; ++ ++ check_syslog_udp (send_syslog_large, 0, check_syslog_message_large); ++ check_syslog_tcp (send_syslog_large, 0, check_syslog_message_large); ++ ++ check_syslog_udp (send_vsyslog_large, 0, check_syslog_message_large); ++ check_syslog_tcp (send_vsyslog_large, 0, check_syslog_message_large); ++ ++ check_syslog_udp (send_openlog_large, 0, check_openlog_message_large); ++ check_syslog_tcp (send_openlog_large, 0, check_openlog_message_large); ++ ++ check_syslog_udp (send_openlog_large, LOG_PID, check_openlog_message_large); ++ check_syslog_tcp (send_openlog_large, LOG_PID, check_openlog_message_large); ++ ++ check_syslog_console (send_openlog_large, check_syslog_console_read_large); ++ ++ check_syslog_perror (true); + + return 0; + } +diff --git a/nis/nis_call.c b/nis/nis_call.c +index 90187e30b1..5b9dd50151 100644 +--- a/nis/nis_call.c ++++ b/nis/nis_call.c +@@ -574,7 +574,7 @@ static struct nis_server_cache + unsigned int size; + unsigned int server_used; + unsigned int current_ep; +- __time64_t expires; ++ time_t expires; + char name[]; + } *nis_server_cache[16]; + static time_t nis_cold_start_mtime; +@@ -583,7 +583,7 @@ __libc_lock_define_initialized (static, nis_server_cache_lock) + static directory_obj * + nis_server_cache_search (const_nis_name name, int search_parent, + unsigned int *server_used, unsigned int *current_ep, +- struct __timespec64 *now) ++ struct timespec *now) + { + directory_obj *ret = NULL; + int i; +@@ -641,7 +641,7 @@ nis_server_cache_search (const_nis_name name, int search_parent, + static void + nis_server_cache_add (const_nis_name name, int search_parent, + directory_obj *dir, unsigned int server_used, +- unsigned int current_ep, struct __timespec64 *now) ++ unsigned int current_ep, struct timespec *now) + { + struct nis_server_cache **loc; + struct nis_server_cache *new; +@@ -707,7 +707,7 @@ __nisfind_server (const_nis_name name, int search_parent, + nis_error result = NIS_SUCCESS; + nis_error status; + directory_obj *obj; +- struct __timespec64 ts; ++ struct timespec ts; + unsigned int server_used = ~0; + unsigned int current_ep = ~0; + +@@ -717,7 +717,7 @@ __nisfind_server (const_nis_name name, int search_parent, + if (*dir != NULL) + return NIS_SUCCESS; + +- __clock_gettime64 (CLOCK_REALTIME, &ts); ++ clock_gettime (CLOCK_REALTIME, &ts); + + if ((flags & NO_CACHE) == 0) + *dir = nis_server_cache_search (name, search_parent, &server_used, +diff --git a/nscd/aicache.c b/nscd/aicache.c +index 51e793199f..e0baed170b 100644 +--- a/nscd/aicache.c ++++ b/nscd/aicache.c +@@ -110,11 +110,10 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + "gethostbyname4_r"); + if (fct4 != NULL) + { +- struct gaih_addrtuple atmem; + struct gaih_addrtuple *at; + while (1) + { +- at = &atmem; ++ at = NULL; + rc6 = 0; + herrno = 0; + status[1] = DL_CALL_FCT (fct4, (key, &at, +@@ -137,7 +136,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + goto next_nip; + + /* We found the data. Count the addresses and the size. */ +- for (const struct gaih_addrtuple *at2 = at = &atmem; at2 != NULL; ++ for (const struct gaih_addrtuple *at2 = at; at2 != NULL; + at2 = at2->next) + { + ++naddrs; +diff --git a/nscd/connections.c b/nscd/connections.c +index 61d1674eb4..531d2e83df 100644 +--- a/nscd/connections.c ++++ b/nscd/connections.c +@@ -2284,7 +2284,8 @@ main_loop_epoll (int efd) + sizeof (buf))) != -1) + ; + +- __bump_nl_timestamp (); ++ dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP] ++ = __bump_nl_timestamp (); + } + # endif + else +diff --git a/nscd/nscd.h b/nscd/nscd.h +index 368091aef8..f15321585b 100644 +--- a/nscd/nscd.h ++++ b/nscd/nscd.h +@@ -65,7 +65,7 @@ typedef enum + struct traced_file + { + /* Tracks the last modified time of the traced file. */ +- time_t mtime; ++ __time64_t mtime; + /* Support multiple registered files per database. */ + struct traced_file *next; + int call_res_init; +diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c +index 9becb62033..31c64275f0 100644 +--- a/nscd/nscd_gethst_r.c ++++ b/nscd/nscd_gethst_r.c +@@ -112,7 +112,7 @@ __nscd_get_nl_timestamp (void) + if (map == NULL + || (map != NO_MAPPING + && map->head->nscd_certainly_running == 0 +- && map->head->timestamp + MAPPING_TIMEOUT < time_now ())) ++ && map->head->timestamp + MAPPING_TIMEOUT < time64_now ())) + map = __nscd_get_mapping (GETFDHST, "hosts", &__hst_map_handle.mapped); + + if (map == NO_MAPPING) +diff --git a/nss/Makefile b/nss/Makefile +index a978e3927a..7a52c68791 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -81,6 +81,7 @@ tests-container := \ + tst-nss-test3 \ + tst-reload1 \ + tst-reload2 \ ++ tst-nss-gai-hv2-canonname \ + # tests-container + + # Tests which need libdl +@@ -144,7 +145,17 @@ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) + ifeq ($(build-static-nss),yes) + tests-static += tst-nss-static + endif +-extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os ++extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \ ++ nss_test_gai_hv2_canonname.os ++ ++ifeq ($(run-built-tests),yes) ++ifneq (no,$(PERL)) ++tests-special += $(objpfx)mtrace-tst-nss-gai-hv2-canonname.out ++endif ++endif ++ ++generated += mtrace-tst-nss-gai-hv2-canonname.out \ ++ tst-nss-gai-hv2-canonname.mtrace + + include ../Rules + +@@ -179,12 +190,16 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver + libof-nss_test1 = extramodules + libof-nss_test2 = extramodules + libof-nss_test_errno = extramodules ++libof-nss_test_gai_hv2_canonname = extramodules + $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps) + $(build-module) ++$(objpfx)/libnss_test_gai_hv2_canonname.so: \ ++ $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps) ++ $(build-module) + $(objpfx)nss_test2.os : nss_test1.c + # Use the nss_files suffix for these objects as well. + $(objpfx)/libnss_test1.so$(libnss_files.so-version): $(objpfx)/libnss_test1.so +@@ -194,10 +209,14 @@ $(objpfx)/libnss_test2.so$(libnss_files.so-version): $(objpfx)/libnss_test2.so + $(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \ + $(objpfx)/libnss_test_errno.so + $(make-link) ++$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \ ++ $(objpfx)/libnss_test_gai_hv2_canonname.so ++ $(make-link) + $(patsubst %,$(objpfx)%.out,$(tests) $(tests-container)) : \ + $(objpfx)/libnss_test1.so$(libnss_files.so-version) \ + $(objpfx)/libnss_test2.so$(libnss_files.so-version) \ +- $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) ++ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \ ++ $(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version) + + ifeq (yes,$(have-thread-library)) + $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) +@@ -206,6 +225,17 @@ endif + $(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so + $(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)/libnss_files.so + ++tst-nss-gai-hv2-canonname-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-nss-gai-hv2-canonname.mtrace \ ++ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so ++$(objpfx)mtrace-tst-nss-gai-hv2-canonname.out: \ ++ $(objpfx)tst-nss-gai-hv2-canonname.out ++ { test -r $(objpfx)tst-nss-gai-hv2-canonname.mtrace \ ++ || ( echo "tst-nss-gai-hv2-canonname.mtrace does not exist"; exit 77; ) \ ++ && $(common-objpfx)malloc/mtrace \ ++ $(objpfx)tst-nss-gai-hv2-canonname.mtrace; } > $@; \ ++ $(evaluate-test) ++ + # Disable DT_RUNPATH on NSS tests so that the glibc internal NSS + # functions can load testing NSS modules via DT_RPATH. + LDFLAGS-tst-nss-test1 = -Wl,--disable-new-dtags +@@ -214,3 +244,4 @@ LDFLAGS-tst-nss-test3 = -Wl,--disable-new-dtags + LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags + LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags + LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags ++LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags +diff --git a/nss/getent.c b/nss/getent.c +index 8178b4b470..d2d2524b0c 100644 +--- a/nss/getent.c ++++ b/nss/getent.c +@@ -58,6 +58,8 @@ static const struct argp_option args_options[] = + { + { "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") }, + { "no-idn", 'i', NULL, 0, N_("disable IDN encoding") }, ++ { "no-addrconfig", 'A', NULL, 0, ++ N_("do not filter out unsupported IPv4/IPv6 addresses (with ahosts*)") }, + { NULL, 0, NULL, 0, NULL }, + }; + +@@ -79,6 +81,9 @@ static struct argp argp = + /* Additional getaddrinfo flags for IDN encoding. */ + static int idn_flags = AI_IDN | AI_CANONIDN; + ++/* Set to 0 by --no-addrconfig. */ ++static int addrconfig_flags = AI_ADDRCONFIG; ++ + /* Print the version information. */ + static void + print_version (FILE *stream, struct argp_state *state) +@@ -346,7 +351,7 @@ ahosts_keys_int (int af, int xflags, int number, char *key[]) + + struct addrinfo hint; + memset (&hint, '\0', sizeof (hint)); +- hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME ++ hint.ai_flags = (AI_V4MAPPED | addrconfig_flags | AI_CANONNAME + | idn_flags | xflags); + hint.ai_family = af; + +@@ -905,6 +910,10 @@ parse_option (int key, char *arg, struct argp_state *state) + idn_flags = 0; + break; + ++ case 'A': ++ addrconfig_flags = 0; ++ break; ++ + default: + return ARGP_ERR_UNKNOWN; + } +diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c +new file mode 100644 +index 0000000000..4439c83c9f +--- /dev/null ++++ b/nss/nss_test_gai_hv2_canonname.c +@@ -0,0 +1,56 @@ ++/* NSS service provider that only provides gethostbyname2_r. ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include "nss/tst-nss-gai-hv2-canonname.h" ++ ++/* Catch misnamed and functions. */ ++#pragma GCC diagnostic error "-Wmissing-prototypes" ++NSS_DECLARE_MODULE_FUNCTIONS (test_gai_hv2_canonname) ++ ++extern enum nss_status _nss_files_gethostbyname2_r (const char *, int, ++ struct hostent *, char *, ++ size_t, int *, int *); ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af, ++ struct hostent *result, ++ char *buffer, size_t buflen, ++ int *errnop, int *herrnop) ++{ ++ return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop, ++ herrnop); ++} ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer, ++ size_t buflen, char **result, ++ int *errnop, int *h_errnop) ++{ ++ /* We expect QUERYNAME, which is a small enough string that it shouldn't fail ++ the test. */ ++ if (memcmp (QUERYNAME, name, sizeof (QUERYNAME)) ++ || buflen < sizeof (QUERYNAME)) ++ abort (); ++ ++ strncpy (buffer, name, buflen); ++ *result = buffer; ++ return NSS_STATUS_SUCCESS; ++} +diff --git a/nss/tst-nss-files-hosts-long.c b/nss/tst-nss-files-hosts-long.c +index 3942cf5fca..a7697e3143 100644 +--- a/nss/tst-nss-files-hosts-long.c ++++ b/nss/tst-nss-files-hosts-long.c +@@ -28,14 +28,15 @@ do_test (void) + { + int ret; + +- /* Run getent to fetch the IPv4 address for host test4. +- This forces /etc/hosts to be parsed. */ +- ret = system("getent ahostsv4 test4"); ++ /* Run getent to fetch the IPv4 address for host test4. This forces ++ /etc/hosts to be parsed. Use --no-addrconfig to return addresses ++ even in an IPv6-only environment. */ ++ ret = system("getent --no-addrconfig ahostsv4 test4"); + if (ret != 0) + FAIL_EXIT1("ahostsv4 failed"); + + /* Likewise for IPv6. */ +- ret = system("getent ahostsv6 test6"); ++ ret = system("getent --no-addrconfig ahostsv6 test6"); + if (ret != 0) + FAIL_EXIT1("ahostsv6 failed"); + +diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c +new file mode 100644 +index 0000000000..7db53cf09d +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.c +@@ -0,0 +1,66 @@ ++/* Test NSS query path for plugins that only implement gethostbyname2 ++ (#30843). ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "nss/tst-nss-gai-hv2-canonname.h" ++ ++#define PREPARE do_prepare ++ ++static void do_prepare (int a, char **av) ++{ ++ FILE *hosts = xfopen ("/etc/hosts", "w"); ++ for (unsigned i = 2; i < 255; i++) ++ { ++ fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i); ++ fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i); ++ } ++ xfclose (hosts); ++} ++ ++static int ++do_test (void) ++{ ++ mtrace (); ++ ++ __nss_configure_lookup ("hosts", "test_gai_hv2_canonname"); ++ ++ struct addrinfo hints = {}; ++ struct addrinfo *result = NULL; ++ ++ hints.ai_family = AF_INET6; ++ hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME; ++ ++ int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result); ++ ++ if (ret != 0) ++ FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret)); ++ ++ TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME); ++ ++ freeaddrinfo(result); ++ return 0; ++} ++ ++#include +diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h +new file mode 100644 +index 0000000000..14f2a9cb08 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.h +@@ -0,0 +1 @@ ++#define QUERYNAME "test.example.com" +diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script +new file mode 100644 +index 0000000000..31848b4a28 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script +@@ -0,0 +1,2 @@ ++cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2 ++su +diff --git a/nss/tst-reload1.c b/nss/tst-reload1.c +index fdc5bdd65b..bc32bb132a 100644 +--- a/nss/tst-reload1.c ++++ b/nss/tst-reload1.c +@@ -43,12 +43,12 @@ static struct passwd pwd_table_1[] = { + + static const char *hostaddr_5[] = + { +- "ABCD", "abcd", "1234", NULL ++ "ABCd", "ABCD", "ABC4", NULL + }; + + static const char *hostaddr_15[] = + { +- "4321", "ghij", NULL ++ "4321", "4322", NULL + }; + + static const char *hostaddr_25[] = +@@ -86,12 +86,12 @@ static const char *hostaddr_6[] = + + static const char *hostaddr_16[] = + { +- "7890", "a1b2", NULL ++ "7890", "7891", NULL + }; + + static const char *hostaddr_26[] = + { +- "qwer", "tyui", NULL ++ "qwer", "qweR", NULL + }; + + static struct hostent host_table_2[] = { +diff --git a/resolv/Makefile b/resolv/Makefile +index 5b15321f9b..28cedf49ee 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -40,12 +40,16 @@ routines := \ + inet_pton \ + ns_makecanon \ + ns_name_compress \ ++ ns_name_length_uncompressed \ + ns_name_ntop \ + ns_name_pack \ + ns_name_pton \ + ns_name_skip \ + ns_name_uncompress \ + ns_name_unpack \ ++ ns_rr_cursor_init \ ++ ns_rr_cursor_next \ ++ ns_samebinaryname \ + ns_samename \ + nsap_addr \ + nss_dns_functions \ +@@ -89,11 +93,15 @@ tests += \ + tst-ns_name_pton \ + tst-res_hconf_reorder \ + tst-res_hnok \ ++ tst-resolv-aliases \ + tst-resolv-basic \ + tst-resolv-binary \ ++ tst-resolv-byaddr \ + tst-resolv-edns \ ++ tst-resolv-invalid-cname \ + tst-resolv-network \ + tst-resolv-noaaaa \ ++ tst-resolv-noaaaa-vc \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ +@@ -104,6 +112,18 @@ tests += \ + tests-internal += tst-resolv-txnid-collision + tests-static += tst-resolv-txnid-collision + ++# Likewise for __ns_samebinaryname. ++tests-internal += tst-ns_samebinaryname ++tests-static += tst-ns_samebinaryname ++ ++# Likewise for __ns_name_length_uncompressed. ++tests-internal += tst-ns_name_length_uncompressed ++tests-static += tst-ns_name_length_uncompressed ++ ++# Likewise for struct ns_rr_cursor and its functions. ++tests-internal += tst-ns_rr_cursor ++tests-static += tst-ns_rr_cursor ++ + # These tests need libdl. + ifeq (yes,$(build-shared)) + tests += \ +@@ -258,8 +278,10 @@ $(objpfx)tst-resolv-ai_idn.out: $(gen-locales) + $(objpfx)tst-resolv-ai_idn-latin1.out: $(gen-locales) + $(objpfx)tst-resolv-ai_idn-nolibidn2.out: \ + $(gen-locales) $(objpfx)tst-no-libidn2.so ++$(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so +@@ -267,7 +289,10 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ + $(shared-thread-library) + $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \ + $(shared-thread-library) ++$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \ ++ $(shared-thread-library) + $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/README b/resolv/README +index 514e9bb617..2146bc3b27 100644 +--- a/resolv/README ++++ b/resolv/README +@@ -146,6 +146,3 @@ res_libc.c is home-brewn, although parts of it are taken from res_data.c. + + res_hconf.c and res_hconf.h were contributed by David Mosberger, and + do not come from BIND. +- +-The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are +-leftovers from BIND 4.9.7. +diff --git a/resolv/mapv4v6addr.h b/resolv/mapv4v6addr.h +deleted file mode 100644 +index 7f85f7d5e3..0000000000 +--- a/resolv/mapv4v6addr.h ++++ /dev/null +@@ -1,69 +0,0 @@ +-/* +- * ++Copyright++ 1985, 1988, 1993 +- * - +- * Copyright (c) 1985, 1988, 1993 +- * The Regents of the University of California. All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 4. Neither the name of the University nor the names of its contributors +- * may be used to endorse or promote products derived from this software +- * without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +- * SUCH DAMAGE. +- * - +- * Portions Copyright (c) 1993 by Digital Equipment Corporation. +- * +- * Permission to use, copy, modify, and distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies, and that +- * the name of Digital Equipment Corporation not be used in advertising or +- * publicity pertaining to distribution of the document or software without +- * specific, written prior permission. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +- * SOFTWARE. +- * - +- * --Copyright-- +- */ +- +-#include +-#include +- +-static void +-map_v4v6_address (const char *src, char *dst) +-{ +- u_char *p = (u_char *) dst; +- int i; +- +- /* Move the IPv4 part to the right position. */ +- memcpy (dst + 12, src, INADDRSZ); +- +- /* Mark this ipv6 addr as a mapped ipv4. */ +- for (i = 0; i < 10; i++) +- *p++ = 0x00; +- *p++ = 0xff; +- *p = 0xff; +-} +diff --git a/resolv/mapv4v6hostent.h b/resolv/mapv4v6hostent.h +deleted file mode 100644 +index c11038adf3..0000000000 +--- a/resolv/mapv4v6hostent.h ++++ /dev/null +@@ -1,84 +0,0 @@ +-/* +- * ++Copyright++ 1985, 1988, 1993 +- * - +- * Copyright (c) 1985, 1988, 1993 +- * The Regents of the University of California. All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 4. Neither the name of the University nor the names of its contributors +- * may be used to endorse or promote products derived from this software +- * without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +- * SUCH DAMAGE. +- * - +- * Portions Copyright (c) 1993 by Digital Equipment Corporation. +- * +- * Permission to use, copy, modify, and distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies, and that +- * the name of Digital Equipment Corporation not be used in advertising or +- * publicity pertaining to distribution of the document or software without +- * specific, written prior permission. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +- * SOFTWARE. +- * - +- * --Copyright-- +- */ +- +-#include +-#include +- +-typedef union { +- int32_t al; +- char ac; +-} align; +- +-static int +-map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp) +-{ +- char **ap; +- +- if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) +- return 0; +- hp->h_addrtype = AF_INET6; +- hp->h_length = IN6ADDRSZ; +- for (ap = hp->h_addr_list; *ap; ap++) +- { +- int i = sizeof (align) - ((u_long) *bpp % sizeof (align)); +- +- if (*lenp < (i + IN6ADDRSZ)) +- /* Out of memory. */ +- return 1; +- *bpp += i; +- *lenp -= i; +- map_v4v6_address (*ap, *bpp); +- *ap = *bpp; +- *bpp += IN6ADDRSZ; +- *lenp -= IN6ADDRSZ; +- } +- return 0; +-} +diff --git a/resolv/ns_name_length_uncompressed.c b/resolv/ns_name_length_uncompressed.c +new file mode 100644 +index 0000000000..51296b47ef +--- /dev/null ++++ b/resolv/ns_name_length_uncompressed.c +@@ -0,0 +1,72 @@ ++/* Skip over an uncompressed name in wire format. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++int ++__ns_name_length_uncompressed (const unsigned char *p, ++ const unsigned char *eom) ++{ ++ const unsigned char *start = p; ++ ++ while (true) ++ { ++ if (p == eom) ++ { ++ /* Truncated packet: no room for label length. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ ++ unsigned char b = *p; ++ ++p; ++ if (b == 0) ++ { ++ /* Root label. */ ++ size_t length = p - start; ++ if (length > NS_MAXCDNAME) ++ { ++ /* Domain name too long. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ return length; ++ } ++ ++ if (b <= 63) ++ { ++ /* Regular label. */ ++ if (b <= eom - p) ++ p += b; ++ else ++ { ++ /* Truncated packet: label incomplete. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ } ++ else ++ { ++ /* Compression reference or corrupted label length. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ } ++} +diff --git a/resolv/ns_rr_cursor_init.c b/resolv/ns_rr_cursor_init.c +new file mode 100644 +index 0000000000..6ee80b30e9 +--- /dev/null ++++ b/resolv/ns_rr_cursor_init.c +@@ -0,0 +1,62 @@ ++/* Initialize a simple DNS packet parser. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++bool ++__ns_rr_cursor_init (struct ns_rr_cursor *c, ++ const unsigned char *buf, size_t len) ++{ ++ c->begin = buf; ++ c->end = buf + len; ++ ++ /* Check for header size and 16-bit question count value (it must be 1). */ ++ if (len < 12 || buf[4] != 0 || buf[5] != 1) ++ { ++ __set_errno (EMSGSIZE); ++ c->current = c->end; ++ return false; ++ } ++ c->current = buf + 12; ++ ++ int consumed = __ns_name_length_uncompressed (c->current, c->end); ++ if (consumed < 0) ++ { ++ __set_errno (EMSGSIZE); ++ c->current = c->end; ++ c->first_rr = NULL; ++ return false; ++ } ++ c->current += consumed; ++ ++ /* Ensure there is room for question type and class. */ ++ if (c->end - c->current < 4) ++ { ++ __set_errno (EMSGSIZE); ++ c->current = c->end; ++ c->first_rr = NULL; ++ return false; ++ } ++ c->current += 4; ++ c->first_rr = c->current; ++ ++ return true; ++} +diff --git a/resolv/ns_rr_cursor_next.c b/resolv/ns_rr_cursor_next.c +new file mode 100644 +index 0000000000..33652fc5da +--- /dev/null ++++ b/resolv/ns_rr_cursor_next.c +@@ -0,0 +1,74 @@ ++/* Simple DNS record parser without textual name decoding. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++bool ++__ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr) ++{ ++ rr->rdata = NULL; ++ ++ /* Extract the record owner name. */ ++ int consumed = __ns_name_unpack (c->begin, c->end, c->current, ++ rr->rname, sizeof (rr->rname)); ++ if (consumed < 0) ++ { ++ memset (rr, 0, sizeof (*rr)); ++ __set_errno (EMSGSIZE); ++ return false; ++ } ++ c->current += consumed; ++ ++ /* Extract the metadata. */ ++ struct ++ { ++ uint16_t rtype; ++ uint16_t rclass; ++ uint32_t ttl; ++ uint16_t rdlength; ++ } __attribute__ ((packed)) metadata; ++ _Static_assert (sizeof (metadata) == 10, "sizeof metadata"); ++ if (c->end - c->current < sizeof (metadata)) ++ { ++ memset (rr, 0, sizeof (*rr)); ++ __set_errno (EMSGSIZE); ++ return false; ++ } ++ memcpy (&metadata, c->current, sizeof (metadata)); ++ c->current += sizeof (metadata); ++ /* Endianess conversion. */ ++ rr->rtype = ntohs (metadata.rtype); ++ rr->rclass = ntohs (metadata.rclass); ++ rr->ttl = ntohl (metadata.ttl); ++ rr->rdlength = ntohs (metadata.rdlength); ++ ++ /* Extract record data. */ ++ if (c->end - c->current < rr->rdlength) ++ { ++ memset (rr, 0, sizeof (*rr)); ++ __set_errno (EMSGSIZE); ++ return false; ++ } ++ rr->rdata = c->current; ++ c->current += rr->rdlength; ++ ++ return true; ++} +diff --git a/resolv/ns_samebinaryname.c b/resolv/ns_samebinaryname.c +new file mode 100644 +index 0000000000..9a47d8e97a +--- /dev/null ++++ b/resolv/ns_samebinaryname.c +@@ -0,0 +1,55 @@ ++/* Compare two binary domain names for quality. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++/* Convert ASCII letters to upper case. */ ++static inline int ++ascii_toupper (unsigned char ch) ++{ ++ if (ch >= 'a' && ch <= 'z') ++ return ch - 'a' + 'A'; ++ else ++ return ch; ++} ++ ++bool ++__ns_samebinaryname (const unsigned char *a, const unsigned char *b) ++{ ++ while (*a != 0 && *b != 0) ++ { ++ if (*a != *b) ++ /* Different label length. */ ++ return false; ++ int labellen = *a; ++ ++a; ++ ++b; ++ for (int i = 0; i < labellen; ++i) ++ { ++ if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b)) ++ /* Different character in label. */ ++ return false; ++ ++a; ++ ++b; ++ } ++ } ++ ++ /* Match if both names are at the root label. */ ++ return *a == 0 && *b == 0; ++} +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 544cffbecd..227734da5c 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -69,6 +69,7 @@ + * --Copyright-- + */ + ++#include + #include + #include + #include +@@ -86,10 +87,6 @@ + #include + #include + +-/* Get implementations of some internal functions. */ +-#include +-#include +- + #define RESOLVSORT + + #if PACKETSZ > 65536 +@@ -103,32 +100,36 @@ + #endif + #define MAXHOSTNAMELEN 256 + +-/* We need this time later. */ +-typedef union querybuf +-{ +- HEADER hdr; +- u_char buf[MAXPACKET]; +-} querybuf; +- +-static enum nss_status getanswer_r (struct resolv_context *ctx, +- const querybuf *answer, int anslen, +- const char *qname, int qtype, +- struct hostent *result, char *buffer, +- size_t buflen, int *errnop, int *h_errnop, +- int map, int32_t *ttlp, char **canonp); +- +-static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, +- const querybuf *answer2, int anslen2, +- const char *qname, ++/* For historic reasons, pointers to IP addresses are char *, so use a ++ single list type for addresses and host names. */ ++#define DYNARRAY_STRUCT ptrlist ++#define DYNARRAY_ELEMENT char * ++#define DYNARRAY_PREFIX ptrlist_ ++#include ++ ++static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen, ++ uint16_t qtype, struct alloc_buffer *abuf, ++ struct ptrlist *addresses, ++ struct ptrlist *aliases, ++ int *errnop, int *h_errnop, int32_t *ttlp); ++static void addrsort (struct resolv_context *ctx, char **ap, int num); ++static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, ++ char **hnamep, int *errnop, ++ int *h_errnop, int32_t *ttlp); ++ ++static enum nss_status gaih_getanswer (unsigned char *packet1, ++ size_t packet1len, ++ unsigned char *packet2, ++ size_t packet2len, ++ struct alloc_buffer *abuf, + struct gaih_addrtuple **pat, +- char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); +-static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1, +- int anslen1, +- const char *qname, ++static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet, ++ size_t packetlen, ++ struct alloc_buffer *abuf, + struct gaih_addrtuple **pat, +- char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); + +@@ -183,16 +184,9 @@ gethostbyname3_context (struct resolv_context *ctx, + char *buffer, size_t buflen, int *errnop, + int *h_errnop, int32_t *ttlp, char **canonp) + { +- union +- { +- querybuf *buf; +- u_char *ptr; +- } host_buffer; +- querybuf *orig_host_buffer; + char tmp[NS_MAXDNAME]; + int size, type, n; + const char *cp; +- int map = 0; + int olderr = errno; + enum nss_status status; + +@@ -223,10 +217,12 @@ gethostbyname3_context (struct resolv_context *ctx, + && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL) + name = cp; + +- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); ++ unsigned char dns_packet_buffer[1024]; ++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; + +- n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf, +- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); ++ n = __res_context_search (ctx, name, C_IN, type, ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); + if (n < 0) + { + switch (errno) +@@ -253,34 +249,79 @@ gethostbyname3_context (struct resolv_context *ctx, + *errnop = EAGAIN; + else + __set_errno (olderr); ++ } ++ else ++ { ++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); + +- /* If we are looking for an IPv6 address and mapping is enabled +- by having the RES_USE_INET6 bit in _res.options set, we try +- another lookup. */ +- if (af == AF_INET6 && res_use_inet6 ()) +- n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf, +- host_buffer.buf != orig_host_buffer +- ? MAXPACKET : 1024, &host_buffer.ptr, +- NULL, NULL, NULL, NULL); ++ struct ptrlist addresses; ++ ptrlist_init (&addresses); ++ struct ptrlist aliases; ++ ptrlist_init (&aliases); + +- if (n < 0) ++ status = getanswer_r (alt_dns_packet_buffer, n, type, ++ &abuf, &addresses, &aliases, ++ errnop, h_errnop, ttlp); ++ if (status == NSS_STATUS_SUCCESS) + { +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); +- return status; +- } ++ if (ptrlist_has_failed (&addresses) ++ || ptrlist_has_failed (&aliases)) ++ { ++ /* malloc failure. Do not retry using the ERANGE protocol. */ ++ *errnop = ENOMEM; ++ *h_errnop = NETDB_INTERNAL; ++ status = NSS_STATUS_UNAVAIL; ++ } + +- map = 1; ++ /* Reserve the address and alias arrays in the result ++ buffer. Both are NULL-terminated, but the first element ++ of the alias array is stored in h_name, so no extra space ++ for the NULL terminator is needed there. */ ++ result->h_addr_list ++ = alloc_buffer_alloc_array (&abuf, char *, ++ ptrlist_size (&addresses) + 1); ++ result->h_aliases ++ = alloc_buffer_alloc_array (&abuf, char *, ++ ptrlist_size (&aliases)); ++ if (alloc_buffer_has_failed (&abuf)) ++ { ++ /* Retry using the ERANGE protocol. */ ++ *errnop = ERANGE; ++ *h_errnop = NETDB_INTERNAL; ++ status = NSS_STATUS_TRYAGAIN; ++ } ++ else ++ { ++ /* Copy the address list and NULL-terminate it. */ ++ memcpy (result->h_addr_list, ptrlist_begin (&addresses), ++ ptrlist_size (&addresses) * sizeof (char *)); ++ result->h_addr_list[ptrlist_size (&addresses)] = NULL; ++ ++ /* Sort the address list if requested. */ ++ if (type == T_A && __resolv_context_sort_count (ctx) > 0) ++ addrsort (ctx, result->h_addr_list, ptrlist_size (&addresses)); + +- result->h_addrtype = AF_INET; +- result->h_length = INADDRSZ; ++ /* Copy the aliases, excluding the last one. */ ++ memcpy (result->h_aliases, ptrlist_begin (&aliases), ++ (ptrlist_size (&aliases) - 1) * sizeof (char *)); ++ result->h_aliases[ptrlist_size (&aliases) - 1] = NULL; ++ ++ /* The last alias goes into h_name. */ ++ assert (ptrlist_size (&aliases) >= 1); ++ result->h_name = ptrlist_end (&aliases)[-1]; ++ ++ /* This is also the canonical name. */ ++ if (canonp != NULL) ++ *canonp = result->h_name; ++ } ++ } ++ ++ ptrlist_free (&aliases); ++ ptrlist_free (&addresses); + } + +- status = getanswer_r +- (ctx, host_buffer.buf, n, name, type, result, buffer, buflen, +- errnop, h_errnop, map, ttlp, canonp); +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); + return status; + } + +@@ -324,13 +365,8 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } +- status = NSS_STATUS_NOTFOUND; +- if (res_use_inet6 ()) +- status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer, +- buflen, errnop, h_errnop, NULL, NULL); +- if (status == NSS_STATUS_NOTFOUND) +- status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, +- buflen, errnop, h_errnop, NULL, NULL); ++ status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, ++ buflen, errnop, h_errnop, NULL, NULL); + __resolv_context_put (ctx); + return status; + } +@@ -365,17 +401,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + name = cp; + } + +- union +- { +- querybuf *buf; +- u_char *ptr; +- } host_buffer; +- querybuf *orig_host_buffer; +- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048); ++ unsigned char dns_packet_buffer[2048]; ++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; + u_char *ans2p = NULL; + int nans2p = 0; + int resplen2 = 0; + int ans2p_malloced = 0; ++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); + + + int olderr = errno; +@@ -384,22 +416,21 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + if ((ctx->resp->options & RES_NOAAAA) == 0) + { + n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, +- host_buffer.buf->buf, 2048, &host_buffer.ptr, +- &ans2p, &nans2p, &resplen2, &ans2p_malloced); ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, &ans2p, &nans2p, ++ &resplen2, &ans2p_malloced); + if (n >= 0) +- status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p, +- resplen2, name, pat, buffer, buflen, +- errnop, herrnop, ttlp); ++ status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2, ++ &abuf, pat, errnop, herrnop, ttlp); + } + else + { + n = __res_context_search (ctx, name, C_IN, T_A, +- host_buffer.buf->buf, 2048, NULL, +- NULL, NULL, NULL, NULL); ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); + if (n >= 0) +- status = gaih_getanswer_noaaaa (host_buffer.buf, n, +- name, pat, buffer, buflen, +- errnop, herrnop, ttlp); ++ status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n, ++ &abuf, pat, errnop, herrnop, ttlp); + } + if (n < 0) + { +@@ -430,12 +461,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + __set_errno (olderr); + } + ++ /* Implement the buffer resizing protocol. */ ++ if (alloc_buffer_has_failed (&abuf)) ++ { ++ *errnop = ERANGE; ++ *herrnop = NETDB_INTERNAL; ++ status = NSS_STATUS_TRYAGAIN; ++ } ++ + /* Check whether ans2p was separately allocated. */ + if (ans2p_malloced) + free (ans2p); + +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); + + __resolv_context_put (ctx); + return status; +@@ -451,36 +490,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, + static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; + static const u_char v6local[] = { 0,0, 0,1 }; + const u_char *uaddr = (const u_char *)addr; +- struct host_data +- { +- char *aliases[MAX_NR_ALIASES]; +- unsigned char host_addr[16]; /* IPv4 or IPv6 */ +- char *h_addr_ptrs[MAX_NR_ADDRS + 1]; +- char linebuffer[0]; +- } *host_data = (struct host_data *) buffer; +- union +- { +- querybuf *buf; +- u_char *ptr; +- } host_buffer; +- querybuf *orig_host_buffer; + char qbuf[MAXDNAME+1], *qp = NULL; + size_t size; + int n, status; + int olderr = errno; + +- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); +- buffer += pad; +- buflen = buflen > pad ? buflen - pad : 0; +- +- if (__glibc_unlikely (buflen < sizeof (struct host_data))) +- { +- *errnop = ERANGE; +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; +- } +- +- host_data = (struct host_data *) buffer; ++ /* Prepare the allocation buffer. Store the pointer array first, to ++ benefit from buffer alignment. */ ++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); ++ char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2); ++ if (address_array == NULL) ++ { ++ *errnop = ERANGE; ++ *h_errnop = NETDB_INTERNAL; ++ return NSS_STATUS_TRYAGAIN; ++ } + + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) +@@ -524,8 +548,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, + return NSS_STATUS_UNAVAIL; + } + +- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); +- + switch (af) + { + case AF_INET: +@@ -549,36 +571,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, + break; + } + +- n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf, +- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); ++ unsigned char dns_packet_buffer[1024]; ++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; ++ n = __res_context_query (ctx, qbuf, C_IN, T_PTR, ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, ++ NULL, NULL, NULL, NULL); + if (n < 0) + { + *h_errnop = h_errno; + __set_errno (olderr); +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); + __resolv_context_put (ctx); + return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + } + +- status = getanswer_r +- (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen, +- errnop, h_errnop, 0 /* XXX */, ttlp, NULL); +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ status = getanswer_ptr (alt_dns_packet_buffer, n, ++ &abuf, &result->h_name, errnop, h_errnop, ttlp); ++ ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); ++ __resolv_context_put (ctx); ++ + if (status != NSS_STATUS_SUCCESS) +- { +- __resolv_context_put (ctx); +- return status; +- } ++ return status; + ++ /* result->h_name has already been set by getanswer_ptr. */ + result->h_addrtype = af; + result->h_length = len; +- memcpy (host_data->host_addr, addr, len); +- host_data->h_addr_ptrs[0] = (char *) host_data->host_addr; +- host_data->h_addr_ptrs[1] = NULL; ++ /* Increase the alignment to 4, in case there are applications out ++ there that expect at least this level of address alignment. */ ++ address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t); ++ alloc_buffer_copy_bytes (&abuf, uaddr, len); ++ address_array[1] = NULL; ++ ++ /* This check also covers allocation failure in getanswer_ptr. */ ++ if (alloc_buffer_has_failed (&abuf)) ++ { ++ *errnop = ERANGE; ++ *h_errnop = NETDB_INTERNAL; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ result->h_addr_list = address_array; ++ result->h_aliases = &address_array[1]; /* Points to NULL. */ ++ + *h_errnop = NETDB_SUCCESS; +- __resolv_context_put (ctx); + return NSS_STATUS_SUCCESS; + } + libc_hidden_def (_nss_dns_gethostbyaddr2_r) +@@ -640,650 +678,362 @@ addrsort (struct resolv_context *ctx, char **ap, int num) + break; + } + +-static enum nss_status +-getanswer_r (struct resolv_context *ctx, +- const querybuf *answer, int anslen, const char *qname, int qtype, +- struct hostent *result, char *buffer, size_t buflen, +- int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp) ++/* Convert the uncompressed, binary domain name CDNAME into its ++ textual representation and add it to the end of ALIASES, allocating ++ space for a copy of the name from ABUF. Skip adding the name if it ++ is not a valid host name, and return false in that case, otherwise ++ true. */ ++static bool ++getanswer_r_store_alias (const unsigned char *cdname, ++ struct alloc_buffer *abuf, ++ struct ptrlist *aliases) + { +- struct host_data +- { +- char *aliases[MAX_NR_ALIASES]; +- unsigned char host_addr[16]; /* IPv4 or IPv6 */ +- char *h_addr_ptrs[0]; +- } *host_data; +- int linebuflen; +- const HEADER *hp; +- const u_char *end_of_message, *cp; +- int n, ancount, qdcount; +- int haveanswer, had_error; +- char *bp, **ap, **hap; +- char tbuf[MAXDNAME]; +- const char *tname; +- int (*name_ok) (const char *); +- u_char packtmp[NS_MAXCDNAME]; +- int have_to_map = 0; +- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); +- buffer += pad; +- buflen = buflen > pad ? buflen - pad : 0; +- if (__glibc_unlikely (buflen < sizeof (struct host_data))) +- { +- /* The buffer is too small. */ +- too_small: +- *errnop = ERANGE; +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; +- } +- host_data = (struct host_data *) buffer; +- linebuflen = buflen - sizeof (struct host_data); +- if (buflen - sizeof (struct host_data) != linebuflen) +- linebuflen = INT_MAX; +- +- tname = qname; +- result->h_name = NULL; +- end_of_message = answer->buf + anslen; +- switch (qtype) +- { +- case T_A: +- case T_AAAA: +- name_ok = __libc_res_hnok; +- break; +- case T_PTR: +- name_ok = __libc_res_dnok; +- break; +- default: +- *errnop = ENOENT; +- return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */ +- } ++ /* Filter out domain names that are not host names. */ ++ if (!__res_binary_hnok (cdname)) ++ return false; ++ ++ /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks ++ for length. */ ++ char dname[MAXHOSTNAMELEN + 1]; ++ if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0) ++ return false; ++ /* Do not report an error on allocation failure, instead store NULL ++ or do nothing. getanswer_r's caller will see NSS_STATUS_SUCCESS ++ and detect the memory allocation failure or buffer space ++ exhaustion, and report it accordingly. */ ++ ptrlist_add (aliases, alloc_buffer_copy_string (abuf, dname)); ++ return true; ++} + +- /* +- * find first satisfactory answer +- */ +- hp = &answer->hdr; +- ancount = ntohs (hp->ancount); +- qdcount = ntohs (hp->qdcount); +- cp = answer->buf + HFIXEDSZ; +- if (__glibc_unlikely (qdcount != 1)) ++static enum nss_status __attribute__ ((noinline)) ++getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype, ++ struct alloc_buffer *abuf, ++ struct ptrlist *addresses, struct ptrlist *aliases, ++ int *errnop, int *h_errnop, int32_t *ttlp) ++{ ++ struct ns_rr_cursor c; ++ if (!__ns_rr_cursor_init (&c, packet, packetlen)) + { ++ /* This should not happen because __res_context_query already ++ perfroms response validation. */ + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +- if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen) +- goto too_small; +- bp = (char *) &host_data->h_addr_ptrs[ancount + 1]; +- linebuflen -= (ancount + 1) * sizeof (char *); +- +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) +- { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; + +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0)) ++ /* Treat the QNAME just like an alias. Error out if it is not a ++ valid host name. */ ++ if (ns_rr_cursor_rcode (&c) == NXDOMAIN ++ || !getanswer_r_store_alias (ns_rr_cursor_qname (&c), abuf, aliases)) + { +- *errnop = errno; +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- if (__glibc_unlikely (name_ok (bp) == 0)) +- { +- errno = EBADMSG; +- *errnop = EBADMSG; +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; ++ if (ttlp != NULL) ++ /* No negative caching. */ ++ *ttlp = 0; ++ *h_errnop = HOST_NOT_FOUND; ++ *errnop = ENOENT; ++ return NSS_STATUS_NOTFOUND; + } +- cp += n + QFIXEDSZ; + +- if (qtype == T_A || qtype == T_AAAA) ++ int ancount = ns_rr_cursor_ancount (&c); ++ const unsigned char *expected_name = ns_rr_cursor_qname (&c); ++ /* expected_name may be updated to point into this buffer. */ ++ unsigned char name_buffer[NS_MAXCDNAME]; ++ ++ for (; ancount > 0; --ancount) + { +- /* res_send() has already verified that the query name is the +- * same as the one we sent; this just gets the expanded name +- * (i.e., with the succeeding search-domain tacked on). +- */ +- n = strlen (bp) + 1; /* for the \0 */ +- if (n >= MAXHOSTNAMELEN) ++ struct ns_rr_wire rr; ++ if (!__ns_rr_cursor_next (&c, &rr)) + { + *h_errnop = NO_RECOVERY; +- *errnop = ENOENT; +- return NSS_STATUS_TRYAGAIN; ++ return NSS_STATUS_UNAVAIL; + } +- result->h_name = bp; +- bp += n; +- linebuflen -= n; +- if (linebuflen < 0) +- goto too_small; +- /* The qname can be abbreviated, but h_name is now absolute. */ +- qname = result->h_name; +- } + +- ap = host_data->aliases; +- *ap = NULL; +- result->h_aliases = host_data->aliases; +- hap = host_data->h_addr_ptrs; +- *hap = NULL; +- result->h_addr_list = host_data->h_addr_ptrs; +- haveanswer = 0; +- had_error = 0; ++ /* Skip over records with the wrong class. */ ++ if (rr.rclass != C_IN) ++ continue; + +- while (ancount-- > 0 && cp < end_of_message && had_error == 0) +- { +- int type, class; ++ /* Update TTL for recognized record types. */ ++ if ((rr.rtype == T_CNAME || rr.rtype == qtype) ++ && ttlp != NULL && *ttlp > rr.ttl) ++ *ttlp = rr.ttl; + +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) ++ if (rr.rtype == T_CNAME) + { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; ++ /* NB: No check for owner name match, based on historic ++ precedent. Record the CNAME target as the new expected ++ name. */ ++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)); ++ if (n < 0) ++ { ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; ++ } ++ /* And store the new name as an alias. */ ++ getanswer_r_store_alias (name_buffer, abuf, aliases); ++ expected_name = name_buffer; + } +- +- if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0)) ++ else if (rr.rtype == qtype ++ && __ns_samebinaryname (rr.rname, expected_name) ++ && rr.rdlength == rrtype_to_rdata_length (qtype)) + { +- ++had_error; +- continue; ++ /* Make a copy of the address and store it. Increase the ++ alignment to 4, in case there are applications out there ++ that expect at least this level of address alignment. */ ++ ptrlist_add (addresses, (char *) alloc_buffer_next (abuf, uint32_t)); ++ alloc_buffer_copy_bytes (abuf, rr.rdata, rr.rdlength); + } +- cp += n; /* name */ ++ } + +- if (__glibc_unlikely (cp + 10 > end_of_message)) +- { +- ++had_error; +- continue; +- } ++ if (ptrlist_size (addresses) == 0) ++ { ++ /* No address record found. */ ++ if (ttlp != NULL) ++ /* No caching of negative responses. */ ++ *ttlp = 0; + +- NS_GET16 (type, cp); +- NS_GET16 (class, cp); +- int32_t ttl; +- NS_GET32 (ttl, cp); +- NS_GET16 (n, cp); /* RDATA length. */ ++ *h_errnop = NO_RECOVERY; ++ *errnop = ENOENT; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ else ++ { ++ *h_errnop = NETDB_SUCCESS; ++ return NSS_STATUS_SUCCESS; ++ } ++} + +- if (end_of_message - cp < n) +- { +- /* RDATA extends beyond the end of the packet. */ +- ++had_error; +- continue; +- } ++static enum nss_status ++getanswer_ptr (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, char **hnamep, ++ int *errnop, int *h_errnop, int32_t *ttlp) ++{ ++ struct ns_rr_cursor c; ++ if (!__ns_rr_cursor_init (&c, packet, packetlen)) ++ { ++ /* This should not happen because __res_context_query already ++ perfroms response validation. */ ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; ++ } ++ int ancount = ns_rr_cursor_ancount (&c); ++ const unsigned char *expected_name = ns_rr_cursor_qname (&c); ++ /* expected_name may be updated to point into this buffer. */ ++ unsigned char name_buffer[NS_MAXCDNAME]; + +- if (__glibc_unlikely (class != C_IN)) ++ while (ancount > 0) ++ { ++ struct ns_rr_wire rr; ++ if (!__ns_rr_cursor_next (&c, &rr)) + { +- /* XXX - debug? syslog? */ +- cp += n; +- continue; /* XXX - had_error++ ? */ ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } + +- if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) +- { +- /* A CNAME could also have a TTL entry. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- +- if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1]) +- continue; +- n = __libc_dn_expand (answer->buf, end_of_message, cp, +- tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0)) +- { +- ++had_error; +- continue; +- } +- cp += n; +- /* Store alias. */ +- *ap++ = bp; +- n = strlen (bp) + 1; /* For the \0. */ +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) +- { +- ++had_error; +- continue; +- } +- bp += n; +- linebuflen -= n; +- /* Get canonical name. */ +- n = strlen (tbuf) + 1; /* For the \0. */ +- if (__glibc_unlikely (n > linebuflen)) +- goto too_small; +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) +- { +- ++had_error; +- continue; +- } +- result->h_name = bp; +- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ +- linebuflen -= n; +- continue; +- } ++ /* Skip over records with the wrong class. */ ++ if (rr.rclass != C_IN) ++ continue; + +- if (qtype == T_PTR && type == T_CNAME) +- { +- /* A CNAME could also have a TTL entry. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; ++ /* Update TTL for known record types. */ ++ if ((rr.rtype == T_CNAME || rr.rtype == T_PTR) ++ && ttlp != NULL && *ttlp > rr.ttl) ++ *ttlp = rr.ttl; + +- n = __libc_dn_expand (answer->buf, end_of_message, cp, +- tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0)) +- { +- ++had_error; +- continue; +- } +- cp += n; +- /* Get canonical name. */ +- n = strlen (tbuf) + 1; /* For the \0. */ +- if (__glibc_unlikely (n > linebuflen)) +- goto too_small; +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) ++ if (rr.rtype == T_CNAME) ++ { ++ /* NB: No check for owner name match, based on historic ++ precedent. Record the CNAME target as the new expected ++ name. */ ++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)); ++ if (n < 0) + { +- ++had_error; +- continue; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } +- tname = bp; +- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ +- linebuflen -= n; +- continue; ++ expected_name = name_buffer; + } +- +- if (type == T_A && qtype == T_AAAA && map) +- have_to_map = 1; +- else if (__glibc_unlikely (type != qtype)) ++ else if (rr.rtype == T_PTR ++ && __ns_samebinaryname (rr.rname, expected_name)) + { +- cp += n; +- continue; /* XXX - had_error++ ? */ +- } +- +- switch (type) +- { +- case T_PTR: +- if (__glibc_unlikely (__strcasecmp (tname, bp) != 0)) ++ /* Decompress the target of the PTR record. This is the ++ host name we are looking for. We can only use it if it ++ is syntactically valid. Historically, only one host name ++ is returned here. If the recursive resolver performs DNS ++ record rotation, the returned host name is essentially ++ random, which is why multiple PTR records are rarely ++ used. Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for ++ additional length checking. */ ++ char hname[MAXHOSTNAMELEN + 1]; ++ if (__ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)) < 0 ++ || !__res_binary_hnok (expected_name) ++ || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0) + { +- cp += n; +- continue; /* XXX - had_error++ ? */ ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } +- +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) +- { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0)) +- { +- ++had_error; +- break; +- } +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- /* bind would put multiple PTR records as aliases, but we don't do +- that. */ +- result->h_name = bp; +- *h_errnop = NETDB_SUCCESS; ++ /* Successful allocation is checked by the caller. */ ++ *hnamep = alloc_buffer_copy_string (abuf, hname); + return NSS_STATUS_SUCCESS; +- case T_A: +- case T_AAAA: +- if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0)) +- { +- cp += n; +- continue; /* XXX - had_error++ ? */ +- } +- +- /* Stop parsing at a record whose length is incorrect. */ +- if (n != rrtype_to_rdata_length (type)) +- { +- ++had_error; +- break; +- } +- +- /* Skip records of the wrong type. */ +- if (n != result->h_length) +- { +- cp += n; +- continue; +- } +- if (!haveanswer) +- { +- int nn; +- +- /* We compose a single hostent out of the entire chain of +- entries, so the TTL of the hostent is essentially the lowest +- TTL in the chain. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- if (canonp != NULL) +- *canonp = bp; +- result->h_name = bp; +- nn = strlen (bp) + 1; /* for the \0 */ +- bp += nn; +- linebuflen -= nn; +- } +- +- /* Provide sufficient alignment for both address +- families. */ +- enum { align = 4 }; +- _Static_assert ((align % __alignof__ (struct in_addr)) == 0, +- "struct in_addr alignment"); +- _Static_assert ((align % __alignof__ (struct in6_addr)) == 0, +- "struct in6_addr alignment"); +- { +- char *new_bp = PTR_ALIGN_UP (bp, align); +- linebuflen -= new_bp - bp; +- bp = new_bp; +- } +- +- if (__glibc_unlikely (n > linebuflen)) +- goto too_small; +- bp = __mempcpy (*hap++ = bp, cp, n); +- cp += n; +- linebuflen -= n; +- break; +- default: +- abort (); + } +- if (had_error == 0) +- ++haveanswer; + } + +- if (haveanswer > 0) +- { +- *ap = NULL; +- *hap = NULL; +- /* +- * Note: we sort even if host can take only one address +- * in its return structures - should give it the "best" +- * address in that case, not some random one +- */ +- if (haveanswer > 1 && qtype == T_A +- && __resolv_context_sort_count (ctx) > 0) +- addrsort (ctx, host_data->h_addr_ptrs, haveanswer); +- +- if (result->h_name == NULL) +- { +- n = strlen (qname) + 1; /* For the \0. */ +- if (n > linebuflen) +- goto too_small; +- if (n >= MAXHOSTNAMELEN) +- goto no_recovery; +- result->h_name = bp; +- bp = __mempcpy (bp, qname, n); /* Cannot overflow. */ +- linebuflen -= n; +- } ++ /* No PTR record found. */ ++ if (ttlp != NULL) ++ /* No caching of negative responses. */ ++ *ttlp = 0; + +- if (have_to_map) +- if (map_v4v6_hostent (result, &bp, &linebuflen)) +- goto too_small; +- *h_errnop = NETDB_SUCCESS; +- return NSS_STATUS_SUCCESS; +- } +- no_recovery: + *h_errnop = NO_RECOVERY; + *errnop = ENOENT; +- /* Special case here: if the resolver sent a result but it only +- contains a CNAME while we are looking for a T_A or T_AAAA record, +- we fail with NOTFOUND instead of TRYAGAIN. */ +- return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases +- ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN); ++ return NSS_STATUS_TRYAGAIN; + } + +- ++/* Parses DNS data found in PACKETLEN bytes at PACKET in struct ++ gaih_addrtuple address tuples. The new address tuples are linked ++ from **TAILP, with backing store allocated from ABUF, and *TAILP is ++ updated to point where the next tuple pointer should be stored. If ++ TTLP is not null, *TTLP is updated to reflect the minimum TTL. If ++ STORE_CANON is true, the canonical name is stored as part of the ++ first address tuple being written. */ + static enum nss_status +-gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, +- struct gaih_addrtuple ***patp, +- char **bufferp, size_t *buflenp, +- int *errnop, int *h_errnop, int32_t *ttlp, int *firstp) ++gaih_getanswer_slice (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, ++ struct gaih_addrtuple ***tailp, ++ int *errnop, int *h_errnop, int32_t *ttlp, ++ bool store_canon) + { +- char *buffer = *bufferp; +- size_t buflen = *buflenp; +- +- struct gaih_addrtuple **pat = *patp; +- const HEADER *hp = &answer->hdr; +- int ancount = ntohs (hp->ancount); +- int qdcount = ntohs (hp->qdcount); +- const u_char *cp = answer->buf + HFIXEDSZ; +- const u_char *end_of_message = answer->buf + anslen; +- if (__glibc_unlikely (qdcount != 1)) +- { +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- +- u_char packtmp[NS_MAXCDNAME]; +- int n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- /* We unpack the name to check it for validity. But we do not need +- it later. */ +- if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1) +- { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- { +- too_small: +- *errnop = ERANGE; +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; +- } +- +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0)) ++ struct ns_rr_cursor c; ++ if (!__ns_rr_cursor_init (&c, packet, packetlen)) + { +- *errnop = errno; ++ /* This should not happen because __res_context_query already ++ perfroms response validation. */ + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +- if (__glibc_unlikely (__libc_res_hnok (buffer) == 0)) +- { +- errno = EBADMSG; +- *errnop = EBADMSG; +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- cp += n + QFIXEDSZ; +- +- int haveanswer = 0; +- int had_error = 0; +- char *canon = NULL; +- char *h_name = NULL; +- int h_namelen = 0; +- +- if (ancount == 0) ++ bool haveanswer = false; /* Set to true if at least one address. */ ++ uint16_t qtype = ns_rr_cursor_qtype (&c); ++ int ancount = ns_rr_cursor_ancount (&c); ++ const unsigned char *expected_name = ns_rr_cursor_qname (&c); ++ /* expected_name may be updated to point into this buffer. */ ++ unsigned char name_buffer[NS_MAXCDNAME]; ++ ++ /* This is a pointer to a possibly-compressed name in the packet. ++ Eventually it is equivalent to the canonical name. If needed, it ++ is uncompressed and translated to text form when the first ++ address tuple is encountered. */ ++ const unsigned char *compressed_alias_name = expected_name; ++ ++ if (ancount == 0 || !__res_binary_hnok (compressed_alias_name)) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + +- while (ancount-- > 0 && cp < end_of_message && had_error == 0) ++ for (; ancount > -0; --ancount) + { +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && +- (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1) ++ struct ns_rr_wire rr; ++ if (!__ns_rr_cursor_next (&c, &rr)) + { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; +- } +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0)) +- { +- ++had_error; +- continue; +- } +- if (*firstp && canon == NULL) +- { +- h_name = buffer; +- buffer += h_namelen; +- buflen -= h_namelen; +- } +- +- cp += n; /* name */ +- +- if (__glibc_unlikely (cp + 10 > end_of_message)) +- { +- ++had_error; +- continue; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } + +- uint16_t type; +- NS_GET16 (type, cp); +- uint16_t class; +- NS_GET16 (class, cp); +- int32_t ttl; +- NS_GET32 (ttl, cp); +- NS_GET16 (n, cp); /* RDATA length. */ ++ /* Update TTL for known record types. */ ++ if ((rr.rtype == T_CNAME || rr.rtype == qtype) ++ && ttlp != NULL && *ttlp > rr.ttl) ++ *ttlp = rr.ttl; + +- if (end_of_message - cp < n) ++ if (rr.rtype == T_CNAME) + { +- /* RDATA extends beyond the end of the packet. */ +- ++had_error; +- continue; +- } +- +- if (class != C_IN) +- { +- cp += n; +- continue; +- } +- +- if (type == T_CNAME) +- { +- char tbuf[MAXDNAME]; +- +- /* A CNAME could also have a TTL entry. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- +- n = __libc_dn_expand (answer->buf, end_of_message, cp, +- tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0)) ++ /* NB: No check for owner name match, based on historic ++ precedent. Record the CNAME target as the new expected ++ name. */ ++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)); ++ if (n < 0) + { +- ++had_error; +- continue; +- } +- cp += n; +- +- if (*firstp) +- { +- /* Reclaim buffer space. */ +- if (h_name + h_namelen == buffer) +- { +- buffer = h_name; +- buflen += h_namelen; +- } +- +- n = strlen (tbuf) + 1; +- if (__glibc_unlikely (n > buflen)) +- goto too_small; +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) +- { +- ++had_error; +- continue; +- } +- +- canon = buffer; +- buffer = __mempcpy (buffer, tbuf, n); +- buflen -= n; +- h_namelen = 0; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } +- continue; ++ expected_name = name_buffer; ++ if (store_canon && __res_binary_hnok (name_buffer)) ++ /* This name can be used as a canonical name. Do not ++ translate to text form here to conserve buffer space. ++ Point to the compressed name because name_buffer can be ++ overwritten with an unusable name later. */ ++ compressed_alias_name = rr.rdata; + } +- +- /* Stop parsing if we encounter a record with incorrect RDATA +- length. */ +- if (type == T_A || type == T_AAAA) ++ else if (rr.rtype == qtype ++ && __ns_samebinaryname (rr.rname, expected_name) ++ && rr.rdlength == rrtype_to_rdata_length (qtype)) + { +- if (n != rrtype_to_rdata_length (type)) ++ struct gaih_addrtuple *ntup ++ = alloc_buffer_alloc (abuf, struct gaih_addrtuple); ++ /* Delay error reporting to the callers (they implement the ++ ERANGE buffer resizing handshake). */ ++ if (ntup != NULL) + { +- ++had_error; +- continue; ++ ntup->next = NULL; ++ if (store_canon && compressed_alias_name != NULL) ++ { ++ /* This assumes that all the CNAME records come ++ first. Use MAXHOSTNAMELEN instead of ++ NS_MAXCDNAME for additional length checking. ++ However, these checks are not expected to fail ++ because all size NS_MAXCDNAME names should into ++ the hname buffer because no escaping is ++ needed. */ ++ char unsigned nbuf[NS_MAXCDNAME]; ++ char hname[MAXHOSTNAMELEN + 1]; ++ if (__ns_name_unpack (c.begin, c.end, ++ compressed_alias_name, ++ nbuf, sizeof (nbuf)) >= 0 ++ && __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0) ++ /* Space checking is performed by the callers. */ ++ ntup->name = alloc_buffer_copy_string (abuf, hname); ++ store_canon = false; ++ } ++ else ++ ntup->name = NULL; ++ if (rr.rdlength == 4) ++ ntup->family = AF_INET; ++ else ++ ntup->family = AF_INET6; ++ memcpy (ntup->addr, rr.rdata, rr.rdlength); ++ ntup->scopeid = 0; ++ ++ /* Link in the new tuple, and update the tail pointer to ++ point to its next field. */ ++ **tailp = ntup; ++ *tailp = &ntup->next; ++ ++ haveanswer = true; + } + } +- else +- { +- /* Skip unknown records. */ +- cp += n; +- continue; +- } +- +- assert (type == T_A || type == T_AAAA); +- if (*pat == NULL) +- { +- uintptr_t pad = (-(uintptr_t) buffer +- % __alignof__ (struct gaih_addrtuple)); +- buffer += pad; +- buflen = buflen > pad ? buflen - pad : 0; +- +- if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple))) +- goto too_small; +- +- *pat = (struct gaih_addrtuple *) buffer; +- buffer += sizeof (struct gaih_addrtuple); +- buflen -= sizeof (struct gaih_addrtuple); +- } +- +- (*pat)->name = NULL; +- (*pat)->next = NULL; +- +- if (*firstp) +- { +- /* We compose a single hostent out of the entire chain of +- entries, so the TTL of the hostent is essentially the lowest +- TTL in the chain. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- +- (*pat)->name = canon ?: h_name; +- +- *firstp = 0; +- } +- +- (*pat)->family = type == T_A ? AF_INET : AF_INET6; +- memcpy ((*pat)->addr, cp, n); +- cp += n; +- (*pat)->scopeid = 0; +- +- pat = &((*pat)->next); +- +- haveanswer = 1; + } + + if (haveanswer) + { +- *patp = pat; +- *bufferp = buffer; +- *buflenp = buflen; +- + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; + } +- +- /* Special case here: if the resolver sent a result but it only +- contains a CNAME while we are looking for a T_A or T_AAAA record, +- we fail with NOTFOUND instead of TRYAGAIN. */ +- if (canon != NULL) ++ else + { ++ /* Special case here: if the resolver sent a result but it only ++ contains a CNAME while we are looking for a T_A or T_AAAA ++ record, we fail with NOTFOUND. */ + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } +- +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; + } + + + static enum nss_status +-gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, +- int anslen2, const char *qname, +- struct gaih_addrtuple **pat, char *buffer, size_t buflen, ++gaih_getanswer (unsigned char *packet1, size_t packet1len, ++ unsigned char *packet2, size_t packet2len, ++ struct alloc_buffer *abuf, struct gaih_addrtuple **pat, + int *errnop, int *h_errnop, int32_t *ttlp) + { +- int first = 1; +- + enum nss_status status = NSS_STATUS_NOTFOUND; + + /* Combining the NSS status of two distinct queries requires some +@@ -1295,7 +1045,10 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable). + A recoverable TRYAGAIN is almost always due to buffer size issues + and returns ERANGE in errno and the caller is expected to retry +- with a larger buffer. ++ with a larger buffer. (The caller, _nss_dns_gethostbyname4_r, ++ ignores the return status if it detects that the result buffer ++ has been exhausted and generates a TRYAGAIN failure with an ++ ERANGE code.) + + Lastly, you may be tempted to make significant changes to the + conditions in this code to bring about symmetry between responses. +@@ -1375,36 +1128,30 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + is a recoverable error we now return TRYAGIN even if the first + response was SUCCESS. */ + +- if (anslen1 > 0) +- status = gaih_getanswer_slice(answer1, anslen1, qname, +- &pat, &buffer, &buflen, +- errnop, h_errnop, ttlp, +- &first); +- +- if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND +- || (status == NSS_STATUS_TRYAGAIN +- /* We want to look at the second answer in case of an +- NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e. +- *h_errnop is NO_RECOVERY. If not, and if the failure was due to +- an insufficient buffer (ERANGE), then we need to drop the results +- and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can +- repeat the query with a larger buffer. */ +- && (*errnop != ERANGE || *h_errnop == NO_RECOVERY))) +- && answer2 != NULL && anslen2 > 0) ++ if (packet1len > 0) + { +- enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname, +- &pat, &buffer, &buflen, +- errnop, h_errnop, ttlp, +- &first); ++ status = gaih_getanswer_slice (packet1, packet1len, ++ abuf, &pat, errnop, h_errnop, ttlp, true); ++ if (alloc_buffer_has_failed (abuf)) ++ /* Do not try parsing the second packet if a larger result ++ buffer is needed. The caller implements the resizing ++ protocol because *abuf has been exhausted. */ ++ return NSS_STATUS_TRYAGAIN; /* Ignored by the caller. */ ++ } ++ ++ if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND) ++ && packet2 != NULL && packet2len > 0) ++ { ++ enum nss_status status2 ++ = gaih_getanswer_slice (packet2, packet2len, ++ abuf, &pat, errnop, h_errnop, ttlp, ++ /* Success means that data with a ++ canonical name has already been ++ stored. Do not store the name again. */ ++ status != NSS_STATUS_SUCCESS); + /* Use the second response status in some cases. */ + if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND) + status = status2; +- /* Do not return a truncated second response (unless it was +- unavoidable e.g. unrecoverable TRYAGAIN). */ +- if (status == NSS_STATUS_SUCCESS +- && (status2 == NSS_STATUS_TRYAGAIN +- && *errnop == ERANGE && *h_errnop != NO_RECOVERY)) +- status = NSS_STATUS_TRYAGAIN; + } + + return status; +@@ -1412,18 +1159,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + + /* Variant of gaih_getanswer without a second (AAAA) response. */ + static enum nss_status +-gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname, +- struct gaih_addrtuple **pat, +- char *buffer, size_t buflen, ++gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, struct gaih_addrtuple **pat, + int *errnop, int *h_errnop, int32_t *ttlp) + { +- int first = 1; +- + enum nss_status status = NSS_STATUS_NOTFOUND; +- if (anslen1 > 0) +- status = gaih_getanswer_slice (answer1, anslen1, qname, +- &pat, &buffer, &buflen, +- errnop, h_errnop, ttlp, +- &first); ++ if (packetlen > 0) ++ status = gaih_getanswer_slice (packet, packetlen, ++ abuf, &pat, errnop, h_errnop, ttlp, true); + return status; + } +diff --git a/resolv/res-name-checking.c b/resolv/res-name-checking.c +index 07a412d8ff..213edceaf3 100644 +--- a/resolv/res-name-checking.c ++++ b/resolv/res-name-checking.c +@@ -138,6 +138,12 @@ binary_leading_dash (const unsigned char *dn) + return dn[0] > 0 && dn[1] == '-'; + } + ++bool ++__res_binary_hnok (const unsigned char *dn) ++{ ++ return !binary_leading_dash (dn) && binary_hnok (dn); ++} ++ + /* Return 1 if res_hnok is a valid host name. Labels must only + contain [0-9a-zA-Z_-] characters, and the name must not start with + a '-'. The latter is to avoid confusion with program options. */ +@@ -145,11 +151,9 @@ int + ___res_hnok (const char *dn) + { + unsigned char buf[NS_MAXCDNAME]; +- if (!printable_string (dn) +- || __ns_name_pton (dn, buf, sizeof (buf)) < 0 +- || binary_leading_dash (buf)) +- return 0; +- return binary_hnok (buf); ++ return (printable_string (dn) ++ && __ns_name_pton (dn, buf, sizeof (buf)) >= 0 ++ && __res_binary_hnok (buf)); + } + versioned_symbol (libc, ___res_hnok, res_hnok, GLIBC_2_34); + versioned_symbol (libc, ___res_hnok, __libc_res_hnok, GLIBC_PRIVATE); +diff --git a/resolv/tst-ns_name_length_uncompressed.c b/resolv/tst-ns_name_length_uncompressed.c +new file mode 100644 +index 0000000000..c4a2904db7 +--- /dev/null ++++ b/resolv/tst-ns_name_length_uncompressed.c +@@ -0,0 +1,135 @@ ++/* Test __ns_name_length_uncompressed. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Reference implementation based on other building blocks. */ ++static int ++reference_length (const unsigned char *p, const unsigned char *eom) ++{ ++ unsigned char buf[NS_MAXCDNAME]; ++ int n = __ns_name_unpack (p, eom, p, buf, sizeof (buf)); ++ if (n < 0) ++ return n; ++ const unsigned char *q = buf; ++ if (__ns_name_skip (&q, array_end (buf)) < 0) ++ return -1; ++ if (q - buf != n) ++ /* Compressed name. */ ++ return -1; ++ return n; ++} ++ ++static int ++do_test (void) ++{ ++ { ++ unsigned char buf[] = { 3, 'w', 'w', 'w', 0, 0, 0 }; ++ TEST_COMPARE (reference_length (buf, array_end (buf)), sizeof (buf) - 2); ++ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), ++ sizeof (buf) - 2); ++ TEST_COMPARE (reference_length (array_end (buf) - 1, array_end (buf)), 1); ++ TEST_COMPARE (__ns_name_length_uncompressed (array_end (buf) - 1, ++ array_end (buf)), 1); ++ buf[4] = 0xc0; /* Forward compression reference. */ ++ buf[5] = 0x06; ++ TEST_COMPARE (reference_length (buf, array_end (buf)), -1); ++ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -1); ++ } ++ ++ struct support_next_to_fault ntf = support_next_to_fault_allocate (300); ++ ++ /* Buffer region with all possible bytes at start and end. */ ++ for (int length = 1; length <= 300; ++length) ++ { ++ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length; ++ unsigned char *start = end - length; ++ memset (start, 'X', length); ++ for (int first = 0; first <= 255; ++first) ++ { ++ *start = first; ++ for (int last = 0; last <= 255; ++last) ++ { ++ start[length - 1] = last; ++ TEST_COMPARE (reference_length (start, end), ++ __ns_name_length_uncompressed (start, end)); ++ } ++ } ++ } ++ ++ /* Poor man's fuzz testing: patch two bytes. */ ++ { ++ unsigned char ref[] = ++ { ++ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, 0, 0 ++ }; ++ TEST_COMPARE (reference_length (ref, array_end (ref)), 13); ++ TEST_COMPARE (__ns_name_length_uncompressed (ref, array_end (ref)), 13); ++ ++ int good = 0; ++ int bad = 0; ++ for (int length = 1; length <= sizeof (ref); ++length) ++ { ++ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length; ++ unsigned char *start = end - length; ++ memcpy (start, ref, length); ++ ++ for (int patch1_pos = 0; patch1_pos < length; ++patch1_pos) ++ { ++ for (int patch1_value = 0; patch1_value <= 255; ++patch1_value) ++ { ++ start[patch1_pos] = patch1_value; ++ for (int patch2_pos = 0; patch2_pos < length; ++patch2_pos) ++ { ++ for (int patch2_value = 0; patch2_value <= 255; ++ ++patch2_value) ++ { ++ start[patch2_pos] = patch2_value; ++ int expected = reference_length (start, end); ++ errno = EINVAL; ++ int actual ++ = __ns_name_length_uncompressed (start, end); ++ if (actual > 0) ++ ++good; ++ else ++ { ++ TEST_COMPARE (errno, EMSGSIZE); ++ ++bad; ++ } ++ TEST_COMPARE (expected, actual); ++ } ++ start[patch2_pos] = ref[patch2_pos]; ++ } ++ } ++ start[patch1_pos] = ref[patch1_pos]; ++ } ++ } ++ printf ("info: patched inputs with success: %d\n", good); ++ printf ("info: patched inputs with failure: %d\n", bad); ++ } ++ ++ support_next_to_fault_free (&ntf); ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-ns_rr_cursor.c b/resolv/tst-ns_rr_cursor.c +new file mode 100644 +index 0000000000..c3c0908905 +--- /dev/null ++++ b/resolv/tst-ns_rr_cursor.c +@@ -0,0 +1,227 @@ ++/* Tests for resource record parsing. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* Reference packet for packet parsing. */ ++static const unsigned char valid_packet[] = ++ { 0x11, 0x12, 0x13, 0x14, ++ 0x00, 0x01, /* Question count. */ ++ 0x00, 0x02, /* Answer count. */ ++ 0x21, 0x22, 0x23, 0x24, /* Other counts (not actually in packet). */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0, ++ 0x00, 0x1c, /* Question type: AAAA. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ 0xc0, 0x0c, /* Compression reference to QNAME. */ ++ 0x00, 0x1c, /* Record type: AAAA. */ ++ 0x00, 0x01, /* Record class: IN. */ ++ 0x12, 0x34, 0x56, 0x78, /* Record TTL. */ ++ 0x00, 0x10, /* Record data length (16 bytes). */ ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* IPv6 address. */ ++ 0xc0, 0x0c, /* Compression reference to QNAME. */ ++ 0x00, 0x1c, /* Record type: AAAA. */ ++ 0x00, 0x01, /* Record class: IN. */ ++ 0x11, 0x33, 0x55, 0x77, /* Record TTL. */ ++ 0x00, 0x10, /* Record data length (16 bytes). */ ++ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, ++ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* IPv6 address. */ ++ }; ++ ++/* Special offsets in valid_packet. */ ++enum ++ { ++ offset_of_first_record = 29, ++ offset_of_second_record = 57, ++ }; ++ ++/* Check that parsing valid_packet succeeds. */ ++static void ++test_valid (void) ++{ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, valid_packet, ++ sizeof (valid_packet))); ++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); ++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); ++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); ++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); ++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); ++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); ++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); ++ TEST_COMPARE (c.current - valid_packet, offset_of_first_record); ++ ++ struct ns_rr_wire r; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); ++ TEST_COMPARE (r.rtype, T_AAAA); ++ TEST_COMPARE (r.rclass, C_IN); ++ TEST_COMPARE (r.ttl, 0x12345678); ++ TEST_COMPARE_BLOB (r.rdata, r.rdlength, ++ "\x90\x91\x92\x93\x94\x95\x96\x97" ++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16); ++ TEST_COMPARE (c.current - valid_packet, offset_of_second_record); ++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); ++ TEST_COMPARE (r.rtype, T_AAAA); ++ TEST_COMPARE (r.rclass, C_IN); ++ TEST_COMPARE (r.ttl, 0x11335577); ++ TEST_COMPARE_BLOB (r.rdata, r.rdlength, ++ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" ++ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 16); ++ TEST_VERIFY (c.current == c.end); ++} ++ ++/* Check that trying to parse a packet with a compressed QNAME fails. */ ++static void ++test_compressed_qname (void) ++{ ++ static const unsigned char packet[] = ++ { 0x11, 0x12, 0x13, 0x14, ++ 0x00, 0x01, /* Question count. */ ++ 0x00, 0x00, /* Answer count. */ ++ 0x00, 0x00, 0x00, 0x00, /* Other counts. */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, ++ 0x00, 0x01, /* Question type: A. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ }; ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet))); ++} ++ ++/* Check that trying to parse a packet with two questions fails. */ ++static void ++test_two_questions (void) ++{ ++ static const unsigned char packet[] = ++ { 0x11, 0x12, 0x13, 0x14, ++ 0x00, 0x02, /* Question count. */ ++ 0x00, 0x00, /* Answer count. */ ++ 0x00, 0x00, 0x00, 0x00, /* Other counts. */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, ++ 0x00, 0x01, /* Question type: A. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, ++ 0x00, 0x1c, /* Question type: AAAA. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ }; ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet))); ++} ++ ++/* Used to check that parsing truncated packets does not over-read. */ ++static struct support_next_to_fault ntf; ++ ++/* Truncated packet in the second resource record. */ ++static void ++test_truncated_one_rr (size_t length) ++{ ++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; ++ unsigned char *start = end - length; ++ ++ /* Produce the truncated packet. */ ++ memcpy (start, valid_packet, length); ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length)); ++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); ++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); ++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); ++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); ++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); ++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); ++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); ++ TEST_COMPARE (c.current - start, offset_of_first_record); ++ ++ struct ns_rr_wire r; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); ++ TEST_COMPARE (r.rtype, T_AAAA); ++ TEST_COMPARE (r.rclass, C_IN); ++ TEST_COMPARE (r.ttl, 0x12345678); ++ TEST_COMPARE_BLOB (r.rdata, r.rdlength, ++ "\x90\x91\x92\x93\x94\x95\x96\x97" ++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16); ++ TEST_COMPARE (c.current - start, offset_of_second_record); ++ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r)); ++} ++ ++/* Truncated packet in the first resource record. */ ++static void ++test_truncated_no_rr (size_t length) ++{ ++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; ++ unsigned char *start = end - length; ++ ++ /* Produce the truncated packet. */ ++ memcpy (start, valid_packet, length); ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length)); ++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); ++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); ++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); ++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); ++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); ++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); ++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); ++ TEST_COMPARE (c.current - start, offset_of_first_record); ++ ++ struct ns_rr_wire r; ++ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r)); ++} ++ ++/* Truncated packet before first resource record. */ ++static void ++test_truncated_before_rr (size_t length) ++{ ++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; ++ unsigned char *start = end - length; ++ ++ /* Produce the truncated packet. */ ++ memcpy (start, valid_packet, length); ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, start, length)); ++} ++ ++static int ++do_test (void) ++{ ++ ntf = support_next_to_fault_allocate (sizeof (valid_packet)); ++ ++ test_valid (); ++ test_compressed_qname (); ++ test_two_questions (); ++ ++ for (int length = offset_of_second_record; length < sizeof (valid_packet); ++ ++length) ++ test_truncated_one_rr (length); ++ for (int length = offset_of_first_record; length < offset_of_second_record; ++ ++length) ++ test_truncated_no_rr (length); ++ for (int length = 0; length < offset_of_first_record; ++length) ++ test_truncated_before_rr (length); ++ ++ support_next_to_fault_free (&ntf); ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c +new file mode 100644 +index 0000000000..b06ac610b4 +--- /dev/null ++++ b/resolv/tst-ns_samebinaryname.c +@@ -0,0 +1,62 @@ ++/* Test the __ns_samebinaryname function. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* First character denotes the comparison group: All names with the ++ same first character are expected to compare equal. */ ++static const char *const cases[] = ++ { ++ " ", ++ "1\001a", "1\001A", ++ "2\002ab", "2\002aB", "2\002Ab", "2\002AB", ++ "3\001a\002ab", "3\001A\002ab", ++ "w\003www\007example\003com", "w\003Www\007Example\003Com", ++ "w\003WWW\007EXAMPLE\003COM", ++ "W\003WWW", "W\003www", ++ }; ++ ++static int ++do_test (void) ++{ ++ for (int i = 0; i < array_length (cases); ++i) ++ for (int j = 0; j < array_length (cases); ++j) ++ { ++ unsigned char *a = (unsigned char *) &cases[i][1]; ++ unsigned char *b = (unsigned char *) &cases[j][1]; ++ bool actual = __ns_samebinaryname (a, b); ++ bool expected = cases[i][0] == cases[j][0]; ++ if (actual != expected) ++ { ++ char a1[NS_MAXDNAME]; ++ TEST_VERIFY (ns_name_ntop (a, a1, sizeof (a1)) > 0); ++ char b1[NS_MAXDNAME]; ++ TEST_VERIFY (ns_name_ntop (b, b1, sizeof (b1)) > 0); ++ printf ("error: \"%s\" \"%s\": expected %s\n", ++ a1, b1, expected ? "equal" : "unqueal"); ++ support_record_failure (); ++ } ++ } ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-aliases.c b/resolv/tst-resolv-aliases.c +new file mode 100644 +index 0000000000..b212823aa0 +--- /dev/null ++++ b/resolv/tst-resolv-aliases.c +@@ -0,0 +1,254 @@ ++/* Test alias handling (mainly for gethostbyname). ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "tst-resolv-maybe_insert_sig.h" ++ ++/* QNAME format: ++ ++ aADDRESSES-cCNAMES.example.net ++ ++ CNAMES is the length of the CNAME chain, ADDRESSES is the number of ++ addresses in the response. The special value 255 means that there ++ are no addresses, and the RCODE is NXDOMAIN. */ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_COMPARE (qclass, C_IN); ++ if (qtype != T_A) ++ TEST_COMPARE (qtype, T_AAAA); ++ ++ unsigned int addresses, cnames; ++ char *tail; ++ if (sscanf (qname, "a%u-c%u%ms", &addresses, &cnames, &tail) == 3) ++ { ++ if (strcmp (tail, ".example.com") == 0 ++ || strcmp (tail, ".example.net.example.net") == 0 ++ || strcmp (tail, ".example.net.example.com") == 0) ++ /* These only happen after NXDOMAIN. */ ++ TEST_VERIFY (addresses == 255); ++ else if (strcmp (tail, ".example.net") != 0) ++ FAIL_EXIT1 ("invalid QNAME: %s", qname); ++ } ++ free (tail); ++ ++ int rcode; ++ if (addresses == 255) ++ { ++ /* Special case: Use no addresses with NXDOMAIN response. */ ++ rcode = ns_r_nxdomain; ++ addresses = 0; ++ } ++ else ++ rcode = 0; ++ ++ struct resolv_response_flags flags = { .rcode = rcode }; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ maybe_insert_sig (b, qname); ++ ++ /* Provide the requested number of CNAME records. */ ++ char *previous_name = (char *) qname; ++ for (int unique = 0; unique < cnames; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); ++ char *new_name = xasprintf ("%d.alias.example", unique); ++ resolv_response_add_name (b, new_name); ++ resolv_response_close_record (b); ++ ++ maybe_insert_sig (b, qname); ++ ++ if (previous_name != qname) ++ free (previous_name); ++ previous_name = new_name; ++ } ++ ++ for (int unique = 0; unique < addresses; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, qtype, 60); ++ ++ if (qtype == T_A) ++ { ++ char ipv4[4] = {192, 0, 2, 1 + unique}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ } ++ else if (qtype == T_AAAA) ++ { ++ char ipv6[16] = ++ { ++ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 1 + unique ++ }; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ } ++ resolv_response_close_record (b); ++ } ++ ++ if (previous_name != qname) ++ free (previous_name); ++} ++ ++static char * ++make_qname (bool do_search, int cnames, int addresses) ++{ ++ return xasprintf ("a%d-c%d%s", ++ addresses, cnames, do_search ? "" : ".example.net"); ++} ++ ++static void ++check_cnames_failure (int af, bool do_search, int cnames, int addresses) ++{ ++ char *qname = make_qname (do_search, cnames, addresses); ++ ++ struct hostent *e; ++ if (af == AF_UNSPEC) ++ e = gethostbyname (qname); ++ else ++ e = gethostbyname2 (qname, af); ++ ++ if (addresses == 0) ++ check_hostent (qname, e, "error: NO_RECOVERY\n"); ++ else ++ check_hostent (qname, e, "error: HOST_NOT_FOUND\n"); ++ ++ free (qname); ++} ++ ++static void ++check (int af, bool do_search, int cnames, int addresses) ++{ ++ char *qname = make_qname (do_search, cnames, addresses); ++ char *fqdn = make_qname (false, cnames, addresses); ++ ++ struct hostent *e; ++ if (af == AF_UNSPEC) ++ e = gethostbyname (qname); ++ else ++ e = gethostbyname2 (qname, af); ++ if (e == NULL) ++ FAIL_EXIT1 ("unexpected failure for %d, %d, %d", af, cnames, addresses); ++ ++ if (af == AF_UNSPEC || af == AF_INET) ++ { ++ TEST_COMPARE (e->h_addrtype, AF_INET); ++ TEST_COMPARE (e->h_length, 4); ++ } ++ else ++ { ++ TEST_COMPARE (e->h_addrtype, AF_INET6); ++ TEST_COMPARE (e->h_length, 16); ++ } ++ ++ for (int i = 0; i < addresses; ++i) ++ { ++ char ipv4[4] = {192, 0, 2, 1 + i}; ++ char ipv6[16] = ++ { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + i }; ++ char *expected = e->h_addrtype == AF_INET ? ipv4 : ipv6; ++ TEST_COMPARE_BLOB (e->h_addr_list[i], e->h_length, ++ expected, e->h_length); ++ } ++ TEST_VERIFY (e->h_addr_list[addresses] == NULL); ++ ++ ++ if (cnames == 0) ++ { ++ /* QNAME is fully qualified. */ ++ TEST_COMPARE_STRING (e->h_name, fqdn); ++ TEST_VERIFY (e->h_aliases[0] == NULL); ++ } ++ else ++ { ++ /* Fully-qualified QNAME is demoted to an aliases. */ ++ TEST_COMPARE_STRING (e->h_aliases[0], fqdn); ++ ++ for (int i = 1; i <= cnames; ++i) ++ { ++ char *expected = xasprintf ("%d.alias.example", i - 1); ++ if (i == cnames) ++ TEST_COMPARE_STRING (e->h_name, expected); ++ else ++ TEST_COMPARE_STRING (e->h_aliases[i], expected); ++ free (expected); ++ } ++ TEST_VERIFY (e->h_aliases[cnames] == NULL); ++ } ++ ++ free (fqdn); ++ free (qname); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ .search = { "example.net", "example.com" }, ++ }); ++ ++ static const int families[] = { AF_UNSPEC, AF_INET, AF_INET6 }; ++ ++ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig) ++ { ++ insert_sig = do_insert_sig; ++ ++ /* If do_search is true, a bare host name (for example, a1-c1) ++ is used. This exercises search path processing and FQDN ++ qualification. */ ++ for (int do_search = 0; do_search < 2; ++do_search) ++ for (const int *paf = families; paf != array_end (families); ++paf) ++ { ++ for (int cnames = 0; cnames <= 100; ++cnames) ++ { ++ check_cnames_failure (*paf, do_search, cnames, 0); ++ /* Now with NXDOMAIN responses. */ ++ check_cnames_failure (*paf, do_search, cnames, 255); ++ } ++ ++ for (int cnames = 0; cnames <= 10; ++cnames) ++ for (int addresses = 1; addresses <= 10; ++addresses) ++ check (*paf, do_search, cnames, addresses); ++ ++ /* The current implementation is limited to 47 aliases. ++ Addresses do not have such a limit. */ ++ check (*paf, do_search, 47, 60); ++ } ++ } ++ ++ resolv_test_end (obj); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-byaddr.c b/resolv/tst-resolv-byaddr.c +new file mode 100644 +index 0000000000..6299e89837 +--- /dev/null ++++ b/resolv/tst-resolv-byaddr.c +@@ -0,0 +1,326 @@ ++/* Test reverse DNS lookup. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "tst-resolv-maybe_insert_sig.h" ++ ++/* QNAME format: ++ ++ ADDRESSES.CNAMES...(lots of 0s)...8.b.d.0.1.0.0.2.ip6.arpa. ++ CNAMES|ADDRESSES.2.0.192.in-addr-arpa. ++ ++ For the IPv4 reverse lookup, the address count is in the lower ++ bits. ++ ++ CNAMES is the length of the CNAME chain, ADDRESSES is the number of ++ addresses in the response. The special value 15 means that there ++ are no addresses, and the RCODE is NXDOMAIN. */ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_COMPARE (qclass, C_IN); ++ TEST_COMPARE (qtype, T_PTR); ++ ++ unsigned int addresses, cnames, bits; ++ char *tail; ++ if (strstr (qname, "ip6.arpa") != NULL ++ && sscanf (qname, "%x.%x.%ms", &addresses, &cnames, &tail) == 3) ++ TEST_COMPARE_STRING (tail, "\ ++0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"); ++ else if (sscanf (qname, "%u.%ms", &bits, &tail) == 2) ++ { ++ TEST_COMPARE_STRING (tail, "2.0.192.in-addr.arpa"); ++ addresses = bits & 0x0f; ++ cnames = bits >> 4; ++ } ++ else ++ FAIL_EXIT1 ("invalid QNAME: %s", qname); ++ free (tail); ++ ++ int rcode; ++ if (addresses == 15) ++ { ++ /* Special case: Use no addresses with NXDOMAIN response. */ ++ rcode = ns_r_nxdomain; ++ addresses = 0; ++ } ++ else ++ rcode = 0; ++ ++ struct resolv_response_flags flags = { .rcode = rcode }; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ maybe_insert_sig (b, qname); ++ ++ /* Provide the requested number of CNAME records. */ ++ char *previous_name = (char *) qname; ++ for (int unique = 0; unique < cnames; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); ++ char *new_name = xasprintf ("%d.alias.example", unique); ++ resolv_response_add_name (b, new_name); ++ resolv_response_close_record (b); ++ ++ maybe_insert_sig (b, qname); ++ ++ if (previous_name != qname) ++ free (previous_name); ++ previous_name = new_name; ++ } ++ ++ for (int unique = 0; unique < addresses; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_PTR, 60); ++ char *ptr = xasprintf ("unique-%d.cnames-%u.addresses-%u.example", ++ unique, cnames, addresses); ++ resolv_response_add_name (b, ptr); ++ free (ptr); ++ resolv_response_close_record (b); ++ } ++ ++ if (previous_name != qname) ++ free (previous_name); ++} ++ ++/* Used to check that gethostbyaddr_r does not write past the buffer ++ end. */ ++static struct support_next_to_fault ntf; ++ ++/* Perform a gethostbyaddr call and check the result. */ ++static void ++check_gethostbyaddr (const char *address, const char *expected) ++{ ++ unsigned char bytes[16]; ++ unsigned int byteslen; ++ int family; ++ if (strchr (address, ':') != NULL) ++ { ++ family = AF_INET6; ++ byteslen = 16; ++ } ++ else ++ { ++ family = AF_INET; ++ byteslen = 4; ++ } ++ TEST_COMPARE (inet_pton (family, address, bytes), 1); ++ ++ struct hostent *e = gethostbyaddr (bytes, byteslen, family); ++ check_hostent (address, e, expected); ++ ++ if (e == NULL) ++ return; ++ ++ /* Try gethostbyaddr_r with increasing sizes until success. First ++ compute a reasonable minimum buffer size, to avoid many pointless ++ attempts. */ ++ size_t minimum_size = strlen (e->h_name); ++ for (int i = 0; e->h_addr_list[i] != NULL; ++i) ++ minimum_size += e->h_length + sizeof (char *); ++ for (int i = 0; e->h_aliases[i] != NULL; ++i) ++ minimum_size += strlen (e->h_aliases[i]) + 1 + sizeof (char *); ++ ++ /* Gradually increase the size until success. */ ++ for (size_t size = minimum_size; size < ntf.length; ++size) ++ { ++ struct hostent result; ++ int herrno; ++ int ret = gethostbyaddr_r (bytes, byteslen, family, &result, ++ ntf.buffer + ntf.length - size, size, ++ &e, &herrno); ++ if (ret == ERANGE) ++ /* Retry with larger size. */ ++ TEST_COMPARE (herrno, NETDB_INTERNAL); ++ else if (ret == 0) ++ { ++ TEST_VERIFY (size > minimum_size); ++ check_hostent (address, e, expected); ++ return; ++ } ++ else ++ FAIL_EXIT1 ("Unexpected gethostbyaddr_r failure: %d", ret); ++ } ++ ++ FAIL_EXIT1 ("gethostbyaddr_r always failed for: %s", address); ++} ++ ++/* Perform a getnameinfo call and check the result. */ ++static void ++check_getnameinfo (const char *address, const char *expected) ++{ ++ struct sockaddr_in sin = { }; ++ struct sockaddr_in6 sin6 = { }; ++ void *sa; ++ socklen_t salen; ++ if (strchr (address, ':') != NULL) ++ { ++ sin6.sin6_family = AF_INET6; ++ TEST_COMPARE (inet_pton (AF_INET6, address, &sin6.sin6_addr), 1); ++ sin6.sin6_port = htons (80); ++ sa = &sin6; ++ salen = sizeof (sin6); ++ } ++ else ++ { ++ sin.sin_family = AF_INET; ++ TEST_COMPARE (inet_pton (AF_INET, address, &sin.sin_addr), 1); ++ sin.sin_port = htons (80); ++ sa = &sin; ++ salen = sizeof (sin); ++ } ++ ++ char host[64]; ++ char service[64]; ++ int ret = getnameinfo (sa, salen, host, ++ sizeof (host), service, sizeof (service), ++ NI_NAMEREQD | NI_NUMERICSERV); ++ switch (ret) ++ { ++ case 0: ++ TEST_COMPARE_STRING (host, expected); ++ TEST_COMPARE_STRING (service, "80"); ++ break; ++ case EAI_SYSTEM: ++ TEST_COMPARE_STRING (strerror (errno), expected); ++ break; ++ default: ++ TEST_COMPARE_STRING (gai_strerror (ret), expected); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ /* Some reasonably upper bound for the maximum response size. */ ++ ntf = support_next_to_fault_allocate (4096); ++ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig) ++ { ++ insert_sig = do_insert_sig; ++ ++ /* No PTR record, RCODE=0. */ ++ check_gethostbyaddr ("192.0.2.0", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("192.0.2.0", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.16", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("192.0.2.16", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.32", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("192.0.2.32", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("2001:db8::", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::10", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("2001:db8::10", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::20", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("2001:db8::20", "Name or service not known"); ++ ++ /* No PTR record, NXDOMAIN. */ ++ check_gethostbyaddr ("192.0.2.15", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("192.0.2.15", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.31", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("192.0.2.31", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.47", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("192.0.2.47", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::f", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("2001:db8::f", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::1f", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("2001:db8::1f", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::2f", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("2001:db8::2f", "Name or service not known"); ++ ++ /* Actual response data. Only the first PTR record is returned. */ ++ check_gethostbyaddr ("192.0.2.1", ++ "name: unique-0.cnames-0.addresses-1.example\n" ++ "address: 192.0.2.1\n"); ++ check_getnameinfo ("192.0.2.1", ++ "unique-0.cnames-0.addresses-1.example"); ++ check_gethostbyaddr ("192.0.2.17", ++ "name: unique-0.cnames-1.addresses-1.example\n" ++ "address: 192.0.2.17\n"); ++ check_getnameinfo ("192.0.2.17", ++ "unique-0.cnames-1.addresses-1.example"); ++ check_gethostbyaddr ("192.0.2.18", ++ "name: unique-0.cnames-1.addresses-2.example\n" ++ "address: 192.0.2.18\n"); ++ check_getnameinfo ("192.0.2.18", ++ "unique-0.cnames-1.addresses-2.example"); ++ check_gethostbyaddr ("192.0.2.33", ++ "name: unique-0.cnames-2.addresses-1.example\n" ++ "address: 192.0.2.33\n"); ++ check_getnameinfo ("192.0.2.33", ++ "unique-0.cnames-2.addresses-1.example"); ++ check_gethostbyaddr ("192.0.2.34", ++ "name: unique-0.cnames-2.addresses-2.example\n" ++ "address: 192.0.2.34\n"); ++ check_getnameinfo ("192.0.2.34", ++ "unique-0.cnames-2.addresses-2.example"); ++ ++ /* Same for IPv6 addresses. */ ++ check_gethostbyaddr ("2001:db8::1", ++ "name: unique-0.cnames-0.addresses-1.example\n" ++ "address: 2001:db8::1\n"); ++ check_getnameinfo ("2001:db8::1", ++ "unique-0.cnames-0.addresses-1.example"); ++ check_gethostbyaddr ("2001:db8::11", ++ "name: unique-0.cnames-1.addresses-1.example\n" ++ "address: 2001:db8::11\n"); ++ check_getnameinfo ("2001:db8::11", ++ "unique-0.cnames-1.addresses-1.example"); ++ check_gethostbyaddr ("2001:db8::12", ++ "name: unique-0.cnames-1.addresses-2.example\n" ++ "address: 2001:db8::12\n"); ++ check_getnameinfo ("2001:db8::12", ++ "unique-0.cnames-1.addresses-2.example"); ++ check_gethostbyaddr ("2001:db8::21", ++ "name: unique-0.cnames-2.addresses-1.example\n" ++ "address: 2001:db8::21\n"); ++ check_getnameinfo ("2001:db8::21", ++ "unique-0.cnames-2.addresses-1.example"); ++ check_gethostbyaddr ("2001:db8::22", ++ "name: unique-0.cnames-2.addresses-2.example\n" ++ "address: 2001:db8::22\n"); ++ check_getnameinfo ("2001:db8::22", ++ "unique-0.cnames-2.addresses-2.example"); ++ } ++ ++ resolv_test_end (obj); ++ ++ support_next_to_fault_free (&ntf); ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c +new file mode 100644 +index 0000000000..63dac90e02 +--- /dev/null ++++ b/resolv/tst-resolv-invalid-cname.c +@@ -0,0 +1,406 @@ ++/* Test handling of CNAMEs with non-host domain names (bug 12154). ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Query strings describe the CNAME chain in the response. They have ++ the format "bitsBITS.countCOUNT.example.", where BITS and COUNT are ++ replaced by unsigned decimal numbers. COUNT is the number of CNAME ++ records in the response. BITS has two bits for each CNAME record, ++ describing a special prefix that is added to that CNAME. ++ ++ 0: No special leading label. ++ 1: Starting with "*.". ++ 2: Starting with "-x.". ++ 3: Starting with "star.*.". ++ ++ The first CNAME in the response using the two least significant ++ bits. ++ ++ For PTR queries, the QNAME format is different, it is either ++ COUNT.BITS.168.192.in-addr.arpa. (with BITS and COUNT still ++ decimal), or: ++ ++COUNT.BITS0.BITS1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. ++ ++ where BITS and COUNT are hexadecimal. */ ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_COMPARE (qclass, C_IN); ++ ++ /* The only other query type besides A is PTR. */ ++ if (qtype != T_A && qtype != T_AAAA) ++ TEST_COMPARE (qtype, T_PTR); ++ ++ unsigned int bits, bits1, count; ++ char *tail = NULL; ++ if (sscanf (qname, "bits%u.count%u.%ms", &bits, &count, &tail) == 3) ++ TEST_COMPARE_STRING (tail, "example"); ++ else if (strstr (qname, "in-addr.arpa") != NULL ++ && sscanf (qname, "%u.%u.%ms", &bits, &count, &tail) == 3) ++ TEST_COMPARE_STRING (tail, "168.192.in-addr.arpa"); ++ else if (sscanf (qname, "%x.%x.%x.%ms", &bits, &bits1, &count, &tail) == 4) ++ { ++ TEST_COMPARE_STRING (tail, "\ ++0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"); ++ bits |= bits1 << 4; ++ } ++ else ++ FAIL_EXIT1 ("invalid QNAME: %s\n", qname); ++ free (tail); ++ ++ struct resolv_response_flags flags = {}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ ++ /* Provide the requested number of CNAME records. */ ++ char *previous_name = (char *) qname; ++ unsigned int original_bits = bits; ++ for (int unique = 0; unique < count; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); ++ ++ static const char bits_to_prefix[4][8] = { "", "*.", "-x.", "star.*." }; ++ char *new_name = xasprintf ("%sunique%d.example", ++ bits_to_prefix[bits & 3], unique); ++ bits >>= 2; ++ resolv_response_add_name (b, new_name); ++ resolv_response_close_record (b); ++ ++ if (previous_name != qname) ++ free (previous_name); ++ previous_name = new_name; ++ } ++ ++ /* Actual answer record. */ ++ resolv_response_open_record (b, previous_name, qclass, qtype, 60); ++ switch (qtype) ++ { ++ case T_A: ++ { ++ char ipv4[4] = {192, 168, count, original_bits}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ } ++ break; ++ case T_AAAA: ++ { ++ char ipv6[16] = ++ { ++ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ count, original_bits ++ }; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ } ++ break; ++ ++ case T_PTR: ++ { ++ char *name = xasprintf ("bits%u.count%u.example", ++ original_bits, count); ++ resolv_response_add_name (b, name); ++ free (name); ++ } ++ break; ++ } ++ resolv_response_close_record (b); ++ ++ if (previous_name != qname) ++ free (previous_name); ++} ++ ++/* Controls which name resolution function is invoked. */ ++enum test_mode ++ { ++ byname, /* gethostbyname. */ ++ byname2, /* gethostbyname2. */ ++ gai, /* getaddrinfo without AI_CANONNAME. */ ++ gai_canon, /* getaddrinfo with AI_CANONNAME. */ ++ ++ test_mode_num /* Number of enum values. */ ++ }; ++ ++static const char * ++test_mode_to_string (enum test_mode mode) ++{ ++ switch (mode) ++ { ++ case byname: ++ return "byname"; ++ case byname2: ++ return "byname2"; ++ case gai: ++ return "gai"; ++ case gai_canon: ++ return "gai_canon"; ++ case test_mode_num: ++ break; /* Report error below. */ ++ } ++ FAIL_EXIT1 ("invalid test_mode: %d", mode); ++} ++ ++/* Append the name and aliases to OUT. */ ++static void ++append_names (FILE *out, const char *qname, int bits, int count, ++ enum test_mode mode) ++{ ++ /* Largest valid index which has a corresponding zero in bits ++ (meaning a syntactically valid CNAME). */ ++ int last_valid_cname = -1; ++ ++ for (int i = 0; i < count; ++i) ++ if ((bits & (3 << (i * 2))) == 0) ++ last_valid_cname = i; ++ ++ if (mode != gai) ++ { ++ const char *label; ++ if (mode == gai_canon) ++ label = "canonname"; ++ else ++ label = "name"; ++ if (last_valid_cname >= 0) ++ fprintf (out, "%s: unique%d.example\n", label, last_valid_cname); ++ else ++ fprintf (out, "%s: %s\n", label, qname); ++ } ++ ++ if (mode == byname || mode == byname2) ++ { ++ if (last_valid_cname >= 0) ++ fprintf (out, "alias: %s\n", qname); ++ for (int i = 0; i < count; ++i) ++ { ++ if ((bits & (3 << (i * 2))) == 0 && i != last_valid_cname) ++ fprintf (out, "alias: unique%d.example\n", i); ++ } ++ } ++} ++ ++/* Append the address information to OUT. */ ++static void ++append_addresses (FILE *out, int af, int bits, int count, enum test_mode mode) ++{ ++ int last = count * 256 + bits; ++ if (mode == gai || mode == gai_canon) ++ { ++ if (af == AF_INET || af == AF_UNSPEC) ++ fprintf (out, "address: STREAM/TCP 192.168.%d.%d 80\n", count, bits); ++ if (af == AF_INET6 || af == AF_UNSPEC) ++ { ++ if (last == 0) ++ fprintf (out, "address: STREAM/TCP 2001:db8:: 80\n"); ++ else ++ fprintf (out, "address: STREAM/TCP 2001:db8::%x 80\n", last); ++ } ++ } ++ else ++ { ++ TEST_VERIFY (af != AF_UNSPEC); ++ if (af == AF_INET) ++ fprintf (out, "address: 192.168.%d.%d\n", count, bits); ++ if (af == AF_INET6) ++ { ++ if (last == 0) ++ fprintf (out, "address: 2001:db8::\n"); ++ else ++ fprintf (out, "address: 2001:db8::%x\n", last); ++ } ++ } ++} ++ ++/* Perform one test using a forward lookup. */ ++static void ++check_forward (int af, int bits, int count, enum test_mode mode) ++{ ++ char *qname = xasprintf ("bits%d.count%d.example", bits, count); ++ char *label = xasprintf ("af=%d bits=%d count=%d mode=%s qname=%s", ++ af, bits, count, test_mode_to_string (mode), qname); ++ ++ struct xmemstream expected; ++ xopen_memstream (&expected); ++ if (mode == gai_canon) ++ fprintf (expected.out, "flags: AI_CANONNAME\n"); ++ append_names (expected.out, qname, bits, count, mode); ++ append_addresses (expected.out, af, bits, count, mode); ++ xfclose_memstream (&expected); ++ ++ if (mode == gai || mode == gai_canon) ++ { ++ struct addrinfo *ai; ++ struct addrinfo hints = ++ { ++ .ai_family = af, ++ .ai_socktype = SOCK_STREAM, ++ }; ++ if (mode == gai_canon) ++ hints.ai_flags |= AI_CANONNAME; ++ int ret = getaddrinfo (qname, "80", &hints, &ai); ++ check_addrinfo (label, ai, ret, expected.buffer); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ } ++ else ++ { ++ struct hostent *e; ++ if (mode == gai) ++ { ++ TEST_COMPARE (af, AF_INET); ++ e = gethostbyname (qname); ++ } ++ else ++ { ++ if (af != AF_INET) ++ TEST_COMPARE (af, AF_INET6); ++ e = gethostbyname2 (qname, af); ++ } ++ check_hostent (label, e, expected.buffer); ++ } ++ ++ free (expected.buffer); ++ free (label); ++ free (qname); ++} ++ ++/* Perform one check using a reverse lookup. */ ++ ++static void ++check_reverse (int af, int bits, int count) ++{ ++ TEST_VERIFY (af == AF_INET || af == AF_INET6); ++ ++ char *label = xasprintf ("af=%d bits=%d count=%d", af, bits, count); ++ char *fqdn = xasprintf ("bits%d.count%d.example", bits, count); ++ ++ struct xmemstream expected; ++ xopen_memstream (&expected); ++ fprintf (expected.out, "name: %s\n", fqdn); ++ append_addresses (expected.out, af, bits, count, byname); ++ xfclose_memstream (&expected); ++ ++ char addr[16] = { 0 }; ++ socklen_t addrlen; ++ if (af == AF_INET) ++ { ++ addr[0] = 192; ++ addr[1] = 168; ++ addr[2] = count; ++ addr[3] = bits; ++ addrlen = 4; ++ } ++ else ++ { ++ addr[0] = 0x20; ++ addr[1] = 0x01; ++ addr[2] = 0x0d; ++ addr[3] = 0xb8; ++ addr[14] = count; ++ addr[15] = bits; ++ addrlen = 16; ++ } ++ ++ struct hostent *e = gethostbyaddr (addr, addrlen, af); ++ check_hostent (label, e, expected.buffer); ++ ++ /* getnameinfo check is different. There is no generic check_* ++ function for it. */ ++ { ++ struct sockaddr_in sin = { }; ++ struct sockaddr_in6 sin6 = { }; ++ void *sa; ++ socklen_t salen; ++ if (af == AF_INET) ++ { ++ sin.sin_family = AF_INET; ++ memcpy (&sin.sin_addr, addr, addrlen); ++ sin.sin_port = htons (80); ++ sa = &sin; ++ salen = sizeof (sin); ++ } ++ else ++ { ++ sin6.sin6_family = AF_INET6; ++ memcpy (&sin6.sin6_addr, addr, addrlen); ++ sin6.sin6_port = htons (80); ++ sa = &sin6; ++ salen = sizeof (sin6); ++ } ++ ++ char host[64]; ++ char service[64]; ++ int ret = getnameinfo (sa, salen, host, ++ sizeof (host), service, sizeof (service), ++ NI_NAMEREQD | NI_NUMERICSERV); ++ TEST_COMPARE (ret, 0); ++ TEST_COMPARE_STRING (host, fqdn); ++ TEST_COMPARE_STRING (service, "80"); ++ } ++ ++ free (expected.buffer); ++ free (fqdn); ++ free (label); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ for (int count = 0; count <= 3; ++count) ++ for (int bits = 0; bits <= 1 << (count * 2); ++bits) ++ { ++ if (count > 0 && bits == count) ++ /* The last bits value is only checked if count == 0. */ ++ continue; ++ ++ for (enum test_mode mode = 0; mode < test_mode_num; ++mode) ++ { ++ check_forward (AF_INET, bits, count, mode); ++ if (mode != byname) ++ check_forward (AF_INET6, bits, count, mode); ++ if (mode == gai || mode == gai_canon) ++ check_forward (AF_UNSPEC, bits, count, mode); ++ } ++ ++ check_reverse (AF_INET, bits, count); ++ check_reverse (AF_INET6, bits, count); ++ } ++ ++ resolv_test_end (obj); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-maybe_insert_sig.h b/resolv/tst-resolv-maybe_insert_sig.h +new file mode 100644 +index 0000000000..05725225af +--- /dev/null ++++ b/resolv/tst-resolv-maybe_insert_sig.h +@@ -0,0 +1,32 @@ ++/* Code snippet for optionally inserting ignored SIG records in resolver tests. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Set to true for an alternative pass that inserts (ignored) SIG ++ records. This does not alter the response, so this property is not ++ encoded in the QNAME. The variable needs to be volatile because ++ leaf attributes tell GCC that the response function is not ++ called. */ ++static volatile bool insert_sig; ++ ++static void ++maybe_insert_sig (struct resolv_response_builder *b, const char *owner) ++{ ++ resolv_response_open_record (b, owner, C_IN, T_SIG, 60); ++ resolv_response_add_data (b, "", 1); ++ resolv_response_close_record (b); ++} +diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c +new file mode 100644 +index 0000000000..9f5aebd99f +--- /dev/null ++++ b/resolv/tst-resolv-noaaaa-vc.c +@@ -0,0 +1,129 @@ ++/* Test the RES_NOAAAA resolver option with a large response. ++ Copyright (C) 2022-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Used to keep track of the number of queries. */ ++static volatile unsigned int queries; ++ ++/* If true, add a large TXT record at the start of the answer section. */ ++static volatile bool stuff_txt; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* If not using TCP, just force its use. */ ++ if (!ctx->tcp) ++ { ++ struct resolv_response_flags flags = {.tc = true}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ return; ++ } ++ ++ /* The test needs to send four queries, the first three are used to ++ grow the NSS buffer via the ERANGE handshake. */ ++ ++queries; ++ TEST_VERIFY (queries <= 4); ++ ++ /* AAAA queries are supposed to be disabled. */ ++ TEST_COMPARE (qtype, T_A); ++ TEST_COMPARE (qclass, C_IN); ++ TEST_COMPARE_STRING (qname, "example.com"); ++ ++ struct resolv_response_flags flags = {}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ ++ resolv_response_section (b, ns_s_an); ++ ++ if (stuff_txt) ++ { ++ resolv_response_open_record (b, qname, qclass, T_TXT, 60); ++ int zero = 0; ++ for (int i = 0; i <= 15000; ++i) ++ resolv_response_add_data (b, &zero, sizeof (zero)); ++ resolv_response_close_record (b); ++ } ++ ++ for (int i = 0; i < 200; ++i) ++ { ++ resolv_response_open_record (b, qname, qclass, qtype, 60); ++ char ipv4[4] = {192, 0, 2, i + 1}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ resolv_response_close_record (b); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ _res.options |= RES_NOAAAA; ++ ++ for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt) ++ { ++ queries = 0; ++ stuff_txt = do_stuff_txt; ++ ++ struct addrinfo *ai = NULL; ++ int ret; ++ ret = getaddrinfo ("example.com", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ ++ char *expected_result; ++ { ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ for (int i = 0; i < 200; ++i) ++ fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1); ++ xfclose_memstream (&mem); ++ expected_result = mem.buffer; ++ } ++ ++ check_addrinfo ("example.com", ai, ret, expected_result); ++ ++ free (expected_result); ++ freeaddrinfo (ai); ++ } ++ ++ resolv_test_end (obj); ++ return 0; ++} ++ ++#include +diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py +index 2dd6bfda18..b87cf2f809 100644 +--- a/scripts/dso-ordering-test.py ++++ b/scripts/dso-ordering-test.py +@@ -707,13 +707,12 @@ def process_testcase(t): + "\t$(compile.c) $(OUTPUT_OPTION)\n") + makefile.write (rule) + +- not_depended_objs = find_objs_not_depended_on(test_descr) +- if not_depended_objs: +- depstr = "" +- for dep in not_depended_objs: +- depstr += (" $(objpfx)" + test_subdir + "/" +- + test_name + "-" + dep + ".so") +- makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr)) ++ # Ensure that all shared objects are built before running the ++ # test, whether there link-time dependencies or not. ++ depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep) ++ for dep in test_descr.objs] ++ makefile.write("$(objpfx){}.out: {}\n".format( ++ base_test_name, " ".join(depobjs))) + + # Add main executable to test-srcs + makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name)) +diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py +index 43ab58ffe2..36d204c9b0 100644 +--- a/scripts/glibcextract.py ++++ b/scripts/glibcextract.py +@@ -17,6 +17,7 @@ + # License along with the GNU C Library; if not, see + # . + ++import collections + import os.path + import re + import subprocess +@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None, + if not allow_extra_2: + ret = 1 + return ret ++ ++CompileResult = collections.namedtuple("CompileResult", "returncode output") ++ ++def compile_c_snippet(snippet, cc, extra_cc_args=''): ++ """Compile and return whether the SNIPPET can be build with CC along ++ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE ++ being 0 for success, or the failure value and the compiler output. ++ """ ++ with tempfile.TemporaryDirectory() as temp_dir: ++ c_file_name = os.path.join(temp_dir, 'test.c') ++ obj_file_name = os.path.join(temp_dir, 'test.o') ++ with open(c_file_name, 'w') as c_file: ++ c_file.write(snippet + '\n') ++ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name, ++ c_file_name] ++ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT) ++ return CompileResult(r.returncode, r.stdout) +diff --git a/socket/Makefile b/socket/Makefile +index 156eec6c85..2bde78387f 100644 +--- a/socket/Makefile ++++ b/socket/Makefile +@@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt \ + tests := \ + tst-accept4 \ + tst-sockopt \ ++ tst-cmsghdr \ + # tests + + tests-internal := \ +diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c +new file mode 100644 +index 0000000000..4c6898569b +--- /dev/null ++++ b/socket/tst-cmsghdr-skeleton.c +@@ -0,0 +1,92 @@ ++/* Test ancillary data header creation. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* We use the preprocessor to generate the function/macro tests instead of ++ using indirection because having all the macro expansions alongside ++ each other lets the compiler warn us about suspicious pointer ++ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */ ++ ++#include ++ ++#define RUN_TEST_CONCAT(suffix) run_test_##suffix ++#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix) ++ ++static void ++RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void) ++{ ++ struct msghdr m = {0}; ++ struct cmsghdr *cmsg; ++ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0}; ++ ++ m.msg_control = cmsgbuf; ++ m.msg_controllen = sizeof (cmsgbuf); ++ ++ /* First header should point to the start of the buffer. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ ++ /* If the first header length consumes the entire buffer, there is no ++ space remaining for additional headers. */ ++ cmsg->cmsg_len = sizeof (cmsgbuf); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ /* The first header length is so big, using it would cause an overflow. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len = SIZE_MAX; ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ /* The first header leaves just enough space to hold another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ ++ /* The first header leaves space but not enough for another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len ++; ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ /* The second header leaves just enough space to hold another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD)); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ cmsg->cmsg_len = sizeof (cmsgbuf) ++ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */ ++ - sizeof (struct cmsghdr); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ ++ /* The second header leaves space but not enough for another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ cmsg->cmsg_len ++; ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ return; ++} +diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c +new file mode 100644 +index 0000000000..68c96d3c9d +--- /dev/null ++++ b/socket/tst-cmsghdr.c +@@ -0,0 +1,56 @@ ++/* Test ancillary data header creation. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#define PAYLOAD "Hello, World!" ++ ++/* CMSG_NXTHDR is a macro that calls an inline function defined in ++ bits/socket.h. In case the function cannot be inlined, libc.so carries ++ a copy. Both versions need to be tested. */ ++ ++#define CMSG_NXTHDR_IMPL CMSG_NXTHDR ++#include "tst-cmsghdr-skeleton.c" ++#undef CMSG_NXTHDR_IMPL ++ ++static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *); ++ ++#define CMSG_NXTHDR_IMPL cmsg_nxthdr ++#include "tst-cmsghdr-skeleton.c" ++#undef CMSG_NXTHDR_IMPL ++ ++static int ++do_test (void) ++{ ++ static void *handle; ++ ++ run_test_CMSG_NXTHDR (); ++ ++ handle = xdlopen (LIBC_SO, RTLD_LAZY); ++ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *)) ++ xdlsym (handle, "__cmsg_nxthdr"); ++ ++ run_test_cmsg_nxthdr (); ++ ++ return 0; ++} ++ ++#include +diff --git a/stdlib/Makefile b/stdlib/Makefile +index f7b25c1981..3d49c4941a 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -171,6 +171,7 @@ tests := \ + test-a64l \ + test-at_quick_exit-race \ + test-atexit-race \ ++ test-atexit-recursive \ + test-bz22786 \ + test-canon \ + test-canon2 \ +diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c +index e417ef624d..960a38f295 100644 +--- a/stdlib/arc4random.c ++++ b/stdlib/arc4random.c +@@ -34,7 +34,7 @@ void + __arc4random_buf (void *p, size_t n) + { + static int seen_initialized; +- size_t l; ++ ssize_t l; + int fd; + + if (n == 0) +diff --git a/stdlib/exit.c b/stdlib/exit.c +index bc46109f3e..dc12e212bc 100644 +--- a/stdlib/exit.c ++++ b/stdlib/exit.c +@@ -53,7 +53,10 @@ __run_exit_handlers (int status, struct exit_function_list **listp, + exit (). */ + while (true) + { +- struct exit_function_list *cur = *listp; ++ struct exit_function_list *cur; ++ ++ restart: ++ cur = *listp; + + if (cur == NULL) + { +@@ -118,7 +121,7 @@ __run_exit_handlers (int status, struct exit_function_list **listp, + if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called)) + /* The last exit function, or another thread, has registered + more exit functions. Start the loop over. */ +- continue; ++ goto restart; + } + + *listp = cur->next; +diff --git a/stdlib/longlong.h b/stdlib/longlong.h +index 9b89469ac2..d8f76a43b5 100644 +--- a/stdlib/longlong.h ++++ b/stdlib/longlong.h +@@ -593,6 +593,18 @@ extern UDItype __umulsidi3 (USItype, USItype); + #define UMUL_TIME 14 + #endif + ++#ifdef __loongarch__ ++# if W_TYPE_SIZE == 32 ++# define count_leading_zeros(count, x) ((count) = __builtin_clz (x)) ++# define count_trailing_zeros(count, x) ((count) = __builtin_ctz (x)) ++# define COUNT_LEADING_ZEROS_0 32 ++# elif W_TYPE_SIZE == 64 ++# define count_leading_zeros(count, x) ((count) = __builtin_clzll (x)) ++# define count_trailing_zeros(count, x) ((count) = __builtin_ctzll (x)) ++# define COUNT_LEADING_ZEROS_0 64 ++# endif ++#endif ++ + #if defined (__M32R__) && W_TYPE_SIZE == 32 + #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + /* The cmp clears the condition bit. */ \ +diff --git a/stdlib/test-atexit-recursive.c b/stdlib/test-atexit-recursive.c +new file mode 100644 +index 0000000000..0596b9763b +--- /dev/null ++++ b/stdlib/test-atexit-recursive.c +@@ -0,0 +1,75 @@ ++/* Support file for atexit/exit, etc. race tests (BZ #27749). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Check that atexit handler registed from another handler still called. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++atexit_cb (void) ++{ ++} ++ ++static void ++atexit_last (void) ++{ ++ _exit (1); ++} ++ ++static void ++atexit_recursive (void) ++{ ++ atexit (&atexit_cb); ++ atexit (&atexit_last); ++} ++ ++_Noreturn static void ++test_and_exit (int count) ++{ ++ for (int i = 0; i < count; ++i) ++ atexit (&atexit_cb); ++ atexit (&atexit_recursive); ++ exit (0); ++} ++ ++static int ++do_test (void) ++{ ++ for (int i = 0; i < 100; ++i) ++ if (xfork () == 0) ++ test_and_exit (i); ++ ++ for (int i = 0; i < 100; ++i) ++ { ++ int status; ++ xwaitpid (0, &status, 0); ++ if (!WIFEXITED (status)) ++ FAIL_EXIT1 ("Failed iterations %d", i); ++ TEST_COMPARE (WEXITSTATUS (status), 1); ++ } ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION do_test ++#include +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index f7fa74b2a6..5e0c79475f 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + + static char *tmpdir; +@@ -71,6 +72,20 @@ call_system (void *closure) + } + } + ++static void * ++sleep_and_check_sigchld (void *closure) ++{ ++ double *seconds = (double *) closure; ++ char cmd[namemax]; ++ sprintf (cmd, "sleep %lf" , *seconds); ++ TEST_COMPARE (system (cmd), 0); ++ ++ sigset_t blocked = {0}; ++ TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0); ++ TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0); ++ return NULL; ++} ++ + static int + do_test (void) + { +@@ -154,6 +169,17 @@ do_test (void) + xchmod (_PATH_BSHELL, st.st_mode); + } + ++ { ++ pthread_t long_sleep_thread = xpthread_create (NULL, ++ sleep_and_check_sigchld, ++ &(double) { 0.2 }); ++ pthread_t short_sleep_thread = xpthread_create (NULL, ++ sleep_and_check_sigchld, ++ &(double) { 0.1 }); ++ xpthread_join (short_sleep_thread); ++ xpthread_join (long_sleep_thread); ++ } ++ + TEST_COMPARE (system (""), 0); + + return 0; +diff --git a/string/test-strnlen.c b/string/test-strnlen.c +index 4a9375112a..5cbaf4b734 100644 +--- a/string/test-strnlen.c ++++ b/string/test-strnlen.c +@@ -73,7 +73,7 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char) + { + size_t i; + +- align &= 63; ++ align &= (getpagesize () / sizeof (CHAR) - 1); + if ((align + len) * sizeof (CHAR) >= page_size) + return; + +@@ -90,38 +90,50 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char) + static void + do_overflow_tests (void) + { +- size_t i, j, len; ++ size_t i, j, al_idx, repeats, len; + const size_t one = 1; + uintptr_t buf_addr = (uintptr_t) buf1; ++ const size_t alignments[] = { 0, 1, 7, 9, 31, 33, 63, 65, 95, 97, 127, 129 }; + +- for (i = 0; i < 750; ++i) ++ for (al_idx = 0; al_idx < sizeof (alignments) / sizeof (alignments[0]); ++ al_idx++) + { +- do_test (1, i, SIZE_MAX, BIG_CHAR); +- +- do_test (0, i, SIZE_MAX - i, BIG_CHAR); +- do_test (0, i, i - buf_addr, BIG_CHAR); +- do_test (0, i, -buf_addr - i, BIG_CHAR); +- do_test (0, i, SIZE_MAX - buf_addr - i, BIG_CHAR); +- do_test (0, i, SIZE_MAX - buf_addr + i, BIG_CHAR); +- +- len = 0; +- for (j = 8 * sizeof(size_t) - 1; j ; --j) +- { +- len |= one << j; +- do_test (0, i, len - i, BIG_CHAR); +- do_test (0, i, len + i, BIG_CHAR); +- do_test (0, i, len - buf_addr - i, BIG_CHAR); +- do_test (0, i, len - buf_addr + i, BIG_CHAR); +- +- do_test (0, i, ~len - i, BIG_CHAR); +- do_test (0, i, ~len + i, BIG_CHAR); +- do_test (0, i, ~len - buf_addr - i, BIG_CHAR); +- do_test (0, i, ~len - buf_addr + i, BIG_CHAR); +- +- do_test (0, i, -buf_addr, BIG_CHAR); +- do_test (0, i, j - buf_addr, BIG_CHAR); +- do_test (0, i, -buf_addr - j, BIG_CHAR); +- } ++ for (repeats = 0; repeats < 2; ++repeats) ++ { ++ size_t align = repeats ? (getpagesize () - alignments[al_idx]) ++ : alignments[al_idx]; ++ align /= sizeof (CHAR); ++ for (i = 0; i < 750; ++i) ++ { ++ do_test (align, i, SIZE_MAX, BIG_CHAR); ++ ++ do_test (align, i, SIZE_MAX - i, BIG_CHAR); ++ do_test (align, i, i - buf_addr, BIG_CHAR); ++ do_test (align, i, -buf_addr - i, BIG_CHAR); ++ do_test (align, i, SIZE_MAX - buf_addr - i, BIG_CHAR); ++ do_test (align, i, SIZE_MAX - buf_addr + i, BIG_CHAR); ++ ++ len = 0; ++ for (j = 8 * sizeof (size_t) - 1; j; --j) ++ { ++ len |= one << j; ++ do_test (align, i, len, BIG_CHAR); ++ do_test (align, i, len - i, BIG_CHAR); ++ do_test (align, i, len + i, BIG_CHAR); ++ do_test (align, i, len - buf_addr - i, BIG_CHAR); ++ do_test (align, i, len - buf_addr + i, BIG_CHAR); ++ ++ do_test (align, i, ~len - i, BIG_CHAR); ++ do_test (align, i, ~len + i, BIG_CHAR); ++ do_test (align, i, ~len - buf_addr - i, BIG_CHAR); ++ do_test (align, i, ~len - buf_addr + i, BIG_CHAR); ++ ++ do_test (align, i, -buf_addr, BIG_CHAR); ++ do_test (align, i, j - buf_addr, BIG_CHAR); ++ do_test (align, i, -buf_addr - j, BIG_CHAR); ++ } ++ } ++ } + } + } + +diff --git a/sunrpc/netname.c b/sunrpc/netname.c +index bf7f0b81c4..c1d1c43e50 100644 +--- a/sunrpc/netname.c ++++ b/sunrpc/netname.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "nsswitch.h" + +@@ -48,7 +49,12 @@ user2netname (char netname[MAXNETNAMELEN + 1], const uid_t uid, + if ((strlen (dfltdom) + OPSYS_LEN + 3 + MAXIPRINT) > (size_t) MAXNETNAMELEN) + return 0; + ++ /* GCC with -Os warns that sprint might overflow while handling dfltdom, ++ however the above test does check if an overflow would happen. */ ++ DIAG_PUSH_NEEDS_COMMENT; ++ DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wformat-overflow"); + sprintf (netname, "%s.%d@%s", OPSYS, uid, dfltdom); ++ DIAG_POP_NEEDS_COMMENT; + i = strlen (netname); + if (netname[i - 1] == '.') + netname[i - 1] = '\0'; +diff --git a/support/Makefile b/support/Makefile +index 9b50eac117..2b661a7eb8 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -32,6 +32,8 @@ libsupport-routines = \ + check_hostent \ + check_netent \ + delayed_exit \ ++ dtotimespec \ ++ dtotimespec-time64 \ + ignore_stderr \ + next_to_fault \ + oom_error \ +diff --git a/support/dtotimespec-time64.c b/support/dtotimespec-time64.c +new file mode 100644 +index 0000000000..b3d5e351e3 +--- /dev/null ++++ b/support/dtotimespec-time64.c +@@ -0,0 +1,27 @@ ++/* Convert double to timespec. 64-bit time support. ++ Copyright (C) 2011-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library and is also part of gnulib. ++ Patches to this file should be submitted to both projects. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++#if __TIMESIZE != 64 ++# define timespec __timespec64 ++# define time_t __time64_t ++# define dtotimespec dtotimespec_time64 ++# include "dtotimespec.c" ++#endif +diff --git a/support/dtotimespec.c b/support/dtotimespec.c +new file mode 100644 +index 0000000000..cde5b4d74c +--- /dev/null ++++ b/support/dtotimespec.c +@@ -0,0 +1,50 @@ ++/* Convert double to timespec. ++ Copyright (C) 2011-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library and is also part of gnulib. ++ Patches to this file should be submitted to both projects. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Convert the double value SEC to a struct timespec. Round toward ++ positive infinity. On overflow, return an extremal value. */ ++ ++#include ++#include ++ ++struct timespec ++dtotimespec (double sec) ++{ ++ if (sec <= TYPE_MINIMUM (time_t)) ++ return make_timespec (TYPE_MINIMUM (time_t), 0); ++ else if (sec >= 1.0 + TYPE_MAXIMUM (time_t)) ++ return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1); ++ else ++ { ++ time_t s = sec; ++ double frac = TIMESPEC_HZ * (sec - s); ++ long ns = frac; ++ ns += ns < frac; ++ s += ns / TIMESPEC_HZ; ++ ns %= TIMESPEC_HZ; ++ ++ if (ns < 0) ++ { ++ s--; ++ ns += TIMESPEC_HZ; ++ } ++ ++ return make_timespec (s, ns); ++ } ++} +diff --git a/support/shell-container.c b/support/shell-container.c +index 1c73666f0a..6698061b9b 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -39,6 +39,7 @@ + #include + + #include ++#include + + /* Design considerations + +@@ -171,6 +172,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 +208,7 @@ static struct { + { "cp", copy_func }, + { "exit", exit_func }, + { "kill", kill_func }, ++ { "sleep", sleep_func }, + { NULL, NULL } + }; + +diff --git a/support/timespec.h b/support/timespec.h +index 4d2ac2737d..1bba3a6837 100644 +--- a/support/timespec.h ++++ b/support/timespec.h +@@ -57,6 +57,8 @@ int support_timespec_check_in_range (struct timespec expected, + struct timespec observed, + double lower_bound, double upper_bound); + ++struct timespec dtotimespec (double sec) __attribute__((const)); ++ + #else + struct timespec __REDIRECT (timespec_add, (struct timespec, struct timespec), + timespec_add_time64); +@@ -82,6 +84,8 @@ int __REDIRECT (support_timespec_check_in_range, (struct timespec expected, + double lower_bound, + double upper_bound), + support_timespec_check_in_range_time64); ++ ++struct timespec __REDIRECT (dtotimespec, (double sec), dtotimespec_time64); + #endif + + /* Check that the timespec on the left represents a time before the +diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S +index 909b208578..d66f0b9c45 100644 +--- a/sysdeps/aarch64/dl-trampoline.S ++++ b/sysdeps/aarch64/dl-trampoline.S +@@ -298,12 +298,11 @@ _dl_runtime_profile: + stp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] + stp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] + stp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] +- str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] + stp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] + stp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] + stp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] + stp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] +- str xzr, [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS] ++ str xzr, [X29, #OFFSET_RV + DL_OFFSET_RV_VPCS] + + /* Setup call to pltexit */ + ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0] +@@ -315,7 +314,6 @@ _dl_runtime_profile: + ldp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] + ldp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] + ldp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] +- ldr x8, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4] + ldp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] + ldp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] + ldp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 050a3032de..c2627fced7 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -105,6 +105,9 @@ typedef struct link_map *lookup_t; + DT_PREINIT_ARRAY. */ + typedef void (*dl_init_t) (int, char **, char **); + ++/* Type of a constructor function, in DT_FINI, DT_FINI_ARRAY. */ ++typedef void (*fini_t) (void); ++ + /* On some architectures a pointer to a function is not just a pointer + to the actual code of the function but rather an architecture + specific descriptor. */ +@@ -1048,9 +1051,16 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv, + initializer functions have completed. */ + extern void _dl_fini (void) attribute_hidden; + +-/* Sort array MAPS according to dependencies of the contained objects. */ ++/* Invoke the DT_FINI_ARRAY and DT_FINI destructors for MAP, which ++ must be a struct link_map *. Can be used as an argument to ++ _dl_catch_exception. */ ++void _dl_call_fini (void *map) attribute_hidden; ++ ++/* Sort array MAPS according to dependencies of the contained objects. ++ If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies ++ say otherwise. */ + extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps, +- unsigned int skip, bool for_fini) attribute_hidden; ++ bool force_first, bool for_fini) attribute_hidden; + + /* The dynamic linker calls this function before and having changing + any shared object mappings. The `r_state' member of `struct r_debug' +diff --git a/sysdeps/generic/libc-lock-arch.h b/sysdeps/generic/libc-lock-arch.h +new file mode 100644 +index 0000000000..4713b30a8a +--- /dev/null ++++ b/sysdeps/generic/libc-lock-arch.h +@@ -0,0 +1,25 @@ ++/* Private libc-internal arch-specific definitions. Generic version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of the ++ License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If ++ not, see . */ ++ ++#ifndef _LIBC_LOCK_ARCH_H ++#define _LIBC_LOCK_ARCH_H ++ ++/* The default definition uses the natural alignment from the lock type. */ ++#define __LIBC_LOCK_ALIGNMENT ++ ++#endif +diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h +index c865713be1..1d51948566 100644 +--- a/sysdeps/hppa/dl-machine.h ++++ b/sysdeps/hppa/dl-machine.h +@@ -347,6 +347,16 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[], + its return value is the user program's entry point. */ + + #define RTLD_START \ ++/* Set up dp for any non-PIC lib constructors that may be called. */ \ ++static struct link_map * __attribute__((used)) \ ++set_dp (struct link_map *map) \ ++{ \ ++ register Elf32_Addr dp asm ("%r27"); \ ++ dp = D_PTR (map, l_info[DT_PLTGOT]); \ ++ asm volatile ("" : : "r" (dp)); \ ++ return map; \ ++} \ ++ \ + asm ( \ + " .text\n" \ + " .globl _start\n" \ +@@ -426,6 +436,13 @@ asm ( \ + direct loader invocation. Thus, argc and argv must be \ + reloaded from from _dl_argc and _dl_argv. */ \ + \ ++ /* Load main_map from _rtld_local and setup dp. */ \ ++" addil LT'_rtld_local,%r19\n" \ ++" ldw RT'_rtld_local(%r1),%r26\n" \ ++" bl set_dp, %r2\n" \ ++" ldw 0(%r26),%r26\n" \ ++" copy %ret0,%r26\n" \ ++ \ + /* Load argc from _dl_argc. */ \ + " addil LT'_dl_argc,%r19\n" \ + " ldw RT'_dl_argc(%r1),%r20\n" \ +@@ -438,13 +455,10 @@ asm ( \ + " ldw 0(%r20),%r24\n" \ + " stw %r24,-44(%sp)\n" \ + \ +- /* Call _dl_init(main_map, argc, argv, envp). */ \ +-" addil LT'_rtld_local,%r19\n" \ +-" ldw RT'_rtld_local(%r1),%r26\n" \ +-" ldw 0(%r26),%r26\n" \ +- \ + /* envp = argv + argc + 1 */ \ + " sh2add %r25,%r24,%r23\n" \ ++ \ ++ /* Call _dl_init(main_map, argc, argv, envp). */ \ + " bl _dl_init,%r2\n" \ + " ldo 4(%r23),%r23\n" /* delay slot */ \ + \ +diff --git a/sysdeps/ieee754/ldbl-128/e_j1l.c b/sysdeps/ieee754/ldbl-128/e_j1l.c +index 54c457681a..9a9c5c6f00 100644 +--- a/sysdeps/ieee754/ldbl-128/e_j1l.c ++++ b/sysdeps/ieee754/ldbl-128/e_j1l.c +@@ -869,10 +869,13 @@ __ieee754_y1l (_Float128 x) + { + /* 0 <= x <= 2 */ + SET_RESTORE_ROUNDL (FE_TONEAREST); ++ xx = math_opt_barrier (xx); ++ x = math_opt_barrier (x); + z = xx * xx; + p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D); + p = -TWOOPI / xx + p; + p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p; ++ math_force_eval (p); + return p; + } + +diff --git a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c +index f85ba94466..0a5fe68342 100644 +--- a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c ++++ b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c +@@ -792,10 +792,13 @@ __ieee754_y1l (long double x) + { + /* 0 <= x <= 2 */ + SET_RESTORE_ROUNDL (FE_TONEAREST); ++ xx = math_opt_barrier (xx); ++ x = math_opt_barrier (x); + z = xx * xx; + p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D); + p = -TWOOPI / xx + p; + p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p; ++ math_force_eval (p); + return p; + } + +diff --git a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c +index d85154e73a..d8c0de1faf 100644 +--- a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c ++++ b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c +@@ -66,38 +66,35 @@ __llroundl (long double x) + /* Peg at max/min values, assuming that the above conversions do so. + Strictly speaking, we can return anything for values that overflow, + but this is more useful. */ +- res = hi + lo; +- +- /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */ +- if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0))) ++ if (__glibc_unlikely (__builtin_add_overflow (hi, lo, &res))) + goto overflow; + + xh -= lo; + ldbl_canonicalize (&xh, &xl); + +- hi = res; + if (xh > 0.5) + { +- res += 1; ++ if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res))) ++ goto overflow; + } + else if (xh == 0.5) + { + if (xl > 0.0 || (xl == 0.0 && res >= 0)) +- res += 1; ++ if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res))) ++ goto overflow; + } + else if (-xh > 0.5) + { +- res -= 1; ++ if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res))) ++ goto overflow; + } + else if (-xh == 0.5) + { + if (xl < 0.0 || (xl == 0.0 && res <= 0)) +- res -= 1; ++ if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res))) ++ goto overflow; + } + +- if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0))) +- goto overflow; +- + return res; + } + else +diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h +index 5b35ea81ec..70fce4fb27 100644 +--- a/sysdeps/mach/hurd/bits/socket.h ++++ b/sysdeps/mach/hurd/bits/socket.h +@@ -249,6 +249,12 @@ struct cmsghdr + + CMSG_ALIGN (sizeof (struct cmsghdr))) + #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + ++/* Given a length, return the additional padding necessary such that ++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ ++#define __CMSG_PADDING(len) ((sizeof (size_t) \ ++ - ((len) & (sizeof (size_t) - 1))) \ ++ & (sizeof (size_t) - 1)) ++ + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + struct cmsghdr *__cmsg) __THROW; + #ifdef __USE_EXTERN_INLINES +@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + _EXTERN_INLINE struct cmsghdr * + __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) + { ++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and ++ __mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of __cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; ++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; ++ ++ size_t __size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (__cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ + return (struct cmsghdr *) 0; + ++ /* There isn't enough space between __cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) ++ < __size_needed) ++ || ((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr ++ - __size_needed) ++ < __cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; ++ ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); +- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control +- + __mhdr->msg_controllen) +- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) +- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) +- /* No more entries. */ +- return (struct cmsghdr *) 0; + return __cmsg; + } + #endif /* Use `extern inline'. */ +diff --git a/sysdeps/nptl/libc-lock.h b/sysdeps/nptl/libc-lock.h +index 5af476c48b..63b3f3d75c 100644 +--- a/sysdeps/nptl/libc-lock.h ++++ b/sysdeps/nptl/libc-lock.h +@@ -22,6 +22,7 @@ + #include + #define __need_NULL + #include ++#include + + + /* Mutex type. */ +@@ -29,7 +30,12 @@ + # if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC + typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; + # else +-typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t; ++typedef struct ++{ ++ int lock __LIBC_LOCK_ALIGNMENT; ++ int cnt; ++ void *owner; ++} __libc_lock_recursive_t; + # endif + #else + typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; +diff --git a/sysdeps/nptl/libc-lockP.h b/sysdeps/nptl/libc-lockP.h +index d3a6837fd2..425f514c5c 100644 +--- a/sysdeps/nptl/libc-lockP.h ++++ b/sysdeps/nptl/libc-lockP.h +@@ -32,9 +32,10 @@ + ld.so might be used on old kernels with a different libc.so. */ + #include + #include ++#include + + /* Mutex type. */ +-typedef int __libc_lock_t; ++typedef int __libc_lock_t __LIBC_LOCK_ALIGNMENT; + typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t; + typedef pthread_rwlock_t __libc_rwlock_t; + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index bcff909b2f..f975dcd2bc 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -120,6 +120,7 @@ struct gaih_result + { + struct gaih_addrtuple *at; + char *canon; ++ char *h_name; + bool free_at; + bool got_ipv6; + }; +@@ -165,6 +166,7 @@ gaih_result_reset (struct gaih_result *res) + if (res->free_at) + free (res->at); + free (res->canon); ++ free (res->h_name); + memset (res, 0, sizeof (*res)); + } + +@@ -203,9 +205,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + return 0; + } + +-/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name +- is not copied, and the struct hostent object must not be deallocated +- prematurely. The new addresses are appended to the tuple array in RES. */ ++/* Convert struct hostent to a list of struct gaih_addrtuple objects. The new ++ addresses are appended to the tuple array in RES. */ + static bool + convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + struct hostent *h, struct gaih_result *res) +@@ -238,6 +239,15 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + res->at = array; + res->free_at = true; + ++ /* Duplicate h_name because it may get reclaimed when the underlying storage ++ is freed. */ ++ if (res->h_name == NULL) ++ { ++ res->h_name = __strdup (h->h_name); ++ if (res->h_name == NULL) ++ return false; ++ } ++ + /* Update the next pointers on reallocation. */ + for (size_t i = 0; i < old; i++) + array[i].next = array + i + 1; +@@ -262,7 +272,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + } + array[i].next = array + i + 1; + } +- array[0].name = h->h_name; + array[count - 1].next = NULL; + + return true; +@@ -324,15 +333,15 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name, + memory allocation failure. The returned string is allocated on the + heap; the caller has to free it. */ + static char * +-getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name) ++getcanonname (nss_action_list nip, const char *hname, const char *name) + { + nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r"); + char *s = (char *) name; + if (cfct != NULL) + { + char buf[256]; +- if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf), +- &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS) ++ if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno, ++ &h_errno)) != NSS_STATUS_SUCCESS) + /* If the canonical name cannot be determined, use the passed + string. */ + s = (char *) name; +@@ -540,11 +549,11 @@ get_nscd_addresses (const char *name, const struct addrinfo *req, + at[count].addr[2] = htonl (0xffff); + } + else if (req->ai_family == AF_UNSPEC +- || air->family[count] == req->ai_family) ++ || air->family[i] == req->ai_family) + { +- at[count].family = air->family[count]; ++ at[count].family = air->family[i]; + memcpy (at[count].addr, addrs, size); +- if (air->family[count] == AF_INET6) ++ if (air->family[i] == AF_INET6) + res->got_ipv6 = true; + } + at[count].next = at + count + 1; +@@ -771,7 +780,7 @@ get_nss_addresses (const char *name, const struct addrinfo *req, + if ((req->ai_flags & AI_CANONNAME) != 0 + && res->canon == NULL) + { +- char *canonbuf = getcanonname (nip, res->at, name); ++ char *canonbuf = getcanonname (nip, res->h_name, name); + if (canonbuf == NULL) + { + __resolv_context_put (res_ctx); +@@ -1187,9 +1196,7 @@ free_and_return: + if (malloc_name) + free ((char *) name); + free (addrmem); +- if (res.free_at) +- free (res.at); +- free (res.canon); ++ gaih_result_reset (&res); + + return result; + } +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 8014f63355..20c9420dd4 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -179,16 +179,16 @@ do_system (const char *line) + as if the shell had terminated using _exit(127). */ + status = W_EXITCODE (127, 0); + ++ /* sigaction can not fail with SIGINT/SIGQUIT used with old ++ disposition. Same applies for sigprocmask. */ + DO_LOCK (); + if (SUB_REF () == 0) + { +- /* sigaction can not fail with SIGINT/SIGQUIT used with old +- disposition. Same applies for sigprocmask. */ + __sigaction (SIGINT, &intr, NULL); + __sigaction (SIGQUIT, &quit, NULL); +- __sigprocmask (SIG_SETMASK, &omask, NULL); + } + DO_UNLOCK (); ++ __sigprocmask (SIG_SETMASK, &omask, NULL); + + if (ret != 0) + __set_errno (ret); +diff --git a/sysdeps/powerpc/mod-tlsopt-powerpc.c b/sysdeps/powerpc/mod-tlsopt-powerpc.c +index 2a82e53baf..d941024963 100644 +--- a/sysdeps/powerpc/mod-tlsopt-powerpc.c ++++ b/sysdeps/powerpc/mod-tlsopt-powerpc.c +@@ -22,7 +22,11 @@ tls_get_addr_opt_test (void) + tls_index *tls_arg; + #ifdef __powerpc64__ + register unsigned long thread_pointer __asm__ ("r13"); +- asm ("addi %0,2,foo@got@tlsgd" : "=r" (tls_arg)); ++# ifdef __PCREL__ ++ asm ("paddi %0,0,foo@got@tlsgd@pcrel,1" : "=b" (tls_arg)); ++# else ++ asm ("addi %0,2,foo@got@tlsgd" : "=b" (tls_arg)); ++# endif + #else + register unsigned long thread_pointer __asm__ ("r2"); + asm ("bcl 20,31,1f\n1:\t" +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index a139a16532..d5d9af4de2 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -265,6 +265,14 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py + < /dev/null > $@ 2>&1; $(evaluate-test) + $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps) + ++tests-special += $(objpfx)tst-mount-compile.out ++$(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py ++ $(sysdeps-linux-python) \ ++ ../sysdeps/unix/sysv/linux/tst-mount-compile.py \ ++ $(sysdeps-linux-python-cc) \ ++ < /dev/null > $@ 2>&1; $(evaluate-test) ++$(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps) ++ + tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0 + + endif # $(subdir) == misc +@@ -354,6 +362,8 @@ sysdep_headers += netinet/if_fddi.h netinet/if_tr.h \ + netrom/netrom.h netpacket/packet.h netrose/rose.h \ + neteconet/ec.h netiucv/iucv.h + sysdep_routines += netlink_assert_response ++ ++CFLAGS-check_pf.c += -fexceptions + endif + + # Don't compile the ctype glue code, since there is no old non-GNU C library. +diff --git a/sysdeps/unix/sysv/linux/alpha/brk_call.h b/sysdeps/unix/sysv/linux/alpha/brk_call.h +index b8088cf13f..0b851b6c86 100644 +--- a/sysdeps/unix/sysv/linux/alpha/brk_call.h ++++ b/sysdeps/unix/sysv/linux/alpha/brk_call.h +@@ -21,8 +21,7 @@ __brk_call (void *addr) + { + unsigned long int result = INTERNAL_SYSCALL_CALL (brk, addr); + if (result == -ENOMEM) +- /* Mimic the default error reporting behavior. */ +- return addr; +- else +- return (void *) result; ++ /* Mimic the generic error reporting behavior. */ ++ result = INTERNAL_SYSCALL_CALL (brk, 0); ++ return (void *) result; + } +diff --git a/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h +new file mode 100644 +index 0000000000..30ee6279d2 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h +@@ -0,0 +1,139 @@ ++/* Definition for struct stat. Linux/arm version. ++ Copyright (C) 2020-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library. If not, see ++ . */ ++ ++#if !defined _SYS_STAT_H && !defined _FCNTL_H ++# error "Never include directly; use instead." ++#endif ++ ++#ifndef _BITS_STRUCT_STAT_H ++#define _BITS_STRUCT_STAT_H 1 ++ ++#include ++#include ++ ++struct stat ++ { ++#ifdef __USE_TIME_BITS64 ++# include ++#else ++ __dev_t st_dev; /* Device. */ ++ unsigned short int __pad1; ++# ifndef __USE_FILE_OFFSET64 ++ __ino_t st_ino; /* File serial number. */ ++# else ++ __ino_t __st_ino; /* 32bit file serial number. */ ++# endif ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned short int __pad2; ++# ifndef __USE_FILE_OFFSET64 ++ __off_t st_size; /* Size of file, in bytes. */ ++# else ++ __off64_t st_size; /* Size of file, in bytes. */ ++# endif ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++# ifndef __USE_FILE_OFFSET64 ++ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ ++# else ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# endif ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++# ifndef __USE_FILE_OFFSET64 ++ unsigned long int __glibc_reserved4; ++ unsigned long int __glibc_reserved5; ++# else ++ __ino64_t st_ino; /* File serial number. */ ++# endif ++#endif /* __USE_TIME_BITS64 */ ++ }; ++ ++#ifdef __USE_LARGEFILE64 ++struct stat64 ++ { ++# ifdef __USE_TIME_BITS64 ++# include ++# else ++ __dev_t st_dev; /* Device. */ ++ unsigned int __pad1; ++ ++ __ino_t __st_ino; /* 32bit file serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned int __pad2; ++ __off64_t st_size; /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++ __ino64_t st_ino; /* File serial number. */ ++# endif /* __USE_TIME_BITS64 */ ++ }; ++#endif ++ ++/* Tell code we have these members. */ ++#define _STATBUF_ST_BLKSIZE ++#define _STATBUF_ST_RDEV ++/* Nanosecond resolution time values are supported. */ ++#define _STATBUF_ST_NSEC ++ ++ ++#endif /* _BITS_STRUCT_STAT_H */ +diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h +index 33ff88ce59..bfc674235d 100644 +--- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h ++++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h +@@ -101,7 +101,7 @@ + #endif + + #ifndef F_GETLK +-# ifndef __USE_FILE_OFFSET64 ++# if !defined __USE_FILE_OFFSET64 && __TIMESIZE != 64 + # define F_GETLK 5 /* Get record locking info. */ + # define F_SETLK 6 /* Set record locking info (non-blocking). */ + # define F_SETLKW 7 /* Set record locking info (blocking). */ +diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h +index 4f1f810ea1..539b8d7716 100644 +--- a/sysdeps/unix/sysv/linux/bits/socket.h ++++ b/sysdeps/unix/sysv/linux/bits/socket.h +@@ -307,6 +307,12 @@ struct cmsghdr + + CMSG_ALIGN (sizeof (struct cmsghdr))) + #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + ++/* Given a length, return the additional padding necessary such that ++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ ++#define __CMSG_PADDING(len) ((sizeof (size_t) \ ++ - ((len) & (sizeof (size_t) - 1))) \ ++ & (sizeof (size_t) - 1)) ++ + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + struct cmsghdr *__cmsg) __THROW; + #ifdef __USE_EXTERN_INLINES +@@ -316,18 +322,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + _EXTERN_INLINE struct cmsghdr * + __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) + { ++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and ++ __mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of __cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; ++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; ++ ++ size_t __size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (__cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ + return (struct cmsghdr *) 0; + ++ /* There isn't enough space between __cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) ++ < __size_needed) ++ || ((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr ++ - __size_needed) ++ < __cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; ++ ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); +- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control +- + __mhdr->msg_controllen) +- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) +- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) +- /* No more entries. */ +- return (struct cmsghdr *) 0; + return __cmsg; + } + #endif /* Use `extern inline'. */ +diff --git a/sysdeps/unix/sysv/linux/bits/struct_stat.h b/sysdeps/unix/sysv/linux/bits/struct_stat.h +index 25bd6cb638..fb11a3fba4 100644 +--- a/sysdeps/unix/sysv/linux/bits/struct_stat.h ++++ b/sysdeps/unix/sysv/linux/bits/struct_stat.h +@@ -26,37 +26,36 @@ + #include + #include + +-struct stat +- { +-#ifdef __USE_TIME_BITS64 +-# include +-#else +- __dev_t st_dev; /* Device. */ +- unsigned short int __pad1; +-# ifndef __USE_FILE_OFFSET64 +- __ino_t st_ino; /* File serial number. */ +-# else +- __ino_t __st_ino; /* 32bit file serial number. */ ++#if defined __USE_FILE_OFFSET64 ++# define __field64(type, type64, name) type64 name ++#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T ++# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T ++# error "ino_t and off_t must both be the same type" + # endif +- __mode_t st_mode; /* File mode. */ +- __nlink_t st_nlink; /* Link count. */ +- __uid_t st_uid; /* User ID of the file's owner. */ +- __gid_t st_gid; /* Group ID of the file's group.*/ +- __dev_t st_rdev; /* Device number, if device. */ +- unsigned short int __pad2; +-# ifndef __USE_FILE_OFFSET64 +- __off_t st_size; /* Size of file, in bytes. */ +-# else +- __off64_t st_size; /* Size of file, in bytes. */ +-# endif +- __blksize_t st_blksize; /* Optimal block size for I/O. */ ++# define __field64(type, type64, name) type name ++#elif __BYTE_ORDER == __LITTLE_ENDIAN ++# define __field64(type, type64, name) \ ++ type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad ++#else ++# define __field64(type, type64, name) \ ++ int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name ++#endif + +-# ifndef __USE_FILE_OFFSET64 +- __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ +-# else +- __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +-# endif +-# ifdef __USE_XOPEN2K8 ++struct stat ++ { ++ __dev_t st_dev; /* Device. */ ++ __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ __dev_t __pad1; ++ __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ int __pad2; ++ __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ ++#ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the +@@ -66,47 +65,38 @@ struct stat + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +-# define st_atime st_atim.tv_sec /* Backward compatibility. */ +-# define st_mtime st_mtim.tv_sec +-# define st_ctime st_ctim.tv_sec +-# else ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++#else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +-# endif +-# ifndef __USE_FILE_OFFSET64 +- unsigned long int __glibc_reserved4; +- unsigned long int __glibc_reserved5; +-# else +- __ino64_t st_ino; /* File serial number. */ +-# endif +-#endif /* __USE_TIME_BITS64 */ ++#endif ++ int __glibc_reserved[2]; + }; + ++#undef __field64 ++ + #ifdef __USE_LARGEFILE64 + struct stat64 + { +-# ifdef __USE_TIME_BITS64 +-# include +-# else +- __dev_t st_dev; /* Device. */ +- unsigned int __pad1; +- +- __ino_t __st_ino; /* 32bit file serial number. */ +- __mode_t st_mode; /* File mode. */ +- __nlink_t st_nlink; /* Link count. */ +- __uid_t st_uid; /* User ID of the file's owner. */ +- __gid_t st_gid; /* Group ID of the file's group.*/ +- __dev_t st_rdev; /* Device number, if device. */ +- unsigned int __pad2; +- __off64_t st_size; /* Size of file, in bytes. */ +- __blksize_t st_blksize; /* Optimal block size for I/O. */ +- +- __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +-# ifdef __USE_XOPEN2K8 ++ __dev_t st_dev; /* Device. */ ++ __ino64_t st_ino; /* File serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ __dev_t __pad1; ++ __off64_t st_size; /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ int __pad2; ++ __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ ++#ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the +@@ -116,16 +106,15 @@ struct stat64 + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +-# else ++#else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +-# endif +- __ino64_t st_ino; /* File serial number. */ +-# endif /* __USE_TIME_BITS64 */ ++#endif ++ int __glibc_reserved[2]; + }; + #endif + +@@ -135,5 +124,4 @@ struct stat64 + /* Nanosecond resolution time values are supported. */ + #define _STATBUF_ST_NSEC + +- + #endif /* _BITS_STRUCT_STAT_H */ +diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c +index fe73fe3ba8..ca20043408 100644 +--- a/sysdeps/unix/sysv/linux/check_pf.c ++++ b/sysdeps/unix/sysv/linux/check_pf.c +@@ -292,6 +292,14 @@ make_request (int fd, pid_t pid) + return NULL; + } + ++#ifdef __EXCEPTIONS ++static void ++cancel_handler (void *arg __attribute__((unused))) ++{ ++ /* Release the lock. */ ++ __libc_lock_unlock (lock); ++} ++#endif + + void + attribute_hidden +@@ -304,6 +312,10 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6, + struct cached_data *olddata = NULL; + struct cached_data *data = NULL; + ++#ifdef __EXCEPTIONS ++ /* Make sure that lock is released when the thread is cancelled. */ ++ __libc_cleanup_push (cancel_handler, NULL); ++#endif + __libc_lock_lock (lock); + + if (cache_valid_p ()) +@@ -338,6 +350,9 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6, + } + } + ++#ifdef __EXCEPTIONS ++ __libc_cleanup_pop (0); ++#endif + __libc_lock_unlock (lock); + + if (data != NULL) +diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c +index 15b7a3a925..24f72b797a 100644 +--- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c ++++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c +@@ -23,18 +23,38 @@ + struct cmsghdr * + __cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg) + { ++ /* We may safely assume that cmsg lies between mhdr->msg_control and ++ mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control; ++ unsigned char * cmsg_ptr = (unsigned char *) cmsg; ++ ++ size_t size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ +- return NULL; ++ return (struct cmsghdr *) 0; ++ ++ /* There isn't enough space between cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr) ++ < size_needed) ++ || ((size_t) ++ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr ++ - size_needed) ++ < cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; + ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + cmsg = (struct cmsghdr *) ((unsigned char *) cmsg + + CMSG_ALIGN (cmsg->cmsg_len)); +- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control +- + mhdr->msg_controllen) +- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len) +- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen))) +- /* No more entries. */ +- return NULL; + return cmsg; + } + libc_hidden_def (__cmsg_nxthdr) +diff --git a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h +similarity index 92% +rename from sysdeps/unix/sysv/linux/generic/bits/struct_stat.h +rename to sysdeps/unix/sysv/linux/csky/bits/struct_stat.h +index fb11a3fba4..f0ee455748 100644 +--- a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h ++++ b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h +@@ -1,4 +1,4 @@ +-/* Definition for struct stat. ++/* Definition for struct stat. Linux/csky version. + Copyright (C) 2020-2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -43,6 +43,9 @@ + + struct stat + { ++#ifdef __USE_TIME_BITS64 ++# include ++#else + __dev_t st_dev; /* Device. */ + __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ + __mode_t st_mode; /* File mode. */ +@@ -55,7 +58,7 @@ struct stat + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ +-#ifdef __USE_XOPEN2K8 ++# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the +@@ -65,18 +68,19 @@ struct stat + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +-# define st_atime st_atim.tv_sec /* Backward compatibility. */ +-# define st_mtime st_mtim.tv_sec +-# define st_ctime st_ctim.tv_sec +-#else ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +-#endif ++# endif + int __glibc_reserved[2]; ++#endif + }; + + #undef __field64 +@@ -84,6 +88,9 @@ struct stat + #ifdef __USE_LARGEFILE64 + struct stat64 + { ++# ifdef __USE_TIME_BITS64 ++# include ++# else + __dev_t st_dev; /* Device. */ + __ino64_t st_ino; /* File serial number. */ + __mode_t st_mode; /* File mode. */ +@@ -96,7 +103,7 @@ struct stat64 + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ +-#ifdef __USE_XOPEN2K8 ++# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the +@@ -106,15 +113,16 @@ struct stat64 + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +-#else ++# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +-#endif ++# endif + int __glibc_reserved[2]; ++# endif + }; + #endif + +diff --git a/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h +new file mode 100644 +index 0000000000..38b6e13e68 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h +@@ -0,0 +1,139 @@ ++/* Definition for struct stat. Linux/hppa version. ++ Copyright (C) 2020-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library. If not, see ++ . */ ++ ++#if !defined _SYS_STAT_H && !defined _FCNTL_H ++# error "Never include directly; use instead." ++#endif ++ ++#ifndef _BITS_STRUCT_STAT_H ++#define _BITS_STRUCT_STAT_H 1 ++ ++#include ++#include ++ ++struct stat ++ { ++#ifdef __USE_TIME_BITS64 ++# include ++#else ++ __dev_t st_dev; /* Device. */ ++ unsigned short int __pad1; ++# ifndef __USE_FILE_OFFSET64 ++ __ino_t st_ino; /* File serial number. */ ++# else ++ __ino_t __st_ino; /* 32bit file serial number. */ ++# endif ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned short int __pad2; ++# ifndef __USE_FILE_OFFSET64 ++ __off_t st_size; /* Size of file, in bytes. */ ++# else ++ __off64_t st_size; /* Size of file, in bytes. */ ++# endif ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++# ifndef __USE_FILE_OFFSET64 ++ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ ++# else ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# endif ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++# ifndef __USE_FILE_OFFSET64 ++ unsigned long int __glibc_reserved4; ++ unsigned long int __glibc_reserved5; ++# else ++ __ino64_t st_ino; /* File serial number. */ ++# endif ++#endif /* __USE_TIME_BITS64 */ ++ }; ++ ++#ifdef __USE_LARGEFILE64 ++struct stat64 ++ { ++# ifdef __USE_TIME_BITS64 ++# include ++# else ++ __dev_t st_dev; /* Device. */ ++ unsigned int __pad1; ++ ++ __ino_t __st_ino; /* 32bit file serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned int __pad2; ++ __off64_t st_size; /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++ __ino64_t st_ino; /* File serial number. */ ++# endif /* __USE_TIME_BITS64 */ ++ }; ++#endif ++ ++/* Tell code we have these members. */ ++#define _STATBUF_ST_BLKSIZE ++#define _STATBUF_ST_RDEV ++/* Nanosecond resolution time values are supported. */ ++#define _STATBUF_ST_NSEC ++ ++ ++#endif /* _BITS_STRUCT_STAT_H */ +diff --git a/sysdeps/unix/sysv/linux/hppa/kernel-features.h b/sysdeps/unix/sysv/linux/hppa/kernel-features.h +index 0cd21ef0fa..079612e4aa 100644 +--- a/sysdeps/unix/sysv/linux/hppa/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/hppa/kernel-features.h +@@ -30,3 +30,6 @@ + + #undef __ASSUME_CLONE_DEFAULT + #define __ASSUME_CLONE_BACKWARDS 1 ++ ++/* QEMU does not support set_robust_list. */ ++#undef __ASSUME_SET_ROBUST_LIST +diff --git a/sysdeps/unix/sysv/linux/ipc_priv.h b/sysdeps/unix/sysv/linux/ipc_priv.h +index 87893a6757..2f50c31a8e 100644 +--- a/sysdeps/unix/sysv/linux/ipc_priv.h ++++ b/sysdeps/unix/sysv/linux/ipc_priv.h +@@ -63,4 +63,10 @@ struct __old_ipc_perm + # define __IPC_TIME64 0 + #endif + ++#if __IPC_TIME64 || defined __ASSUME_SYSVIPC_BROKEN_MODE_T ++# define IPC_CTL_NEED_TRANSLATION 1 ++#else ++# define IPC_CTL_NEED_TRANSLATION 0 ++#endif ++ + #include +diff --git a/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h +new file mode 100644 +index 0000000000..1844bbaf6f +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h +@@ -0,0 +1,25 @@ ++/* Private libc-internal arch-specific definitions. m68k version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of the ++ License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If ++ not, see . */ ++ ++#ifndef _LIBC_LOCK_ARCH_H ++#define _LIBC_LOCK_ARCH_H ++ ++/* Linux enforces 4-bytes alignment on futex inputs. */ ++#define __LIBC_LOCK_ALIGNMENT __attribute__ ((__aligned__ (4))) ++ ++#endif +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c +new file mode 100644 +index 0000000000..fe6c3a0dda +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c +@@ -0,0 +1,51 @@ ++/* Get file status. Linux/MIPSn64 version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++/* Different than other ABIs, mips64 has different layouts for non-LFS ++ and LFS struct stat. */ ++int ++__fstatat (int fd, const char *file, struct stat *buf, int flag) ++{ ++ struct __stat64_t64 st64; ++ int r = __fstatat64_time64 (fd, file, &st64, flag); ++ if (r == 0) ++ { ++ /* Clear internal pad and reserved fields. */ ++ memset (buf, 0, sizeof (*buf)); ++ ++ buf->st_dev = st64.st_dev; ++ buf->st_ino = st64.st_ino; ++ buf->st_mode = st64.st_mode; ++ buf->st_nlink = st64.st_nlink; ++ buf->st_uid = st64.st_uid; ++ buf->st_gid = st64.st_gid; ++ buf->st_rdev = st64.st_rdev; ++ buf->st_size = st64.st_size; ++ buf->st_blksize = st64.st_blksize; ++ buf->st_blocks = st64.st_blocks; ++ buf->st_atim = st64.st_atim; ++ buf->st_mtim = st64.st_mtim; ++ buf->st_ctim = st64.st_ctim; ++ } ++ return r; ++} ++ ++weak_alias (__fstatat, fstatat) +diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c +index e824ebb095..2072205252 100644 +--- a/sysdeps/unix/sysv/linux/msgctl.c ++++ b/sysdeps/unix/sysv/linux/msgctl.c +@@ -85,11 +85,19 @@ msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf) + int + __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) + { +-#if __IPC_TIME64 ++#if IPC_CTL_NEED_TRANSLATION ++# if __IPC_TIME64 + struct kernel_msqid64_ds ksemid, *arg = NULL; +-#else ++# else + msgctl_arg_t *arg; +-#endif ++# endif ++ ++ /* Some applications pass the __IPC_64 flag in cmd, to invoke ++ previously unsupported commands back when there was no EINVAL ++ error checking in glibc. Mask the flag for the switch statements ++ below. msgctl_syscall adds back the __IPC_64 flag for the actual ++ system call. */ ++ cmd &= ~__IPC_64; + + switch (cmd) + { +@@ -101,19 +109,19 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) + case IPC_STAT: + case MSG_STAT: + case MSG_STAT_ANY: +-#if __IPC_TIME64 ++# if __IPC_TIME64 + if (buf != NULL) + { + msqid64_to_kmsqid64 (buf, &ksemid); + arg = &ksemid; + } +-# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T ++# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T + if (cmd == IPC_SET) + arg->msg_perm.mode *= 0x10000U; +-# endif +-#else ++# endif ++# else + arg = buf; +-#endif ++# endif + break; + + case IPC_INFO: +@@ -137,21 +145,25 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) + case IPC_STAT: + case MSG_STAT: + case MSG_STAT_ANY: +-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T ++# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T + arg->msg_perm.mode >>= 16; +-#else ++# else + /* Old Linux kernel versions might not clear the mode padding. */ + if (sizeof ((struct msqid_ds){0}.msg_perm.mode) + != sizeof (__kernel_mode_t)) + arg->msg_perm.mode &= 0xFFFF; +-#endif ++# endif + +-#if __IPC_TIME64 ++# if __IPC_TIME64 + kmsqid64_to_msqid64 (arg, buf); +-#endif ++# endif + } + + return ret; ++ ++#else /* !IPC_CTL_NEED_TRANSLATION */ ++ return msgctl_syscall (msqid, cmd, buf); ++#endif + } + #if __TIMESIZE != 64 + libc_hidden_def (__msgctl64) +diff --git a/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h +new file mode 100644 +index 0000000000..e00e71173e +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h +@@ -0,0 +1,135 @@ ++/* Definition for struct stat. Linux/nios2 version. ++ Copyright (C) 2020-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library. If not, see ++ . */ ++ ++#if !defined _SYS_STAT_H && !defined _FCNTL_H ++# error "Never include directly; use instead." ++#endif ++ ++#ifndef _BITS_STRUCT_STAT_H ++#define _BITS_STRUCT_STAT_H 1 ++ ++#include ++#include ++ ++#if defined __USE_FILE_OFFSET64 ++# define __field64(type, type64, name) type64 name ++#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T ++# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T ++# error "ino_t and off_t must both be the same type" ++# endif ++# define __field64(type, type64, name) type name ++#elif __BYTE_ORDER == __LITTLE_ENDIAN ++# define __field64(type, type64, name) \ ++ type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad ++#else ++# define __field64(type, type64, name) \ ++ int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name ++#endif ++ ++struct stat ++ { ++#ifdef __USE_TIME_BITS64 ++# include ++#else ++ __dev_t st_dev; /* Device. */ ++ __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ __dev_t __pad1; ++ __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ int __pad2; ++ __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++ int __glibc_reserved[2]; ++#endif ++ }; ++ ++#undef __field64 ++ ++#ifdef __USE_LARGEFILE64 ++struct stat64 ++ { ++# ifdef __USE_TIME_BITS64 ++# include ++# else ++ __dev_t st_dev; /* Device. */ ++ __ino64_t st_ino; /* File serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ __dev_t __pad1; ++ __off64_t st_size; /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ int __pad2; ++ __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++ int __glibc_reserved[2]; ++# endif ++ }; ++#endif ++ ++/* Tell code we have these members. */ ++#define _STATBUF_ST_BLKSIZE ++#define _STATBUF_ST_RDEV ++/* Nanosecond resolution time values are supported. */ ++#define _STATBUF_ST_NSEC ++ ++#endif /* _BITS_STRUCT_STAT_H */ +diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h +index a263d294b1..cf35c8bfc9 100644 +--- a/sysdeps/unix/sysv/linux/not-cancel.h ++++ b/sysdeps/unix/sysv/linux/not-cancel.h +@@ -68,7 +68,7 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt) + INTERNAL_SYSCALL_CALL (writev, fd, iov, iovcnt); + } + +-static inline int ++static inline ssize_t + __getrandom_nocancel (void *buf, size_t buflen, unsigned int flags) + { + return INLINE_SYSCALL_CALL (getrandom, buf, buflen, flags); +diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h +index d7cf158b33..0ca6e69ee9 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h ++++ b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h +@@ -33,6 +33,12 @@ + # define __O_LARGEFILE 0200000 + #endif + ++#if __WORDSIZE == 64 && !defined __USE_FILE_OFFSET64 ++# define F_GETLK 5 ++# define F_SETLK 6 ++# define F_SETLKW 7 ++#endif ++ + struct flock + { + short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */ +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +index bf4be80f8d..202520ee25 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +@@ -122,6 +122,7 @@ + #define __NR_mbind 235 + #define __NR_membarrier 283 + #define __NR_memfd_create 279 ++#define __NR_memfd_secret 447 + #define __NR_migrate_pages 238 + #define __NR_mincore 232 + #define __NR_mkdirat 34 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +index d656aedcc2..4e65f337d4 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +@@ -127,6 +127,7 @@ + #define __NR_mbind 235 + #define __NR_membarrier 283 + #define __NR_memfd_create 279 ++#define __NR_memfd_secret 447 + #define __NR_migrate_pages 238 + #define __NR_mincore 232 + #define __NR_mkdirat 34 +diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c +index 77a8130c18..3458b018bc 100644 +--- a/sysdeps/unix/sysv/linux/semctl.c ++++ b/sysdeps/unix/sysv/linux/semctl.c +@@ -140,6 +140,13 @@ __semctl64 (int semid, int semnum, int cmd, ...) + union semun64 arg64 = { 0 }; + va_list ap; + ++ /* Some applications pass the __IPC_64 flag in cmd, to invoke ++ previously unsupported commands back when there was no EINVAL ++ error checking in glibc. Mask the flag for the switch statements ++ below. semctl_syscall adds back the __IPC_64 flag for the actual ++ system call. */ ++ cmd &= ~__IPC_64; ++ + /* Get the argument only if required. */ + switch (cmd) + { +diff --git a/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h +new file mode 100644 +index 0000000000..0f7c9cdc89 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h +@@ -0,0 +1,139 @@ ++/* Definition for struct stat. Linux/sh version. ++ Copyright (C) 2020-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library. If not, see ++ . */ ++ ++#if !defined _SYS_STAT_H && !defined _FCNTL_H ++# error "Never include directly; use instead." ++#endif ++ ++#ifndef _BITS_STRUCT_STAT_H ++#define _BITS_STRUCT_STAT_H 1 ++ ++#include ++#include ++ ++struct stat ++ { ++#ifdef __USE_TIME_BITS64 ++# include ++#else ++ __dev_t st_dev; /* Device. */ ++ unsigned short int __pad1; ++# ifndef __USE_FILE_OFFSET64 ++ __ino_t st_ino; /* File serial number. */ ++# else ++ __ino_t __st_ino; /* 32bit file serial number. */ ++# endif ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned short int __pad2; ++# ifndef __USE_FILE_OFFSET64 ++ __off_t st_size; /* Size of file, in bytes. */ ++# else ++ __off64_t st_size; /* Size of file, in bytes. */ ++# endif ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++# ifndef __USE_FILE_OFFSET64 ++ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ ++# else ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# endif ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++# ifndef __USE_FILE_OFFSET64 ++ unsigned long int __glibc_reserved4; ++ unsigned long int __glibc_reserved5; ++# else ++ __ino64_t st_ino; /* File serial number. */ ++# endif ++#endif /* __USE_TIME_BITS64 */ ++ }; ++ ++#ifdef __USE_LARGEFILE64 ++struct stat64 ++ { ++# ifdef __USE_TIME_BITS64 ++# include ++# else ++ __dev_t st_dev; /* Device. */ ++ unsigned int __pad1; ++ ++ __ino_t __st_ino; /* 32bit file serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned int __pad2; ++ __off64_t st_size; /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++ __ino64_t st_ino; /* File serial number. */ ++# endif /* __USE_TIME_BITS64 */ ++ }; ++#endif ++ ++/* Tell code we have these members. */ ++#define _STATBUF_ST_BLKSIZE ++#define _STATBUF_ST_RDEV ++/* Nanosecond resolution time values are supported. */ ++#define _STATBUF_ST_NSEC ++ ++ ++#endif /* _BITS_STRUCT_STAT_H */ +diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c +index ea38935497..f00817a6f6 100644 +--- a/sysdeps/unix/sysv/linux/shmctl.c ++++ b/sysdeps/unix/sysv/linux/shmctl.c +@@ -85,11 +85,19 @@ shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf) + int + __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) + { +-#if __IPC_TIME64 ++#if IPC_CTL_NEED_TRANSLATION ++# if __IPC_TIME64 + struct kernel_shmid64_ds kshmid, *arg = NULL; +-#else ++# else + shmctl_arg_t *arg; +-#endif ++# endif ++ ++ /* Some applications pass the __IPC_64 flag in cmd, to invoke ++ previously unsupported commands back when there was no EINVAL ++ error checking in glibc. Mask the flag for the switch statements ++ below. shmctl_syscall adds back the __IPC_64 flag for the actual ++ system call. */ ++ cmd &= ~__IPC_64; + + switch (cmd) + { +@@ -103,19 +111,19 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) + case IPC_STAT: + case SHM_STAT: + case SHM_STAT_ANY: +-#if __IPC_TIME64 ++# if __IPC_TIME64 + if (buf != NULL) + { + shmid64_to_kshmid64 (buf, &kshmid); + arg = &kshmid; + } +-# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T ++# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T + if (cmd == IPC_SET) + arg->shm_perm.mode *= 0x10000U; +-# endif +-#else ++# endif ++# else + arg = buf; +-#endif ++# endif + break; + + case IPC_INFO: +@@ -140,21 +148,25 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) + case IPC_STAT: + case SHM_STAT: + case SHM_STAT_ANY: +-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T ++# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T + arg->shm_perm.mode >>= 16; +-#else ++# else + /* Old Linux kernel versions might not clear the mode padding. */ + if (sizeof ((struct shmid_ds){0}.shm_perm.mode) + != sizeof (__kernel_mode_t)) + arg->shm_perm.mode &= 0xFFFF; +-#endif ++# endif + +-#if __IPC_TIME64 ++# if __IPC_TIME64 + kshmid64_to_shmid64 (arg, buf); +-#endif ++# endif + } + + return ret; ++ ++#else /* !IPC_CTL_NEED_TRANSLATION */ ++ return shmctl_syscall (shmid, cmd, buf); ++#endif + } + #if __TIMESIZE != 64 + libc_hidden_def (__shmctl64) +diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h +index f965986ba8..19841d0738 100644 +--- a/sysdeps/unix/sysv/linux/sys/mount.h ++++ b/sysdeps/unix/sysv/linux/sys/mount.h +@@ -27,77 +27,113 @@ + #include + #include + +-#define BLOCK_SIZE 1024 ++#ifdef __has_include ++# if __has_include ("linux/mount.h") ++# include "linux/mount.h" ++# endif ++#endif ++ ++ + #define BLOCK_SIZE_BITS 10 ++#define BLOCK_SIZE (1<. ++ ++import argparse ++import sys ++ ++import glibcextract ++ ++ ++def main(): ++ """The main entry point.""" ++ parser = argparse.ArgumentParser( ++ description='Check if glibc provided sys/mount.h can be ' ++ ' used along related kernel headers.') ++ parser.add_argument('--cc', metavar='CC', ++ help='C compiler (including options) to use') ++ args = parser.parse_args() ++ ++ if glibcextract.compile_c_snippet( ++ '#include ', ++ args.cc).returncode != 0: ++ sys.exit (77) ++ ++ def check(testname, snippet): ++ # Add -Werror to catch macro redefinitions and _ISOMAC to avoid ++ # internal glibc definitions. ++ r = glibcextract.compile_c_snippet(snippet, args.cc, ++ '-Werror -D_ISOMAC') ++ if r.returncode != 0: ++ print('error: test {}:\n{}'.format(testname, r.output.decode())) ++ return r.returncode ++ ++ status = max( ++ check("sys/mount.h + linux/mount.h", ++ "#include \n" ++ "#include "), ++ check("sys/mount.h + linux/fs.h", ++ "#include \n" ++ "#include "), ++ check("linux/mount.h + sys/mount.h", ++ "#include \n" ++ "#include "), ++ check("linux/fs.h + sys/mount.h", ++ "#include \n" ++ "#include ")) ++ sys.exit(status) ++ ++if __name__ == '__main__': ++ main() +diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py +index a62f803123..be2ef2daf1 100755 +--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py +@@ -33,6 +33,11 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + ++ if glibcextract.compile_c_snippet( ++ '#include ', ++ args.cc).returncode != 0: ++ sys.exit (77) ++ + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) + # Constants in glibc were updated to match Linux v5.16. When glibc + # constants are updated this value should be updated to match the +diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +index 90cbb9be64..d732173abd 100644 +--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +@@ -33,11 +33,13 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + +- linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- # Linux started to provide pidfd.h with 5.10. +- if linux_version_headers < (5, 10): ++ if glibcextract.compile_c_snippet( ++ '#include ', ++ args.cc).returncode != 0: + sys.exit (77) +- linux_version_glibc = (5, 18) ++ ++ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) ++ linux_version_glibc = (5, 19) + sys.exit(glibcextract.compare_macro_consts( + '#include \n', + '#include \n' +diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c +index 037af22290..5711d1c312 100644 +--- a/sysdeps/unix/sysv/linux/tst-pidfd.c ++++ b/sysdeps/unix/sysv/linux/tst-pidfd.c +@@ -147,8 +147,11 @@ do_test (void) + may be denied if the process doesn't have CAP_SYS_PTRACE or + if a LSM security_ptrace_access_check denies access. */ + if (fd == -1 && errno == EPERM) +- FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, " +- "skipping test"); ++ { ++ TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0); ++ FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, " ++ "skipping test"); ++ } + TEST_VERIFY (fd > 0); + + char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd); +diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h +index e9f3382108..d95c1efa2c 100644 +--- a/sysdeps/x86/dl-cacheinfo.h ++++ b/sysdeps/x86/dl-cacheinfo.h +@@ -478,7 +478,7 @@ handle_zhaoxin (int name) + } + + static void +-get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, ++get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, unsigned int *threads_ptr, + long int core) + { + unsigned int eax; +@@ -497,6 +497,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, + unsigned int family = cpu_features->basic.family; + unsigned int model = cpu_features->basic.model; + long int shared = *shared_ptr; ++ long int shared_per_thread = *shared_per_thread_ptr; + unsigned int threads = *threads_ptr; + bool inclusive_cache = true; + bool support_count_mask = true; +@@ -512,6 +513,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, + /* Try L2 otherwise. */ + level = 2; + shared = core; ++ shared_per_thread = core; + threads_l2 = 0; + threads_l3 = -1; + } +@@ -668,29 +670,27 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, + } + else + { +-intel_bug_no_cache_info: +- /* Assume that all logical threads share the highest cache +- level. */ +- threads +- = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16) +- & 0xff); +- } +- +- /* Cap usage of highest cache level to the number of supported +- threads. */ +- if (shared > 0 && threads > 0) +- shared /= threads; ++ intel_bug_no_cache_info: ++ /* Assume that all logical threads share the highest cache ++ level. */ ++ threads = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16) ++ & 0xff); ++ } ++ /* Get per-thread size of highest level cache. */ ++ if (shared_per_thread > 0 && threads > 0) ++ shared_per_thread /= threads; + } + + /* Account for non-inclusive L2 and L3 caches. */ + if (!inclusive_cache) + { +- if (threads_l2 > 0) +- core /= threads_l2; ++ long int core_per_thread = threads_l2 > 0 ? (core / threads_l2) : core; ++ shared_per_thread += core_per_thread; + shared += core; + } + + *shared_ptr = shared; ++ *shared_per_thread_ptr = shared_per_thread; + *threads_ptr = threads; + } + +@@ -704,6 +704,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + int max_cpuid_ex; + long int data = -1; + long int shared = -1; ++ long int shared_per_thread = -1; + long int core = -1; + unsigned int threads = 0; + unsigned long int level1_icache_size = -1; +@@ -724,6 +725,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); + core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); + shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); ++ shared_per_thread = shared; + + level1_icache_size + = handle_intel (_SC_LEVEL1_ICACHE_SIZE, cpu_features); +@@ -747,13 +749,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + level4_cache_size + = handle_intel (_SC_LEVEL4_CACHE_SIZE, cpu_features); + +- get_common_cache_info (&shared, &threads, core); ++ get_common_cache_info (&shared, &shared_per_thread, &threads, core); + } + else if (cpu_features->basic.kind == arch_kind_zhaoxin) + { + data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); + core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); + shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); ++ shared_per_thread = shared; + + level1_icache_size = handle_zhaoxin (_SC_LEVEL1_ICACHE_SIZE); + level1_icache_linesize = handle_zhaoxin (_SC_LEVEL1_ICACHE_LINESIZE); +@@ -767,13 +770,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + level3_cache_assoc = handle_zhaoxin (_SC_LEVEL3_CACHE_ASSOC); + level3_cache_linesize = handle_zhaoxin (_SC_LEVEL3_CACHE_LINESIZE); + +- get_common_cache_info (&shared, &threads, core); ++ get_common_cache_info (&shared, &shared_per_thread, &threads, core); + } + else if (cpu_features->basic.kind == arch_kind_amd) + { + data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); + core = handle_amd (_SC_LEVEL2_CACHE_SIZE); + shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); ++ shared_per_thread = shared; + + level1_icache_size = handle_amd (_SC_LEVEL1_ICACHE_SIZE); + level1_icache_linesize = handle_amd (_SC_LEVEL1_ICACHE_LINESIZE); +@@ -791,8 +795,11 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx); + + if (shared <= 0) +- /* No shared L3 cache. All we have is the L2 cache. */ +- shared = core; ++ { ++ /* No shared L3 cache. All we have is the L2 cache. */ ++ shared = core; ++ shared_per_thread = core; ++ } + else + { + /* Figure out the number of logical threads that share L3. */ +@@ -816,7 +823,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + /* Cap usage of highest cache level to the number of + supported threads. */ + if (threads > 0) +- shared /= threads; ++ shared_per_thread /= threads; + + /* Get shared cache per ccx for Zen architectures. */ + if (cpu_features->basic.family >= 0x17) +@@ -827,12 +834,13 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); + + unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; +- shared *= threads_per_ccx; ++ shared_per_thread *= threads_per_ccx; + } + else + { + /* Account for exclusive L2 and L3 caches. */ + shared += core; ++ shared_per_thread += core; + } + } + } +@@ -850,17 +858,46 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + cpu_features->level3_cache_linesize = level3_cache_linesize; + cpu_features->level4_cache_size = level4_cache_size; + +- /* The default setting for the non_temporal threshold is 3/4 of one +- thread's share of the chip's cache. For most Intel and AMD processors +- with an initial release date between 2017 and 2020, a thread's typical +- share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4 +- threshold leaves 125 KBytes to 500 KBytes of the thread's data +- in cache after a maximum temporal copy, which will maintain +- in cache a reasonable portion of the thread's stack and other +- active data. If the threshold is set higher than one thread's +- share of the cache, it has a substantial risk of negatively +- impacting the performance of other threads running on the chip. */ +- unsigned long int non_temporal_threshold = shared * 3 / 4; ++ /* The default setting for the non_temporal threshold is 1/4 of size ++ of the chip's cache. For most Intel and AMD processors with an ++ initial release date between 2017 and 2023, a thread's typical ++ share of the cache is from 18-64MB. Using the 1/4 L3 is meant to ++ estimate the point where non-temporal stores begin out-competing ++ REP MOVSB. As well the point where the fact that non-temporal ++ stores are forced back to main memory would already occurred to the ++ majority of the lines in the copy. Note, concerns about the ++ entire L3 cache being evicted by the copy are mostly alleviated ++ by the fact that modern HW detects streaming patterns and ++ provides proper LRU hints so that the maximum thrashing ++ capped at 1/associativity. */ ++ unsigned long int non_temporal_threshold = shared / 4; ++ ++ /* If the computed non_temporal_threshold <= 3/4 * per-thread L3, we most ++ likely have incorrect/incomplete cache info in which case, default to ++ 3/4 * per-thread L3 to avoid regressions. */ ++ unsigned long int non_temporal_threshold_lowbound ++ = shared_per_thread * 3 / 4; ++ if (non_temporal_threshold < non_temporal_threshold_lowbound) ++ non_temporal_threshold = non_temporal_threshold_lowbound; ++ ++ /* If no ERMS, we use the per-thread L3 chunking. Normal cacheable stores run ++ a higher risk of actually thrashing the cache as they don't have a HW LRU ++ hint. As well, their performance in highly parallel situations is ++ noticeably worse. */ ++ if (!CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ non_temporal_threshold = non_temporal_threshold_lowbound; ++ /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of ++ 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best ++ if that operation cannot overflow. Minimum of 0x4040 (16448) because the ++ L(large_memset_4x) loops need 64-byte to cache align and enough space for ++ at least 1 iteration of 4x PAGE_SIZE unrolled loop. Both values are ++ reflected in the manual. */ ++ unsigned long int maximum_non_temporal_threshold = SIZE_MAX >> 4; ++ unsigned long int minimum_non_temporal_threshold = 0x4040; ++ if (non_temporal_threshold < minimum_non_temporal_threshold) ++ non_temporal_threshold = minimum_non_temporal_threshold; ++ else if (non_temporal_threshold > maximum_non_temporal_threshold) ++ non_temporal_threshold = maximum_non_temporal_threshold; + + #if HAVE_TUNABLES + /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ +@@ -915,8 +952,8 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + shared = tunable_size; + + tunable_size = TUNABLE_GET (x86_non_temporal_threshold, long int, NULL); +- /* NB: Ignore the default value 0. */ +- if (tunable_size != 0) ++ if (tunable_size > minimum_non_temporal_threshold ++ && tunable_size <= maximum_non_temporal_threshold) + non_temporal_threshold = tunable_size; + + tunable_size = TUNABLE_GET (x86_rep_movsb_threshold, long int, NULL); +@@ -931,14 +968,9 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + + TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, data, 0, SIZE_MAX); + TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, shared, 0, SIZE_MAX); +- /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of +- 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best +- if that operation cannot overflow. Minimum of 0x4040 (16448) because the +- L(large_memset_4x) loops need 64-byte to cache align and enough space for +- at least 1 iteration of 4x PAGE_SIZE unrolled loop. Both values are +- reflected in the manual. */ + TUNABLE_SET_WITH_BOUNDS (x86_non_temporal_threshold, non_temporal_threshold, +- 0x4040, SIZE_MAX >> 4); ++ minimum_non_temporal_threshold, ++ maximum_non_temporal_threshold); + TUNABLE_SET_WITH_BOUNDS (x86_rep_movsb_threshold, rep_movsb_threshold, + minimum_rep_movsb_threshold, SIZE_MAX); + TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1, +diff --git a/sysdeps/x86/get-isa-level.h b/sysdeps/x86/get-isa-level.h +index 1ade78ab73..5b4dd5f062 100644 +--- a/sysdeps/x86/get-isa-level.h ++++ b/sysdeps/x86/get-isa-level.h +@@ -47,6 +47,8 @@ get_isa_level (const struct cpu_features *cpu_features) + isa_level |= GNU_PROPERTY_X86_ISA_1_V2; + if (CPU_FEATURE_USABLE_P (cpu_features, AVX) + && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI1) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && CPU_FEATURE_USABLE_P (cpu_features, F16C) + && CPU_FEATURE_USABLE_P (cpu_features, FMA) + && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) +diff --git a/sysdeps/x86/isa-level.h b/sysdeps/x86/isa-level.h +index 3c4480aba7..06f6c9663e 100644 +--- a/sysdeps/x86/isa-level.h ++++ b/sysdeps/x86/isa-level.h +@@ -79,7 +79,9 @@ + /* ISA level >= 3 guaranteed includes. */ + #define AVX_X86_ISA_LEVEL 3 + #define AVX2_X86_ISA_LEVEL 3 ++#define BMI1_X86_ISA_LEVEL 3 + #define BMI2_X86_ISA_LEVEL 3 ++#define LZCNT_X86_ISA_LEVEL 3 + #define MOVBE_X86_ISA_LEVEL 3 + + /* ISA level >= 2 guaranteed includes. */ +diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S +index 0db2cb4152..7619e743e1 100644 +--- a/sysdeps/x86_64/dl-tlsdesc.S ++++ b/sysdeps/x86_64/dl-tlsdesc.S +@@ -61,7 +61,7 @@ _dl_tlsdesc_return: + _dl_tlsdesc_undefweak: + _CET_ENDBR + movq 8(%rax), %rax +- subq %fs:0, %rax ++ sub %fs:0, %RAX_LP + ret + cfi_endproc + .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak +@@ -102,7 +102,7 @@ _dl_tlsdesc_dynamic: + /* Preserve call-clobbered registers that we modify. + We need two scratch regs anyway. */ + movq %rsi, -16(%rsp) +- movq %fs:DTV_OFFSET, %rsi ++ mov %fs:DTV_OFFSET, %RSI_LP + movq %rdi, -8(%rsp) + movq TLSDESC_ARG(%rax), %rdi + movq (%rsi), %rax +@@ -116,7 +116,7 @@ _dl_tlsdesc_dynamic: + addq TLSDESC_MODOFF(%rdi), %rax + .Lret: + movq -16(%rsp), %rsi +- subq %fs:0, %rax ++ sub %fs:0, %RAX_LP + movq -8(%rsp), %rdi + ret + .Lslow: +diff --git a/sysdeps/x86_64/fpu/fraiseexcpt.c b/sysdeps/x86_64/fpu/fraiseexcpt.c +index 864f4777a2..23446ff4ac 100644 +--- a/sysdeps/x86_64/fpu/fraiseexcpt.c ++++ b/sysdeps/x86_64/fpu/fraiseexcpt.c +@@ -33,7 +33,7 @@ __feraiseexcept (int excepts) + /* One example of an invalid operation is 0.0 / 0.0. */ + float f = 0.0; + +- __asm__ __volatile__ ("divss %0, %0 " : : "x" (f)); ++ __asm__ __volatile__ ("divss %0, %0 " : "+x" (f)); + (void) &f; + } + +@@ -43,7 +43,7 @@ __feraiseexcept (int excepts) + float f = 1.0; + float g = 0.0; + +- __asm__ __volatile__ ("divss %1, %0" : : "x" (f), "x" (g)); ++ __asm__ __volatile__ ("divss %1, %0" : "+x" (f) : "x" (g)); + (void) &f; + } + +diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h +index a57a9952f3..f2f5e8a211 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h +@@ -36,7 +36,9 @@ IFUNC_SELECTOR (void) + const struct cpu_features *cpu_features = __get_cpu_features (); + + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI1) + && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, LZCNT) + && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, + AVX_Fast_Unaligned_Load, )) + { +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index a71444eccb..00a91123d3 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -69,10 +69,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __memchr_evex_rtm) + X86_IFUNC_IMPL_ADD_V3 (array, i, memchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __memchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, memchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __memchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -207,13 +209,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, memrchr, + X86_IFUNC_IMPL_ADD_V4 (array, i, memrchr, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (LZCNT)), + __memrchr_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (LZCNT)), + __memrchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (LZCNT) + && CPU_FEATURE_USABLE (RTM)), + __memrchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -335,10 +343,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __rawmemchr_evex_rtm) + X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __rawmemchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __rawmemchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -448,13 +458,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcasecmp, + X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strcasecmp_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp, +@@ -470,13 +483,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcasecmp_l, + X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_l_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_l_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strcasecmp_l_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp_l, +@@ -562,13 +578,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strrchr, + X86_IFUNC_IMPL_ADD_V4 (array, i, strrchr, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2)), + __strrchr_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2)), + __strrchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strrchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -585,10 +607,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __strcmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strcmp_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strcmp, +@@ -638,13 +662,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncasecmp, + X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strncasecmp_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp, +@@ -660,13 +687,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncasecmp_l, + X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ & CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_l_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_l_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strncasecmp_l_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp_l, +@@ -773,13 +803,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + X86_IFUNC_IMPL_ADD_V4 (array, i, wcsrchr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI1) + && CPU_FEATURE_USABLE (BMI2)), + __wcsrchr_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcsrchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcsrchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -796,10 +831,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __wcscmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcscmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcscmp_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -816,10 +853,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __wcsncmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcsncmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcsncmp_avx2_rtm) + /* ISA V2 wrapper for GENERIC implementation because the +@@ -909,10 +948,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __wmemchr_evex_rtm) + X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wmemchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wmemchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -1162,13 +1203,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncmp, + X86_IFUNC_IMPL_ADD_V4 (array, i, strncmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strncmp_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strncmp, +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +index 68646ef199..7622af259c 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +@@ -34,6 +34,7 @@ IFUNC_SELECTOR (void) + const struct cpu_features *cpu_features = __get_cpu_features (); + + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, + AVX_Fast_Unaligned_Load, )) + { +diff --git a/sysdeps/x86_64/multiarch/memcmp-sse2.S b/sysdeps/x86_64/multiarch/memcmp-sse2.S +index afd450d020..51bc9344f0 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-sse2.S ++++ b/sysdeps/x86_64/multiarch/memcmp-sse2.S +@@ -308,7 +308,17 @@ L(ret_nonzero_vec_end_0): + setg %dl + leal -1(%rdx, %rdx), %eax + # else +- addl %edx, %eax ++ /* Use `addq` instead of `addl` here so that even if `rax` + `rdx` ++ is negative value of the sum will be usable as a 64-bit offset ++ (negative 32-bit numbers zero-extend to a large and often ++ out-of-bounds 64-bit offsets). Note that `rax` + `rdx` >= 0 is ++ an invariant when `memcmp` is used correctly, but if the input ++ strings `rsi`/`rdi` are concurrently modified as the function ++ runs (there is a Data-Race) it is possible for `rax` + `rdx` to ++ be negative. Given that there is virtually no extra to cost ++ using `addq` instead of `addl` we may as well protect the ++ data-race case. */ ++ addq %rdx, %rax + movzbl (VEC_SIZE * -1 + SIZE_OFFSET)(%rsi, %rax), %ecx + movzbl (VEC_SIZE * -1 + SIZE_OFFSET)(%rdi, %rax), %eax + subl %ecx, %eax +diff --git a/sysdeps/x86_64/multiarch/rtld-strcpy.S b/sysdeps/x86_64/multiarch/rtld-strcpy.S +new file mode 100644 +index 0000000000..19439c553d +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/rtld-strcpy.S +@@ -0,0 +1,18 @@ ++/* Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include "../strcpy.S" +diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c +index fdd5afe3af..9d6c9f66ba 100644 +--- a/sysdeps/x86_64/multiarch/strcmp.c ++++ b/sysdeps/x86_64/multiarch/strcmp.c +@@ -45,12 +45,12 @@ IFUNC_SELECTOR (void) + const struct cpu_features *cpu_features = __get_cpu_features (); + + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, + AVX_Fast_Unaligned_Load, )) + { + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) +- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) + return OPTIMIZE (evex); + + if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) +diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S +index 0593fb303b..b9b58ef599 100644 +--- a/sysdeps/x86_64/multiarch/strlen-avx2.S ++++ b/sysdeps/x86_64/multiarch/strlen-avx2.S +@@ -544,14 +544,11 @@ L(return_vzeroupper): + L(cross_page_less_vec): + tzcntl %eax, %eax + # ifdef USE_AS_WCSLEN +- /* NB: Multiply length by 4 to get byte count. */ +- sall $2, %esi ++ /* NB: Divide by 4 to convert from byte-count to length. */ ++ shrl $2, %eax + # endif + cmpq %rax, %rsi + cmovb %esi, %eax +-# ifdef USE_AS_WCSLEN +- shrl $2, %eax +-# endif + VZEROUPPER_RETURN + # endif + +diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c +index 4ebe4bde30..c4f8b6bbb5 100644 +--- a/sysdeps/x86_64/multiarch/strncmp.c ++++ b/sysdeps/x86_64/multiarch/strncmp.c +@@ -41,12 +41,12 @@ IFUNC_SELECTOR (void) + const struct cpu_features *cpu_features = __get_cpu_features (); + + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, + AVX_Fast_Unaligned_Load, )) + { + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) +- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) + return OPTIMIZE (evex); + + if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) +diff --git a/time/Makefile b/time/Makefile +index 470275b90c..2f4aa2d528 100644 +--- a/time/Makefile ++++ b/time/Makefile +@@ -50,7 +50,7 @@ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \ + tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 \ + tst-adjtime tst-ctime tst-difftime tst-mktime4 tst-clock_settime \ + tst-settimeofday tst-itimer tst-gmtime tst-timegm \ +- tst-timespec_get tst-timespec_getres ++ tst-timespec_get tst-timespec_getres tst-strftime4 + + tests-time64 := \ + tst-adjtime-time64 \ +@@ -65,6 +65,7 @@ tests-time64 := \ + tst-itimer-time64 \ + tst-mktime4-time64 \ + tst-settimeofday-time64 \ ++ tst-strftime4-time64 \ + tst-timegm-time64 \ + tst-timespec_get-time64 \ + tst-timespec_getres-time64 \ +diff --git a/time/mktime.c b/time/mktime.c +index 494c89bf54..e9a6006710 100644 +--- a/time/mktime.c ++++ b/time/mktime.c +@@ -429,8 +429,13 @@ __mktime_internal (struct tm *tp, + time with the right value, and use its UTC offset. + + Heuristic: probe the adjacent timestamps in both directions, +- looking for the desired isdst. This should work for all real +- time zone histories in the tz database. */ ++ looking for the desired isdst. If none is found within a ++ reasonable duration bound, assume a one-hour DST difference. ++ This should work for all real time zone histories in the tz ++ database. */ ++ ++ /* +1 if we wanted standard time but got DST, -1 if the reverse. */ ++ int dst_difference = (isdst == 0) - (tm.tm_isdst == 0); + + /* Distance between probes when looking for a DST boundary. In + tzdata2003a, the shortest period of DST is 601200 seconds +@@ -441,12 +446,14 @@ __mktime_internal (struct tm *tp, + periods when probing. */ + int stride = 601200; + +- /* The longest period of DST in tzdata2003a is 536454000 seconds +- (e.g., America/Jujuy starting 1946-10-01 01:00). The longest +- period of non-DST is much longer, but it makes no real sense +- to search for more than a year of non-DST, so use the DST +- max. */ +- int duration_max = 536454000; ++ /* In TZDB 2021e, the longest period of DST (or of non-DST), in ++ which the DST (or adjacent DST) difference is not one hour, ++ is 457243209 seconds: e.g., America/Cambridge_Bay with leap ++ seconds, starting 1965-10-31 00:00 in a switch from ++ double-daylight time (-05) to standard time (-07), and ++ continuing to 1980-04-27 02:00 in a switch from standard time ++ (-07) to daylight time (-06). */ ++ int duration_max = 457243209; + + /* Search in both directions, so the maximum distance is half + the duration; add the stride to avoid off-by-1 problems. */ +@@ -483,6 +490,11 @@ __mktime_internal (struct tm *tp, + } + } + ++ /* No unusual DST offset was found nearby. Assume one-hour DST. */ ++ t += 60 * 60 * dst_difference; ++ if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm)) ++ goto offset_found; ++ + __set_errno (EOVERFLOW); + return -1; + } +diff --git a/time/strftime_l.c b/time/strftime_l.c +index 75554fee7c..4d7c4ea828 100644 +--- a/time/strftime_l.c ++++ b/time/strftime_l.c +@@ -159,6 +159,10 @@ extern char *tzname[]; + #ifdef _LIBC + # define tzname __tzname + # define tzset __tzset ++ ++# define time_t __time64_t ++# define __gmtime_r(t, tp) __gmtime64_r (t, tp) ++# define mktime(tp) __mktime64 (tp) + #endif + + #if !HAVE_TM_GMTOFF +diff --git a/time/strptime_l.c b/time/strptime_l.c +index a3c5681fc2..f927448204 100644 +--- a/time/strptime_l.c ++++ b/time/strptime_l.c +@@ -30,8 +30,10 @@ + #ifdef _LIBC + # define HAVE_LOCALTIME_R 0 + # include "../locale/localeinfo.h" +-#endif + ++# define time_t __time64_t ++# define __localtime_r(t, tp) __localtime64_r (t, tp) ++#endif + + #if ! HAVE_LOCALTIME_R && ! defined localtime_r + # ifdef _LIBC +diff --git a/time/tst-strftime4-time64.c b/time/tst-strftime4-time64.c +new file mode 100644 +index 0000000000..4d47ee7d79 +--- /dev/null ++++ b/time/tst-strftime4-time64.c +@@ -0,0 +1 @@ ++#include "tst-strftime4.c" +diff --git a/time/tst-strftime4.c b/time/tst-strftime4.c +new file mode 100644 +index 0000000000..659716d0fa +--- /dev/null ++++ b/time/tst-strftime4.c +@@ -0,0 +1,52 @@ ++/* Test strftime and strptime after 2038-01-19 03:14:07 UTC (bug 30053). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ TEST_VERIFY_EXIT (setenv ("TZ", "UTC0", 1) == 0); ++ tzset (); ++ if (sizeof (time_t) > 4) ++ { ++ time_t wrap = (time_t) 2147483648LL; ++ char buf[80]; ++ struct tm *tm = gmtime (&wrap); ++ TEST_VERIFY_EXIT (tm != NULL); ++ TEST_VERIFY_EXIT (strftime (buf, sizeof buf, "%s", tm) > 0); ++ puts (buf); ++ TEST_VERIFY (strcmp (buf, "2147483648") == 0); ++ ++ struct tm tm2; ++ char *p = strptime (buf, "%s", &tm2); ++ TEST_VERIFY_EXIT (p != NULL && *p == '\0'); ++ time_t t = mktime (&tm2); ++ printf ("%lld\n", (long long) t); ++ TEST_VERIFY (t == wrap); ++ } ++ else ++ FAIL_UNSUPPORTED ("32-bit time_t"); ++ return 0; ++} ++ ++#include +diff --git a/time/tzfile.c b/time/tzfile.c +index dd75848ba9..8bba4e5b8d 100644 +--- a/time/tzfile.c ++++ b/time/tzfile.c +@@ -32,7 +32,7 @@ + int __use_tzfile; + static dev_t tzfile_dev; + static ino64_t tzfile_ino; +-static time_t tzfile_mtime; ++static __time64_t tzfile_mtime; + + struct ttinfo + { +@@ -61,6 +61,10 @@ static size_t num_leaps; + static struct leap *leaps; + static char *tzspec; + ++/* Used to restore the daylight variable during time conversion, as if ++ tzset had been called. */ ++static int daylight_saved; ++ + #include + #include + +@@ -438,36 +442,35 @@ __tzfile_read (const char *file, size_t extra, char **extrap) + if (__tzname[1] == NULL) + __tzname[1] = __tzname[0]; + ++ daylight_saved = 0; + if (num_transitions == 0) + /* Use the first rule (which should also be the only one). */ + rule_stdoff = rule_dstoff = types[0].offset; + else + { +- int stdoff_set = 0, dstoff_set = 0; +- rule_stdoff = rule_dstoff = 0; ++ rule_stdoff = 0; ++ ++ /* Search for the last rule with a standard time offset. This ++ will be used for the global timezone variable. */ + i = num_transitions - 1; + do +- { +- if (!stdoff_set && !types[type_idxs[i]].isdst) +- { +- stdoff_set = 1; +- rule_stdoff = types[type_idxs[i]].offset; +- } +- else if (!dstoff_set && types[type_idxs[i]].isdst) +- { +- dstoff_set = 1; +- rule_dstoff = types[type_idxs[i]].offset; +- } +- if (stdoff_set && dstoff_set) ++ if (!types[type_idxs[i]].isdst) ++ { ++ rule_stdoff = types[type_idxs[i]].offset; + break; +- } ++ } ++ else ++ daylight_saved = 1; + while (i-- > 0); + +- if (!dstoff_set) +- rule_dstoff = rule_stdoff; ++ /* Keep searching to see if there is a DST rule. This ++ information will be used to set the global daylight ++ variable. */ ++ while (i-- > 0 && !daylight_saved) ++ daylight_saved = types[type_idxs[i]].isdst; + } + +- __daylight = rule_stdoff != rule_dstoff; ++ __daylight = daylight_saved; + __timezone = -rule_stdoff; + + done: +@@ -731,7 +734,7 @@ __tzfile_compute (__time64_t timer, int use_localtime, + } + + struct ttinfo *info = &types[i]; +- __daylight = rule_stdoff != rule_dstoff; ++ __daylight = daylight_saved; + __timezone = -rule_stdoff; + + if (__tzname[0] == NULL) +diff --git a/timezone/Makefile b/timezone/Makefile +index a789c22d26..5002de39ad 100644 +--- a/timezone/Makefile ++++ b/timezone/Makefile +@@ -23,7 +23,7 @@ subdir := timezone + include ../Makeconfig + + others := zdump zic +-tests := test-tz tst-timezone tst-tzset tst-bz28707 ++tests := test-tz tst-timezone tst-tzset tst-bz28707 tst-bz29951 + + generated-dirs += testdata + +@@ -86,11 +86,13 @@ $(objpfx)tst-timezone.out: $(addprefix $(testdata)/, \ + Europe/London) + $(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4) + $(objpfx)tst-bz28707.out: $(testdata)/XT5 ++$(objpfx)tst-bz29951.out: $(testdata)/XT6 + + test-tz-ENV = TZDIR=$(testdata) + tst-timezone-ENV = TZDIR=$(testdata) + tst-tzset-ENV = TZDIR=$(testdata) + tst-bz28707-ENV = TZDIR=$(testdata) ++tst-bz29951-ENV = TZDIR=$(testdata) + + # Note this must come second in the deps list for $(built-program-cmd) to work. + zic-deps = $(objpfx)zic $(leapseconds) yearistype +diff --git a/timezone/testdata/XT6 b/timezone/testdata/XT6 +new file mode 100644 +index 0000000000..07b393bb7d +Binary files /dev/null and b/timezone/testdata/XT6 differ +diff --git a/timezone/tst-bz29951.c b/timezone/tst-bz29951.c +new file mode 100644 +index 0000000000..abd334683b +--- /dev/null ++++ b/timezone/tst-bz29951.c +@@ -0,0 +1,68 @@ ++/* Check that daylight is set if the last DST transition did not change offset. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* Set the specified time zone with error checking. */ ++static void ++set_timezone (const char *name) ++{ ++ TEST_VERIFY (setenv ("TZ", name, 1) == 0); ++ errno = 0; ++ tzset (); ++ TEST_COMPARE (errno, 0); ++} ++ ++static int ++do_test (void) ++{ ++ /* Test zone based on tz-2022g version of Africa/Tripoli. The last ++ DST transition coincided with a change in the standard time ++ offset, effectively making it a no-op. ++ ++ Africa/Tripoli Thu Oct 24 23:59:59 2013 UT ++ = Fri Oct 25 01:59:59 2013 CEST isdst=1 gmtoff=7200 ++ Africa/Tripoli Fri Oct 25 00:00:00 2013 UT ++ = Fri Oct 25 02:00:00 2013 EET isdst=0 gmtoff=7200 ++ */ ++ set_timezone ("XT6"); ++ TEST_VERIFY (daylight != 0); ++ TEST_COMPARE (timezone, -7200); ++ ++ /* Check that localtime re-initializes the two variables. */ ++ daylight = timezone = 17; ++ time_t t = 844034401; ++ struct tm *tm = localtime (&t); ++ TEST_VERIFY (daylight != 0); ++ TEST_COMPARE (timezone, -7200); ++ TEST_COMPARE (tm->tm_year, 96); ++ TEST_COMPARE (tm->tm_mon, 8); ++ TEST_COMPARE (tm->tm_mday, 29); ++ TEST_COMPARE (tm->tm_hour, 23); ++ TEST_COMPARE (tm->tm_min, 0); ++ TEST_COMPARE (tm->tm_sec, 1); ++ TEST_COMPARE (tm->tm_gmtoff, 3600); ++ TEST_COMPARE (tm->tm_isdst, 0); ++ ++ return 0; ++} ++ ++#include +diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile +index e6b9e8743a..4af102a3f6 100644 +--- a/wcsmbs/Makefile ++++ b/wcsmbs/Makefile +@@ -22,8 +22,9 @@ subdir := wcsmbs + + include ../Makeconfig + +-headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h \ +- bits/types/__mbstate_t.h bits/types/mbstate_t.h bits/types/wint_t.h ++headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar2-decl.h \ ++ bits/wchar-ldbl.h uchar.h bits/types/__mbstate_t.h \ ++ bits/types/mbstate_t.h bits/types/wint_t.h + + routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ + wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \ +@@ -73,6 +74,8 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales) + $(objpfx)tst-wcstod-nan-locale.out: $(gen-locales) + $(objpfx)tst-c16-surrogate.out: $(gen-locales) + $(objpfx)tst-c32-state.out: $(gen-locales) ++$(objpfx)test-c8rtomb.out: $(gen-locales) ++$(objpfx)test-mbrtoc8.out: $(gen-locales) + endif + + $(objpfx)tst-wcstod-round: $(libm) +diff --git a/wcsmbs/bits/wchar2-decl.h b/wcsmbs/bits/wchar2-decl.h +new file mode 100644 +index 0000000000..8e1735c33b +--- /dev/null ++++ b/wcsmbs/bits/wchar2-decl.h +@@ -0,0 +1,124 @@ ++/* Checking macros for wchar functions. Declarations only. ++ Copyright (C) 2004-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _BITS_WCHAR2_DECL_H ++#define _BITS_WCHAR2_DECL_H 1 ++ ++#ifndef _WCHAR_H ++# error "Never include directly; use instead." ++#endif ++ ++ ++extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1, ++ const wchar_t *__restrict __s2, size_t __n, ++ size_t __ns1) __THROW; ++extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2, ++ size_t __n, size_t __ns1) __THROW; ++ ++ ++#ifdef __USE_GNU ++ ++extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1, ++ const wchar_t *__restrict __s2, size_t __n, ++ size_t __ns1) __THROW; ++ ++#endif ++ ++ ++extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n, ++ size_t __ns) __THROW; ++extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __n) __THROW; ++extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, size_t __n, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, size_t __n, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __n, size_t __destlen) __THROW; ++extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n, ++ int __flag, size_t __s_len, ++ const wchar_t *__restrict __format, ...) ++ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */; ++extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, ++ int __flag, size_t __s_len, ++ const wchar_t *__restrict __format, ++ __gnuc_va_list __arg) ++ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; ++ ++#if __USE_FORTIFY_LEVEL > 1 ++ ++extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag, ++ const wchar_t *__restrict __format, ...); ++extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format, ++ ...); ++extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag, ++ const wchar_t *__restrict __format, ++ __gnuc_va_list __ap); ++extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format, ++ __gnuc_va_list __ap); ++ ++#endif ++ ++extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n, ++ __FILE *__restrict __stream) __wur; ++ ++#ifdef __USE_GNU ++ ++extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size, ++ int __n, __FILE *__restrict __stream) ++ __wur; ++ ++#endif ++ ++extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar, ++ mbstate_t *__restrict __p, ++ size_t __buflen) __THROW __wur; ++extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst, ++ const char **__restrict __src, ++ size_t __len, mbstate_t *__restrict __ps, ++ size_t __dstlen) __THROW; ++extern size_t __wcsrtombs_chk (char *__restrict __dst, ++ const wchar_t **__restrict __src, ++ size_t __len, mbstate_t *__restrict __ps, ++ size_t __dstlen) __THROW; ++ ++#ifdef __USE_XOPEN2K8 ++ ++extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, ++ const char **__restrict __src, size_t __nmc, ++ size_t __len, mbstate_t *__restrict __ps, ++ size_t __dstlen) __THROW; ++extern size_t __wcsnrtombs_chk (char *__restrict __dst, ++ const wchar_t **__restrict __src, ++ size_t __nwc, size_t __len, ++ mbstate_t *__restrict __ps, size_t __dstlen) ++ __THROW; ++ ++#endif ++ ++#endif /* bits/wchar2-decl.h. */ +diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h +index 0e017f458b..3f110efe57 100644 +--- a/wcsmbs/bits/wchar2.h ++++ b/wcsmbs/bits/wchar2.h +@@ -21,9 +21,6 @@ + #endif + + +-extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1, +- const wchar_t *__restrict __s2, size_t __n, +- size_t __ns1) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmemcpy_alias, + (wchar_t *__restrict __s1, + const wchar_t *__restrict __s2, size_t __n), +@@ -45,8 +42,6 @@ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, + } + + +-extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2, +- size_t __n, size_t __ns1) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmemmove_alias, (wchar_t *__s1, + const wchar_t *__s2, + size_t __n), wmemmove); +@@ -66,9 +61,6 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n)) + + + #ifdef __USE_GNU +-extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1, +- const wchar_t *__restrict __s2, size_t __n, +- size_t __ns1) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmempcpy_alias, + (wchar_t *__restrict __s1, + const wchar_t *__restrict __s2, +@@ -91,8 +83,6 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, + #endif + + +-extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n, +- size_t __ns) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmemset_alias, (wchar_t *__s, wchar_t __c, + size_t __n), wmemset); + extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn, +@@ -110,9 +100,6 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n)) + } + + +-extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __n) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcscpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src), wcscpy); +@@ -127,9 +114,6 @@ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + } + + +-extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src), wcpcpy); +@@ -144,9 +128,6 @@ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + } + + +-extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, size_t __n, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcsncpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, +@@ -168,9 +149,6 @@ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + } + + +-extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, size_t __n, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcpncpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, +@@ -192,9 +170,6 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + } + + +-extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcscat_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src), wcscat); +@@ -209,9 +184,6 @@ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + } + + +-extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __n, size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcsncat_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, +@@ -228,10 +200,6 @@ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + } + + +-extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n, +- int __flag, size_t __s_len, +- const wchar_t *__restrict __format, ...) +- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */; + + extern int __REDIRECT_NTH_LDBL (__swprintf_alias, + (wchar_t *__restrict __s, size_t __n, +@@ -258,11 +226,6 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n, + : swprintf (s, n, __VA_ARGS__)) + #endif + +-extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, +- int __flag, size_t __s_len, +- const wchar_t *__restrict __format, +- __gnuc_va_list __arg) +- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; + + extern int __REDIRECT_NTH_LDBL (__vswprintf_alias, + (wchar_t *__restrict __s, size_t __n, +@@ -283,16 +246,6 @@ __NTH (vswprintf (wchar_t *__restrict __s, size_t __n, + + #if __USE_FORTIFY_LEVEL > 1 + +-extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag, +- const wchar_t *__restrict __format, ...); +-extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format, +- ...); +-extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag, +- const wchar_t *__restrict __format, +- __gnuc_va_list __ap); +-extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format, +- __gnuc_va_list __ap); +- + # ifdef __va_arg_pack + __fortify_function int + wprintf (const wchar_t *__restrict __fmt, ...) +@@ -328,8 +281,6 @@ vfwprintf (__FILE *__restrict __stream, + + #endif + +-extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n, +- __FILE *__restrict __stream) __wur; + extern wchar_t *__REDIRECT (__fgetws_alias, + (wchar_t *__restrict __s, int __n, + __FILE *__restrict __stream), fgetws) __wur; +@@ -351,9 +302,6 @@ fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) + } + + #ifdef __USE_GNU +-extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size, +- int __n, __FILE *__restrict __stream) +- __wur; + extern wchar_t *__REDIRECT (__fgetws_unlocked_alias, + (wchar_t *__restrict __s, int __n, + __FILE *__restrict __stream), fgetws_unlocked) +@@ -379,9 +327,6 @@ fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) + #endif + + +-extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar, +- mbstate_t *__restrict __p, +- size_t __buflen) __THROW __wur; + extern size_t __REDIRECT_NTH (__wcrtomb_alias, + (char *__restrict __s, wchar_t __wchar, + mbstate_t *__restrict __ps), wcrtomb) __wur; +@@ -404,10 +349,6 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar, + } + + +-extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst, +- const char **__restrict __src, +- size_t __len, mbstate_t *__restrict __ps, +- size_t __dstlen) __THROW; + extern size_t __REDIRECT_NTH (__mbsrtowcs_alias, + (wchar_t *__restrict __dst, + const char **__restrict __src, +@@ -431,10 +372,6 @@ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, + } + + +-extern size_t __wcsrtombs_chk (char *__restrict __dst, +- const wchar_t **__restrict __src, +- size_t __len, mbstate_t *__restrict __ps, +- size_t __dstlen) __THROW; + extern size_t __REDIRECT_NTH (__wcsrtombs_alias, + (char *__restrict __dst, + const wchar_t **__restrict __src, +@@ -458,10 +395,6 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src, + + + #ifdef __USE_XOPEN2K8 +-extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, +- const char **__restrict __src, size_t __nmc, +- size_t __len, mbstate_t *__restrict __ps, +- size_t __dstlen) __THROW; + extern size_t __REDIRECT_NTH (__mbsnrtowcs_alias, + (wchar_t *__restrict __dst, + const char **__restrict __src, size_t __nmc, +@@ -485,11 +418,6 @@ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, + } + + +-extern size_t __wcsnrtombs_chk (char *__restrict __dst, +- const wchar_t **__restrict __src, +- size_t __nwc, size_t __len, +- mbstate_t *__restrict __ps, size_t __dstlen) +- __THROW; + extern size_t __REDIRECT_NTH (__wcsnrtombs_alias, + (char *__restrict __dst, + const wchar_t **__restrict __src, +diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h +index c37e8619a0..5f7139f279 100644 +--- a/wcsmbs/uchar.h ++++ b/wcsmbs/uchar.h +@@ -34,8 +34,16 @@ + /* Declare the C2x char8_t typedef in C2x modes, but only if the C++ + __cpp_char8_t feature test macro is not defined. */ + #if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t ++#if __GNUC_PREREQ (10, 0) && defined __cplusplus ++/* Suppress the diagnostic regarding char8_t being a keyword in C++20. */ ++# pragma GCC diagnostic push ++# pragma GCC diagnostic ignored "-Wc++20-compat" ++#endif + /* Define the 8-bit character type. */ + typedef unsigned char char8_t; ++#if __GNUC_PREREQ (10, 0) && defined __cplusplus ++# pragma GCC diagnostic pop ++#endif + #endif + + #ifndef __USE_ISOCXX11 +diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h +index 5d6a40853d..c1321c7518 100644 +--- a/wcsmbs/wchar.h ++++ b/wcsmbs/wchar.h +@@ -864,14 +864,21 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize, + + /* Define some macros helping to catch buffer overflows. */ + #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function +-# include ++/* Declare all functions from bits/wchar2-decl.h first. */ ++# include + #endif + +-#include ++/* The following headers provide asm redirections. These redirections must ++ appear before the first usage of these functions, e.g. in bits/wchar.h. */ + #if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 + # include + #endif + ++#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function ++/* Now include the function definitions and redirects too. */ ++# include ++#endif ++ + __END_DECLS + + #endif /* wchar.h */ diff --git a/glibc/glibc-2.36-8.patch b/glibc/glibc-2.36-8.patch new file mode 100644 index 00000000..df41fa4b --- /dev/null +++ b/glibc/glibc-2.36-8.patch @@ -0,0 +1,11330 @@ +diff --git a/Makeconfig b/Makeconfig +index ba70321af1..9dd058e04b 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -43,6 +43,22 @@ else + $(error objdir must be defined by the build-directory Makefile) + endif + ++# Did we request 'make -s' run? "yes" or "no". ++# Starting from make-4.4 MAKEFLAGS now contains long ++# options like '--shuffle'. To detect presence of 's' ++# we pick first word with short options. Long options ++# are guaranteed to come after whitespace. We use '-' ++# prefix to always have a word before long options ++# even if no short options were passed. ++# Typical MAKEFLAGS values to watch for: ++# "rs --shuffle=42" (silent) ++# " --shuffle" (not silent) ++ifeq ($(findstring s, $(firstword -$(MAKEFLAGS))),) ++silent-make := no ++else ++silent-make := yes ++endif ++ + # Root of the sysdeps tree. + sysdep_dir := $(..)sysdeps + export sysdep_dir := $(sysdep_dir) +@@ -868,7 +884,7 @@ endif + # Use 64 bit time_t support for installed programs + installed-modules = nonlib nscd lddlibc4 ldconfig locale_programs \ + iconvprogs libnss_files libnss_compat libnss_db libnss_hesiod \ +- libutil libpcprofile libSegFault ++ libutil libpcprofile libSegFault libnsl + +extra-time-flags = $(if $(filter $(installed-modules),\ + $(in-module)),-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64) + +@@ -917,7 +933,7 @@ endif + # umpteen zillion filenames along with it (we use `...' instead) + # but we don't want this echoing done when the user has said + # he doesn't want to see commands echoed by using -s. +-ifneq "$(findstring s,$(MAKEFLAGS))" "" # if -s ++ifeq ($(silent-make),yes) # if -s + +cmdecho := echo >/dev/null + else # not -s + +cmdecho := echo +diff --git a/Makerules b/Makerules +index d1e139d03c..09c0cf8357 100644 +--- a/Makerules ++++ b/Makerules +@@ -794,7 +794,7 @@ endif + # Maximize efficiency by minimizing the number of rules. + .SUFFIXES: # Clear the suffix list. We don't use suffix rules. + # Don't define any builtin rules. +-MAKEFLAGS := $(MAKEFLAGS)r ++MAKEFLAGS := $(MAKEFLAGS) -r + + # Generic rule for making directories. + %/: +@@ -811,7 +811,7 @@ MAKEFLAGS := $(MAKEFLAGS)r + .PRECIOUS: $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c)) + + # Use the verbose option of ar and tar when not running silently. +-ifeq "$(findstring s,$(MAKEFLAGS))" "" # if not -s ++ifeq ($(silent-make),no) # if not -s + verbose := v + else # -s + verbose := +diff --git a/NEWS b/NEWS +index f61e521fc8..0f0ebce3f0 100644 +--- a/NEWS ++++ b/NEWS +@@ -5,6 +5,94 @@ See the end for copying conditions. + Please send GNU C library bug reports via + using `glibc' in the "product" field. + ++Version 2.36.1 ++ ++Major new features: ++ ++* The getent tool now supports the --no-addrconfig option. The output of ++ getent with --no-addrconfig may contain addresses of families not ++ configured on the current host i.e. as-if you had not passed ++ AI_ADDRCONFIG to getaddrinfo calls. ++ ++Security related changes: ++ ++ CVE-2022-39046: When the syslog function is passed a crafted input ++ string larger than 1024 bytes, it reads uninitialized memory from the ++ heap and prints it to the target log file, potentially revealing a ++ portion of the contents of the heap. ++ ++ CVE-2023-4527: If the system is configured in no-aaaa mode via ++ /etc/resolv.conf, getaddrinfo is called for the AF_UNSPEC address ++ family, and a DNS response is received over TCP that is larger than ++ 2048 bytes, getaddrinfo may potentially disclose stack contents via ++ the returned address data, or crash. ++ ++ CVE-2023-4806: When an NSS plugin only implements the ++ _gethostbyname2_r and _getcanonname_r callbacks, getaddrinfo could use ++ memory that was freed during buffer resizing, potentially causing a ++ crash or read or write to arbitrary memory. ++ ++ CVE-2023-5156: The fix for CVE-2023-4806 introduced a memory leak when ++ an application calls getaddrinfo for AF_INET6 with AI_CANONNAME, ++ AI_ALL and AI_V4MAPPED flags set. ++ ++ CVE-2023-4911: If a tunable of the form NAME=NAME=VAL is passed in the ++ environment of a setuid program and NAME is valid, it may result in a ++ buffer overflow, which could be exploited to achieve escalated ++ privileges. This flaw was introduced in glibc 2.34. ++ ++The following bugs are resolved with this release: ++ ++ [12154] Do not fail DNS resolution for CNAMEs which are not host names ++ [20975] Deferred cancellation triggers in __check_pf and looses lock leading to deadlock ++ [24816] Fix tst-nss-files-hosts-long on single-stack hosts ++ [27576] gmon: improve mcount overflow handling ++ [28846] CMSG_NXTHDR may trigger -Wstrict-overflow warning ++ [29039] Corrupt DTV after reuse of a TLS module ID following dlclose with unused TLS ++ [29444] gmon: Fix allocated buffer overflow (bug 29444) ++ [29864] libc: __libc_start_main() should obtain program headers ++ address (_dl_phdr) from the auxv, not the ELF header. ++ [29305] Conserve NSS buffer space during DNS packet parsing ++ [29402] nscd: nscd: No such file or directory ++ [29415] nscd: Fix netlink cache invalidation if epoll is used ++ [28937] New DSO dependency sorter does not put new map first if in a cycle ++ [29446] _dlopen now ignores dl_caller argument in static mode ++ [29485] Linux: Terminate subprocess on late failure in tst-pidfd ++ [29490] alpha: New __brk_call implementation is broken ++ [29463] math/test-float128-y1 fails on x86_64 ++ [29488] test-ibm128-llround fails on ppc64el when built with gcc-12 and -O2 ++ or higher ++ [29528] elf: Call __libc_early_init for reused namespaces ++ [29537] libc: [2.34 regression]: Alignment issue on m68k when using ++ [29539] libc: LD_TRACE_LOADED_OBJECTS changed how vDSO library are ++ [29576] build: librtld.os: in function `_dl_start_profile': ++ (.text+0x9444): undefined reference to `strcpy' ++ [29583] Use 64-bit interfaces in gconv_parseconfdir ++ [29600] Do not completely clear reused namespace in dlmopen ++ [29607] nscd repeatably crashes calling __strlen_avx2 when hosts cache is ++ enabled ++ [29638] libc: stdlib: arc4random fallback is never used ++ [29657] libc: Incorrect struct stat for 64-bit time on linux/generic ++ platforms ++ [29730] broken y2038 support in fstatat on MIPS N64 ++ [29771] Restore IPC_64 support in sysvipc *ctl functions ++ [29776] elf/tst-tlsopt-powerpc fails when compiled with -mcpu=power10 ++ [29951] time: Set daylight to 1 for matching DST/offset change ++ [30053] time: strftime %s returns -1 after 2038 on 32 bits systems ++ [30101] gmon: fix memory corruption issues ++ [30151] gshadow: Matching sgetsgent, sgetsgent_r ERANGE handling ++ [30163] posix: Fix system blocks SIGCHLD erroneously ++ [30305] x86_64: Fix asm constraints in feraiseexcept ++ [30477] libc: [RISCV]: time64 does not work on riscv32 ++ [30515] _dl_find_object incorrectly returns 1 during early startup ++ [30745] Slight bug in cache info codes for x86 ++ [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with ++ -D_FILE_OFFSET_BITS=64 ++ [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) ++ [30843] potential use-after-free in getcanonname (CVE-2023-4806) ++ [31184] FAIL: elf/tst-tlsgap ++ [31185] Incorrect thread point access in _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic ++ + Version 2.36 + + Major new features: +diff --git a/bits/socket.h b/bits/socket.h +index 2b99dea33b..aac8c49b00 100644 +--- a/bits/socket.h ++++ b/bits/socket.h +@@ -245,6 +245,12 @@ struct cmsghdr + + CMSG_ALIGN (sizeof (struct cmsghdr))) + #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + ++/* Given a length, return the additional padding necessary such that ++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ ++#define __CMSG_PADDING(len) ((sizeof (size_t) \ ++ - ((len) & (sizeof (size_t) - 1))) \ ++ & (sizeof (size_t) - 1)) ++ + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + struct cmsghdr *__cmsg) __THROW; + #ifdef __USE_EXTERN_INLINES +@@ -254,18 +260,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + _EXTERN_INLINE struct cmsghdr * + __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) + { ++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and ++ __mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of __cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; ++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; ++ ++ size_t __size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (__cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ + return (struct cmsghdr *) 0; + ++ /* There isn't enough space between __cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) ++ < __size_needed) ++ || ((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr ++ - __size_needed) ++ < __cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; ++ ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); +- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control +- + __mhdr->msg_controllen) +- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) +- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) +- /* No more entries. */ +- return (struct cmsghdr *) 0; + return __cmsg; + } + #endif /* Use `extern inline'. */ +diff --git a/csu/libc-start.c b/csu/libc-start.c +index 543560f36c..bfeee6d851 100644 +--- a/csu/libc-start.c ++++ b/csu/libc-start.c +@@ -262,28 +262,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL), + } + # endif + _dl_aux_init (auxvec); +- if (GL(dl_phdr) == NULL) + # endif +- { +- /* Starting from binutils-2.23, the linker will define the +- magic symbol __ehdr_start to point to our own ELF header +- if it is visible in a segment that also includes the phdrs. +- So we can set up _dl_phdr and _dl_phnum even without any +- information from auxv. */ +- +- extern const ElfW(Ehdr) __ehdr_start +-# if BUILD_PIE_DEFAULT +- __attribute__ ((visibility ("hidden"))); +-# else +- __attribute__ ((weak, visibility ("hidden"))); +- if (&__ehdr_start != NULL) +-# endif +- { +- assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr)); +- GL(dl_phdr) = (const void *) &__ehdr_start + __ehdr_start.e_phoff; +- GL(dl_phnum) = __ehdr_start.e_phnum; +- } +- } + + __tunables_init (__environ); + +diff --git a/csu/libc-tls.c b/csu/libc-tls.c +index 0a216c5502..7fdf7cd7a8 100644 +--- a/csu/libc-tls.c ++++ b/csu/libc-tls.c +@@ -118,19 +118,18 @@ __libc_setup_tls (void) + __tls_pre_init_tp (); + + /* Look through the TLS segment if there is any. */ +- if (_dl_phdr != NULL) +- for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) +- if (phdr->p_type == PT_TLS) +- { +- /* Remember the values we need. */ +- memsz = phdr->p_memsz; +- filesz = phdr->p_filesz; +- initimage = (void *) phdr->p_vaddr + main_map->l_addr; +- align = phdr->p_align; +- if (phdr->p_align > max_align) +- max_align = phdr->p_align; +- break; +- } ++ for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr) ++ if (phdr->p_type == PT_TLS) ++ { ++ /* Remember the values we need. */ ++ memsz = phdr->p_memsz; ++ filesz = phdr->p_filesz; ++ initimage = (void *) phdr->p_vaddr + main_map->l_addr; ++ align = phdr->p_align; ++ if (phdr->p_align > max_align) ++ max_align = phdr->p_align; ++ break; ++ } + + /* Calculate the size of the static TLS surplus, with 0 auditors. */ + _dl_tls_static_surplus_init (0); +diff --git a/dlfcn/dlopen.c b/dlfcn/dlopen.c +index 2696dde4b1..9b07b4e132 100644 +--- a/dlfcn/dlopen.c ++++ b/dlfcn/dlopen.c +@@ -90,7 +90,7 @@ compat_symbol (libdl, ___dlopen, dlopen, GLIBC_2_1); + void * + __dlopen (const char *file, int mode, void *dl_caller) + { +- return dlopen_implementation (file, mode, RETURN_ADDRESS (0)); ++ return dlopen_implementation (file, mode, dl_caller); + } + + void * +diff --git a/elf/Makefile b/elf/Makefile +index fd77d0c7c8..30c9af1de9 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -53,6 +53,7 @@ routines = \ + # profiled libraries. + dl-routines = \ + dl-call-libc-early-init \ ++ dl-call_fini \ + dl-close \ + dl-debug \ + dl-debug-symbols \ +@@ -374,6 +375,8 @@ tests += \ + tst-align \ + tst-align2 \ + tst-align3 \ ++ tst-audit-tlsdesc \ ++ tst-audit-tlsdesc-dlopen \ + tst-audit1 \ + tst-audit2 \ + tst-audit8 \ +@@ -408,6 +411,7 @@ tests += \ + tst-dlmopen4 \ + tst-dlmopen-dlerror \ + tst-dlmopen-gethostbyname \ ++ tst-dlmopen-twice \ + tst-dlopenfail \ + tst-dlopenfail-2 \ + tst-dlopenrpath \ +@@ -631,6 +635,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 +770,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 +805,7 @@ modules-names += \ + tst-auditmanymod7 \ + tst-auditmanymod8 \ + tst-auditmanymod9 \ ++ tst-auditmod-tlsdesc \ + tst-auditmod1 \ + tst-auditmod9a \ + tst-auditmod9b \ +@@ -834,6 +842,8 @@ modules-names += \ + tst-dlmopen1mod \ + tst-dlmopen-dlerror-mod \ + tst-dlmopen-gethostbyname-mod \ ++ tst-dlmopen-twice-mod1 \ ++ tst-dlmopen-twice-mod2 \ + tst-dlopenfaillinkmod \ + tst-dlopenfailmod1 \ + tst-dlopenfailmod2 \ +@@ -990,23 +1000,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 +2405,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 +2967,25 @@ $(objpfx)tst-tls-allocation-failure-static-patched.out: \ + grep -q '^Fatal glibc error: Cannot allocate TLS block$$' $@ \ + && grep -q '^status: 127$$' $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-audit-tlsdesc: $(objpfx)tst-audit-tlsdesc-mod1.so \ ++ $(objpfx)tst-audit-tlsdesc-mod2.so \ ++ $(shared-thread-library) ++ifeq (yes,$(have-mtls-dialect-gnu2)) ++# The test is valid for all TLS types, but we want to exercise GNU2 ++# TLS if possible. ++CFLAGS-tst-audit-tlsdesc-mod1.c += -mtls-dialect=gnu2 ++CFLAGS-tst-audit-tlsdesc-mod2.c += -mtls-dialect=gnu2 ++endif ++$(objpfx)tst-audit-tlsdesc-dlopen: $(shared-thread-library) ++$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-audit-tlsdesc-mod1.so \ ++ $(objpfx)tst-audit-tlsdesc-mod2.so ++$(objpfx)tst-audit-tlsdesc-mod1.so: $(objpfx)tst-audit-tlsdesc-mod2.so ++$(objpfx)tst-audit-tlsdesc.out: $(objpfx)tst-auditmod-tlsdesc.so ++tst-audit-tlsdesc-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so ++$(objpfx)tst-audit-tlsdesc-dlopen.out: $(objpfx)tst-auditmod-tlsdesc.so ++tst-audit-tlsdesc-dlopen-ENV = LD_AUDIT=$(objpfx)tst-auditmod-tlsdesc.so ++ ++$(objpfx)tst-dlmopen-twice.out: \ ++ $(objpfx)tst-dlmopen-twice-mod1.so \ ++ $(objpfx)tst-dlmopen-twice-mod2.so +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 8bbf110d02..b97c17b3a9 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -509,8 +509,9 @@ _dl_load_cache_lookup (const char *name) + we are accessing. Therefore we must make the copy of the + mapping data without using malloc. */ + char *temp; +- temp = alloca (strlen (best) + 1); +- strcpy (temp, best); ++ size_t best_len = strlen (best) + 1; ++ temp = alloca (best_len); ++ memcpy (temp, best, best_len); + return __strdup (temp); + } + +diff --git a/elf/dl-call_fini.c b/elf/dl-call_fini.c +new file mode 100644 +index 0000000000..9e7ba10fa2 +--- /dev/null ++++ b/elf/dl-call_fini.c +@@ -0,0 +1,50 @@ ++/* Invoke DT_FINI and DT_FINI_ARRAY callbacks. ++ Copyright (C) 1996-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++void ++_dl_call_fini (void *closure_map) ++{ ++ struct link_map *map = closure_map; ++ ++ /* When debugging print a message first. */ ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS)) ++ _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", map->l_name, map->l_ns); ++ ++ /* Make sure nothing happens if we are called twice. */ ++ map->l_init_called = 0; ++ ++ ElfW(Dyn) *fini_array = map->l_info[DT_FINI_ARRAY]; ++ if (fini_array != NULL) ++ { ++ ElfW(Addr) *array = (ElfW(Addr) *) (map->l_addr ++ + fini_array->d_un.d_ptr); ++ size_t sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val ++ / sizeof (ElfW(Addr))); ++ ++ while (sz-- > 0) ++ ((fini_t) array[sz]) (); ++ } ++ ++ /* Next try the old-style destructor. */ ++ ElfW(Dyn) *fini = map->l_info[DT_FINI]; ++ if (fini != NULL) ++ DL_CALL_DT_FINI (map, ((void *) map->l_addr + fini->d_un.d_ptr)); ++} +diff --git a/elf/dl-close.c b/elf/dl-close.c +index bcd6e206e9..14deca2e2b 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -36,11 +36,6 @@ + + #include + +- +-/* Type of the constructor functions. */ +-typedef void (*fini_t) (void); +- +- + /* Special l_idx value used to indicate which objects remain loaded. */ + #define IDX_STILL_USED -1 + +@@ -110,31 +105,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp, + return false; + } + +-/* Invoke dstructors for CLOSURE (a struct link_map *). Called with +- exception handling temporarily disabled, to make errors fatal. */ +-static void +-call_destructors (void *closure) +-{ +- struct link_map *map = closure; +- +- if (map->l_info[DT_FINI_ARRAY] != NULL) +- { +- ElfW(Addr) *array = +- (ElfW(Addr) *) (map->l_addr +- + map->l_info[DT_FINI_ARRAY]->d_un.d_ptr); +- unsigned int sz = (map->l_info[DT_FINI_ARRAYSZ]->d_un.d_val +- / sizeof (ElfW(Addr))); +- +- while (sz-- > 0) +- ((fini_t) array[sz]) (); +- } +- +- /* Next try the old-style destructor. */ +- if (map->l_info[DT_FINI] != NULL) +- DL_CALL_DT_FINI (map, ((void *) map->l_addr +- + map->l_info[DT_FINI]->d_un.d_ptr)); +-} +- + void + _dl_close_worker (struct link_map *map, bool force) + { +@@ -280,17 +250,7 @@ _dl_close_worker (struct link_map *map, bool force) + half-cooked objects. Temporarily disable exception + handling, so that errors are fatal. */ + if (imap->l_init_called) +- { +- /* When debugging print a message first. */ +- if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, +- 0)) +- _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", +- imap->l_name, nsid); +- +- if (imap->l_info[DT_FINI_ARRAY] != NULL +- || imap->l_info[DT_FINI] != NULL) +- _dl_catch_exception (NULL, call_destructors, imap); +- } ++ _dl_catch_exception (NULL, _dl_call_fini, imap); + + #ifdef SHARED + /* Auditing checkpoint: we remove an object. */ +diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c +index 4d5831b6f4..2e5b456c11 100644 +--- a/elf/dl-find_object.c ++++ b/elf/dl-find_object.c +@@ -46,7 +46,7 @@ _dl_find_object_slow (void *pc, struct dl_find_object *result) + struct dl_find_object_internal internal; + _dl_find_object_from_map (l, &internal); + _dl_find_object_to_external (&internal, result); +- return 1; ++ return 0; + } + + /* Object not found. */ +diff --git a/elf/dl-fini.c b/elf/dl-fini.c +index 030b1fcbcd..50ff94db16 100644 +--- a/elf/dl-fini.c ++++ b/elf/dl-fini.c +@@ -21,11 +21,6 @@ + #include + #include + +- +-/* Type of the constructor functions. */ +-typedef void (*fini_t) (void); +- +- + void + _dl_fini (void) + { +@@ -116,38 +111,7 @@ _dl_fini (void) + + if (l->l_init_called) + { +- /* Make sure nothing happens if we are called twice. */ +- l->l_init_called = 0; +- +- /* Is there a destructor function? */ +- if (l->l_info[DT_FINI_ARRAY] != NULL +- || (ELF_INITFINI && l->l_info[DT_FINI] != NULL)) +- { +- /* When debugging print a message first. */ +- if (__builtin_expect (GLRO(dl_debug_mask) +- & DL_DEBUG_IMPCALLS, 0)) +- _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", +- DSO_FILENAME (l->l_name), +- ns); +- +- /* First see whether an array is given. */ +- if (l->l_info[DT_FINI_ARRAY] != NULL) +- { +- ElfW(Addr) *array = +- (ElfW(Addr) *) (l->l_addr +- + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); +- unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val +- / sizeof (ElfW(Addr))); +- while (i-- > 0) +- ((fini_t) array[i]) (); +- } +- +- /* Next try the old-style destructor. */ +- if (ELF_INITFINI && l->l_info[DT_FINI] != NULL) +- DL_CALL_DT_FINI +- (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr); +- } +- ++ _dl_call_fini (l); + #ifdef SHARED + /* Auditing checkpoint: another object closed. */ + _dl_audit_objclose (l); +diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c +index 6f161f6ad5..92eb53790e 100644 +--- a/elf/dl-hwcaps.c ++++ b/elf/dl-hwcaps.c +@@ -193,7 +193,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + /* Each hwcaps subdirectory has a GLIBC_HWCAPS_PREFIX string prefix + and a "/" suffix once stored in the result. */ + hwcaps_counts.maximum_length += strlen (GLIBC_HWCAPS_PREFIX) + 1; +- size_t total = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) ++ size_t hwcaps_sz = (hwcaps_counts.count * (strlen (GLIBC_HWCAPS_PREFIX) + 1) + + hwcaps_counts.total_length); + + /* Count the number of bits set in the masked value. */ +@@ -229,11 +229,12 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + assert (m == cnt); + + /* Determine the total size of all strings together. */ ++ size_t total; + if (cnt == 1) +- total += temp[0].len + 1; ++ total = temp[0].len + 1; + else + { +- total += temp[0].len + temp[cnt - 1].len + 2; ++ total = temp[0].len + temp[cnt - 1].len + 2; + if (cnt > 2) + { + total <<= 1; +@@ -255,6 +256,7 @@ _dl_important_hwcaps (const char *glibc_hwcaps_prepend, + /* This is the overall result, including both glibc-hwcaps + subdirectories and the legacy hwcaps subdirectories using the + power set construction. */ ++ total += hwcaps_sz; + struct r_strlenpair *overall_result + = malloc (*sz * sizeof (*result) + total); + if (overall_result == NULL) +diff --git a/elf/dl-init.c b/elf/dl-init.c +index deefeb099a..fca8e3a05e 100644 +--- a/elf/dl-init.c ++++ b/elf/dl-init.c +@@ -25,10 +25,14 @@ + static void + call_init (struct link_map *l, int argc, char **argv, char **env) + { ++ /* Do not run constructors for proxy objects. */ ++ if (l != l->l_real) ++ return; ++ + /* If the object has not been relocated, this is a bug. The + function pointers are invalid in this case. (Executables do not +- need relocation, and neither do proxy objects.) */ +- assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable); ++ need relocation.) */ ++ assert (l->l_relocated || l->l_type == lt_executable); + + if (l->l_init_called) + /* This object is all done. */ +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 4c86dc694e..67fb2e31e2 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -854,6 +854,23 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map, + if (__glibc_unlikely (current_value.m->l_used == 0)) + current_value.m->l_used = 1; + ++ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)) ++ { ++ const char *reference_name = undef_map->l_name; ++ ++ _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'", ++ DSO_FILENAME (reference_name), ++ undef_map->l_ns, ++ DSO_FILENAME (current_value.m->l_name), ++ current_value.m->l_ns, ++ protected ? "protected" : "normal", undef_name); ++ if (version) ++ _dl_debug_printf_c (" [%s]\n", version->name); ++ else ++ _dl_debug_printf_c ("\n"); ++ } ++ ++ + *ref = current_value.s; + return LOOKUP_VALUE (current_value.m); + } +diff --git a/elf/dl-open.c b/elf/dl-open.c +index a23e65926b..e7db5e9642 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -850,6 +850,7 @@ no more namespaces available for dlmopen()")); + ++GL(dl_nns); + } + ++ GL(dl_ns)[nsid].libc_map = NULL; + _dl_debug_update (nsid)->r_state = RT_CONSISTENT; + } + /* Never allow loading a DSO in a namespace which is empty. Such +diff --git a/elf/dl-sort-maps.c b/elf/dl-sort-maps.c +index 96638d7ed1..3e2a6a584e 100644 +--- a/elf/dl-sort-maps.c ++++ b/elf/dl-sort-maps.c +@@ -27,12 +27,12 @@ + If FOR_FINI is true, this is called for finishing an object. */ + static void + _dl_sort_maps_original (struct link_map **maps, unsigned int nmaps, +- unsigned int skip, bool for_fini) ++ bool force_first, bool for_fini) + { + /* Allows caller to do the common optimization of skipping the first map, + usually the main binary. */ +- maps += skip; +- nmaps -= skip; ++ maps += force_first; ++ nmaps -= force_first; + + /* A list of one element need not be sorted. */ + if (nmaps <= 1) +@@ -182,8 +182,9 @@ dfs_traversal (struct link_map ***rpo, struct link_map *map, + + static void + _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, +- unsigned int skip __attribute__ ((unused)), bool for_fini) ++ bool force_first, bool for_fini) + { ++ struct link_map *first_map = maps[0]; + for (int i = nmaps - 1; i >= 0; i--) + maps[i]->l_visited = 0; + +@@ -208,14 +209,6 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, + Adjusting the order so that maps[0] is last traversed naturally avoids + this problem. + +- Further, the old "optimization" of skipping the main object at maps[0] +- from the call-site (i.e. _dl_sort_maps(maps+1,nmaps-1)) is in general +- no longer valid, since traversing along object dependency-links +- may "find" the main object even when it is not included in the initial +- order (e.g. a dlopen()'ed shared object can have circular dependencies +- linked back to itself). In such a case, traversing N-1 objects will +- create a N-object result, and raise problems. +- + To summarize, just passing in the full list, and iterating from back + to front makes things much more straightforward. */ + +@@ -274,6 +267,27 @@ _dl_sort_maps_dfs (struct link_map **maps, unsigned int nmaps, + } + + memcpy (maps, rpo, sizeof (struct link_map *) * nmaps); ++ ++ /* Skipping the first object at maps[0] is not valid in general, ++ since traversing along object dependency-links may "find" that ++ first object even when it is not included in the initial order ++ (e.g., a dlopen'ed shared object can have circular dependencies ++ linked back to itself). In such a case, traversing N-1 objects ++ will create a N-object result, and raise problems. Instead, ++ force the object back into first place after sorting. This naive ++ approach may introduce further dependency ordering violations ++ compared to rotating the cycle until the first map is again in ++ the first position, but as there is a cycle, at least one ++ violation is already present. */ ++ if (force_first && maps[0] != first_map) ++ { ++ int i; ++ for (i = 0; maps[i] != first_map; ++i) ++ ; ++ assert (i < nmaps); ++ memmove (&maps[1], maps, i * sizeof (maps[0])); ++ maps[0] = first_map; ++ } + } + + void +@@ -286,7 +300,7 @@ _dl_sort_maps_init (void) + + void + _dl_sort_maps (struct link_map **maps, unsigned int nmaps, +- unsigned int skip, bool for_fini) ++ bool force_first, bool for_fini) + { + /* It can be tempting to use a static function pointer to store and call + the current selected sorting algorithm routine, but experimentation +@@ -296,9 +310,9 @@ _dl_sort_maps (struct link_map **maps, unsigned int nmaps, + input cases. A simple if-case with direct function calls appears to + be the fastest. */ + if (__glibc_likely (GLRO(dl_dso_sort_algo) == dso_sort_algorithm_original)) +- _dl_sort_maps_original (maps, nmaps, skip, for_fini); ++ _dl_sort_maps_original (maps, nmaps, force_first, for_fini); + else +- _dl_sort_maps_dfs (maps, nmaps, skip, for_fini); ++ _dl_sort_maps_dfs (maps, nmaps, force_first, for_fini); + } + + #endif /* HAVE_TUNABLES. */ +diff --git a/elf/dl-support.c b/elf/dl-support.c +index 4af0b5b2ce..f45b630ba5 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -255,6 +255,25 @@ _dl_aux_init (ElfW(auxv_t) *av) + for (int i = 0; i < array_length (auxv_values); ++i) + auxv_values[i] = 0; + _dl_parse_auxv (av, auxv_values); ++ ++ _dl_phdr = (void*) auxv_values[AT_PHDR]; ++ _dl_phnum = auxv_values[AT_PHNUM]; ++ ++ if (_dl_phdr == NULL) ++ { ++ /* Starting from binutils-2.23, the linker will define the ++ magic symbol __ehdr_start to point to our own ELF header ++ if it is visible in a segment that also includes the phdrs. ++ So we can set up _dl_phdr and _dl_phnum even without any ++ information from auxv. */ ++ ++ extern const ElfW(Ehdr) __ehdr_start attribute_hidden; ++ assert (__ehdr_start.e_phentsize == sizeof *GL(dl_phdr)); ++ _dl_phdr = (const void *) &__ehdr_start + __ehdr_start.e_phoff; ++ _dl_phnum = __ehdr_start.e_phnum; ++ } ++ ++ assert (_dl_phdr != NULL); + } + #endif + +@@ -323,20 +342,19 @@ _dl_non_dynamic_init (void) + if (_dl_platform != NULL) + _dl_platformlen = strlen (_dl_platform); + +- if (_dl_phdr != NULL) +- for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph) +- switch (ph->p_type) +- { +- /* Check if the stack is nonexecutable. */ +- case PT_GNU_STACK: +- _dl_stack_flags = ph->p_flags; +- break; +- +- case PT_GNU_RELRO: +- _dl_main_map.l_relro_addr = ph->p_vaddr; +- _dl_main_map.l_relro_size = ph->p_memsz; +- break; +- } ++ for (const ElfW(Phdr) *ph = _dl_phdr; ph < &_dl_phdr[_dl_phnum]; ++ph) ++ switch (ph->p_type) ++ { ++ /* Check if the stack is nonexecutable. */ ++ case PT_GNU_STACK: ++ _dl_stack_flags = ph->p_flags; ++ break; ++ ++ case PT_GNU_RELRO: ++ _dl_main_map.l_relro_addr = ph->p_vaddr; ++ _dl_main_map.l_relro_size = ph->p_memsz; ++ break; ++ } + + call_function_static_weak (_dl_find_object_init); + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 093cdddb7e..bf0ff0d9e8 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -160,6 +160,7 @@ _dl_assign_tls_modid (struct link_map *l) + { + /* Mark the entry as used, so any dependency see it. */ + atomic_store_relaxed (&runp->slotinfo[result - disp].map, l); ++ atomic_store_relaxed (&runp->slotinfo[result - disp].gen, 0); + break; + } + +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index 8e7ee9df10..76cf8b9da3 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -187,11 +187,7 @@ parse_tunables (char *tunestr, char *valstring) + /* If we reach the end of the string before getting a valid name-value + pair, bail out. */ + if (p[len] == '\0') +- { +- if (__libc_enable_secure) +- tunestr[off] = '\0'; +- return; +- } ++ break; + + /* We did not find a valid name-value pair before encountering the + colon. */ +@@ -251,9 +247,16 @@ parse_tunables (char *tunestr, char *valstring) + } + } + +- if (p[len] != '\0') +- p += len + 1; ++ /* We reached the end while processing the tunable string. */ ++ if (p[len] == '\0') ++ break; ++ ++ p += len + 1; + } ++ ++ /* Terminate tunestr before we leave. */ ++ if (__libc_enable_secure) ++ tunestr[off] = '\0'; + } + #endif + +diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list +index e6a56b3070..9fa3b484cf 100644 +--- a/elf/dl-tunables.list ++++ b/elf/dl-tunables.list +@@ -169,4 +169,17 @@ glibc { + default: 2 + } + } ++ ++ gmon { ++ minarcs { ++ type: INT_32 ++ minval: 50 ++ default: 50 ++ } ++ maxarcs { ++ type: INT_32 ++ minval: 50 ++ default: 1048576 ++ } ++ } + } +diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def +index 5f7f18ef27..4bf9052db1 100644 +--- a/elf/dso-sort-tests-1.def ++++ b/elf/dso-sort-tests-1.def +@@ -64,3 +64,10 @@ output: b>a>{}b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c + output(glibc.rtld.dynamic_sort=1): {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[a1;a->a2;a2->a;b->b1;c->a1;c=>a1 ++output(glibc.rtld.dynamic_sort=1): {+a[a2>a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());}l_faked) + /* The library was not found. */ + _dl_printf ("\t%s => not found\n", l->l_libname->name); ++ else if (strcmp (l->l_libname->name, l->l_name) == 0) ++ /* Print vDSO like libraries without duplicate name. Some ++ consumers depend of this format. */ ++ _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name, ++ (int) sizeof l->l_map_start * 2, ++ (size_t) l->l_map_start); + else + _dl_printf ("\t%s => %s (0x%0*Zx)\n", + DSO_FILENAME (l->l_libname->name), +diff --git a/elf/tst-auditmod28.c b/elf/tst-auditmod28.c +index db7ba95abe..9e0a122c38 100644 +--- a/elf/tst-auditmod28.c ++++ b/elf/tst-auditmod28.c +@@ -71,6 +71,17 @@ la_version (unsigned int current) + TEST_VERIFY (dladdr1 (&_exit, &info, &extra_info, RTLD_DL_LINKMAP) != 0); + TEST_VERIFY (extra_info == handle); + ++ /* Check _dl_find_object. */ ++ struct dl_find_object dlfo; ++ TEST_COMPARE (_dl_find_object (__builtin_return_address (0), &dlfo), 0); ++ /* "ld.so" is seen with --enable-hardcoded-path-in-tests. */ ++ if (strcmp (basename (dlfo.dlfo_link_map->l_name), "ld.so") != 0) ++ TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LD_SO); ++ TEST_COMPARE (_dl_find_object (dlsym (handle, "environ"), &dlfo), 0); ++ TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LIBC_SO); ++ TEST_COMPARE (_dl_find_object ((void *) 1, &dlfo), -1); ++ TEST_COMPARE (_dl_find_object ((void *) -1, &dlfo), -1); ++ + /* Verify that dlmopen creates a new namespace. */ + void *dlmopen_handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); + TEST_VERIFY (dlmopen_handle != handle); +diff --git a/elf/tst-dlmopen-twice-mod1.c b/elf/tst-dlmopen-twice-mod1.c +new file mode 100644 +index 0000000000..0eaf04948c +--- /dev/null ++++ b/elf/tst-dlmopen-twice-mod1.c +@@ -0,0 +1,37 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 1. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod1.so loaded"); ++ fflush (stdout); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod1.so about to be unloaded"); ++ fflush (stdout); ++} ++ ++/* Large allocation. The second module does not have this, so it ++ should load libc at a different address. */ ++char large_allocate[16 * 1024 * 1024]; +diff --git a/elf/tst-dlmopen-twice-mod2.c b/elf/tst-dlmopen-twice-mod2.c +new file mode 100644 +index 0000000000..40c6c01f96 +--- /dev/null ++++ b/elf/tst-dlmopen-twice-mod2.c +@@ -0,0 +1,50 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Module 2. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod2.so loaded"); ++ fflush (stdout); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ puts ("info: tst-dlmopen-twice-mod2.so about to be unloaded"); ++ fflush (stdout); ++} ++ ++int ++run_check (void) ++{ ++ puts ("info: about to call isalpha"); ++ fflush (stdout); ++ ++ volatile char ch = 'a'; ++ if (!isalpha (ch)) ++ { ++ puts ("error: isalpha ('a') is not true"); ++ fflush (stdout); ++ return 1; ++ } ++ return 0; ++} +diff --git a/elf/tst-dlmopen-twice.c b/elf/tst-dlmopen-twice.c +new file mode 100644 +index 0000000000..70c71fe19c +--- /dev/null ++++ b/elf/tst-dlmopen-twice.c +@@ -0,0 +1,54 @@ ++/* Initialization of libc after dlmopen/dlclose/dlmopen (bug 29528). Main. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++/* Run the test multiple times, to check finding a new namespace while ++ another namespace is already in use. This used to trigger bug 29600. */ ++static void ++recurse (int depth) ++{ ++ if (depth == 0) ++ return; ++ ++ printf ("info: running at depth %d\n", depth); ++ void *handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod1.so", ++ RTLD_NOW); ++ xdlclose (handle); ++ handle = xdlmopen (LM_ID_NEWLM, "tst-dlmopen-twice-mod2.so", RTLD_NOW); ++ int (*run_check) (void) = xdlsym (handle, "run_check"); ++ TEST_COMPARE (run_check (), 0); ++ recurse (depth - 1); ++ xdlclose (handle); ++} ++ ++static int ++do_test (void) ++{ ++ /* First run the test without nesting. */ ++ recurse (1); ++ ++ /* Then with nesting. The constant needs to be less than the ++ internal DL_NNS namespace constant. */ ++ recurse (10); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-env-setuid-tunables.c b/elf/tst-env-setuid-tunables.c +index 88182b7b25..5e9e4c5756 100644 +--- a/elf/tst-env-setuid-tunables.c ++++ b/elf/tst-env-setuid-tunables.c +@@ -52,6 +52,8 @@ const char *teststrings[] = + "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", + "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096", + "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.check=2", + "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2", + "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096", + ":glibc.malloc.garbage=2:glibc.malloc.check=1", +@@ -70,6 +72,8 @@ const char *resultstrings[] = + "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", + "glibc.malloc.mmap_threshold=4096", ++ "glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096", ++ "", + "", + "", + "", +@@ -84,11 +88,18 @@ test_child (int off) + const char *val = getenv ("GLIBC_TUNABLES"); + + #if HAVE_TUNABLES ++ printf (" [%d] GLIBC_TUNABLES is %s\n", off, val); ++ fflush (stdout); + if (val != NULL && strcmp (val, resultstrings[off]) == 0) + return 0; + + if (val != NULL) +- printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val); ++ printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n", ++ off, val, resultstrings[off]); ++ else ++ printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off); ++ ++ fflush (stdout); + + return 1; + #else +@@ -117,21 +128,26 @@ do_test (int argc, char **argv) + if (ret != 0) + exit (1); + +- exit (EXIT_SUCCESS); ++ /* Special return code to make sure that the child executed all the way ++ through. */ ++ exit (42); + } + else + { +- int ret = 0; +- + /* Spawn tests. */ + for (int i = 0; i < array_length (teststrings); i++) + { + char buf[INT_BUFSIZE_BOUND (int)]; + +- printf ("Spawned test for %s (%d)\n", teststrings[i], i); ++ printf ("[%d] Spawned test for %s\n", i, teststrings[i]); + snprintf (buf, sizeof (buf), "%d\n", i); ++ fflush (stdout); + if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0) +- exit (1); ++ { ++ printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i); ++ support_record_failure (); ++ continue; ++ } + + int status = support_capture_subprogram_self_sgid (buf); + +@@ -139,9 +155,14 @@ do_test (int argc, char **argv) + if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) + return EXIT_UNSUPPORTED; + +- ret |= status; ++ if (WEXITSTATUS (status) != 42) ++ { ++ printf (" [%d] child failed with status %d\n", i, ++ WEXITSTATUS (status)); ++ support_record_failure (); ++ } + } +- return ret; ++ return 0; + } + } + +diff --git a/elf/tst-ldconfig-p.sh b/elf/tst-ldconfig-p.sh +new file mode 100644 +index 0000000000..ec937bf4ec +--- /dev/null ++++ b/elf/tst-ldconfig-p.sh +@@ -0,0 +1,77 @@ ++#!/bin/sh ++# Test that ldconfig -p prints something useful. ++# Copyright (C) 2023 Free Software Foundation, Inc. ++# This file is part of the GNU C Library. ++ ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++ ++# The GNU C Library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++ ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# . ++ ++# Check that the newly built ldconfig -p can dump the system ++# /etc/ld.so.cache file. This should always work even if the ABIs are ++# not compatible, except in a cross-endian build (that presumably ++# involves emulation when running ldconfig). ++ ++common_objpfx=$1 ++test_wrapper_env=$2 ++run_program_env=$3 ++ ++if ! test -r /etc/ld.so.cache; then ++ echo "warning: /etc/ld.so.cache does not exist, test skipped" ++ exit 77 ++fi ++ ++testout="${common_objpfx}elf/tst-ldconfig-p.out" ++# Truncate file. ++: > "$testout" ++ ++${test_wrapper_env} \ ++${run_program_env} \ ++${common_objpfx}elf/ldconfig -p \ ++ $testroot/lib >>"$testout" 2>>"$testout" ++status=$? ++echo "info: ldconfig exit status: $status" >>"$testout" ++ ++errors=0 ++case $status in ++ (0) ++ if head -n 1 "$testout" | \ ++ grep -q "libs found in cache \`/etc/ld.so.cache'\$" ; then ++ echo "info: initial string found" >>"$testout" ++ else ++ echo "error: initial string not found" >>"$testout" ++ errors=1 ++ fi ++ if grep -q "^ libc\.so\..* => " "$testout"; then ++ echo "info: libc.so.* string found" >>"$testout" ++ else ++ echo "error: libc.so.* string not found" >>"$testout" ++ errors=1 ++ fi ++ ;; ++ (1) ++ if head -n 1 "$testout" | \ ++ grep -q ": Cache file has wrong endianness\.$" ; then ++ echo "info: cache file has wrong endianess" >> "$testout" ++ else ++ echo "error: unexpected ldconfig error message" >> "$testout" ++ errors=1 ++ fi ++ ;; ++ (*) ++ echo "error: unexpected exit status" >> "$testout" ++ errors=1 ++ ;; ++esac ++ ++exit $errors +diff --git a/gmon/Makefile b/gmon/Makefile +index 552b7d7751..fbe2b0ba5c 100644 +--- a/gmon/Makefile ++++ b/gmon/Makefile +@@ -1,4 +1,5 @@ +-# Copyright (C) 1995-2022 Free Software Foundation, Inc. ++# Copyright (C) 1995-2023 Free Software Foundation, Inc. ++# Copyright The GNU Toolchain Authors. + # This file is part of the GNU C Library. + + # The GNU C Library is free software; you can redistribute it and/or +@@ -25,7 +26,7 @@ include ../Makeconfig + headers := sys/gmon.h sys/gmon_out.h sys/profil.h + routines := gmon mcount profil sprofil prof-freq + +-tests = tst-sprofil tst-gmon ++tests = tst-sprofil tst-gmon tst-mcleanup + ifeq ($(build-profile),yes) + tests += tst-profile-static + tests-static += tst-profile-static +@@ -56,6 +57,14 @@ ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)tst-gmon-gprof.out + endif + ++CFLAGS-tst-mcleanup.c := -fno-omit-frame-pointer -pg ++tst-mcleanup-no-pie = yes ++CRT-tst-mcleanup := $(csu-objpfx)g$(start-installed-name) ++tst-mcleanup-ENV := GMON_OUT_PREFIX=$(objpfx)tst-mcleanup.data ++ifeq ($(run-built-tests),yes) ++tests-special += $(objpfx)tst-mcleanup.out ++endif ++ + CFLAGS-tst-gmon-static.c := $(PIE-ccflag) -fno-omit-frame-pointer -pg + CRT-tst-gmon-static := $(csu-objpfx)g$(static-start-installed-name) + tst-gmon-static-no-pie = yes +@@ -103,6 +112,18 @@ $(objpfx)tst-gmon.out: clean-tst-gmon-data + clean-tst-gmon-data: + rm -f $(objpfx)tst-gmon.data.* + ++$(objpfx)tst-mcount-overflow.o: clean-tst-mcount-overflow-data ++clean-tst-mcount-overflow-data: ++ rm -f $(objpfx)tst-mcount-overflow.data.* ++ ++$(objpfx)tst-mcount-overflow-check.out: tst-mcount-overflow-check.sh $(objpfx)tst-mcount-overflow.out ++ $(SHELL) $< $(objpfx)tst-mcount-overflow > $@; \ ++ $(evaluate-test) ++ ++$(objpfx)tst-mcleanup.out: clean-tst-mcleanup-data ++clean-tst-mcleanup-data: ++ rm -f $(objpfx)tst-mcleanup.data.* ++ + $(objpfx)tst-gmon-gprof.out: tst-gmon-gprof.sh $(objpfx)tst-gmon.out + $(SHELL) $< $(GPROF) $(objpfx)tst-gmon $(objpfx)tst-gmon.data.* > $@; \ + $(evaluate-test) +diff --git a/gmon/gmon.c b/gmon/gmon.c +index dee64803ad..97be1f72ca 100644 +--- a/gmon/gmon.c ++++ b/gmon/gmon.c +@@ -97,11 +97,8 @@ __moncontrol (int mode) + { + struct gmonparam *p = &_gmonparam; + +- /* Don't change the state if we ran into an error. */ +- if (p->state == GMON_PROF_ERROR) +- return; +- +- if (mode) ++ /* Treat start request as stop if error or gmon not initialized. */ ++ if (mode && p->state != GMON_PROF_ERROR && p->tos != NULL) + { + /* start */ + __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale); +@@ -111,7 +108,9 @@ __moncontrol (int mode) + { + /* stop */ + __profil(NULL, 0, 0, 0); +- p->state = GMON_PROF_OFF; ++ /* Don't change the state if we ran into an error. */ ++ if (p->state != GMON_PROF_ERROR) ++ p->state = GMON_PROF_OFF; + } + } + libc_hidden_def (__moncontrol) +@@ -124,6 +123,19 @@ __monstartup (u_long lowpc, u_long highpc) + int o; + char *cp; + struct gmonparam *p = &_gmonparam; ++ long int minarcs, maxarcs; ++ ++ /* No tunables, we use hardcoded defaults */ ++ minarcs = MINARCS; ++ maxarcs = MAXARCS; ++ ++ /* ++ * If we are incorrectly called twice in a row (without an ++ * intervening call to _mcleanup), ignore the second call to ++ * prevent leaking memory. ++ */ ++ if (p->tos != NULL) ++ return; + + /* + * round lowpc and highpc to multiples of the density we're using +@@ -132,6 +144,8 @@ __monstartup (u_long lowpc, u_long highpc) + p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->textsize = p->highpc - p->lowpc; ++ /* This looks like a typo, but it's here to align the p->froms ++ section. */ + p->kcountsize = ROUNDUP(p->textsize / HISTFRACTION, sizeof(*p->froms)); + p->hashfraction = HASHFRACTION; + p->log_hashfraction = -1; +@@ -142,12 +156,12 @@ __monstartup (u_long lowpc, u_long highpc) + instead of integer division. Precompute shift amount. */ + p->log_hashfraction = ffs(p->hashfraction * sizeof(*p->froms)) - 1; + } +- p->fromssize = p->textsize / HASHFRACTION; ++ p->fromssize = ROUNDUP(p->textsize / HASHFRACTION, sizeof(*p->froms)); + p->tolimit = p->textsize * ARCDENSITY / 100; +- if (p->tolimit < MINARCS) +- p->tolimit = MINARCS; +- else if (p->tolimit > MAXARCS) +- p->tolimit = MAXARCS; ++ if (p->tolimit < minarcs) ++ p->tolimit = minarcs; ++ else if (p->tolimit > maxarcs) ++ p->tolimit = maxarcs; + p->tossize = p->tolimit * sizeof(struct tostruct); + + cp = calloc (p->kcountsize + p->fromssize + p->tossize, 1); +@@ -440,9 +454,14 @@ _mcleanup (void) + { + __moncontrol (0); + +- if (_gmonparam.state != GMON_PROF_ERROR) ++ if (_gmonparam.state != GMON_PROF_ERROR && _gmonparam.tos != NULL) + write_gmon (); + + /* free the memory. */ + free (_gmonparam.tos); ++ ++ /* reset buffer to initial state for safety */ ++ memset(&_gmonparam, 0, sizeof _gmonparam); ++ /* somewhat confusingly, ON=0, OFF=3 */ ++ _gmonparam.state = GMON_PROF_OFF; + } +diff --git a/gmon/mcount.c b/gmon/mcount.c +index 9d4a1a50fa..f7180fdb83 100644 +--- a/gmon/mcount.c ++++ b/gmon/mcount.c +@@ -41,6 +41,10 @@ static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; + + #include + ++#include ++#include ++#define ERR(s) __write_nocancel (STDERR_FILENO, s, sizeof (s) - 1) ++ + /* + * mcount is called on entry to each function compiled with the profiling + * switch set. _mcount(), which is declared in a machine-dependent way +@@ -170,6 +174,7 @@ done: + return; + overflow: + p->state = GMON_PROF_ERROR; ++ ERR("mcount: call graph buffer size limit exceeded, gmon.out will not be generated\n"); + return; + } + +diff --git a/gmon/sys/gmon.h b/gmon/sys/gmon.h +index b4cc3b043a..af0582a371 100644 +--- a/gmon/sys/gmon.h ++++ b/gmon/sys/gmon.h +@@ -111,6 +111,8 @@ extern struct __bb *__bb_head; + * Always allocate at least this many tostructs. This + * hides the inadequacy of the ARCDENSITY heuristic, at least + * for small programs. ++ * ++ * Value can be overridden at runtime by glibc.gmon.minarcs tunable. + */ + #define MINARCS 50 + +@@ -124,8 +126,8 @@ extern struct __bb *__bb_head; + * Used to be max representable value of ARCINDEX minus 2, but now + * that ARCINDEX is a long, that's too large; we don't really want + * to allow a 48 gigabyte table. +- * The old value of 1<<16 wasn't high enough in practice for large C++ +- * programs; will 1<<20 be adequate for long? FIXME ++ * ++ * Value can be overridden at runtime by glibc.gmon.maxarcs tunable. + */ + #define MAXARCS (1 << 20) + +diff --git a/gmon/tst-mcleanup.c b/gmon/tst-mcleanup.c +new file mode 100644 +index 0000000000..b259653ec8 +--- /dev/null ++++ b/gmon/tst-mcleanup.c +@@ -0,0 +1,31 @@ ++/* Test program for repeated invocation of _mcleanup ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Intentionally calls _mcleanup() twice: once manually, it will be ++ called again as an atexit handler. This is incorrect use of the API, ++ but the point of the test is to make sure we don't crash when the ++ API is misused in this way. */ ++ ++#include ++ ++int ++main (void) ++{ ++ _mcleanup(); ++ return 0; ++} +diff --git a/gmon/tst-mcount-overflow-check.sh b/gmon/tst-mcount-overflow-check.sh +new file mode 100644 +index 0000000000..27eb5538fd +--- /dev/null ++++ b/gmon/tst-mcount-overflow-check.sh +@@ -0,0 +1,45 @@ ++#!/bin/sh ++# Test expected messages generated when mcount overflows ++# Copyright (C) 2017-2023 Free Software Foundation, Inc. ++# Copyright The GNU Toolchain Authors. ++# This file is part of the GNU C Library. ++ ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++ ++# The GNU C Library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++ ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# . ++ ++LC_ALL=C ++export LC_ALL ++set -e ++exec 2>&1 ++ ++program="$1" ++ ++check_msg() { ++ if ! grep -q "$1" "$program.out"; then ++ echo "FAIL: expected message not in output: $1" ++ exit 1 ++ fi ++} ++ ++check_msg 'monstartup: maxarcs < minarcs, setting maxarcs = minarcs' ++check_msg 'mcount: call graph buffer size limit exceeded, gmon.out will not be generated' ++ ++for data_file in $1.data.*; do ++ if [ -f "$data_file" ]; then ++ echo "FAIL: expected no data files, but found $data_file" ++ exit 1 ++ fi ++done ++ ++echo PASS +diff --git a/gmon/tst-mcount-overflow.c b/gmon/tst-mcount-overflow.c +new file mode 100644 +index 0000000000..06cc93ef87 +--- /dev/null ++++ b/gmon/tst-mcount-overflow.c +@@ -0,0 +1,72 @@ ++/* Test program to trigger mcount overflow in profiling collection. ++ Copyright (C) 2017-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Program with sufficiently complex, yet pointless, call graph ++ that it will trigger an mcount overflow, when you set the ++ minarcs/maxarcs tunables to very low values. */ ++ ++#define PREVENT_TAIL_CALL asm volatile ("") ++ ++/* Calls REP(n) macro 16 times, for n=0..15. ++ * You need to define REP(n) before using this. ++ */ ++#define REPS \ ++ REP(0) REP(1) REP(2) REP(3) REP(4) REP(5) REP(6) REP(7) \ ++ REP(8) REP(9) REP(10) REP(11) REP(12) REP(13) REP(14) REP(15) ++ ++/* Defines 16 leaf functions named f1_0 to f1_15 */ ++#define REP(n) \ ++ __attribute__ ((noinline, noclone, weak)) void f1_##n (void) {}; ++REPS ++#undef REP ++ ++/* Calls all 16 leaf functions f1_* in succession */ ++__attribute__ ((noinline, noclone, weak)) void ++f2 (void) ++{ ++# define REP(n) f1_##n(); ++ REPS ++# undef REP ++ PREVENT_TAIL_CALL; ++} ++ ++/* Defines 16 functions named f2_0 to f2_15, which all just call f2 */ ++#define REP(n) \ ++ __attribute__ ((noinline, noclone, weak)) void \ ++ f2_##n (void) { f2(); PREVENT_TAIL_CALL; }; ++REPS ++#undef REP ++ ++__attribute__ ((noinline, noclone, weak)) void ++f3 (int count) ++{ ++ for (int i = 0; i < count; ++i) ++ { ++ /* Calls f1_0(), f2_0(), f1_1(), f2_1(), f3_0(), etc */ ++# define REP(n) f1_##n(); f2_##n(); ++ REPS ++# undef REP ++ } ++} ++ ++int ++main (void) ++{ ++ f3 (1000); ++ return 0; ++} +diff --git a/gshadow/Makefile b/gshadow/Makefile +index eff303f538..5b3fa7e387 100644 +--- a/gshadow/Makefile ++++ b/gshadow/Makefile +@@ -26,7 +26,7 @@ headers = gshadow.h + routines = getsgent getsgnam sgetsgent fgetsgent putsgent \ + getsgent_r getsgnam_r sgetsgent_r fgetsgent_r + +-tests = tst-gshadow tst-putsgent tst-fgetsgent_r ++tests = tst-gshadow tst-putsgent tst-fgetsgent_r tst-sgetsgent + + CFLAGS-getsgent_r.c += -fexceptions + CFLAGS-getsgent.c += -fexceptions +diff --git a/gshadow/sgetsgent_r.c b/gshadow/sgetsgent_r.c +index 28c826c9b5..a767a643d4 100644 +--- a/gshadow/sgetsgent_r.c ++++ b/gshadow/sgetsgent_r.c +@@ -61,7 +61,10 @@ __sgetsgent_r (const char *string, struct sgrp *resbuf, char *buffer, + buffer[buflen - 1] = '\0'; + sp = strncpy (buffer, string, buflen); + if (buffer[buflen - 1] != '\0') +- return ERANGE; ++ { ++ __set_errno (ERANGE); ++ return ERANGE; ++ } + } + else + sp = (char *) string; +diff --git a/gshadow/tst-sgetsgent.c b/gshadow/tst-sgetsgent.c +new file mode 100644 +index 0000000000..0370c10fd0 +--- /dev/null ++++ b/gshadow/tst-sgetsgent.c +@@ -0,0 +1,69 @@ ++/* Test large input for sgetsgent (bug 30151). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Create a shadow group with 1000 members. */ ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ const char *passwd = "k+zD0nucwfxAo3sw1NXUj6K5vt5M16+X0TVGdE1uFvq5R8V7efJ"; ++ fprintf (mem.out, "group-name:%s::m0", passwd); ++ for (int i = 1; i < 1000; ++i) ++ fprintf (mem.out, ",m%d", i); ++ xfclose_memstream (&mem); ++ ++ /* Call sgetsgent. */ ++ char *input = mem.buffer; ++ struct sgrp *e = sgetsgent (input); ++ TEST_VERIFY_EXIT (e != NULL); ++ TEST_COMPARE_STRING (e->sg_namp, "group-name"); ++ TEST_COMPARE_STRING (e->sg_passwd, passwd); ++ /* No administrators. */ ++ TEST_COMPARE_STRING (e->sg_adm[0], NULL); ++ /* Check the members list. */ ++ for (int i = 0; i < 1000; ++i) ++ { ++ char *member = xasprintf ("m%d", i); ++ TEST_COMPARE_STRING (e->sg_mem[i], member); ++ free (member); ++ } ++ TEST_COMPARE_STRING (e->sg_mem[1000], NULL); ++ ++ /* Check that putsgent brings back the input string. */ ++ xopen_memstream (&mem); ++ TEST_COMPARE (putsgent (e, mem.out), 0); ++ xfclose_memstream (&mem); ++ /* Compare without the trailing '\n' that putsgent added. */ ++ TEST_COMPARE (mem.buffer[mem.length - 1], '\n'); ++ mem.buffer[mem.length - 1] = '\0'; ++ TEST_COMPARE_STRING (mem.buffer, input); ++ ++ free (mem.buffer); ++ free (input); ++ return 0; ++} ++ ++#include +diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h +index debb96b322..b72933b526 100644 +--- a/iconv/gconv_parseconfdir.h ++++ b/iconv/gconv_parseconfdir.h +@@ -29,14 +29,14 @@ + # define isspace(__c) __isspace_l ((__c), _nl_C_locobj_ptr) + # define asprintf __asprintf + # define opendir __opendir +-# define readdir __readdir ++# define readdir64 __readdir64 + # define closedir __closedir + # define mempcpy __mempcpy +-# define struct_stat struct __stat64_t64 +-# define lstat __lstat64_time64 ++# define struct_stat64 struct __stat64_t64 ++# define lstat64 __lstat64_time64 + # define feof_unlocked __feof_unlocked + #else +-# define struct_stat struct stat ++# define struct_stat64 struct stat64 + #endif + + /* Name of the file containing the module information in the directories +@@ -148,8 +148,8 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) + DIR *confdir = opendir (buf); + if (confdir != NULL) + { +- struct dirent *ent; +- while ((ent = readdir (confdir)) != NULL) ++ struct dirent64 *ent; ++ while ((ent = readdir64 (confdir)) != NULL) + { + if (ent->d_type != DT_REG && ent->d_type != DT_UNKNOWN) + continue; +@@ -161,12 +161,12 @@ gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len) + && strcmp (ent->d_name + len - strlen (suffix), suffix) == 0) + { + char *conf; +- struct_stat st; ++ struct_stat64 st; + if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0) + continue; + + if (ent->d_type != DT_UNKNOWN +- || (lstat (conf, &st) != -1 && S_ISREG (st.st_mode))) ++ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode))) + found |= read_conf_file (conf, dir, dir_len); + + free (conf); +diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h +index 53f1dbc7c3..c27e7886b7 100644 +--- a/include/arpa/nameser.h ++++ b/include/arpa/nameser.h +@@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW; + int __ns_name_unpack (const unsigned char *, const unsigned char *, + const unsigned char *, unsigned char *, size_t) __THROW; + ++/* Like ns_samename, but for uncompressed binary names. Return true ++ if the two arguments compare are equal as case-insensitive domain ++ names. */ ++_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *) ++ attribute_hidden; ++ + #define ns_msg_getflag(handle, flag) \ + (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift) + +@@ -89,5 +95,105 @@ libc_hidden_proto (__ns_name_unpack) + extern __typeof (ns_samename) __libc_ns_samename; + libc_hidden_proto (__libc_ns_samename) + ++/* Packet parser helper functions. */ ++ ++/* Verify that P points to an uncompressed domain name in wire format. ++ On success, return the length of the encoded name, including the ++ terminating null byte. On failure, return -1 and set errno. EOM ++ must point one past the last byte in the packet. */ ++int __ns_name_length_uncompressed (const unsigned char *p, ++ const unsigned char *eom) attribute_hidden; ++ ++/* Iterator over the resource records in a DNS packet. */ ++struct ns_rr_cursor ++{ ++ /* These members are not changed after initialization. */ ++ const unsigned char *begin; /* First byte of packet. */ ++ const unsigned char *end; /* One past the last byte of the packet. */ ++ const unsigned char *first_rr; /* First resource record (or packet end). */ ++ ++ /* Advanced towards the end while reading the packet. */ ++ const unsigned char *current; ++}; ++ ++/* Returns the RCODE field from the DNS header. */ ++static inline int ++ns_rr_cursor_rcode (const struct ns_rr_cursor *c) ++{ ++ return c->begin[3] & 0x0f; /* Lower 4 bits at offset 3. */ ++} ++ ++/* Returns the length of the answer section according to the DNS header. */ ++static inline int ++ns_rr_cursor_ancount (const struct ns_rr_cursor *c) ++{ ++ return c->begin[6] * 256 + c->begin[7]; /* 16 bits at offset 6. */ ++} ++ ++/* Returns the length of the authority (name server) section according ++ to the DNS header. */ ++static inline int ++ns_rr_cursor_nscount (const struct ns_rr_cursor *c) ++{ ++ return c->begin[8] * 256 + c->begin[9]; /* 16 bits at offset 8. */ ++} ++ ++/* Returns the length of the additional data section according to the ++ DNS header. */ ++static inline int ++ns_rr_cursor_adcount (const struct ns_rr_cursor *c) ++{ ++ return c->begin[10] * 256 + c->begin[11]; /* 16 bits at offset 10. */ ++} ++ ++/* Returns a pointer to the uncompressed question name in wire ++ format. */ ++static inline const unsigned char * ++ns_rr_cursor_qname (const struct ns_rr_cursor *c) ++{ ++ return c->begin + 12; /* QNAME starts right after the header. */ ++} ++ ++/* Returns the question type of the first and only question. */ ++static inline const int ++ns_rr_cursor_qtype (const struct ns_rr_cursor *c) ++{ ++ /* 16 bits 4 bytes back from the first RR header start. */ ++ return c->first_rr[-4] * 256 + c->first_rr[-3]; ++} ++ ++/* Returns the clss of the first and only question (usally C_IN). */ ++static inline const int ++ns_rr_cursor_qclass (const struct ns_rr_cursor *c) ++{ ++ /* 16 bits 2 bytes back from the first RR header start. */ ++ return c->first_rr[-2] * 256 + c->first_rr[-1]; ++} ++ ++/* Initializes *C to cover the packet [BUF, BUF+LEN). Returns false ++ if LEN is less than sizeof (*HD), if the packet does not contain a ++ full (uncompressed) question, or if the question count is not 1. */ ++_Bool __ns_rr_cursor_init (struct ns_rr_cursor *c, ++ const unsigned char *buf, size_t len) ++ attribute_hidden; ++ ++/* Like ns_rr, but the record owner name is not decoded into text format. */ ++struct ns_rr_wire ++{ ++ unsigned char rname[NS_MAXCDNAME]; /* Owner name of the record. */ ++ uint16_t rtype; /* Resource record type (T_*). */ ++ uint16_t rclass; /* Resource record class (C_*). */ ++ uint32_t ttl; /* Time-to-live field. */ ++ const unsigned char *rdata; /* Start of resource record data. */ ++ uint16_t rdlength; /* Length of the data at rdata, in bytes. */ ++}; ++ ++/* Attempts to parse the record at C into *RR. On success, return ++ true, and C is advanced past the record, and RR->rdata points to ++ the record data. On failure, errno is set to EMSGSIZE, and false ++ is returned. */ ++_Bool __ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr) ++ attribute_hidden; ++ + # endif /* !_ISOMAC */ + #endif +diff --git a/include/bits/wchar2-decl.h b/include/bits/wchar2-decl.h +new file mode 100644 +index 0000000000..00b1b93342 +--- /dev/null ++++ b/include/bits/wchar2-decl.h +@@ -0,0 +1 @@ ++#include +diff --git a/include/link.h b/include/link.h +index 0ac82d7c77..87966e8397 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -278,6 +278,10 @@ struct link_map + /* List of object in order of the init and fini calls. */ + struct link_map **l_initfini; + ++ /* Linked list of objects in reverse ELF constructor execution ++ order. Head of list is stored in _dl_init_called_list. */ ++ struct link_map *l_init_called_next; ++ + /* List of the dependencies introduced through symbol binding. */ + struct link_map_reldeps + { +diff --git a/include/resolv.h b/include/resolv.h +index 3590b6f496..4dbbac3800 100644 +--- a/include/resolv.h ++++ b/include/resolv.h +@@ -70,5 +70,8 @@ libc_hidden_proto (__libc_res_nameinquery) + extern __typeof (__res_queriesmatch) __libc_res_queriesmatch; + libc_hidden_proto (__libc_res_queriesmatch) + ++/* Variant of res_hnok which operates on binary (but uncompressed) names. */ ++bool __res_binary_hnok (const unsigned char *dn) attribute_hidden; ++ + # endif /* _RESOLV_H_ && !_ISOMAC */ + #endif +diff --git a/io/Makefile b/io/Makefile +index b1710407d0..b896484320 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -59,6 +59,7 @@ routines := \ + ftw64-time64 \ + closefrom close_range + ++ + others := pwd + test-srcs := ftwtest ftwtest-time64 + tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ +@@ -80,7 +81,9 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ + tst-utimensat \ + tst-closefrom \ + tst-close_range \ +- tst-ftw-bz28126 ++ tst-ftw-bz28126 \ ++ tst-fcntl-lock \ ++ tst-fcntl-lock-lfs + + tests-time64 := \ + tst-fcntl-time64 \ +diff --git a/io/tst-fcntl-lock-lfs.c b/io/tst-fcntl-lock-lfs.c +new file mode 100644 +index 0000000000..f2a909fb02 +--- /dev/null ++++ b/io/tst-fcntl-lock-lfs.c +@@ -0,0 +1,2 @@ ++#define _FILE_OFFSET_BITS 64 ++#include +diff --git a/io/tst-fcntl-lock.c b/io/tst-fcntl-lock.c +new file mode 100644 +index 0000000000..357c4b7b56 +--- /dev/null ++++ b/io/tst-fcntl-lock.c +@@ -0,0 +1,97 @@ ++/* Test for advisory record locking. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License ++ as published by the Free Software Foundation; either version 2 ++ of the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . ++*/ ++ ++#include ++#include ++#include ++ ++/* This is essentially the POSIX lockf. */ ++ ++static int ++fcntl_lockf (int fd, int cmd, off_t len) ++{ ++ struct flock fl = { ++ .l_type = F_WRLCK, ++ .l_whence = SEEK_CUR, ++ .l_len = len ++ }; ++ ++ switch (cmd) ++ { ++ case F_TEST: ++ fl.l_type = F_RDLCK; ++ if (fcntl (fd, F_GETLK, &fl) < 0) ++ return -1; ++ if (fl.l_type == F_UNLCK || fl.l_pid == getpid ()) ++ return 0; ++ errno = EACCES; ++ return -1; ++ ++ case F_ULOCK: ++ fl.l_type = F_UNLCK; ++ return fcntl (fd, F_SETLK, &fl); ++ ++ case F_LOCK: ++ return fcntl (fd, F_SETLKW, &fl); ++ ++ case F_TLOCK: ++ return fcntl (fd, F_SETLK, &fl); ++ } ++ ++ errno = EINVAL; ++ return -1; ++} ++ ++static int ++fcntl64_lockf (int fd, int cmd, off64_t len64) ++ { ++ struct flock64 fl64 = { ++ .l_type = F_WRLCK, ++ .l_whence = SEEK_CUR, ++ .l_len = len64 ++ }; ++ ++ switch (cmd) ++ { ++ case F_TEST: ++ fl64.l_type = F_RDLCK; ++ if (fcntl64 (fd, F_GETLK64, &fl64) < 0) ++ return -1; ++ if (fl64.l_type == F_UNLCK || fl64.l_pid == getpid ()) ++ return 0; ++ errno = EACCES; ++ return -1; ++ ++ case F_ULOCK: ++ fl64.l_type = F_UNLCK; ++ return fcntl64 (fd, F_SETLK64, &fl64); ++ ++ case F_LOCK: ++ return fcntl64 (fd, F_SETLKW64, &fl64); ++ ++ case F_TLOCK: ++ return fcntl64 (fd, F_SETLK64, &fl64); ++ } ++ ++ errno = EINVAL; ++ return -1; ++} ++ ++#define TST_LOCKFD "tst-fcntl-lock." ++#define LOCKF fcntl_lockf ++#define LOCKF64 fcntl64_lockf ++#include "tst-lockf.c" +diff --git a/io/tst-lockf.c b/io/tst-lockf.c +index be92f33fd1..5e41dc19df 100644 +--- a/io/tst-lockf.c ++++ b/io/tst-lockf.c +@@ -24,13 +24,23 @@ + #include + #include + ++#ifndef TST_LOCKFD ++# define TST_LOCKFD "tst-lockfd." ++#endif ++#ifndef LOCKF ++# define LOCKF lockf ++#endif ++#ifndef LOCKF64 ++# define LOCKF64 lockf64 ++#endif ++ + static char *temp_filename; + static int temp_fd; + + static void + do_prepare (int argc, char **argv) + { +- temp_fd = create_temp_file ("tst-lockfd.", &temp_filename); ++ temp_fd = create_temp_file (TST_LOCKFD, &temp_filename); + TEST_VERIFY_EXIT (temp_fd != -1); + } + #define PREPARE do_prepare +@@ -40,22 +50,22 @@ do_test_child_lockf (void *closure) + { + /* Check if parent has [0, 1024) locked. */ + TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0); +- TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), -1); ++ TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), -1); + TEST_COMPARE (errno, EAGAIN); +- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1); ++ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (errno, EACCES); + /* Also Check if parent has last 1024 bytes locked. */ + TEST_COMPARE (lseek (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024); +- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), -1); ++ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), -1); + + /* And try to lock [1024, 2048). */ + TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024); +- TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0); + + /* Check if non-LFS interface cap access to 32-bif off_t. */ + TEST_COMPARE (lseek64 (temp_fd, (off64_t)INT32_MAX, SEEK_SET), + (off64_t)INT32_MAX); +- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0); + } + + static void +@@ -63,32 +73,32 @@ do_test_child_lockf64 (void *closure) + { + /* Check if parent has [0, 1024) locked. */ + TEST_COMPARE (lseek64 (temp_fd, 0, SEEK_SET), 0); +- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1); + TEST_COMPARE (errno, EAGAIN); +- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (errno, EACCES); + /* Also Check if parent has last 1024 bytes locked. */ + TEST_COMPARE (lseek64 (temp_fd, INT32_MAX-1024, SEEK_SET), INT32_MAX-1024); +- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); + + /* And try to lock [1024, 2048). */ + TEST_COMPARE (lseek64 (temp_fd, 1024, SEEK_SET), 1024); +- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); + + /* And also [INT32_MAX, INT32_MAX+1024). */ + { + off64_t off = (off64_t)INT32_MAX; + TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); +- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); + } + + /* Check if [INT32_MAX+1024, INT64_MAX) is locked. */ + { + off64_t off = (off64_t)INT32_MAX+1024; + TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); +- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), -1); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), -1); + TEST_COMPARE (errno, EAGAIN); +- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), -1); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), -1); + TEST_COMPARE (errno, EACCES); + } + } +@@ -97,38 +107,38 @@ static int + do_test (void) + { + /* Basic tests to check if a lock can be obtained and checked. */ +- TEST_COMPARE (lockf (temp_fd, F_LOCK, 1024), 0); +- TEST_COMPARE (lockf (temp_fd, F_LOCK, INT32_MAX), 0); +- TEST_COMPARE (lockf (temp_fd, F_TLOCK, 1024), 0); +- TEST_COMPARE (lockf (temp_fd, F_TEST, 1024), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_LOCK, INT32_MAX), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_TLOCK, 1024), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_TEST, 1024), 0); + TEST_COMPARE (lseek (temp_fd, 1024, SEEK_SET), 1024); +- TEST_COMPARE (lockf (temp_fd, F_ULOCK, 1024), 0); ++ TEST_COMPARE (LOCKF (temp_fd, F_ULOCK, 1024), 0); + /* Parent process should have ([0, 1024), [2048, INT32_MAX)) ranges locked. */ + + { + struct support_capture_subprocess result; + result = support_capture_subprocess (do_test_child_lockf, NULL); +- support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none); ++ support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none); + } + + if (sizeof (off_t) != sizeof (off64_t)) + { + /* Check if previously locked regions with LFS symbol. */ + TEST_COMPARE (lseek (temp_fd, 0, SEEK_SET), 0); +- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); +- TEST_COMPARE (lockf64 (temp_fd, F_TLOCK, 1024), 0); +- TEST_COMPARE (lockf64 (temp_fd, F_TEST, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TLOCK, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_TEST, 1024), 0); + /* Lock region [INT32_MAX+1024, INT64_MAX). */ + off64_t off = (off64_t)INT32_MAX + 1024; + TEST_COMPARE (lseek64 (temp_fd, off, SEEK_SET), off); +- TEST_COMPARE (lockf64 (temp_fd, F_LOCK, 1024), 0); ++ TEST_COMPARE (LOCKF64 (temp_fd, F_LOCK, 1024), 0); + /* Parent process should have ([0, 1024), [2048, INT32_MAX), + [INT32_MAX+1024, INT64_MAX)) ranges locked. */ + + { + struct support_capture_subprocess result; + result = support_capture_subprocess (do_test_child_lockf64, NULL); +- support_capture_subprocess_check (&result, "lockf", 0, sc_allow_none); ++ support_capture_subprocess_check (&result, "LOCKF", 0, sc_allow_none); + } + } + +diff --git a/locale/weight.h b/locale/weight.h +index 8be2d220f8..4a4d5aa6b2 100644 +--- a/locale/weight.h ++++ b/locale/weight.h +@@ -27,7 +27,14 @@ findidx (const int32_t *table, + const unsigned char *extra, + const unsigned char **cpp, size_t len) + { ++ /* With GCC 8 when compiling with -Os the compiler warns that ++ seq1.back_us and seq2.back_us might be used uninitialized. ++ This uninitialized use is impossible for the same reason ++ as described in comments in locale/weightwc.h. */ ++ DIAG_PUSH_NEEDS_COMMENT; ++ DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wmaybe-uninitialized"); + int32_t i = table[*(*cpp)++]; ++ DIAG_POP_NEEDS_COMMENT; + const unsigned char *cp; + const unsigned char *usrc; + +diff --git a/misc/bits/syslog.h b/misc/bits/syslog.h +index fd30dd3114..916d2b6f12 100644 +--- a/misc/bits/syslog.h ++++ b/misc/bits/syslog.h +@@ -24,6 +24,20 @@ + extern void __syslog_chk (int __pri, int __flag, const char *__fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + ++#ifdef __USE_MISC ++extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt, ++ __gnuc_va_list __ap) ++ __attribute__ ((__format__ (__printf__, 3, 0))); ++#endif ++ ++#include ++#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 ++# include ++#endif ++ ++/* The following functions must be used only after applying all asm ++ redirections, e.g. long double asm redirections. */ ++ + #ifdef __va_arg_pack + __fortify_function void + syslog (int __pri, const char *__fmt, ...) +@@ -37,10 +51,6 @@ syslog (int __pri, const char *__fmt, ...) + + + #ifdef __USE_MISC +-extern void __vsyslog_chk (int __pri, int __flag, const char *__fmt, +- __gnuc_va_list __ap) +- __attribute__ ((__format__ (__printf__, 3, 0))); +- + __fortify_function void + vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap) + { +diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h +index f525f67547..294e633335 100644 +--- a/misc/sys/cdefs.h ++++ b/misc/sys/cdefs.h +@@ -152,6 +152,7 @@ + # define __glibc_objsize(__o) __bos (__o) + #endif + ++#if __USE_FORTIFY_LEVEL > 0 + /* Compile time conditions to choose between the regular, _chk and _chk_warn + variants. These conditions should get evaluated to constant and optimized + away. */ +@@ -187,7 +188,7 @@ + ? __ ## f ## _alias (__VA_ARGS__) \ + : (__glibc_unsafe_len (__l, __s, __osz) \ + ? __ ## f ## _chk_warn (__VA_ARGS__, __osz) \ +- : __ ## f ## _chk (__VA_ARGS__, __osz))) \ ++ : __ ## f ## _chk (__VA_ARGS__, __osz))) + + /* Fortify function f, where object size argument passed to f is the number of + elements and not total size. */ +@@ -197,7 +198,8 @@ + ? __ ## f ## _alias (__VA_ARGS__) \ + : (__glibc_unsafe_len (__l, __s, __osz) \ + ? __ ## f ## _chk_warn (__VA_ARGS__, (__osz) / (__s)) \ +- : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) \ ++ : __ ## f ## _chk (__VA_ARGS__, (__osz) / (__s)))) ++#endif + + #if __GNUC_PREREQ (4,3) + # define __warnattr(msg) __attribute__((__warning__ (msg))) +diff --git a/misc/sys/syslog.h b/misc/sys/syslog.h +index d933fea104..3888153ed2 100644 +--- a/misc/sys/syslog.h ++++ b/misc/sys/syslog.h +@@ -205,11 +205,11 @@ extern void vsyslog (int __pri, const char *__fmt, __gnuc_va_list __ap) + /* Define some macros helping to catch buffer overflows. */ + #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function + # include +-#endif +- +-#include +-#if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 +-# include ++#else ++# include ++# if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 ++# include ++# endif + #endif + + __END_DECLS +diff --git a/misc/syslog.c b/misc/syslog.c +index 554089bfc4..f67d4b58a4 100644 +--- a/misc/syslog.c ++++ b/misc/syslog.c +@@ -167,7 +167,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) +@@ -193,28 +193,32 @@ __vsyslog_internal (int pri, const char *fmt, va_list 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; +- } ++ buf = bufs; ++ bufsize = l + vl; + + va_end (apc); + } + + 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; + + if (has_ts) +- __snprintf (bufs, sizeof bufs, ++ __snprintf (buf, l + 1, + SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); + else +- __snprintf (bufs, sizeof bufs, ++ __snprintf (buf, l + 1, + SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); ++ ++ va_list apc; ++ va_copy (apc, ap); ++ __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, ++ mode_flags); ++ va_end (apc); + } + else + { +diff --git a/misc/tst-syslog.c b/misc/tst-syslog.c +index e550d15796..3560b518a2 100644 +--- a/misc/tst-syslog.c ++++ b/misc/tst-syslog.c +@@ -68,21 +68,19 @@ static const int priorities[] = + LOG_DEBUG + }; + +-enum +- { +- ident_length = 64, +- msg_length = 64 +- }; ++#define IDENT_LENGTH 64 ++#define MSG_LENGTH 1024 + + #define SYSLOG_MSG_BASE "syslog_message" + #define OPENLOG_IDENT "openlog_ident" ++static char large_message[MSG_LENGTH]; + + struct msg_t + { + int priority; + int facility; +- char ident[ident_length]; +- char msg[msg_length]; ++ char ident[IDENT_LENGTH]; ++ char msg[MSG_LENGTH]; + pid_t pid; + }; + +@@ -147,6 +145,37 @@ check_syslog_message (const struct msg_t *msg, int msgnum, int options, + return true; + } + ++static void ++send_syslog_large (int options) ++{ ++ int facility = LOG_USER; ++ int priority = LOG_INFO; ++ ++ syslog (facility | priority, "%s %d %d", large_message, facility, ++ priority); ++} ++ ++static void ++send_vsyslog_large (int options) ++{ ++ int facility = LOG_USER; ++ int priority = LOG_INFO; ++ ++ call_vsyslog (facility | priority, "%s %d %d", large_message, facility, ++ priority); ++} ++ ++static bool ++check_syslog_message_large (const struct msg_t *msg, int msgnum, int options, ++ pid_t pid) ++{ ++ TEST_COMPARE (msg->facility, LOG_USER); ++ TEST_COMPARE (msg->priority, LOG_INFO); ++ TEST_COMPARE_STRING (msg->msg, large_message); ++ ++ return false; ++} ++ + static void + send_openlog (int options) + { +@@ -179,6 +208,17 @@ send_openlog (int options) + closelog (); + } + ++static void ++send_openlog_large (int options) ++{ ++ /* Define a non-default IDENT and a not default facility. */ ++ openlog (OPENLOG_IDENT, options, LOG_LOCAL0); ++ ++ syslog (LOG_INFO, "%s %d %d", large_message, LOG_LOCAL0, LOG_INFO); ++ ++ closelog (); ++} ++ + static bool + check_openlog_message (const struct msg_t *msg, int msgnum, + int options, pid_t pid) +@@ -189,7 +229,7 @@ check_openlog_message (const struct msg_t *msg, int msgnum, + int expected_priority = priorities[msgnum % array_length (priorities)]; + TEST_COMPARE (msg->priority, expected_priority); + +- char expected_ident[ident_length]; ++ char expected_ident[IDENT_LENGTH]; + snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:", + OPENLOG_IDENT, + options & LOG_PID ? "[" : "", +@@ -211,17 +251,43 @@ check_openlog_message (const struct msg_t *msg, int msgnum, + return true; + } + ++static bool ++check_openlog_message_large (const struct msg_t *msg, int msgnum, ++ int options, pid_t pid) ++{ ++ char expected_ident[IDENT_LENGTH]; ++ snprintf (expected_ident, sizeof (expected_ident), "%s%s%.0d%s:", ++ OPENLOG_IDENT, ++ options & LOG_PID ? "[" : "", ++ options & LOG_PID ? pid : 0, ++ options & LOG_PID ? "]" : ""); ++ ++ TEST_COMPARE_STRING (msg->ident, expected_ident); ++ TEST_COMPARE_STRING (msg->msg, large_message); ++ TEST_COMPARE (msg->priority, LOG_INFO); ++ TEST_COMPARE (msg->facility, LOG_LOCAL0); ++ ++ return false; ++} ++ + static struct msg_t + parse_syslog_msg (const char *msg) + { + struct msg_t r = { .pid = -1 }; + int number; ++ int wsb, wsa; ++ ++#define STRINPUT(size) XSTRINPUT(size) ++#define XSTRINPUT(size) "%" # size "s" + + /* The message in the form: +- <179>Apr 8 14:51:19 tst-syslog: syslog message 176 3 */ +- int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d %32s %64s %*d %*d", +- &number, r.ident, r.msg); ++ <179>Apr 8 14:51:19 tst-syslog: message 176 3 */ ++ int n = sscanf (msg, "<%3d>%*s %*d %*d:%*d:%*d%n %n" STRINPUT(IDENT_LENGTH) ++ " " STRINPUT(MSG_LENGTH) " %*d %*d", ++ &number, &wsb, &wsa, r.ident, r.msg); + TEST_COMPARE (n, 3); ++ /* It should only one space between timestamp and message. */ ++ TEST_COMPARE (wsa - wsb, 1); + + r.facility = number & LOG_FACMASK; + r.priority = number & LOG_PRIMASK; +@@ -246,7 +312,7 @@ parse_syslog_console (const char *msg) + + /* The message in the form: + openlog_ident: syslog_message 128 0 */ +- int n = sscanf (msg, "%32s %64s %d %d", ++ int n = sscanf (msg, STRINPUT(IDENT_LENGTH) " " STRINPUT(MSG_LENGTH) " %d %d", + r.ident, r.msg, &facility, &priority); + TEST_COMPARE (n, 4); + +@@ -281,7 +347,7 @@ check_syslog_udp (void (*syslog_send)(int), int options, + int msgnum = 0; + while (1) + { +- char buf[512]; ++ char buf[2048]; + size_t l = xrecvfrom (server_udp, buf, sizeof (buf), 0, + (struct sockaddr *) &addr, &addrlen); + buf[l] = '\0'; +@@ -325,7 +391,7 @@ check_syslog_tcp (void (*syslog_send)(int), int options, + + int client_tcp = xaccept (server_tcp, NULL, NULL); + +- char buf[512], *rb = buf; ++ char buf[2048], *rb = buf; + size_t rbl = sizeof (buf); + size_t prl = 0; /* Track the size of the partial record. */ + int msgnum = 0; +@@ -393,20 +459,34 @@ check_syslog_console_read (FILE *fp) + } + + static void +-check_syslog_console (void) ++check_syslog_console_read_large (FILE *fp) ++{ ++ char buf[2048]; ++ TEST_VERIFY (fgets (buf, sizeof (buf), fp) != NULL); ++ struct msg_t msg = parse_syslog_console (buf); ++ ++ TEST_COMPARE_STRING (msg.ident, OPENLOG_IDENT ":"); ++ TEST_COMPARE_STRING (msg.msg, large_message); ++ TEST_COMPARE (msg.priority, LOG_INFO); ++ TEST_COMPARE (msg.facility, LOG_LOCAL0); ++} ++ ++static void ++check_syslog_console (void (*syslog_send)(int), ++ void (*syslog_check)(FILE *fp)) + { + xmkfifo (_PATH_CONSOLE, 0666); + + pid_t sender_pid = xfork (); + if (sender_pid == 0) + { +- send_openlog (LOG_CONS); ++ syslog_send (LOG_CONS); + _exit (0); + } + + { + FILE *fp = xfopen (_PATH_CONSOLE, "r+"); +- check_syslog_console_read (fp); ++ syslog_check (fp); + xfclose (fp); + } + +@@ -425,16 +505,28 @@ send_openlog_callback (void *clousure) + } + + static void +-check_syslog_perror (void) ++send_openlog_callback_large (void *clousure) ++{ ++ int options = *(int *) clousure; ++ send_openlog_large (options); ++} ++ ++static void ++check_syslog_perror (bool large) + { + struct support_capture_subprocess result; +- result = support_capture_subprocess (send_openlog_callback, ++ result = support_capture_subprocess (large ++ ? send_openlog_callback_large ++ : send_openlog_callback, + &(int){LOG_PERROR}); + + FILE *mfp = fmemopen (result.err.buffer, result.err.length, "r"); + if (mfp == NULL) + FAIL_EXIT1 ("fmemopen: %m"); +- check_syslog_console_read (mfp); ++ if (large) ++ check_syslog_console_read_large (mfp); ++ else ++ check_syslog_console_read (mfp); + xfclose (mfp); + + support_capture_subprocess_check (&result, "tst-openlog-child", 0, +@@ -462,10 +554,31 @@ do_test (void) + check_syslog_tcp (send_openlog, LOG_PID, check_openlog_message); + + /* Check the LOG_CONS option. */ +- check_syslog_console (); ++ check_syslog_console (send_openlog, check_syslog_console_read); + + /* Check the LOG_PERROR option. */ +- check_syslog_perror (); ++ check_syslog_perror (false); ++ ++ /* Similar tests as before, but with a large message to trigger the ++ syslog path that uses dynamically allocated memory. */ ++ memset (large_message, 'a', sizeof large_message - 1); ++ large_message[sizeof large_message - 1] = '\0'; ++ ++ check_syslog_udp (send_syslog_large, 0, check_syslog_message_large); ++ check_syslog_tcp (send_syslog_large, 0, check_syslog_message_large); ++ ++ check_syslog_udp (send_vsyslog_large, 0, check_syslog_message_large); ++ check_syslog_tcp (send_vsyslog_large, 0, check_syslog_message_large); ++ ++ check_syslog_udp (send_openlog_large, 0, check_openlog_message_large); ++ check_syslog_tcp (send_openlog_large, 0, check_openlog_message_large); ++ ++ check_syslog_udp (send_openlog_large, LOG_PID, check_openlog_message_large); ++ check_syslog_tcp (send_openlog_large, LOG_PID, check_openlog_message_large); ++ ++ check_syslog_console (send_openlog_large, check_syslog_console_read_large); ++ ++ check_syslog_perror (true); + + return 0; + } +diff --git a/nis/nis_call.c b/nis/nis_call.c +index 90187e30b1..5b9dd50151 100644 +--- a/nis/nis_call.c ++++ b/nis/nis_call.c +@@ -574,7 +574,7 @@ static struct nis_server_cache + unsigned int size; + unsigned int server_used; + unsigned int current_ep; +- __time64_t expires; ++ time_t expires; + char name[]; + } *nis_server_cache[16]; + static time_t nis_cold_start_mtime; +@@ -583,7 +583,7 @@ __libc_lock_define_initialized (static, nis_server_cache_lock) + static directory_obj * + nis_server_cache_search (const_nis_name name, int search_parent, + unsigned int *server_used, unsigned int *current_ep, +- struct __timespec64 *now) ++ struct timespec *now) + { + directory_obj *ret = NULL; + int i; +@@ -641,7 +641,7 @@ nis_server_cache_search (const_nis_name name, int search_parent, + static void + nis_server_cache_add (const_nis_name name, int search_parent, + directory_obj *dir, unsigned int server_used, +- unsigned int current_ep, struct __timespec64 *now) ++ unsigned int current_ep, struct timespec *now) + { + struct nis_server_cache **loc; + struct nis_server_cache *new; +@@ -707,7 +707,7 @@ __nisfind_server (const_nis_name name, int search_parent, + nis_error result = NIS_SUCCESS; + nis_error status; + directory_obj *obj; +- struct __timespec64 ts; ++ struct timespec ts; + unsigned int server_used = ~0; + unsigned int current_ep = ~0; + +@@ -717,7 +717,7 @@ __nisfind_server (const_nis_name name, int search_parent, + if (*dir != NULL) + return NIS_SUCCESS; + +- __clock_gettime64 (CLOCK_REALTIME, &ts); ++ clock_gettime (CLOCK_REALTIME, &ts); + + if ((flags & NO_CACHE) == 0) + *dir = nis_server_cache_search (name, search_parent, &server_used, +diff --git a/nscd/aicache.c b/nscd/aicache.c +index 51e793199f..e0baed170b 100644 +--- a/nscd/aicache.c ++++ b/nscd/aicache.c +@@ -110,11 +110,10 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + "gethostbyname4_r"); + if (fct4 != NULL) + { +- struct gaih_addrtuple atmem; + struct gaih_addrtuple *at; + while (1) + { +- at = &atmem; ++ at = NULL; + rc6 = 0; + herrno = 0; + status[1] = DL_CALL_FCT (fct4, (key, &at, +@@ -137,7 +136,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req, + goto next_nip; + + /* We found the data. Count the addresses and the size. */ +- for (const struct gaih_addrtuple *at2 = at = &atmem; at2 != NULL; ++ for (const struct gaih_addrtuple *at2 = at; at2 != NULL; + at2 = at2->next) + { + ++naddrs; +diff --git a/nscd/connections.c b/nscd/connections.c +index 61d1674eb4..531d2e83df 100644 +--- a/nscd/connections.c ++++ b/nscd/connections.c +@@ -2284,7 +2284,8 @@ main_loop_epoll (int efd) + sizeof (buf))) != -1) + ; + +- __bump_nl_timestamp (); ++ dbs[hstdb].head->extra_data[NSCD_HST_IDX_CONF_TIMESTAMP] ++ = __bump_nl_timestamp (); + } + # endif + else +diff --git a/nscd/nscd.h b/nscd/nscd.h +index 368091aef8..f15321585b 100644 +--- a/nscd/nscd.h ++++ b/nscd/nscd.h +@@ -65,7 +65,7 @@ typedef enum + struct traced_file + { + /* Tracks the last modified time of the traced file. */ +- time_t mtime; ++ __time64_t mtime; + /* Support multiple registered files per database. */ + struct traced_file *next; + int call_res_init; +diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c +index 9becb62033..31c64275f0 100644 +--- a/nscd/nscd_gethst_r.c ++++ b/nscd/nscd_gethst_r.c +@@ -112,7 +112,7 @@ __nscd_get_nl_timestamp (void) + if (map == NULL + || (map != NO_MAPPING + && map->head->nscd_certainly_running == 0 +- && map->head->timestamp + MAPPING_TIMEOUT < time_now ())) ++ && map->head->timestamp + MAPPING_TIMEOUT < time64_now ())) + map = __nscd_get_mapping (GETFDHST, "hosts", &__hst_map_handle.mapped); + + if (map == NO_MAPPING) +diff --git a/nss/Makefile b/nss/Makefile +index a978e3927a..7a52c68791 100644 +--- a/nss/Makefile ++++ b/nss/Makefile +@@ -81,6 +81,7 @@ tests-container := \ + tst-nss-test3 \ + tst-reload1 \ + tst-reload2 \ ++ tst-nss-gai-hv2-canonname \ + # tests-container + + # Tests which need libdl +@@ -144,7 +145,17 @@ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes)) + ifeq ($(build-static-nss),yes) + tests-static += tst-nss-static + endif +-extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os ++extra-test-objs += nss_test1.os nss_test2.os nss_test_errno.os \ ++ nss_test_gai_hv2_canonname.os ++ ++ifeq ($(run-built-tests),yes) ++ifneq (no,$(PERL)) ++tests-special += $(objpfx)mtrace-tst-nss-gai-hv2-canonname.out ++endif ++endif ++ ++generated += mtrace-tst-nss-gai-hv2-canonname.out \ ++ tst-nss-gai-hv2-canonname.mtrace + + include ../Rules + +@@ -179,12 +190,16 @@ rtld-tests-LDFLAGS += -Wl,--dynamic-list=nss_test.ver + libof-nss_test1 = extramodules + libof-nss_test2 = extramodules + libof-nss_test_errno = extramodules ++libof-nss_test_gai_hv2_canonname = extramodules + $(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test2.so: $(objpfx)nss_test2.os $(link-libc-deps) + $(build-module) + $(objpfx)/libnss_test_errno.so: $(objpfx)nss_test_errno.os $(link-libc-deps) + $(build-module) ++$(objpfx)/libnss_test_gai_hv2_canonname.so: \ ++ $(objpfx)nss_test_gai_hv2_canonname.os $(link-libc-deps) ++ $(build-module) + $(objpfx)nss_test2.os : nss_test1.c + # Use the nss_files suffix for these objects as well. + $(objpfx)/libnss_test1.so$(libnss_files.so-version): $(objpfx)/libnss_test1.so +@@ -194,10 +209,14 @@ $(objpfx)/libnss_test2.so$(libnss_files.so-version): $(objpfx)/libnss_test2.so + $(objpfx)/libnss_test_errno.so$(libnss_files.so-version): \ + $(objpfx)/libnss_test_errno.so + $(make-link) ++$(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version): \ ++ $(objpfx)/libnss_test_gai_hv2_canonname.so ++ $(make-link) + $(patsubst %,$(objpfx)%.out,$(tests) $(tests-container)) : \ + $(objpfx)/libnss_test1.so$(libnss_files.so-version) \ + $(objpfx)/libnss_test2.so$(libnss_files.so-version) \ +- $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) ++ $(objpfx)/libnss_test_errno.so$(libnss_files.so-version) \ ++ $(objpfx)/libnss_test_gai_hv2_canonname.so$(libnss_files.so-version) + + ifeq (yes,$(have-thread-library)) + $(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library) +@@ -206,6 +225,17 @@ endif + $(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so + $(objpfx)tst-nss-files-alias-truncated.out: $(objpfx)/libnss_files.so + ++tst-nss-gai-hv2-canonname-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-nss-gai-hv2-canonname.mtrace \ ++ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so ++$(objpfx)mtrace-tst-nss-gai-hv2-canonname.out: \ ++ $(objpfx)tst-nss-gai-hv2-canonname.out ++ { test -r $(objpfx)tst-nss-gai-hv2-canonname.mtrace \ ++ || ( echo "tst-nss-gai-hv2-canonname.mtrace does not exist"; exit 77; ) \ ++ && $(common-objpfx)malloc/mtrace \ ++ $(objpfx)tst-nss-gai-hv2-canonname.mtrace; } > $@; \ ++ $(evaluate-test) ++ + # Disable DT_RUNPATH on NSS tests so that the glibc internal NSS + # functions can load testing NSS modules via DT_RPATH. + LDFLAGS-tst-nss-test1 = -Wl,--disable-new-dtags +@@ -214,3 +244,4 @@ LDFLAGS-tst-nss-test3 = -Wl,--disable-new-dtags + LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags + LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags + LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags ++LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags +diff --git a/nss/getent.c b/nss/getent.c +index 8178b4b470..d2d2524b0c 100644 +--- a/nss/getent.c ++++ b/nss/getent.c +@@ -58,6 +58,8 @@ static const struct argp_option args_options[] = + { + { "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") }, + { "no-idn", 'i', NULL, 0, N_("disable IDN encoding") }, ++ { "no-addrconfig", 'A', NULL, 0, ++ N_("do not filter out unsupported IPv4/IPv6 addresses (with ahosts*)") }, + { NULL, 0, NULL, 0, NULL }, + }; + +@@ -79,6 +81,9 @@ static struct argp argp = + /* Additional getaddrinfo flags for IDN encoding. */ + static int idn_flags = AI_IDN | AI_CANONIDN; + ++/* Set to 0 by --no-addrconfig. */ ++static int addrconfig_flags = AI_ADDRCONFIG; ++ + /* Print the version information. */ + static void + print_version (FILE *stream, struct argp_state *state) +@@ -346,7 +351,7 @@ ahosts_keys_int (int af, int xflags, int number, char *key[]) + + struct addrinfo hint; + memset (&hint, '\0', sizeof (hint)); +- hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME ++ hint.ai_flags = (AI_V4MAPPED | addrconfig_flags | AI_CANONNAME + | idn_flags | xflags); + hint.ai_family = af; + +@@ -905,6 +910,10 @@ parse_option (int key, char *arg, struct argp_state *state) + idn_flags = 0; + break; + ++ case 'A': ++ addrconfig_flags = 0; ++ break; ++ + default: + return ARGP_ERR_UNKNOWN; + } +diff --git a/nss/nss_test_gai_hv2_canonname.c b/nss/nss_test_gai_hv2_canonname.c +new file mode 100644 +index 0000000000..4439c83c9f +--- /dev/null ++++ b/nss/nss_test_gai_hv2_canonname.c +@@ -0,0 +1,56 @@ ++/* NSS service provider that only provides gethostbyname2_r. ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include "nss/tst-nss-gai-hv2-canonname.h" ++ ++/* Catch misnamed and functions. */ ++#pragma GCC diagnostic error "-Wmissing-prototypes" ++NSS_DECLARE_MODULE_FUNCTIONS (test_gai_hv2_canonname) ++ ++extern enum nss_status _nss_files_gethostbyname2_r (const char *, int, ++ struct hostent *, char *, ++ size_t, int *, int *); ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_gethostbyname2_r (const char *name, int af, ++ struct hostent *result, ++ char *buffer, size_t buflen, ++ int *errnop, int *herrnop) ++{ ++ return _nss_files_gethostbyname2_r (name, af, result, buffer, buflen, errnop, ++ herrnop); ++} ++ ++enum nss_status ++_nss_test_gai_hv2_canonname_getcanonname_r (const char *name, char *buffer, ++ size_t buflen, char **result, ++ int *errnop, int *h_errnop) ++{ ++ /* We expect QUERYNAME, which is a small enough string that it shouldn't fail ++ the test. */ ++ if (memcmp (QUERYNAME, name, sizeof (QUERYNAME)) ++ || buflen < sizeof (QUERYNAME)) ++ abort (); ++ ++ strncpy (buffer, name, buflen); ++ *result = buffer; ++ return NSS_STATUS_SUCCESS; ++} +diff --git a/nss/tst-nss-files-hosts-long.c b/nss/tst-nss-files-hosts-long.c +index 3942cf5fca..a7697e3143 100644 +--- a/nss/tst-nss-files-hosts-long.c ++++ b/nss/tst-nss-files-hosts-long.c +@@ -28,14 +28,15 @@ do_test (void) + { + int ret; + +- /* Run getent to fetch the IPv4 address for host test4. +- This forces /etc/hosts to be parsed. */ +- ret = system("getent ahostsv4 test4"); ++ /* Run getent to fetch the IPv4 address for host test4. This forces ++ /etc/hosts to be parsed. Use --no-addrconfig to return addresses ++ even in an IPv6-only environment. */ ++ ret = system("getent --no-addrconfig ahostsv4 test4"); + if (ret != 0) + FAIL_EXIT1("ahostsv4 failed"); + + /* Likewise for IPv6. */ +- ret = system("getent ahostsv6 test6"); ++ ret = system("getent --no-addrconfig ahostsv6 test6"); + if (ret != 0) + FAIL_EXIT1("ahostsv6 failed"); + +diff --git a/nss/tst-nss-gai-hv2-canonname.c b/nss/tst-nss-gai-hv2-canonname.c +new file mode 100644 +index 0000000000..7db53cf09d +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.c +@@ -0,0 +1,66 @@ ++/* Test NSS query path for plugins that only implement gethostbyname2 ++ (#30843). ++ Copyright The GNU Toolchain Authors. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "nss/tst-nss-gai-hv2-canonname.h" ++ ++#define PREPARE do_prepare ++ ++static void do_prepare (int a, char **av) ++{ ++ FILE *hosts = xfopen ("/etc/hosts", "w"); ++ for (unsigned i = 2; i < 255; i++) ++ { ++ fprintf (hosts, "ff01::ff02:ff03:%u:2\ttest.example.com\n", i); ++ fprintf (hosts, "192.168.0.%u\ttest.example.com\n", i); ++ } ++ xfclose (hosts); ++} ++ ++static int ++do_test (void) ++{ ++ mtrace (); ++ ++ __nss_configure_lookup ("hosts", "test_gai_hv2_canonname"); ++ ++ struct addrinfo hints = {}; ++ struct addrinfo *result = NULL; ++ ++ hints.ai_family = AF_INET6; ++ hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_CANONNAME; ++ ++ int ret = getaddrinfo (QUERYNAME, NULL, &hints, &result); ++ ++ if (ret != 0) ++ FAIL_EXIT1 ("getaddrinfo failed: %s\n", gai_strerror (ret)); ++ ++ TEST_COMPARE_STRING (result->ai_canonname, QUERYNAME); ++ ++ freeaddrinfo(result); ++ return 0; ++} ++ ++#include +diff --git a/nss/tst-nss-gai-hv2-canonname.h b/nss/tst-nss-gai-hv2-canonname.h +new file mode 100644 +index 0000000000..14f2a9cb08 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.h +@@ -0,0 +1 @@ ++#define QUERYNAME "test.example.com" +diff --git a/nss/tst-nss-gai-hv2-canonname.root/postclean.req b/nss/tst-nss-gai-hv2-canonname.root/postclean.req +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script +new file mode 100644 +index 0000000000..31848b4a28 +--- /dev/null ++++ b/nss/tst-nss-gai-hv2-canonname.root/tst-nss-gai-hv2-canonname.script +@@ -0,0 +1,2 @@ ++cp $B/nss/libnss_test_gai_hv2_canonname.so $L/libnss_test_gai_hv2_canonname.so.2 ++su +diff --git a/nss/tst-reload1.c b/nss/tst-reload1.c +index fdc5bdd65b..bc32bb132a 100644 +--- a/nss/tst-reload1.c ++++ b/nss/tst-reload1.c +@@ -43,12 +43,12 @@ static struct passwd pwd_table_1[] = { + + static const char *hostaddr_5[] = + { +- "ABCD", "abcd", "1234", NULL ++ "ABCd", "ABCD", "ABC4", NULL + }; + + static const char *hostaddr_15[] = + { +- "4321", "ghij", NULL ++ "4321", "4322", NULL + }; + + static const char *hostaddr_25[] = +@@ -86,12 +86,12 @@ static const char *hostaddr_6[] = + + static const char *hostaddr_16[] = + { +- "7890", "a1b2", NULL ++ "7890", "7891", NULL + }; + + static const char *hostaddr_26[] = + { +- "qwer", "tyui", NULL ++ "qwer", "qweR", NULL + }; + + static struct hostent host_table_2[] = { +diff --git a/resolv/Makefile b/resolv/Makefile +index 5b15321f9b..28cedf49ee 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -40,12 +40,16 @@ routines := \ + inet_pton \ + ns_makecanon \ + ns_name_compress \ ++ ns_name_length_uncompressed \ + ns_name_ntop \ + ns_name_pack \ + ns_name_pton \ + ns_name_skip \ + ns_name_uncompress \ + ns_name_unpack \ ++ ns_rr_cursor_init \ ++ ns_rr_cursor_next \ ++ ns_samebinaryname \ + ns_samename \ + nsap_addr \ + nss_dns_functions \ +@@ -89,11 +93,15 @@ tests += \ + tst-ns_name_pton \ + tst-res_hconf_reorder \ + tst-res_hnok \ ++ tst-resolv-aliases \ + tst-resolv-basic \ + tst-resolv-binary \ ++ tst-resolv-byaddr \ + tst-resolv-edns \ ++ tst-resolv-invalid-cname \ + tst-resolv-network \ + tst-resolv-noaaaa \ ++ tst-resolv-noaaaa-vc \ + tst-resolv-nondecimal \ + tst-resolv-res_init-multi \ + tst-resolv-search \ +@@ -104,6 +112,18 @@ tests += \ + tests-internal += tst-resolv-txnid-collision + tests-static += tst-resolv-txnid-collision + ++# Likewise for __ns_samebinaryname. ++tests-internal += tst-ns_samebinaryname ++tests-static += tst-ns_samebinaryname ++ ++# Likewise for __ns_name_length_uncompressed. ++tests-internal += tst-ns_name_length_uncompressed ++tests-static += tst-ns_name_length_uncompressed ++ ++# Likewise for struct ns_rr_cursor and its functions. ++tests-internal += tst-ns_rr_cursor ++tests-static += tst-ns_rr_cursor ++ + # These tests need libdl. + ifeq (yes,$(build-shared)) + tests += \ +@@ -258,8 +278,10 @@ $(objpfx)tst-resolv-ai_idn.out: $(gen-locales) + $(objpfx)tst-resolv-ai_idn-latin1.out: $(gen-locales) + $(objpfx)tst-resolv-ai_idn-nolibidn2.out: \ + $(gen-locales) $(objpfx)tst-no-libidn2.so ++$(objpfx)tst-resolv-aliases: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-binary: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-byaddr: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-res_init: $(objpfx)libresolv.so +@@ -267,7 +289,10 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \ + $(shared-thread-library) + $(objpfx)tst-resolv-res_init-thread: $(objpfx)libresolv.so \ + $(shared-thread-library) ++$(objpfx)tst-resolv-invalid-cname: $(objpfx)libresolv.so \ ++ $(shared-thread-library) + $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library) ++$(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) + $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/README b/resolv/README +index 514e9bb617..2146bc3b27 100644 +--- a/resolv/README ++++ b/resolv/README +@@ -146,6 +146,3 @@ res_libc.c is home-brewn, although parts of it are taken from res_data.c. + + res_hconf.c and res_hconf.h were contributed by David Mosberger, and + do not come from BIND. +- +-The files gethnamaddr.c, mapv4v6addr.h and mapv4v6hostent.h are +-leftovers from BIND 4.9.7. +diff --git a/resolv/mapv4v6addr.h b/resolv/mapv4v6addr.h +deleted file mode 100644 +index 7f85f7d5e3..0000000000 +--- a/resolv/mapv4v6addr.h ++++ /dev/null +@@ -1,69 +0,0 @@ +-/* +- * ++Copyright++ 1985, 1988, 1993 +- * - +- * Copyright (c) 1985, 1988, 1993 +- * The Regents of the University of California. All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 4. Neither the name of the University nor the names of its contributors +- * may be used to endorse or promote products derived from this software +- * without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +- * SUCH DAMAGE. +- * - +- * Portions Copyright (c) 1993 by Digital Equipment Corporation. +- * +- * Permission to use, copy, modify, and distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies, and that +- * the name of Digital Equipment Corporation not be used in advertising or +- * publicity pertaining to distribution of the document or software without +- * specific, written prior permission. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +- * SOFTWARE. +- * - +- * --Copyright-- +- */ +- +-#include +-#include +- +-static void +-map_v4v6_address (const char *src, char *dst) +-{ +- u_char *p = (u_char *) dst; +- int i; +- +- /* Move the IPv4 part to the right position. */ +- memcpy (dst + 12, src, INADDRSZ); +- +- /* Mark this ipv6 addr as a mapped ipv4. */ +- for (i = 0; i < 10; i++) +- *p++ = 0x00; +- *p++ = 0xff; +- *p = 0xff; +-} +diff --git a/resolv/mapv4v6hostent.h b/resolv/mapv4v6hostent.h +deleted file mode 100644 +index c11038adf3..0000000000 +--- a/resolv/mapv4v6hostent.h ++++ /dev/null +@@ -1,84 +0,0 @@ +-/* +- * ++Copyright++ 1985, 1988, 1993 +- * - +- * Copyright (c) 1985, 1988, 1993 +- * The Regents of the University of California. All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer. +- * 2. Redistributions in binary form must reproduce the above copyright +- * notice, this list of conditions and the following disclaimer in the +- * documentation and/or other materials provided with the distribution. +- * 4. Neither the name of the University nor the names of its contributors +- * may be used to endorse or promote products derived from this software +- * without specific prior written permission. +- * +- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +- * SUCH DAMAGE. +- * - +- * Portions Copyright (c) 1993 by Digital Equipment Corporation. +- * +- * Permission to use, copy, modify, and distribute this software for any +- * purpose with or without fee is hereby granted, provided that the above +- * copyright notice and this permission notice appear in all copies, and that +- * the name of Digital Equipment Corporation not be used in advertising or +- * publicity pertaining to distribution of the document or software without +- * specific, written prior permission. +- * +- * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL +- * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES +- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT +- * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +- * SOFTWARE. +- * - +- * --Copyright-- +- */ +- +-#include +-#include +- +-typedef union { +- int32_t al; +- char ac; +-} align; +- +-static int +-map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp) +-{ +- char **ap; +- +- if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) +- return 0; +- hp->h_addrtype = AF_INET6; +- hp->h_length = IN6ADDRSZ; +- for (ap = hp->h_addr_list; *ap; ap++) +- { +- int i = sizeof (align) - ((u_long) *bpp % sizeof (align)); +- +- if (*lenp < (i + IN6ADDRSZ)) +- /* Out of memory. */ +- return 1; +- *bpp += i; +- *lenp -= i; +- map_v4v6_address (*ap, *bpp); +- *ap = *bpp; +- *bpp += IN6ADDRSZ; +- *lenp -= IN6ADDRSZ; +- } +- return 0; +-} +diff --git a/resolv/ns_name_length_uncompressed.c b/resolv/ns_name_length_uncompressed.c +new file mode 100644 +index 0000000000..51296b47ef +--- /dev/null ++++ b/resolv/ns_name_length_uncompressed.c +@@ -0,0 +1,72 @@ ++/* Skip over an uncompressed name in wire format. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++int ++__ns_name_length_uncompressed (const unsigned char *p, ++ const unsigned char *eom) ++{ ++ const unsigned char *start = p; ++ ++ while (true) ++ { ++ if (p == eom) ++ { ++ /* Truncated packet: no room for label length. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ ++ unsigned char b = *p; ++ ++p; ++ if (b == 0) ++ { ++ /* Root label. */ ++ size_t length = p - start; ++ if (length > NS_MAXCDNAME) ++ { ++ /* Domain name too long. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ return length; ++ } ++ ++ if (b <= 63) ++ { ++ /* Regular label. */ ++ if (b <= eom - p) ++ p += b; ++ else ++ { ++ /* Truncated packet: label incomplete. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ } ++ else ++ { ++ /* Compression reference or corrupted label length. */ ++ __set_errno (EMSGSIZE); ++ return -1; ++ } ++ } ++} +diff --git a/resolv/ns_rr_cursor_init.c b/resolv/ns_rr_cursor_init.c +new file mode 100644 +index 0000000000..6ee80b30e9 +--- /dev/null ++++ b/resolv/ns_rr_cursor_init.c +@@ -0,0 +1,62 @@ ++/* Initialize a simple DNS packet parser. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++bool ++__ns_rr_cursor_init (struct ns_rr_cursor *c, ++ const unsigned char *buf, size_t len) ++{ ++ c->begin = buf; ++ c->end = buf + len; ++ ++ /* Check for header size and 16-bit question count value (it must be 1). */ ++ if (len < 12 || buf[4] != 0 || buf[5] != 1) ++ { ++ __set_errno (EMSGSIZE); ++ c->current = c->end; ++ return false; ++ } ++ c->current = buf + 12; ++ ++ int consumed = __ns_name_length_uncompressed (c->current, c->end); ++ if (consumed < 0) ++ { ++ __set_errno (EMSGSIZE); ++ c->current = c->end; ++ c->first_rr = NULL; ++ return false; ++ } ++ c->current += consumed; ++ ++ /* Ensure there is room for question type and class. */ ++ if (c->end - c->current < 4) ++ { ++ __set_errno (EMSGSIZE); ++ c->current = c->end; ++ c->first_rr = NULL; ++ return false; ++ } ++ c->current += 4; ++ c->first_rr = c->current; ++ ++ return true; ++} +diff --git a/resolv/ns_rr_cursor_next.c b/resolv/ns_rr_cursor_next.c +new file mode 100644 +index 0000000000..33652fc5da +--- /dev/null ++++ b/resolv/ns_rr_cursor_next.c +@@ -0,0 +1,74 @@ ++/* Simple DNS record parser without textual name decoding. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++bool ++__ns_rr_cursor_next (struct ns_rr_cursor *c, struct ns_rr_wire *rr) ++{ ++ rr->rdata = NULL; ++ ++ /* Extract the record owner name. */ ++ int consumed = __ns_name_unpack (c->begin, c->end, c->current, ++ rr->rname, sizeof (rr->rname)); ++ if (consumed < 0) ++ { ++ memset (rr, 0, sizeof (*rr)); ++ __set_errno (EMSGSIZE); ++ return false; ++ } ++ c->current += consumed; ++ ++ /* Extract the metadata. */ ++ struct ++ { ++ uint16_t rtype; ++ uint16_t rclass; ++ uint32_t ttl; ++ uint16_t rdlength; ++ } __attribute__ ((packed)) metadata; ++ _Static_assert (sizeof (metadata) == 10, "sizeof metadata"); ++ if (c->end - c->current < sizeof (metadata)) ++ { ++ memset (rr, 0, sizeof (*rr)); ++ __set_errno (EMSGSIZE); ++ return false; ++ } ++ memcpy (&metadata, c->current, sizeof (metadata)); ++ c->current += sizeof (metadata); ++ /* Endianess conversion. */ ++ rr->rtype = ntohs (metadata.rtype); ++ rr->rclass = ntohs (metadata.rclass); ++ rr->ttl = ntohl (metadata.ttl); ++ rr->rdlength = ntohs (metadata.rdlength); ++ ++ /* Extract record data. */ ++ if (c->end - c->current < rr->rdlength) ++ { ++ memset (rr, 0, sizeof (*rr)); ++ __set_errno (EMSGSIZE); ++ return false; ++ } ++ rr->rdata = c->current; ++ c->current += rr->rdlength; ++ ++ return true; ++} +diff --git a/resolv/ns_samebinaryname.c b/resolv/ns_samebinaryname.c +new file mode 100644 +index 0000000000..9a47d8e97a +--- /dev/null ++++ b/resolv/ns_samebinaryname.c +@@ -0,0 +1,55 @@ ++/* Compare two binary domain names for quality. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++/* Convert ASCII letters to upper case. */ ++static inline int ++ascii_toupper (unsigned char ch) ++{ ++ if (ch >= 'a' && ch <= 'z') ++ return ch - 'a' + 'A'; ++ else ++ return ch; ++} ++ ++bool ++__ns_samebinaryname (const unsigned char *a, const unsigned char *b) ++{ ++ while (*a != 0 && *b != 0) ++ { ++ if (*a != *b) ++ /* Different label length. */ ++ return false; ++ int labellen = *a; ++ ++a; ++ ++b; ++ for (int i = 0; i < labellen; ++i) ++ { ++ if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b)) ++ /* Different character in label. */ ++ return false; ++ ++a; ++ ++b; ++ } ++ } ++ ++ /* Match if both names are at the root label. */ ++ return *a == 0 && *b == 0; ++} +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 544cffbecd..227734da5c 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -69,6 +69,7 @@ + * --Copyright-- + */ + ++#include + #include + #include + #include +@@ -86,10 +87,6 @@ + #include + #include + +-/* Get implementations of some internal functions. */ +-#include +-#include +- + #define RESOLVSORT + + #if PACKETSZ > 65536 +@@ -103,32 +100,36 @@ + #endif + #define MAXHOSTNAMELEN 256 + +-/* We need this time later. */ +-typedef union querybuf +-{ +- HEADER hdr; +- u_char buf[MAXPACKET]; +-} querybuf; +- +-static enum nss_status getanswer_r (struct resolv_context *ctx, +- const querybuf *answer, int anslen, +- const char *qname, int qtype, +- struct hostent *result, char *buffer, +- size_t buflen, int *errnop, int *h_errnop, +- int map, int32_t *ttlp, char **canonp); +- +-static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1, +- const querybuf *answer2, int anslen2, +- const char *qname, ++/* For historic reasons, pointers to IP addresses are char *, so use a ++ single list type for addresses and host names. */ ++#define DYNARRAY_STRUCT ptrlist ++#define DYNARRAY_ELEMENT char * ++#define DYNARRAY_PREFIX ptrlist_ ++#include ++ ++static enum nss_status getanswer_r (unsigned char *packet, size_t packetlen, ++ uint16_t qtype, struct alloc_buffer *abuf, ++ struct ptrlist *addresses, ++ struct ptrlist *aliases, ++ int *errnop, int *h_errnop, int32_t *ttlp); ++static void addrsort (struct resolv_context *ctx, char **ap, int num); ++static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, ++ char **hnamep, int *errnop, ++ int *h_errnop, int32_t *ttlp); ++ ++static enum nss_status gaih_getanswer (unsigned char *packet1, ++ size_t packet1len, ++ unsigned char *packet2, ++ size_t packet2len, ++ struct alloc_buffer *abuf, + struct gaih_addrtuple **pat, +- char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); +-static enum nss_status gaih_getanswer_noaaaa (const querybuf *answer1, +- int anslen1, +- const char *qname, ++static enum nss_status gaih_getanswer_noaaaa (unsigned char *packet, ++ size_t packetlen, ++ struct alloc_buffer *abuf, + struct gaih_addrtuple **pat, +- char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); + +@@ -183,16 +184,9 @@ gethostbyname3_context (struct resolv_context *ctx, + char *buffer, size_t buflen, int *errnop, + int *h_errnop, int32_t *ttlp, char **canonp) + { +- union +- { +- querybuf *buf; +- u_char *ptr; +- } host_buffer; +- querybuf *orig_host_buffer; + char tmp[NS_MAXDNAME]; + int size, type, n; + const char *cp; +- int map = 0; + int olderr = errno; + enum nss_status status; + +@@ -223,10 +217,12 @@ gethostbyname3_context (struct resolv_context *ctx, + && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL) + name = cp; + +- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); ++ unsigned char dns_packet_buffer[1024]; ++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; + +- n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf, +- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); ++ n = __res_context_search (ctx, name, C_IN, type, ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); + if (n < 0) + { + switch (errno) +@@ -253,34 +249,79 @@ gethostbyname3_context (struct resolv_context *ctx, + *errnop = EAGAIN; + else + __set_errno (olderr); ++ } ++ else ++ { ++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); + +- /* If we are looking for an IPv6 address and mapping is enabled +- by having the RES_USE_INET6 bit in _res.options set, we try +- another lookup. */ +- if (af == AF_INET6 && res_use_inet6 ()) +- n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf, +- host_buffer.buf != orig_host_buffer +- ? MAXPACKET : 1024, &host_buffer.ptr, +- NULL, NULL, NULL, NULL); ++ struct ptrlist addresses; ++ ptrlist_init (&addresses); ++ struct ptrlist aliases; ++ ptrlist_init (&aliases); + +- if (n < 0) ++ status = getanswer_r (alt_dns_packet_buffer, n, type, ++ &abuf, &addresses, &aliases, ++ errnop, h_errnop, ttlp); ++ if (status == NSS_STATUS_SUCCESS) + { +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); +- return status; +- } ++ if (ptrlist_has_failed (&addresses) ++ || ptrlist_has_failed (&aliases)) ++ { ++ /* malloc failure. Do not retry using the ERANGE protocol. */ ++ *errnop = ENOMEM; ++ *h_errnop = NETDB_INTERNAL; ++ status = NSS_STATUS_UNAVAIL; ++ } + +- map = 1; ++ /* Reserve the address and alias arrays in the result ++ buffer. Both are NULL-terminated, but the first element ++ of the alias array is stored in h_name, so no extra space ++ for the NULL terminator is needed there. */ ++ result->h_addr_list ++ = alloc_buffer_alloc_array (&abuf, char *, ++ ptrlist_size (&addresses) + 1); ++ result->h_aliases ++ = alloc_buffer_alloc_array (&abuf, char *, ++ ptrlist_size (&aliases)); ++ if (alloc_buffer_has_failed (&abuf)) ++ { ++ /* Retry using the ERANGE protocol. */ ++ *errnop = ERANGE; ++ *h_errnop = NETDB_INTERNAL; ++ status = NSS_STATUS_TRYAGAIN; ++ } ++ else ++ { ++ /* Copy the address list and NULL-terminate it. */ ++ memcpy (result->h_addr_list, ptrlist_begin (&addresses), ++ ptrlist_size (&addresses) * sizeof (char *)); ++ result->h_addr_list[ptrlist_size (&addresses)] = NULL; ++ ++ /* Sort the address list if requested. */ ++ if (type == T_A && __resolv_context_sort_count (ctx) > 0) ++ addrsort (ctx, result->h_addr_list, ptrlist_size (&addresses)); + +- result->h_addrtype = AF_INET; +- result->h_length = INADDRSZ; ++ /* Copy the aliases, excluding the last one. */ ++ memcpy (result->h_aliases, ptrlist_begin (&aliases), ++ (ptrlist_size (&aliases) - 1) * sizeof (char *)); ++ result->h_aliases[ptrlist_size (&aliases) - 1] = NULL; ++ ++ /* The last alias goes into h_name. */ ++ assert (ptrlist_size (&aliases) >= 1); ++ result->h_name = ptrlist_end (&aliases)[-1]; ++ ++ /* This is also the canonical name. */ ++ if (canonp != NULL) ++ *canonp = result->h_name; ++ } ++ } ++ ++ ptrlist_free (&aliases); ++ ptrlist_free (&addresses); + } + +- status = getanswer_r +- (ctx, host_buffer.buf, n, name, type, result, buffer, buflen, +- errnop, h_errnop, map, ttlp, canonp); +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); + return status; + } + +@@ -324,13 +365,8 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result, + *h_errnop = NETDB_INTERNAL; + return NSS_STATUS_UNAVAIL; + } +- status = NSS_STATUS_NOTFOUND; +- if (res_use_inet6 ()) +- status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer, +- buflen, errnop, h_errnop, NULL, NULL); +- if (status == NSS_STATUS_NOTFOUND) +- status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, +- buflen, errnop, h_errnop, NULL, NULL); ++ status = gethostbyname3_context (ctx, name, AF_INET, result, buffer, ++ buflen, errnop, h_errnop, NULL, NULL); + __resolv_context_put (ctx); + return status; + } +@@ -365,17 +401,13 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + name = cp; + } + +- union +- { +- querybuf *buf; +- u_char *ptr; +- } host_buffer; +- querybuf *orig_host_buffer; +- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048); ++ unsigned char dns_packet_buffer[2048]; ++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; + u_char *ans2p = NULL; + int nans2p = 0; + int resplen2 = 0; + int ans2p_malloced = 0; ++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); + + + int olderr = errno; +@@ -384,22 +416,21 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + if ((ctx->resp->options & RES_NOAAAA) == 0) + { + n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA, +- host_buffer.buf->buf, 2048, &host_buffer.ptr, +- &ans2p, &nans2p, &resplen2, &ans2p_malloced); ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, &ans2p, &nans2p, ++ &resplen2, &ans2p_malloced); + if (n >= 0) +- status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p, +- resplen2, name, pat, buffer, buflen, +- errnop, herrnop, ttlp); ++ status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2, ++ &abuf, pat, errnop, herrnop, ttlp); + } + else + { + n = __res_context_search (ctx, name, C_IN, T_A, +- host_buffer.buf->buf, 2048, NULL, +- NULL, NULL, NULL, NULL); ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, NULL, NULL, NULL, NULL); + if (n >= 0) +- status = gaih_getanswer_noaaaa (host_buffer.buf, n, +- name, pat, buffer, buflen, +- errnop, herrnop, ttlp); ++ status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n, ++ &abuf, pat, errnop, herrnop, ttlp); + } + if (n < 0) + { +@@ -430,12 +461,20 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + __set_errno (olderr); + } + ++ /* Implement the buffer resizing protocol. */ ++ if (alloc_buffer_has_failed (&abuf)) ++ { ++ *errnop = ERANGE; ++ *herrnop = NETDB_INTERNAL; ++ status = NSS_STATUS_TRYAGAIN; ++ } ++ + /* Check whether ans2p was separately allocated. */ + if (ans2p_malloced) + free (ans2p); + +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); + + __resolv_context_put (ctx); + return status; +@@ -451,36 +490,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, + static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; + static const u_char v6local[] = { 0,0, 0,1 }; + const u_char *uaddr = (const u_char *)addr; +- struct host_data +- { +- char *aliases[MAX_NR_ALIASES]; +- unsigned char host_addr[16]; /* IPv4 or IPv6 */ +- char *h_addr_ptrs[MAX_NR_ADDRS + 1]; +- char linebuffer[0]; +- } *host_data = (struct host_data *) buffer; +- union +- { +- querybuf *buf; +- u_char *ptr; +- } host_buffer; +- querybuf *orig_host_buffer; + char qbuf[MAXDNAME+1], *qp = NULL; + size_t size; + int n, status; + int olderr = errno; + +- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); +- buffer += pad; +- buflen = buflen > pad ? buflen - pad : 0; +- +- if (__glibc_unlikely (buflen < sizeof (struct host_data))) +- { +- *errnop = ERANGE; +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; +- } +- +- host_data = (struct host_data *) buffer; ++ /* Prepare the allocation buffer. Store the pointer array first, to ++ benefit from buffer alignment. */ ++ struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen); ++ char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2); ++ if (address_array == NULL) ++ { ++ *errnop = ERANGE; ++ *h_errnop = NETDB_INTERNAL; ++ return NSS_STATUS_TRYAGAIN; ++ } + + struct resolv_context *ctx = __resolv_context_get (); + if (ctx == NULL) +@@ -524,8 +548,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, + return NSS_STATUS_UNAVAIL; + } + +- host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024); +- + switch (af) + { + case AF_INET: +@@ -549,36 +571,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af, + break; + } + +- n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf, +- 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL); ++ unsigned char dns_packet_buffer[1024]; ++ unsigned char *alt_dns_packet_buffer = dns_packet_buffer; ++ n = __res_context_query (ctx, qbuf, C_IN, T_PTR, ++ dns_packet_buffer, sizeof (dns_packet_buffer), ++ &alt_dns_packet_buffer, ++ NULL, NULL, NULL, NULL); + if (n < 0) + { + *h_errnop = h_errno; + __set_errno (olderr); +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); + __resolv_context_put (ctx); + return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND; + } + +- status = getanswer_r +- (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen, +- errnop, h_errnop, 0 /* XXX */, ttlp, NULL); +- if (host_buffer.buf != orig_host_buffer) +- free (host_buffer.buf); ++ status = getanswer_ptr (alt_dns_packet_buffer, n, ++ &abuf, &result->h_name, errnop, h_errnop, ttlp); ++ ++ if (alt_dns_packet_buffer != dns_packet_buffer) ++ free (alt_dns_packet_buffer); ++ __resolv_context_put (ctx); ++ + if (status != NSS_STATUS_SUCCESS) +- { +- __resolv_context_put (ctx); +- return status; +- } ++ return status; + ++ /* result->h_name has already been set by getanswer_ptr. */ + result->h_addrtype = af; + result->h_length = len; +- memcpy (host_data->host_addr, addr, len); +- host_data->h_addr_ptrs[0] = (char *) host_data->host_addr; +- host_data->h_addr_ptrs[1] = NULL; ++ /* Increase the alignment to 4, in case there are applications out ++ there that expect at least this level of address alignment. */ ++ address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t); ++ alloc_buffer_copy_bytes (&abuf, uaddr, len); ++ address_array[1] = NULL; ++ ++ /* This check also covers allocation failure in getanswer_ptr. */ ++ if (alloc_buffer_has_failed (&abuf)) ++ { ++ *errnop = ERANGE; ++ *h_errnop = NETDB_INTERNAL; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ result->h_addr_list = address_array; ++ result->h_aliases = &address_array[1]; /* Points to NULL. */ ++ + *h_errnop = NETDB_SUCCESS; +- __resolv_context_put (ctx); + return NSS_STATUS_SUCCESS; + } + libc_hidden_def (_nss_dns_gethostbyaddr2_r) +@@ -640,650 +678,362 @@ addrsort (struct resolv_context *ctx, char **ap, int num) + break; + } + +-static enum nss_status +-getanswer_r (struct resolv_context *ctx, +- const querybuf *answer, int anslen, const char *qname, int qtype, +- struct hostent *result, char *buffer, size_t buflen, +- int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp) ++/* Convert the uncompressed, binary domain name CDNAME into its ++ textual representation and add it to the end of ALIASES, allocating ++ space for a copy of the name from ABUF. Skip adding the name if it ++ is not a valid host name, and return false in that case, otherwise ++ true. */ ++static bool ++getanswer_r_store_alias (const unsigned char *cdname, ++ struct alloc_buffer *abuf, ++ struct ptrlist *aliases) + { +- struct host_data +- { +- char *aliases[MAX_NR_ALIASES]; +- unsigned char host_addr[16]; /* IPv4 or IPv6 */ +- char *h_addr_ptrs[0]; +- } *host_data; +- int linebuflen; +- const HEADER *hp; +- const u_char *end_of_message, *cp; +- int n, ancount, qdcount; +- int haveanswer, had_error; +- char *bp, **ap, **hap; +- char tbuf[MAXDNAME]; +- const char *tname; +- int (*name_ok) (const char *); +- u_char packtmp[NS_MAXCDNAME]; +- int have_to_map = 0; +- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data); +- buffer += pad; +- buflen = buflen > pad ? buflen - pad : 0; +- if (__glibc_unlikely (buflen < sizeof (struct host_data))) +- { +- /* The buffer is too small. */ +- too_small: +- *errnop = ERANGE; +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; +- } +- host_data = (struct host_data *) buffer; +- linebuflen = buflen - sizeof (struct host_data); +- if (buflen - sizeof (struct host_data) != linebuflen) +- linebuflen = INT_MAX; +- +- tname = qname; +- result->h_name = NULL; +- end_of_message = answer->buf + anslen; +- switch (qtype) +- { +- case T_A: +- case T_AAAA: +- name_ok = __libc_res_hnok; +- break; +- case T_PTR: +- name_ok = __libc_res_dnok; +- break; +- default: +- *errnop = ENOENT; +- return NSS_STATUS_UNAVAIL; /* XXX should be abort(); */ +- } ++ /* Filter out domain names that are not host names. */ ++ if (!__res_binary_hnok (cdname)) ++ return false; ++ ++ /* Note: Not NS_MAXCDNAME, so that __ns_name_ntop implicitly checks ++ for length. */ ++ char dname[MAXHOSTNAMELEN + 1]; ++ if (__ns_name_ntop (cdname, dname, sizeof (dname)) < 0) ++ return false; ++ /* Do not report an error on allocation failure, instead store NULL ++ or do nothing. getanswer_r's caller will see NSS_STATUS_SUCCESS ++ and detect the memory allocation failure or buffer space ++ exhaustion, and report it accordingly. */ ++ ptrlist_add (aliases, alloc_buffer_copy_string (abuf, dname)); ++ return true; ++} + +- /* +- * find first satisfactory answer +- */ +- hp = &answer->hdr; +- ancount = ntohs (hp->ancount); +- qdcount = ntohs (hp->qdcount); +- cp = answer->buf + HFIXEDSZ; +- if (__glibc_unlikely (qdcount != 1)) ++static enum nss_status __attribute__ ((noinline)) ++getanswer_r (unsigned char *packet, size_t packetlen, uint16_t qtype, ++ struct alloc_buffer *abuf, ++ struct ptrlist *addresses, struct ptrlist *aliases, ++ int *errnop, int *h_errnop, int32_t *ttlp) ++{ ++ struct ns_rr_cursor c; ++ if (!__ns_rr_cursor_init (&c, packet, packetlen)) + { ++ /* This should not happen because __res_context_query already ++ perfroms response validation. */ + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +- if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen) +- goto too_small; +- bp = (char *) &host_data->h_addr_ptrs[ancount + 1]; +- linebuflen -= (ancount + 1) * sizeof (char *); +- +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) +- { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; + +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0)) ++ /* Treat the QNAME just like an alias. Error out if it is not a ++ valid host name. */ ++ if (ns_rr_cursor_rcode (&c) == NXDOMAIN ++ || !getanswer_r_store_alias (ns_rr_cursor_qname (&c), abuf, aliases)) + { +- *errnop = errno; +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- if (__glibc_unlikely (name_ok (bp) == 0)) +- { +- errno = EBADMSG; +- *errnop = EBADMSG; +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; ++ if (ttlp != NULL) ++ /* No negative caching. */ ++ *ttlp = 0; ++ *h_errnop = HOST_NOT_FOUND; ++ *errnop = ENOENT; ++ return NSS_STATUS_NOTFOUND; + } +- cp += n + QFIXEDSZ; + +- if (qtype == T_A || qtype == T_AAAA) ++ int ancount = ns_rr_cursor_ancount (&c); ++ const unsigned char *expected_name = ns_rr_cursor_qname (&c); ++ /* expected_name may be updated to point into this buffer. */ ++ unsigned char name_buffer[NS_MAXCDNAME]; ++ ++ for (; ancount > 0; --ancount) + { +- /* res_send() has already verified that the query name is the +- * same as the one we sent; this just gets the expanded name +- * (i.e., with the succeeding search-domain tacked on). +- */ +- n = strlen (bp) + 1; /* for the \0 */ +- if (n >= MAXHOSTNAMELEN) ++ struct ns_rr_wire rr; ++ if (!__ns_rr_cursor_next (&c, &rr)) + { + *h_errnop = NO_RECOVERY; +- *errnop = ENOENT; +- return NSS_STATUS_TRYAGAIN; ++ return NSS_STATUS_UNAVAIL; + } +- result->h_name = bp; +- bp += n; +- linebuflen -= n; +- if (linebuflen < 0) +- goto too_small; +- /* The qname can be abbreviated, but h_name is now absolute. */ +- qname = result->h_name; +- } + +- ap = host_data->aliases; +- *ap = NULL; +- result->h_aliases = host_data->aliases; +- hap = host_data->h_addr_ptrs; +- *hap = NULL; +- result->h_addr_list = host_data->h_addr_ptrs; +- haveanswer = 0; +- had_error = 0; ++ /* Skip over records with the wrong class. */ ++ if (rr.rclass != C_IN) ++ continue; + +- while (ancount-- > 0 && cp < end_of_message && had_error == 0) +- { +- int type, class; ++ /* Update TTL for recognized record types. */ ++ if ((rr.rtype == T_CNAME || rr.rtype == qtype) ++ && ttlp != NULL && *ttlp > rr.ttl) ++ *ttlp = rr.ttl; + +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) ++ if (rr.rtype == T_CNAME) + { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; ++ /* NB: No check for owner name match, based on historic ++ precedent. Record the CNAME target as the new expected ++ name. */ ++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)); ++ if (n < 0) ++ { ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; ++ } ++ /* And store the new name as an alias. */ ++ getanswer_r_store_alias (name_buffer, abuf, aliases); ++ expected_name = name_buffer; + } +- +- if (__glibc_unlikely (n < 0 || (*name_ok) (bp) == 0)) ++ else if (rr.rtype == qtype ++ && __ns_samebinaryname (rr.rname, expected_name) ++ && rr.rdlength == rrtype_to_rdata_length (qtype)) + { +- ++had_error; +- continue; ++ /* Make a copy of the address and store it. Increase the ++ alignment to 4, in case there are applications out there ++ that expect at least this level of address alignment. */ ++ ptrlist_add (addresses, (char *) alloc_buffer_next (abuf, uint32_t)); ++ alloc_buffer_copy_bytes (abuf, rr.rdata, rr.rdlength); + } +- cp += n; /* name */ ++ } + +- if (__glibc_unlikely (cp + 10 > end_of_message)) +- { +- ++had_error; +- continue; +- } ++ if (ptrlist_size (addresses) == 0) ++ { ++ /* No address record found. */ ++ if (ttlp != NULL) ++ /* No caching of negative responses. */ ++ *ttlp = 0; + +- NS_GET16 (type, cp); +- NS_GET16 (class, cp); +- int32_t ttl; +- NS_GET32 (ttl, cp); +- NS_GET16 (n, cp); /* RDATA length. */ ++ *h_errnop = NO_RECOVERY; ++ *errnop = ENOENT; ++ return NSS_STATUS_TRYAGAIN; ++ } ++ else ++ { ++ *h_errnop = NETDB_SUCCESS; ++ return NSS_STATUS_SUCCESS; ++ } ++} + +- if (end_of_message - cp < n) +- { +- /* RDATA extends beyond the end of the packet. */ +- ++had_error; +- continue; +- } ++static enum nss_status ++getanswer_ptr (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, char **hnamep, ++ int *errnop, int *h_errnop, int32_t *ttlp) ++{ ++ struct ns_rr_cursor c; ++ if (!__ns_rr_cursor_init (&c, packet, packetlen)) ++ { ++ /* This should not happen because __res_context_query already ++ perfroms response validation. */ ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; ++ } ++ int ancount = ns_rr_cursor_ancount (&c); ++ const unsigned char *expected_name = ns_rr_cursor_qname (&c); ++ /* expected_name may be updated to point into this buffer. */ ++ unsigned char name_buffer[NS_MAXCDNAME]; + +- if (__glibc_unlikely (class != C_IN)) ++ while (ancount > 0) ++ { ++ struct ns_rr_wire rr; ++ if (!__ns_rr_cursor_next (&c, &rr)) + { +- /* XXX - debug? syslog? */ +- cp += n; +- continue; /* XXX - had_error++ ? */ ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } + +- if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) +- { +- /* A CNAME could also have a TTL entry. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- +- if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1]) +- continue; +- n = __libc_dn_expand (answer->buf, end_of_message, cp, +- tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0)) +- { +- ++had_error; +- continue; +- } +- cp += n; +- /* Store alias. */ +- *ap++ = bp; +- n = strlen (bp) + 1; /* For the \0. */ +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) +- { +- ++had_error; +- continue; +- } +- bp += n; +- linebuflen -= n; +- /* Get canonical name. */ +- n = strlen (tbuf) + 1; /* For the \0. */ +- if (__glibc_unlikely (n > linebuflen)) +- goto too_small; +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) +- { +- ++had_error; +- continue; +- } +- result->h_name = bp; +- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ +- linebuflen -= n; +- continue; +- } ++ /* Skip over records with the wrong class. */ ++ if (rr.rclass != C_IN) ++ continue; + +- if (qtype == T_PTR && type == T_CNAME) +- { +- /* A CNAME could also have a TTL entry. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; ++ /* Update TTL for known record types. */ ++ if ((rr.rtype == T_CNAME || rr.rtype == T_PTR) ++ && ttlp != NULL && *ttlp > rr.ttl) ++ *ttlp = rr.ttl; + +- n = __libc_dn_expand (answer->buf, end_of_message, cp, +- tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0)) +- { +- ++had_error; +- continue; +- } +- cp += n; +- /* Get canonical name. */ +- n = strlen (tbuf) + 1; /* For the \0. */ +- if (__glibc_unlikely (n > linebuflen)) +- goto too_small; +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) ++ if (rr.rtype == T_CNAME) ++ { ++ /* NB: No check for owner name match, based on historic ++ precedent. Record the CNAME target as the new expected ++ name. */ ++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)); ++ if (n < 0) + { +- ++had_error; +- continue; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } +- tname = bp; +- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */ +- linebuflen -= n; +- continue; ++ expected_name = name_buffer; + } +- +- if (type == T_A && qtype == T_AAAA && map) +- have_to_map = 1; +- else if (__glibc_unlikely (type != qtype)) ++ else if (rr.rtype == T_PTR ++ && __ns_samebinaryname (rr.rname, expected_name)) + { +- cp += n; +- continue; /* XXX - had_error++ ? */ +- } +- +- switch (type) +- { +- case T_PTR: +- if (__glibc_unlikely (__strcasecmp (tname, bp) != 0)) ++ /* Decompress the target of the PTR record. This is the ++ host name we are looking for. We can only use it if it ++ is syntactically valid. Historically, only one host name ++ is returned here. If the recursive resolver performs DNS ++ record rotation, the returned host name is essentially ++ random, which is why multiple PTR records are rarely ++ used. Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for ++ additional length checking. */ ++ char hname[MAXHOSTNAMELEN + 1]; ++ if (__ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)) < 0 ++ || !__res_binary_hnok (expected_name) ++ || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0) + { +- cp += n; +- continue; /* XXX - had_error++ ? */ ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } +- +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1) +- { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0)) +- { +- ++had_error; +- break; +- } +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- /* bind would put multiple PTR records as aliases, but we don't do +- that. */ +- result->h_name = bp; +- *h_errnop = NETDB_SUCCESS; ++ /* Successful allocation is checked by the caller. */ ++ *hnamep = alloc_buffer_copy_string (abuf, hname); + return NSS_STATUS_SUCCESS; +- case T_A: +- case T_AAAA: +- if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0)) +- { +- cp += n; +- continue; /* XXX - had_error++ ? */ +- } +- +- /* Stop parsing at a record whose length is incorrect. */ +- if (n != rrtype_to_rdata_length (type)) +- { +- ++had_error; +- break; +- } +- +- /* Skip records of the wrong type. */ +- if (n != result->h_length) +- { +- cp += n; +- continue; +- } +- if (!haveanswer) +- { +- int nn; +- +- /* We compose a single hostent out of the entire chain of +- entries, so the TTL of the hostent is essentially the lowest +- TTL in the chain. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- if (canonp != NULL) +- *canonp = bp; +- result->h_name = bp; +- nn = strlen (bp) + 1; /* for the \0 */ +- bp += nn; +- linebuflen -= nn; +- } +- +- /* Provide sufficient alignment for both address +- families. */ +- enum { align = 4 }; +- _Static_assert ((align % __alignof__ (struct in_addr)) == 0, +- "struct in_addr alignment"); +- _Static_assert ((align % __alignof__ (struct in6_addr)) == 0, +- "struct in6_addr alignment"); +- { +- char *new_bp = PTR_ALIGN_UP (bp, align); +- linebuflen -= new_bp - bp; +- bp = new_bp; +- } +- +- if (__glibc_unlikely (n > linebuflen)) +- goto too_small; +- bp = __mempcpy (*hap++ = bp, cp, n); +- cp += n; +- linebuflen -= n; +- break; +- default: +- abort (); + } +- if (had_error == 0) +- ++haveanswer; + } + +- if (haveanswer > 0) +- { +- *ap = NULL; +- *hap = NULL; +- /* +- * Note: we sort even if host can take only one address +- * in its return structures - should give it the "best" +- * address in that case, not some random one +- */ +- if (haveanswer > 1 && qtype == T_A +- && __resolv_context_sort_count (ctx) > 0) +- addrsort (ctx, host_data->h_addr_ptrs, haveanswer); +- +- if (result->h_name == NULL) +- { +- n = strlen (qname) + 1; /* For the \0. */ +- if (n > linebuflen) +- goto too_small; +- if (n >= MAXHOSTNAMELEN) +- goto no_recovery; +- result->h_name = bp; +- bp = __mempcpy (bp, qname, n); /* Cannot overflow. */ +- linebuflen -= n; +- } ++ /* No PTR record found. */ ++ if (ttlp != NULL) ++ /* No caching of negative responses. */ ++ *ttlp = 0; + +- if (have_to_map) +- if (map_v4v6_hostent (result, &bp, &linebuflen)) +- goto too_small; +- *h_errnop = NETDB_SUCCESS; +- return NSS_STATUS_SUCCESS; +- } +- no_recovery: + *h_errnop = NO_RECOVERY; + *errnop = ENOENT; +- /* Special case here: if the resolver sent a result but it only +- contains a CNAME while we are looking for a T_A or T_AAAA record, +- we fail with NOTFOUND instead of TRYAGAIN. */ +- return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases +- ? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN); ++ return NSS_STATUS_TRYAGAIN; + } + +- ++/* Parses DNS data found in PACKETLEN bytes at PACKET in struct ++ gaih_addrtuple address tuples. The new address tuples are linked ++ from **TAILP, with backing store allocated from ABUF, and *TAILP is ++ updated to point where the next tuple pointer should be stored. If ++ TTLP is not null, *TTLP is updated to reflect the minimum TTL. If ++ STORE_CANON is true, the canonical name is stored as part of the ++ first address tuple being written. */ + static enum nss_status +-gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, +- struct gaih_addrtuple ***patp, +- char **bufferp, size_t *buflenp, +- int *errnop, int *h_errnop, int32_t *ttlp, int *firstp) ++gaih_getanswer_slice (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, ++ struct gaih_addrtuple ***tailp, ++ int *errnop, int *h_errnop, int32_t *ttlp, ++ bool store_canon) + { +- char *buffer = *bufferp; +- size_t buflen = *buflenp; +- +- struct gaih_addrtuple **pat = *patp; +- const HEADER *hp = &answer->hdr; +- int ancount = ntohs (hp->ancount); +- int qdcount = ntohs (hp->qdcount); +- const u_char *cp = answer->buf + HFIXEDSZ; +- const u_char *end_of_message = answer->buf + anslen; +- if (__glibc_unlikely (qdcount != 1)) +- { +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- +- u_char packtmp[NS_MAXCDNAME]; +- int n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- /* We unpack the name to check it for validity. But we do not need +- it later. */ +- if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1) +- { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- { +- too_small: +- *errnop = ERANGE; +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; +- } +- +- n = -1; +- } +- +- if (__glibc_unlikely (n < 0)) ++ struct ns_rr_cursor c; ++ if (!__ns_rr_cursor_init (&c, packet, packetlen)) + { +- *errnop = errno; ++ /* This should not happen because __res_context_query already ++ perfroms response validation. */ + *h_errnop = NO_RECOVERY; + return NSS_STATUS_UNAVAIL; + } +- if (__glibc_unlikely (__libc_res_hnok (buffer) == 0)) +- { +- errno = EBADMSG; +- *errnop = EBADMSG; +- *h_errnop = NO_RECOVERY; +- return NSS_STATUS_UNAVAIL; +- } +- cp += n + QFIXEDSZ; +- +- int haveanswer = 0; +- int had_error = 0; +- char *canon = NULL; +- char *h_name = NULL; +- int h_namelen = 0; +- +- if (ancount == 0) ++ bool haveanswer = false; /* Set to true if at least one address. */ ++ uint16_t qtype = ns_rr_cursor_qtype (&c); ++ int ancount = ns_rr_cursor_ancount (&c); ++ const unsigned char *expected_name = ns_rr_cursor_qname (&c); ++ /* expected_name may be updated to point into this buffer. */ ++ unsigned char name_buffer[NS_MAXCDNAME]; ++ ++ /* This is a pointer to a possibly-compressed name in the packet. ++ Eventually it is equivalent to the canonical name. If needed, it ++ is uncompressed and translated to text form when the first ++ address tuple is encountered. */ ++ const unsigned char *compressed_alias_name = expected_name; ++ ++ if (ancount == 0 || !__res_binary_hnok (compressed_alias_name)) + { + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } + +- while (ancount-- > 0 && cp < end_of_message && had_error == 0) ++ for (; ancount > -0; --ancount) + { +- n = __ns_name_unpack (answer->buf, end_of_message, cp, +- packtmp, sizeof packtmp); +- if (n != -1 && +- (h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1) ++ struct ns_rr_wire rr; ++ if (!__ns_rr_cursor_next (&c, &rr)) + { +- if (__glibc_unlikely (errno == EMSGSIZE)) +- goto too_small; +- +- n = -1; +- } +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (buffer) == 0)) +- { +- ++had_error; +- continue; +- } +- if (*firstp && canon == NULL) +- { +- h_name = buffer; +- buffer += h_namelen; +- buflen -= h_namelen; +- } +- +- cp += n; /* name */ +- +- if (__glibc_unlikely (cp + 10 > end_of_message)) +- { +- ++had_error; +- continue; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } + +- uint16_t type; +- NS_GET16 (type, cp); +- uint16_t class; +- NS_GET16 (class, cp); +- int32_t ttl; +- NS_GET32 (ttl, cp); +- NS_GET16 (n, cp); /* RDATA length. */ ++ /* Update TTL for known record types. */ ++ if ((rr.rtype == T_CNAME || rr.rtype == qtype) ++ && ttlp != NULL && *ttlp > rr.ttl) ++ *ttlp = rr.ttl; + +- if (end_of_message - cp < n) ++ if (rr.rtype == T_CNAME) + { +- /* RDATA extends beyond the end of the packet. */ +- ++had_error; +- continue; +- } +- +- if (class != C_IN) +- { +- cp += n; +- continue; +- } +- +- if (type == T_CNAME) +- { +- char tbuf[MAXDNAME]; +- +- /* A CNAME could also have a TTL entry. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- +- n = __libc_dn_expand (answer->buf, end_of_message, cp, +- tbuf, sizeof tbuf); +- if (__glibc_unlikely (n < 0 || __libc_res_hnok (tbuf) == 0)) ++ /* NB: No check for owner name match, based on historic ++ precedent. Record the CNAME target as the new expected ++ name. */ ++ int n = __ns_name_unpack (c.begin, c.end, rr.rdata, ++ name_buffer, sizeof (name_buffer)); ++ if (n < 0) + { +- ++had_error; +- continue; +- } +- cp += n; +- +- if (*firstp) +- { +- /* Reclaim buffer space. */ +- if (h_name + h_namelen == buffer) +- { +- buffer = h_name; +- buflen += h_namelen; +- } +- +- n = strlen (tbuf) + 1; +- if (__glibc_unlikely (n > buflen)) +- goto too_small; +- if (__glibc_unlikely (n >= MAXHOSTNAMELEN)) +- { +- ++had_error; +- continue; +- } +- +- canon = buffer; +- buffer = __mempcpy (buffer, tbuf, n); +- buflen -= n; +- h_namelen = 0; ++ *h_errnop = NO_RECOVERY; ++ return NSS_STATUS_UNAVAIL; + } +- continue; ++ expected_name = name_buffer; ++ if (store_canon && __res_binary_hnok (name_buffer)) ++ /* This name can be used as a canonical name. Do not ++ translate to text form here to conserve buffer space. ++ Point to the compressed name because name_buffer can be ++ overwritten with an unusable name later. */ ++ compressed_alias_name = rr.rdata; + } +- +- /* Stop parsing if we encounter a record with incorrect RDATA +- length. */ +- if (type == T_A || type == T_AAAA) ++ else if (rr.rtype == qtype ++ && __ns_samebinaryname (rr.rname, expected_name) ++ && rr.rdlength == rrtype_to_rdata_length (qtype)) + { +- if (n != rrtype_to_rdata_length (type)) ++ struct gaih_addrtuple *ntup ++ = alloc_buffer_alloc (abuf, struct gaih_addrtuple); ++ /* Delay error reporting to the callers (they implement the ++ ERANGE buffer resizing handshake). */ ++ if (ntup != NULL) + { +- ++had_error; +- continue; ++ ntup->next = NULL; ++ if (store_canon && compressed_alias_name != NULL) ++ { ++ /* This assumes that all the CNAME records come ++ first. Use MAXHOSTNAMELEN instead of ++ NS_MAXCDNAME for additional length checking. ++ However, these checks are not expected to fail ++ because all size NS_MAXCDNAME names should into ++ the hname buffer because no escaping is ++ needed. */ ++ char unsigned nbuf[NS_MAXCDNAME]; ++ char hname[MAXHOSTNAMELEN + 1]; ++ if (__ns_name_unpack (c.begin, c.end, ++ compressed_alias_name, ++ nbuf, sizeof (nbuf)) >= 0 ++ && __ns_name_ntop (nbuf, hname, sizeof (hname)) >= 0) ++ /* Space checking is performed by the callers. */ ++ ntup->name = alloc_buffer_copy_string (abuf, hname); ++ store_canon = false; ++ } ++ else ++ ntup->name = NULL; ++ if (rr.rdlength == 4) ++ ntup->family = AF_INET; ++ else ++ ntup->family = AF_INET6; ++ memcpy (ntup->addr, rr.rdata, rr.rdlength); ++ ntup->scopeid = 0; ++ ++ /* Link in the new tuple, and update the tail pointer to ++ point to its next field. */ ++ **tailp = ntup; ++ *tailp = &ntup->next; ++ ++ haveanswer = true; + } + } +- else +- { +- /* Skip unknown records. */ +- cp += n; +- continue; +- } +- +- assert (type == T_A || type == T_AAAA); +- if (*pat == NULL) +- { +- uintptr_t pad = (-(uintptr_t) buffer +- % __alignof__ (struct gaih_addrtuple)); +- buffer += pad; +- buflen = buflen > pad ? buflen - pad : 0; +- +- if (__glibc_unlikely (buflen < sizeof (struct gaih_addrtuple))) +- goto too_small; +- +- *pat = (struct gaih_addrtuple *) buffer; +- buffer += sizeof (struct gaih_addrtuple); +- buflen -= sizeof (struct gaih_addrtuple); +- } +- +- (*pat)->name = NULL; +- (*pat)->next = NULL; +- +- if (*firstp) +- { +- /* We compose a single hostent out of the entire chain of +- entries, so the TTL of the hostent is essentially the lowest +- TTL in the chain. */ +- if (ttlp != NULL && ttl < *ttlp) +- *ttlp = ttl; +- +- (*pat)->name = canon ?: h_name; +- +- *firstp = 0; +- } +- +- (*pat)->family = type == T_A ? AF_INET : AF_INET6; +- memcpy ((*pat)->addr, cp, n); +- cp += n; +- (*pat)->scopeid = 0; +- +- pat = &((*pat)->next); +- +- haveanswer = 1; + } + + if (haveanswer) + { +- *patp = pat; +- *bufferp = buffer; +- *buflenp = buflen; +- + *h_errnop = NETDB_SUCCESS; + return NSS_STATUS_SUCCESS; + } +- +- /* Special case here: if the resolver sent a result but it only +- contains a CNAME while we are looking for a T_A or T_AAAA record, +- we fail with NOTFOUND instead of TRYAGAIN. */ +- if (canon != NULL) ++ else + { ++ /* Special case here: if the resolver sent a result but it only ++ contains a CNAME while we are looking for a T_A or T_AAAA ++ record, we fail with NOTFOUND. */ + *h_errnop = HOST_NOT_FOUND; + return NSS_STATUS_NOTFOUND; + } +- +- *h_errnop = NETDB_INTERNAL; +- return NSS_STATUS_TRYAGAIN; + } + + + static enum nss_status +-gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, +- int anslen2, const char *qname, +- struct gaih_addrtuple **pat, char *buffer, size_t buflen, ++gaih_getanswer (unsigned char *packet1, size_t packet1len, ++ unsigned char *packet2, size_t packet2len, ++ struct alloc_buffer *abuf, struct gaih_addrtuple **pat, + int *errnop, int *h_errnop, int32_t *ttlp) + { +- int first = 1; +- + enum nss_status status = NSS_STATUS_NOTFOUND; + + /* Combining the NSS status of two distinct queries requires some +@@ -1295,7 +1045,10 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable). + A recoverable TRYAGAIN is almost always due to buffer size issues + and returns ERANGE in errno and the caller is expected to retry +- with a larger buffer. ++ with a larger buffer. (The caller, _nss_dns_gethostbyname4_r, ++ ignores the return status if it detects that the result buffer ++ has been exhausted and generates a TRYAGAIN failure with an ++ ERANGE code.) + + Lastly, you may be tempted to make significant changes to the + conditions in this code to bring about symmetry between responses. +@@ -1375,36 +1128,30 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + is a recoverable error we now return TRYAGIN even if the first + response was SUCCESS. */ + +- if (anslen1 > 0) +- status = gaih_getanswer_slice(answer1, anslen1, qname, +- &pat, &buffer, &buflen, +- errnop, h_errnop, ttlp, +- &first); +- +- if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND +- || (status == NSS_STATUS_TRYAGAIN +- /* We want to look at the second answer in case of an +- NSS_STATUS_TRYAGAIN only if the error is non-recoverable, i.e. +- *h_errnop is NO_RECOVERY. If not, and if the failure was due to +- an insufficient buffer (ERANGE), then we need to drop the results +- and pass on the NSS_STATUS_TRYAGAIN to the caller so that it can +- repeat the query with a larger buffer. */ +- && (*errnop != ERANGE || *h_errnop == NO_RECOVERY))) +- && answer2 != NULL && anslen2 > 0) ++ if (packet1len > 0) + { +- enum nss_status status2 = gaih_getanswer_slice(answer2, anslen2, qname, +- &pat, &buffer, &buflen, +- errnop, h_errnop, ttlp, +- &first); ++ status = gaih_getanswer_slice (packet1, packet1len, ++ abuf, &pat, errnop, h_errnop, ttlp, true); ++ if (alloc_buffer_has_failed (abuf)) ++ /* Do not try parsing the second packet if a larger result ++ buffer is needed. The caller implements the resizing ++ protocol because *abuf has been exhausted. */ ++ return NSS_STATUS_TRYAGAIN; /* Ignored by the caller. */ ++ } ++ ++ if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND) ++ && packet2 != NULL && packet2len > 0) ++ { ++ enum nss_status status2 ++ = gaih_getanswer_slice (packet2, packet2len, ++ abuf, &pat, errnop, h_errnop, ttlp, ++ /* Success means that data with a ++ canonical name has already been ++ stored. Do not store the name again. */ ++ status != NSS_STATUS_SUCCESS); + /* Use the second response status in some cases. */ + if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND) + status = status2; +- /* Do not return a truncated second response (unless it was +- unavoidable e.g. unrecoverable TRYAGAIN). */ +- if (status == NSS_STATUS_SUCCESS +- && (status2 == NSS_STATUS_TRYAGAIN +- && *errnop == ERANGE && *h_errnop != NO_RECOVERY)) +- status = NSS_STATUS_TRYAGAIN; + } + + return status; +@@ -1412,18 +1159,13 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, + + /* Variant of gaih_getanswer without a second (AAAA) response. */ + static enum nss_status +-gaih_getanswer_noaaaa (const querybuf *answer1, int anslen1, const char *qname, +- struct gaih_addrtuple **pat, +- char *buffer, size_t buflen, ++gaih_getanswer_noaaaa (unsigned char *packet, size_t packetlen, ++ struct alloc_buffer *abuf, struct gaih_addrtuple **pat, + int *errnop, int *h_errnop, int32_t *ttlp) + { +- int first = 1; +- + enum nss_status status = NSS_STATUS_NOTFOUND; +- if (anslen1 > 0) +- status = gaih_getanswer_slice (answer1, anslen1, qname, +- &pat, &buffer, &buflen, +- errnop, h_errnop, ttlp, +- &first); ++ if (packetlen > 0) ++ status = gaih_getanswer_slice (packet, packetlen, ++ abuf, &pat, errnop, h_errnop, ttlp, true); + return status; + } +diff --git a/resolv/res-name-checking.c b/resolv/res-name-checking.c +index 07a412d8ff..213edceaf3 100644 +--- a/resolv/res-name-checking.c ++++ b/resolv/res-name-checking.c +@@ -138,6 +138,12 @@ binary_leading_dash (const unsigned char *dn) + return dn[0] > 0 && dn[1] == '-'; + } + ++bool ++__res_binary_hnok (const unsigned char *dn) ++{ ++ return !binary_leading_dash (dn) && binary_hnok (dn); ++} ++ + /* Return 1 if res_hnok is a valid host name. Labels must only + contain [0-9a-zA-Z_-] characters, and the name must not start with + a '-'. The latter is to avoid confusion with program options. */ +@@ -145,11 +151,9 @@ int + ___res_hnok (const char *dn) + { + unsigned char buf[NS_MAXCDNAME]; +- if (!printable_string (dn) +- || __ns_name_pton (dn, buf, sizeof (buf)) < 0 +- || binary_leading_dash (buf)) +- return 0; +- return binary_hnok (buf); ++ return (printable_string (dn) ++ && __ns_name_pton (dn, buf, sizeof (buf)) >= 0 ++ && __res_binary_hnok (buf)); + } + versioned_symbol (libc, ___res_hnok, res_hnok, GLIBC_2_34); + versioned_symbol (libc, ___res_hnok, __libc_res_hnok, GLIBC_PRIVATE); +diff --git a/resolv/tst-ns_name_length_uncompressed.c b/resolv/tst-ns_name_length_uncompressed.c +new file mode 100644 +index 0000000000..c4a2904db7 +--- /dev/null ++++ b/resolv/tst-ns_name_length_uncompressed.c +@@ -0,0 +1,135 @@ ++/* Test __ns_name_length_uncompressed. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Reference implementation based on other building blocks. */ ++static int ++reference_length (const unsigned char *p, const unsigned char *eom) ++{ ++ unsigned char buf[NS_MAXCDNAME]; ++ int n = __ns_name_unpack (p, eom, p, buf, sizeof (buf)); ++ if (n < 0) ++ return n; ++ const unsigned char *q = buf; ++ if (__ns_name_skip (&q, array_end (buf)) < 0) ++ return -1; ++ if (q - buf != n) ++ /* Compressed name. */ ++ return -1; ++ return n; ++} ++ ++static int ++do_test (void) ++{ ++ { ++ unsigned char buf[] = { 3, 'w', 'w', 'w', 0, 0, 0 }; ++ TEST_COMPARE (reference_length (buf, array_end (buf)), sizeof (buf) - 2); ++ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), ++ sizeof (buf) - 2); ++ TEST_COMPARE (reference_length (array_end (buf) - 1, array_end (buf)), 1); ++ TEST_COMPARE (__ns_name_length_uncompressed (array_end (buf) - 1, ++ array_end (buf)), 1); ++ buf[4] = 0xc0; /* Forward compression reference. */ ++ buf[5] = 0x06; ++ TEST_COMPARE (reference_length (buf, array_end (buf)), -1); ++ TEST_COMPARE (__ns_name_length_uncompressed (buf, array_end (buf)), -1); ++ } ++ ++ struct support_next_to_fault ntf = support_next_to_fault_allocate (300); ++ ++ /* Buffer region with all possible bytes at start and end. */ ++ for (int length = 1; length <= 300; ++length) ++ { ++ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length; ++ unsigned char *start = end - length; ++ memset (start, 'X', length); ++ for (int first = 0; first <= 255; ++first) ++ { ++ *start = first; ++ for (int last = 0; last <= 255; ++last) ++ { ++ start[length - 1] = last; ++ TEST_COMPARE (reference_length (start, end), ++ __ns_name_length_uncompressed (start, end)); ++ } ++ } ++ } ++ ++ /* Poor man's fuzz testing: patch two bytes. */ ++ { ++ unsigned char ref[] = ++ { ++ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'n', 'e', 't', 0, 0, 0 ++ }; ++ TEST_COMPARE (reference_length (ref, array_end (ref)), 13); ++ TEST_COMPARE (__ns_name_length_uncompressed (ref, array_end (ref)), 13); ++ ++ int good = 0; ++ int bad = 0; ++ for (int length = 1; length <= sizeof (ref); ++length) ++ { ++ unsigned char *end = (unsigned char *) ntf.buffer + ntf.length; ++ unsigned char *start = end - length; ++ memcpy (start, ref, length); ++ ++ for (int patch1_pos = 0; patch1_pos < length; ++patch1_pos) ++ { ++ for (int patch1_value = 0; patch1_value <= 255; ++patch1_value) ++ { ++ start[patch1_pos] = patch1_value; ++ for (int patch2_pos = 0; patch2_pos < length; ++patch2_pos) ++ { ++ for (int patch2_value = 0; patch2_value <= 255; ++ ++patch2_value) ++ { ++ start[patch2_pos] = patch2_value; ++ int expected = reference_length (start, end); ++ errno = EINVAL; ++ int actual ++ = __ns_name_length_uncompressed (start, end); ++ if (actual > 0) ++ ++good; ++ else ++ { ++ TEST_COMPARE (errno, EMSGSIZE); ++ ++bad; ++ } ++ TEST_COMPARE (expected, actual); ++ } ++ start[patch2_pos] = ref[patch2_pos]; ++ } ++ } ++ start[patch1_pos] = ref[patch1_pos]; ++ } ++ } ++ printf ("info: patched inputs with success: %d\n", good); ++ printf ("info: patched inputs with failure: %d\n", bad); ++ } ++ ++ support_next_to_fault_free (&ntf); ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-ns_rr_cursor.c b/resolv/tst-ns_rr_cursor.c +new file mode 100644 +index 0000000000..c3c0908905 +--- /dev/null ++++ b/resolv/tst-ns_rr_cursor.c +@@ -0,0 +1,227 @@ ++/* Tests for resource record parsing. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* Reference packet for packet parsing. */ ++static const unsigned char valid_packet[] = ++ { 0x11, 0x12, 0x13, 0x14, ++ 0x00, 0x01, /* Question count. */ ++ 0x00, 0x02, /* Answer count. */ ++ 0x21, 0x22, 0x23, 0x24, /* Other counts (not actually in packet). */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0, ++ 0x00, 0x1c, /* Question type: AAAA. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ 0xc0, 0x0c, /* Compression reference to QNAME. */ ++ 0x00, 0x1c, /* Record type: AAAA. */ ++ 0x00, 0x01, /* Record class: IN. */ ++ 0x12, 0x34, 0x56, 0x78, /* Record TTL. */ ++ 0x00, 0x10, /* Record data length (16 bytes). */ ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* IPv6 address. */ ++ 0xc0, 0x0c, /* Compression reference to QNAME. */ ++ 0x00, 0x1c, /* Record type: AAAA. */ ++ 0x00, 0x01, /* Record class: IN. */ ++ 0x11, 0x33, 0x55, 0x77, /* Record TTL. */ ++ 0x00, 0x10, /* Record data length (16 bytes). */ ++ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, ++ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* IPv6 address. */ ++ }; ++ ++/* Special offsets in valid_packet. */ ++enum ++ { ++ offset_of_first_record = 29, ++ offset_of_second_record = 57, ++ }; ++ ++/* Check that parsing valid_packet succeeds. */ ++static void ++test_valid (void) ++{ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, valid_packet, ++ sizeof (valid_packet))); ++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); ++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); ++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); ++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); ++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); ++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); ++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); ++ TEST_COMPARE (c.current - valid_packet, offset_of_first_record); ++ ++ struct ns_rr_wire r; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); ++ TEST_COMPARE (r.rtype, T_AAAA); ++ TEST_COMPARE (r.rclass, C_IN); ++ TEST_COMPARE (r.ttl, 0x12345678); ++ TEST_COMPARE_BLOB (r.rdata, r.rdlength, ++ "\x90\x91\x92\x93\x94\x95\x96\x97" ++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16); ++ TEST_COMPARE (c.current - valid_packet, offset_of_second_record); ++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); ++ TEST_COMPARE (r.rtype, T_AAAA); ++ TEST_COMPARE (r.rclass, C_IN); ++ TEST_COMPARE (r.ttl, 0x11335577); ++ TEST_COMPARE_BLOB (r.rdata, r.rdlength, ++ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" ++ "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", 16); ++ TEST_VERIFY (c.current == c.end); ++} ++ ++/* Check that trying to parse a packet with a compressed QNAME fails. */ ++static void ++test_compressed_qname (void) ++{ ++ static const unsigned char packet[] = ++ { 0x11, 0x12, 0x13, 0x14, ++ 0x00, 0x01, /* Question count. */ ++ 0x00, 0x00, /* Answer count. */ ++ 0x00, 0x00, 0x00, 0x00, /* Other counts. */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, ++ 0x00, 0x01, /* Question type: A. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ }; ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet))); ++} ++ ++/* Check that trying to parse a packet with two questions fails. */ ++static void ++test_two_questions (void) ++{ ++ static const unsigned char packet[] = ++ { 0x11, 0x12, 0x13, 0x14, ++ 0x00, 0x02, /* Question count. */ ++ 0x00, 0x00, /* Answer count. */ ++ 0x00, 0x00, 0x00, 0x00, /* Other counts. */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, ++ 0x00, 0x01, /* Question type: A. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ 3, 'w', 'w', 'w', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 0xc0, 0x04, ++ 0x00, 0x1c, /* Question type: AAAA. */ ++ 0x00, 0x01, /* Question class: IN. */ ++ }; ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, packet, sizeof (packet))); ++} ++ ++/* Used to check that parsing truncated packets does not over-read. */ ++static struct support_next_to_fault ntf; ++ ++/* Truncated packet in the second resource record. */ ++static void ++test_truncated_one_rr (size_t length) ++{ ++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; ++ unsigned char *start = end - length; ++ ++ /* Produce the truncated packet. */ ++ memcpy (start, valid_packet, length); ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length)); ++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); ++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); ++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); ++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); ++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); ++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); ++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); ++ TEST_COMPARE (c.current - start, offset_of_first_record); ++ ++ struct ns_rr_wire r; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_next (&c, &r)); ++ TEST_COMPARE (r.rtype, T_AAAA); ++ TEST_COMPARE (r.rclass, C_IN); ++ TEST_COMPARE (r.ttl, 0x12345678); ++ TEST_COMPARE_BLOB (r.rdata, r.rdlength, ++ "\x90\x91\x92\x93\x94\x95\x96\x97" ++ "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f", 16); ++ TEST_COMPARE (c.current - start, offset_of_second_record); ++ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r)); ++} ++ ++/* Truncated packet in the first resource record. */ ++static void ++test_truncated_no_rr (size_t length) ++{ ++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; ++ unsigned char *start = end - length; ++ ++ /* Produce the truncated packet. */ ++ memcpy (start, valid_packet, length); ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (__ns_rr_cursor_init (&c, start, length)); ++ TEST_COMPARE (ns_rr_cursor_rcode (&c), 4); ++ TEST_COMPARE (ns_rr_cursor_ancount (&c), 2); ++ TEST_COMPARE (ns_rr_cursor_nscount (&c), 0x2122); ++ TEST_COMPARE (ns_rr_cursor_adcount (&c), 0x2324); ++ TEST_COMPARE_BLOB (ns_rr_cursor_qname (&c), 13, &valid_packet[12], 13); ++ TEST_COMPARE (ns_rr_cursor_qtype (&c), T_AAAA); ++ TEST_COMPARE (ns_rr_cursor_qclass (&c), C_IN); ++ TEST_COMPARE (c.current - start, offset_of_first_record); ++ ++ struct ns_rr_wire r; ++ TEST_VERIFY (!__ns_rr_cursor_next (&c, &r)); ++} ++ ++/* Truncated packet before first resource record. */ ++static void ++test_truncated_before_rr (size_t length) ++{ ++ unsigned char *end = (unsigned char *) ntf.buffer - ntf.length; ++ unsigned char *start = end - length; ++ ++ /* Produce the truncated packet. */ ++ memcpy (start, valid_packet, length); ++ ++ struct ns_rr_cursor c; ++ TEST_VERIFY_EXIT (!__ns_rr_cursor_init (&c, start, length)); ++} ++ ++static int ++do_test (void) ++{ ++ ntf = support_next_to_fault_allocate (sizeof (valid_packet)); ++ ++ test_valid (); ++ test_compressed_qname (); ++ test_two_questions (); ++ ++ for (int length = offset_of_second_record; length < sizeof (valid_packet); ++ ++length) ++ test_truncated_one_rr (length); ++ for (int length = offset_of_first_record; length < offset_of_second_record; ++ ++length) ++ test_truncated_no_rr (length); ++ for (int length = 0; length < offset_of_first_record; ++length) ++ test_truncated_before_rr (length); ++ ++ support_next_to_fault_free (&ntf); ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c +new file mode 100644 +index 0000000000..b06ac610b4 +--- /dev/null ++++ b/resolv/tst-ns_samebinaryname.c +@@ -0,0 +1,62 @@ ++/* Test the __ns_samebinaryname function. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* First character denotes the comparison group: All names with the ++ same first character are expected to compare equal. */ ++static const char *const cases[] = ++ { ++ " ", ++ "1\001a", "1\001A", ++ "2\002ab", "2\002aB", "2\002Ab", "2\002AB", ++ "3\001a\002ab", "3\001A\002ab", ++ "w\003www\007example\003com", "w\003Www\007Example\003Com", ++ "w\003WWW\007EXAMPLE\003COM", ++ "W\003WWW", "W\003www", ++ }; ++ ++static int ++do_test (void) ++{ ++ for (int i = 0; i < array_length (cases); ++i) ++ for (int j = 0; j < array_length (cases); ++j) ++ { ++ unsigned char *a = (unsigned char *) &cases[i][1]; ++ unsigned char *b = (unsigned char *) &cases[j][1]; ++ bool actual = __ns_samebinaryname (a, b); ++ bool expected = cases[i][0] == cases[j][0]; ++ if (actual != expected) ++ { ++ char a1[NS_MAXDNAME]; ++ TEST_VERIFY (ns_name_ntop (a, a1, sizeof (a1)) > 0); ++ char b1[NS_MAXDNAME]; ++ TEST_VERIFY (ns_name_ntop (b, b1, sizeof (b1)) > 0); ++ printf ("error: \"%s\" \"%s\": expected %s\n", ++ a1, b1, expected ? "equal" : "unqueal"); ++ support_record_failure (); ++ } ++ } ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-aliases.c b/resolv/tst-resolv-aliases.c +new file mode 100644 +index 0000000000..b212823aa0 +--- /dev/null ++++ b/resolv/tst-resolv-aliases.c +@@ -0,0 +1,254 @@ ++/* Test alias handling (mainly for gethostbyname). ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "tst-resolv-maybe_insert_sig.h" ++ ++/* QNAME format: ++ ++ aADDRESSES-cCNAMES.example.net ++ ++ CNAMES is the length of the CNAME chain, ADDRESSES is the number of ++ addresses in the response. The special value 255 means that there ++ are no addresses, and the RCODE is NXDOMAIN. */ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_COMPARE (qclass, C_IN); ++ if (qtype != T_A) ++ TEST_COMPARE (qtype, T_AAAA); ++ ++ unsigned int addresses, cnames; ++ char *tail; ++ if (sscanf (qname, "a%u-c%u%ms", &addresses, &cnames, &tail) == 3) ++ { ++ if (strcmp (tail, ".example.com") == 0 ++ || strcmp (tail, ".example.net.example.net") == 0 ++ || strcmp (tail, ".example.net.example.com") == 0) ++ /* These only happen after NXDOMAIN. */ ++ TEST_VERIFY (addresses == 255); ++ else if (strcmp (tail, ".example.net") != 0) ++ FAIL_EXIT1 ("invalid QNAME: %s", qname); ++ } ++ free (tail); ++ ++ int rcode; ++ if (addresses == 255) ++ { ++ /* Special case: Use no addresses with NXDOMAIN response. */ ++ rcode = ns_r_nxdomain; ++ addresses = 0; ++ } ++ else ++ rcode = 0; ++ ++ struct resolv_response_flags flags = { .rcode = rcode }; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ maybe_insert_sig (b, qname); ++ ++ /* Provide the requested number of CNAME records. */ ++ char *previous_name = (char *) qname; ++ for (int unique = 0; unique < cnames; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); ++ char *new_name = xasprintf ("%d.alias.example", unique); ++ resolv_response_add_name (b, new_name); ++ resolv_response_close_record (b); ++ ++ maybe_insert_sig (b, qname); ++ ++ if (previous_name != qname) ++ free (previous_name); ++ previous_name = new_name; ++ } ++ ++ for (int unique = 0; unique < addresses; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, qtype, 60); ++ ++ if (qtype == T_A) ++ { ++ char ipv4[4] = {192, 0, 2, 1 + unique}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ } ++ else if (qtype == T_AAAA) ++ { ++ char ipv6[16] = ++ { ++ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 1 + unique ++ }; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ } ++ resolv_response_close_record (b); ++ } ++ ++ if (previous_name != qname) ++ free (previous_name); ++} ++ ++static char * ++make_qname (bool do_search, int cnames, int addresses) ++{ ++ return xasprintf ("a%d-c%d%s", ++ addresses, cnames, do_search ? "" : ".example.net"); ++} ++ ++static void ++check_cnames_failure (int af, bool do_search, int cnames, int addresses) ++{ ++ char *qname = make_qname (do_search, cnames, addresses); ++ ++ struct hostent *e; ++ if (af == AF_UNSPEC) ++ e = gethostbyname (qname); ++ else ++ e = gethostbyname2 (qname, af); ++ ++ if (addresses == 0) ++ check_hostent (qname, e, "error: NO_RECOVERY\n"); ++ else ++ check_hostent (qname, e, "error: HOST_NOT_FOUND\n"); ++ ++ free (qname); ++} ++ ++static void ++check (int af, bool do_search, int cnames, int addresses) ++{ ++ char *qname = make_qname (do_search, cnames, addresses); ++ char *fqdn = make_qname (false, cnames, addresses); ++ ++ struct hostent *e; ++ if (af == AF_UNSPEC) ++ e = gethostbyname (qname); ++ else ++ e = gethostbyname2 (qname, af); ++ if (e == NULL) ++ FAIL_EXIT1 ("unexpected failure for %d, %d, %d", af, cnames, addresses); ++ ++ if (af == AF_UNSPEC || af == AF_INET) ++ { ++ TEST_COMPARE (e->h_addrtype, AF_INET); ++ TEST_COMPARE (e->h_length, 4); ++ } ++ else ++ { ++ TEST_COMPARE (e->h_addrtype, AF_INET6); ++ TEST_COMPARE (e->h_length, 16); ++ } ++ ++ for (int i = 0; i < addresses; ++i) ++ { ++ char ipv4[4] = {192, 0, 2, 1 + i}; ++ char ipv6[16] = ++ { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + i }; ++ char *expected = e->h_addrtype == AF_INET ? ipv4 : ipv6; ++ TEST_COMPARE_BLOB (e->h_addr_list[i], e->h_length, ++ expected, e->h_length); ++ } ++ TEST_VERIFY (e->h_addr_list[addresses] == NULL); ++ ++ ++ if (cnames == 0) ++ { ++ /* QNAME is fully qualified. */ ++ TEST_COMPARE_STRING (e->h_name, fqdn); ++ TEST_VERIFY (e->h_aliases[0] == NULL); ++ } ++ else ++ { ++ /* Fully-qualified QNAME is demoted to an aliases. */ ++ TEST_COMPARE_STRING (e->h_aliases[0], fqdn); ++ ++ for (int i = 1; i <= cnames; ++i) ++ { ++ char *expected = xasprintf ("%d.alias.example", i - 1); ++ if (i == cnames) ++ TEST_COMPARE_STRING (e->h_name, expected); ++ else ++ TEST_COMPARE_STRING (e->h_aliases[i], expected); ++ free (expected); ++ } ++ TEST_VERIFY (e->h_aliases[cnames] == NULL); ++ } ++ ++ free (fqdn); ++ free (qname); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response, ++ .search = { "example.net", "example.com" }, ++ }); ++ ++ static const int families[] = { AF_UNSPEC, AF_INET, AF_INET6 }; ++ ++ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig) ++ { ++ insert_sig = do_insert_sig; ++ ++ /* If do_search is true, a bare host name (for example, a1-c1) ++ is used. This exercises search path processing and FQDN ++ qualification. */ ++ for (int do_search = 0; do_search < 2; ++do_search) ++ for (const int *paf = families; paf != array_end (families); ++paf) ++ { ++ for (int cnames = 0; cnames <= 100; ++cnames) ++ { ++ check_cnames_failure (*paf, do_search, cnames, 0); ++ /* Now with NXDOMAIN responses. */ ++ check_cnames_failure (*paf, do_search, cnames, 255); ++ } ++ ++ for (int cnames = 0; cnames <= 10; ++cnames) ++ for (int addresses = 1; addresses <= 10; ++addresses) ++ check (*paf, do_search, cnames, addresses); ++ ++ /* The current implementation is limited to 47 aliases. ++ Addresses do not have such a limit. */ ++ check (*paf, do_search, 47, 60); ++ } ++ } ++ ++ resolv_test_end (obj); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-byaddr.c b/resolv/tst-resolv-byaddr.c +new file mode 100644 +index 0000000000..6299e89837 +--- /dev/null ++++ b/resolv/tst-resolv-byaddr.c +@@ -0,0 +1,326 @@ ++/* Test reverse DNS lookup. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "tst-resolv-maybe_insert_sig.h" ++ ++/* QNAME format: ++ ++ ADDRESSES.CNAMES...(lots of 0s)...8.b.d.0.1.0.0.2.ip6.arpa. ++ CNAMES|ADDRESSES.2.0.192.in-addr-arpa. ++ ++ For the IPv4 reverse lookup, the address count is in the lower ++ bits. ++ ++ CNAMES is the length of the CNAME chain, ADDRESSES is the number of ++ addresses in the response. The special value 15 means that there ++ are no addresses, and the RCODE is NXDOMAIN. */ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_COMPARE (qclass, C_IN); ++ TEST_COMPARE (qtype, T_PTR); ++ ++ unsigned int addresses, cnames, bits; ++ char *tail; ++ if (strstr (qname, "ip6.arpa") != NULL ++ && sscanf (qname, "%x.%x.%ms", &addresses, &cnames, &tail) == 3) ++ TEST_COMPARE_STRING (tail, "\ ++0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"); ++ else if (sscanf (qname, "%u.%ms", &bits, &tail) == 2) ++ { ++ TEST_COMPARE_STRING (tail, "2.0.192.in-addr.arpa"); ++ addresses = bits & 0x0f; ++ cnames = bits >> 4; ++ } ++ else ++ FAIL_EXIT1 ("invalid QNAME: %s", qname); ++ free (tail); ++ ++ int rcode; ++ if (addresses == 15) ++ { ++ /* Special case: Use no addresses with NXDOMAIN response. */ ++ rcode = ns_r_nxdomain; ++ addresses = 0; ++ } ++ else ++ rcode = 0; ++ ++ struct resolv_response_flags flags = { .rcode = rcode }; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ maybe_insert_sig (b, qname); ++ ++ /* Provide the requested number of CNAME records. */ ++ char *previous_name = (char *) qname; ++ for (int unique = 0; unique < cnames; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); ++ char *new_name = xasprintf ("%d.alias.example", unique); ++ resolv_response_add_name (b, new_name); ++ resolv_response_close_record (b); ++ ++ maybe_insert_sig (b, qname); ++ ++ if (previous_name != qname) ++ free (previous_name); ++ previous_name = new_name; ++ } ++ ++ for (int unique = 0; unique < addresses; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_PTR, 60); ++ char *ptr = xasprintf ("unique-%d.cnames-%u.addresses-%u.example", ++ unique, cnames, addresses); ++ resolv_response_add_name (b, ptr); ++ free (ptr); ++ resolv_response_close_record (b); ++ } ++ ++ if (previous_name != qname) ++ free (previous_name); ++} ++ ++/* Used to check that gethostbyaddr_r does not write past the buffer ++ end. */ ++static struct support_next_to_fault ntf; ++ ++/* Perform a gethostbyaddr call and check the result. */ ++static void ++check_gethostbyaddr (const char *address, const char *expected) ++{ ++ unsigned char bytes[16]; ++ unsigned int byteslen; ++ int family; ++ if (strchr (address, ':') != NULL) ++ { ++ family = AF_INET6; ++ byteslen = 16; ++ } ++ else ++ { ++ family = AF_INET; ++ byteslen = 4; ++ } ++ TEST_COMPARE (inet_pton (family, address, bytes), 1); ++ ++ struct hostent *e = gethostbyaddr (bytes, byteslen, family); ++ check_hostent (address, e, expected); ++ ++ if (e == NULL) ++ return; ++ ++ /* Try gethostbyaddr_r with increasing sizes until success. First ++ compute a reasonable minimum buffer size, to avoid many pointless ++ attempts. */ ++ size_t minimum_size = strlen (e->h_name); ++ for (int i = 0; e->h_addr_list[i] != NULL; ++i) ++ minimum_size += e->h_length + sizeof (char *); ++ for (int i = 0; e->h_aliases[i] != NULL; ++i) ++ minimum_size += strlen (e->h_aliases[i]) + 1 + sizeof (char *); ++ ++ /* Gradually increase the size until success. */ ++ for (size_t size = minimum_size; size < ntf.length; ++size) ++ { ++ struct hostent result; ++ int herrno; ++ int ret = gethostbyaddr_r (bytes, byteslen, family, &result, ++ ntf.buffer + ntf.length - size, size, ++ &e, &herrno); ++ if (ret == ERANGE) ++ /* Retry with larger size. */ ++ TEST_COMPARE (herrno, NETDB_INTERNAL); ++ else if (ret == 0) ++ { ++ TEST_VERIFY (size > minimum_size); ++ check_hostent (address, e, expected); ++ return; ++ } ++ else ++ FAIL_EXIT1 ("Unexpected gethostbyaddr_r failure: %d", ret); ++ } ++ ++ FAIL_EXIT1 ("gethostbyaddr_r always failed for: %s", address); ++} ++ ++/* Perform a getnameinfo call and check the result. */ ++static void ++check_getnameinfo (const char *address, const char *expected) ++{ ++ struct sockaddr_in sin = { }; ++ struct sockaddr_in6 sin6 = { }; ++ void *sa; ++ socklen_t salen; ++ if (strchr (address, ':') != NULL) ++ { ++ sin6.sin6_family = AF_INET6; ++ TEST_COMPARE (inet_pton (AF_INET6, address, &sin6.sin6_addr), 1); ++ sin6.sin6_port = htons (80); ++ sa = &sin6; ++ salen = sizeof (sin6); ++ } ++ else ++ { ++ sin.sin_family = AF_INET; ++ TEST_COMPARE (inet_pton (AF_INET, address, &sin.sin_addr), 1); ++ sin.sin_port = htons (80); ++ sa = &sin; ++ salen = sizeof (sin); ++ } ++ ++ char host[64]; ++ char service[64]; ++ int ret = getnameinfo (sa, salen, host, ++ sizeof (host), service, sizeof (service), ++ NI_NAMEREQD | NI_NUMERICSERV); ++ switch (ret) ++ { ++ case 0: ++ TEST_COMPARE_STRING (host, expected); ++ TEST_COMPARE_STRING (service, "80"); ++ break; ++ case EAI_SYSTEM: ++ TEST_COMPARE_STRING (strerror (errno), expected); ++ break; ++ default: ++ TEST_COMPARE_STRING (gai_strerror (ret), expected); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ /* Some reasonably upper bound for the maximum response size. */ ++ ntf = support_next_to_fault_allocate (4096); ++ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ for (int do_insert_sig = 0; do_insert_sig < 2; ++do_insert_sig) ++ { ++ insert_sig = do_insert_sig; ++ ++ /* No PTR record, RCODE=0. */ ++ check_gethostbyaddr ("192.0.2.0", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("192.0.2.0", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.16", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("192.0.2.16", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.32", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("192.0.2.32", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("2001:db8::", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::10", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("2001:db8::10", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::20", "error: NO_RECOVERY\n"); ++ check_getnameinfo ("2001:db8::20", "Name or service not known"); ++ ++ /* No PTR record, NXDOMAIN. */ ++ check_gethostbyaddr ("192.0.2.15", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("192.0.2.15", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.31", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("192.0.2.31", "Name or service not known"); ++ check_gethostbyaddr ("192.0.2.47", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("192.0.2.47", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::f", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("2001:db8::f", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::1f", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("2001:db8::1f", "Name or service not known"); ++ check_gethostbyaddr ("2001:db8::2f", "error: HOST_NOT_FOUND\n"); ++ check_getnameinfo ("2001:db8::2f", "Name or service not known"); ++ ++ /* Actual response data. Only the first PTR record is returned. */ ++ check_gethostbyaddr ("192.0.2.1", ++ "name: unique-0.cnames-0.addresses-1.example\n" ++ "address: 192.0.2.1\n"); ++ check_getnameinfo ("192.0.2.1", ++ "unique-0.cnames-0.addresses-1.example"); ++ check_gethostbyaddr ("192.0.2.17", ++ "name: unique-0.cnames-1.addresses-1.example\n" ++ "address: 192.0.2.17\n"); ++ check_getnameinfo ("192.0.2.17", ++ "unique-0.cnames-1.addresses-1.example"); ++ check_gethostbyaddr ("192.0.2.18", ++ "name: unique-0.cnames-1.addresses-2.example\n" ++ "address: 192.0.2.18\n"); ++ check_getnameinfo ("192.0.2.18", ++ "unique-0.cnames-1.addresses-2.example"); ++ check_gethostbyaddr ("192.0.2.33", ++ "name: unique-0.cnames-2.addresses-1.example\n" ++ "address: 192.0.2.33\n"); ++ check_getnameinfo ("192.0.2.33", ++ "unique-0.cnames-2.addresses-1.example"); ++ check_gethostbyaddr ("192.0.2.34", ++ "name: unique-0.cnames-2.addresses-2.example\n" ++ "address: 192.0.2.34\n"); ++ check_getnameinfo ("192.0.2.34", ++ "unique-0.cnames-2.addresses-2.example"); ++ ++ /* Same for IPv6 addresses. */ ++ check_gethostbyaddr ("2001:db8::1", ++ "name: unique-0.cnames-0.addresses-1.example\n" ++ "address: 2001:db8::1\n"); ++ check_getnameinfo ("2001:db8::1", ++ "unique-0.cnames-0.addresses-1.example"); ++ check_gethostbyaddr ("2001:db8::11", ++ "name: unique-0.cnames-1.addresses-1.example\n" ++ "address: 2001:db8::11\n"); ++ check_getnameinfo ("2001:db8::11", ++ "unique-0.cnames-1.addresses-1.example"); ++ check_gethostbyaddr ("2001:db8::12", ++ "name: unique-0.cnames-1.addresses-2.example\n" ++ "address: 2001:db8::12\n"); ++ check_getnameinfo ("2001:db8::12", ++ "unique-0.cnames-1.addresses-2.example"); ++ check_gethostbyaddr ("2001:db8::21", ++ "name: unique-0.cnames-2.addresses-1.example\n" ++ "address: 2001:db8::21\n"); ++ check_getnameinfo ("2001:db8::21", ++ "unique-0.cnames-2.addresses-1.example"); ++ check_gethostbyaddr ("2001:db8::22", ++ "name: unique-0.cnames-2.addresses-2.example\n" ++ "address: 2001:db8::22\n"); ++ check_getnameinfo ("2001:db8::22", ++ "unique-0.cnames-2.addresses-2.example"); ++ } ++ ++ resolv_test_end (obj); ++ ++ support_next_to_fault_free (&ntf); ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-invalid-cname.c b/resolv/tst-resolv-invalid-cname.c +new file mode 100644 +index 0000000000..63dac90e02 +--- /dev/null ++++ b/resolv/tst-resolv-invalid-cname.c +@@ -0,0 +1,406 @@ ++/* Test handling of CNAMEs with non-host domain names (bug 12154). ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Query strings describe the CNAME chain in the response. They have ++ the format "bitsBITS.countCOUNT.example.", where BITS and COUNT are ++ replaced by unsigned decimal numbers. COUNT is the number of CNAME ++ records in the response. BITS has two bits for each CNAME record, ++ describing a special prefix that is added to that CNAME. ++ ++ 0: No special leading label. ++ 1: Starting with "*.". ++ 2: Starting with "-x.". ++ 3: Starting with "star.*.". ++ ++ The first CNAME in the response using the two least significant ++ bits. ++ ++ For PTR queries, the QNAME format is different, it is either ++ COUNT.BITS.168.192.in-addr.arpa. (with BITS and COUNT still ++ decimal), or: ++ ++COUNT.BITS0.BITS1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. ++ ++ where BITS and COUNT are hexadecimal. */ ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ TEST_COMPARE (qclass, C_IN); ++ ++ /* The only other query type besides A is PTR. */ ++ if (qtype != T_A && qtype != T_AAAA) ++ TEST_COMPARE (qtype, T_PTR); ++ ++ unsigned int bits, bits1, count; ++ char *tail = NULL; ++ if (sscanf (qname, "bits%u.count%u.%ms", &bits, &count, &tail) == 3) ++ TEST_COMPARE_STRING (tail, "example"); ++ else if (strstr (qname, "in-addr.arpa") != NULL ++ && sscanf (qname, "%u.%u.%ms", &bits, &count, &tail) == 3) ++ TEST_COMPARE_STRING (tail, "168.192.in-addr.arpa"); ++ else if (sscanf (qname, "%x.%x.%x.%ms", &bits, &bits1, &count, &tail) == 4) ++ { ++ TEST_COMPARE_STRING (tail, "\ ++0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa"); ++ bits |= bits1 << 4; ++ } ++ else ++ FAIL_EXIT1 ("invalid QNAME: %s\n", qname); ++ free (tail); ++ ++ struct resolv_response_flags flags = {}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ ++ /* Provide the requested number of CNAME records. */ ++ char *previous_name = (char *) qname; ++ unsigned int original_bits = bits; ++ for (int unique = 0; unique < count; ++unique) ++ { ++ resolv_response_open_record (b, previous_name, qclass, T_CNAME, 60); ++ ++ static const char bits_to_prefix[4][8] = { "", "*.", "-x.", "star.*." }; ++ char *new_name = xasprintf ("%sunique%d.example", ++ bits_to_prefix[bits & 3], unique); ++ bits >>= 2; ++ resolv_response_add_name (b, new_name); ++ resolv_response_close_record (b); ++ ++ if (previous_name != qname) ++ free (previous_name); ++ previous_name = new_name; ++ } ++ ++ /* Actual answer record. */ ++ resolv_response_open_record (b, previous_name, qclass, qtype, 60); ++ switch (qtype) ++ { ++ case T_A: ++ { ++ char ipv4[4] = {192, 168, count, original_bits}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ } ++ break; ++ case T_AAAA: ++ { ++ char ipv6[16] = ++ { ++ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ count, original_bits ++ }; ++ resolv_response_add_data (b, &ipv6, sizeof (ipv6)); ++ } ++ break; ++ ++ case T_PTR: ++ { ++ char *name = xasprintf ("bits%u.count%u.example", ++ original_bits, count); ++ resolv_response_add_name (b, name); ++ free (name); ++ } ++ break; ++ } ++ resolv_response_close_record (b); ++ ++ if (previous_name != qname) ++ free (previous_name); ++} ++ ++/* Controls which name resolution function is invoked. */ ++enum test_mode ++ { ++ byname, /* gethostbyname. */ ++ byname2, /* gethostbyname2. */ ++ gai, /* getaddrinfo without AI_CANONNAME. */ ++ gai_canon, /* getaddrinfo with AI_CANONNAME. */ ++ ++ test_mode_num /* Number of enum values. */ ++ }; ++ ++static const char * ++test_mode_to_string (enum test_mode mode) ++{ ++ switch (mode) ++ { ++ case byname: ++ return "byname"; ++ case byname2: ++ return "byname2"; ++ case gai: ++ return "gai"; ++ case gai_canon: ++ return "gai_canon"; ++ case test_mode_num: ++ break; /* Report error below. */ ++ } ++ FAIL_EXIT1 ("invalid test_mode: %d", mode); ++} ++ ++/* Append the name and aliases to OUT. */ ++static void ++append_names (FILE *out, const char *qname, int bits, int count, ++ enum test_mode mode) ++{ ++ /* Largest valid index which has a corresponding zero in bits ++ (meaning a syntactically valid CNAME). */ ++ int last_valid_cname = -1; ++ ++ for (int i = 0; i < count; ++i) ++ if ((bits & (3 << (i * 2))) == 0) ++ last_valid_cname = i; ++ ++ if (mode != gai) ++ { ++ const char *label; ++ if (mode == gai_canon) ++ label = "canonname"; ++ else ++ label = "name"; ++ if (last_valid_cname >= 0) ++ fprintf (out, "%s: unique%d.example\n", label, last_valid_cname); ++ else ++ fprintf (out, "%s: %s\n", label, qname); ++ } ++ ++ if (mode == byname || mode == byname2) ++ { ++ if (last_valid_cname >= 0) ++ fprintf (out, "alias: %s\n", qname); ++ for (int i = 0; i < count; ++i) ++ { ++ if ((bits & (3 << (i * 2))) == 0 && i != last_valid_cname) ++ fprintf (out, "alias: unique%d.example\n", i); ++ } ++ } ++} ++ ++/* Append the address information to OUT. */ ++static void ++append_addresses (FILE *out, int af, int bits, int count, enum test_mode mode) ++{ ++ int last = count * 256 + bits; ++ if (mode == gai || mode == gai_canon) ++ { ++ if (af == AF_INET || af == AF_UNSPEC) ++ fprintf (out, "address: STREAM/TCP 192.168.%d.%d 80\n", count, bits); ++ if (af == AF_INET6 || af == AF_UNSPEC) ++ { ++ if (last == 0) ++ fprintf (out, "address: STREAM/TCP 2001:db8:: 80\n"); ++ else ++ fprintf (out, "address: STREAM/TCP 2001:db8::%x 80\n", last); ++ } ++ } ++ else ++ { ++ TEST_VERIFY (af != AF_UNSPEC); ++ if (af == AF_INET) ++ fprintf (out, "address: 192.168.%d.%d\n", count, bits); ++ if (af == AF_INET6) ++ { ++ if (last == 0) ++ fprintf (out, "address: 2001:db8::\n"); ++ else ++ fprintf (out, "address: 2001:db8::%x\n", last); ++ } ++ } ++} ++ ++/* Perform one test using a forward lookup. */ ++static void ++check_forward (int af, int bits, int count, enum test_mode mode) ++{ ++ char *qname = xasprintf ("bits%d.count%d.example", bits, count); ++ char *label = xasprintf ("af=%d bits=%d count=%d mode=%s qname=%s", ++ af, bits, count, test_mode_to_string (mode), qname); ++ ++ struct xmemstream expected; ++ xopen_memstream (&expected); ++ if (mode == gai_canon) ++ fprintf (expected.out, "flags: AI_CANONNAME\n"); ++ append_names (expected.out, qname, bits, count, mode); ++ append_addresses (expected.out, af, bits, count, mode); ++ xfclose_memstream (&expected); ++ ++ if (mode == gai || mode == gai_canon) ++ { ++ struct addrinfo *ai; ++ struct addrinfo hints = ++ { ++ .ai_family = af, ++ .ai_socktype = SOCK_STREAM, ++ }; ++ if (mode == gai_canon) ++ hints.ai_flags |= AI_CANONNAME; ++ int ret = getaddrinfo (qname, "80", &hints, &ai); ++ check_addrinfo (label, ai, ret, expected.buffer); ++ if (ret == 0) ++ freeaddrinfo (ai); ++ } ++ else ++ { ++ struct hostent *e; ++ if (mode == gai) ++ { ++ TEST_COMPARE (af, AF_INET); ++ e = gethostbyname (qname); ++ } ++ else ++ { ++ if (af != AF_INET) ++ TEST_COMPARE (af, AF_INET6); ++ e = gethostbyname2 (qname, af); ++ } ++ check_hostent (label, e, expected.buffer); ++ } ++ ++ free (expected.buffer); ++ free (label); ++ free (qname); ++} ++ ++/* Perform one check using a reverse lookup. */ ++ ++static void ++check_reverse (int af, int bits, int count) ++{ ++ TEST_VERIFY (af == AF_INET || af == AF_INET6); ++ ++ char *label = xasprintf ("af=%d bits=%d count=%d", af, bits, count); ++ char *fqdn = xasprintf ("bits%d.count%d.example", bits, count); ++ ++ struct xmemstream expected; ++ xopen_memstream (&expected); ++ fprintf (expected.out, "name: %s\n", fqdn); ++ append_addresses (expected.out, af, bits, count, byname); ++ xfclose_memstream (&expected); ++ ++ char addr[16] = { 0 }; ++ socklen_t addrlen; ++ if (af == AF_INET) ++ { ++ addr[0] = 192; ++ addr[1] = 168; ++ addr[2] = count; ++ addr[3] = bits; ++ addrlen = 4; ++ } ++ else ++ { ++ addr[0] = 0x20; ++ addr[1] = 0x01; ++ addr[2] = 0x0d; ++ addr[3] = 0xb8; ++ addr[14] = count; ++ addr[15] = bits; ++ addrlen = 16; ++ } ++ ++ struct hostent *e = gethostbyaddr (addr, addrlen, af); ++ check_hostent (label, e, expected.buffer); ++ ++ /* getnameinfo check is different. There is no generic check_* ++ function for it. */ ++ { ++ struct sockaddr_in sin = { }; ++ struct sockaddr_in6 sin6 = { }; ++ void *sa; ++ socklen_t salen; ++ if (af == AF_INET) ++ { ++ sin.sin_family = AF_INET; ++ memcpy (&sin.sin_addr, addr, addrlen); ++ sin.sin_port = htons (80); ++ sa = &sin; ++ salen = sizeof (sin); ++ } ++ else ++ { ++ sin6.sin6_family = AF_INET6; ++ memcpy (&sin6.sin6_addr, addr, addrlen); ++ sin6.sin6_port = htons (80); ++ sa = &sin6; ++ salen = sizeof (sin6); ++ } ++ ++ char host[64]; ++ char service[64]; ++ int ret = getnameinfo (sa, salen, host, ++ sizeof (host), service, sizeof (service), ++ NI_NAMEREQD | NI_NUMERICSERV); ++ TEST_COMPARE (ret, 0); ++ TEST_COMPARE_STRING (host, fqdn); ++ TEST_COMPARE_STRING (service, "80"); ++ } ++ ++ free (expected.buffer); ++ free (fqdn); ++ free (label); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ for (int count = 0; count <= 3; ++count) ++ for (int bits = 0; bits <= 1 << (count * 2); ++bits) ++ { ++ if (count > 0 && bits == count) ++ /* The last bits value is only checked if count == 0. */ ++ continue; ++ ++ for (enum test_mode mode = 0; mode < test_mode_num; ++mode) ++ { ++ check_forward (AF_INET, bits, count, mode); ++ if (mode != byname) ++ check_forward (AF_INET6, bits, count, mode); ++ if (mode == gai || mode == gai_canon) ++ check_forward (AF_UNSPEC, bits, count, mode); ++ } ++ ++ check_reverse (AF_INET, bits, count); ++ check_reverse (AF_INET6, bits, count); ++ } ++ ++ resolv_test_end (obj); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/tst-resolv-maybe_insert_sig.h b/resolv/tst-resolv-maybe_insert_sig.h +new file mode 100644 +index 0000000000..05725225af +--- /dev/null ++++ b/resolv/tst-resolv-maybe_insert_sig.h +@@ -0,0 +1,32 @@ ++/* Code snippet for optionally inserting ignored SIG records in resolver tests. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Set to true for an alternative pass that inserts (ignored) SIG ++ records. This does not alter the response, so this property is not ++ encoded in the QNAME. The variable needs to be volatile because ++ leaf attributes tell GCC that the response function is not ++ called. */ ++static volatile bool insert_sig; ++ ++static void ++maybe_insert_sig (struct resolv_response_builder *b, const char *owner) ++{ ++ resolv_response_open_record (b, owner, C_IN, T_SIG, 60); ++ resolv_response_add_data (b, "", 1); ++ resolv_response_close_record (b); ++} +diff --git a/resolv/tst-resolv-noaaaa-vc.c b/resolv/tst-resolv-noaaaa-vc.c +new file mode 100644 +index 0000000000..9f5aebd99f +--- /dev/null ++++ b/resolv/tst-resolv-noaaaa-vc.c +@@ -0,0 +1,129 @@ ++/* Test the RES_NOAAAA resolver option with a large response. ++ Copyright (C) 2022-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Used to keep track of the number of queries. */ ++static volatile unsigned int queries; ++ ++/* If true, add a large TXT record at the start of the answer section. */ ++static volatile bool stuff_txt; ++ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ /* If not using TCP, just force its use. */ ++ if (!ctx->tcp) ++ { ++ struct resolv_response_flags flags = {.tc = true}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ return; ++ } ++ ++ /* The test needs to send four queries, the first three are used to ++ grow the NSS buffer via the ERANGE handshake. */ ++ ++queries; ++ TEST_VERIFY (queries <= 4); ++ ++ /* AAAA queries are supposed to be disabled. */ ++ TEST_COMPARE (qtype, T_A); ++ TEST_COMPARE (qclass, C_IN); ++ TEST_COMPARE_STRING (qname, "example.com"); ++ ++ struct resolv_response_flags flags = {}; ++ resolv_response_init (b, flags); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ ++ resolv_response_section (b, ns_s_an); ++ ++ if (stuff_txt) ++ { ++ resolv_response_open_record (b, qname, qclass, T_TXT, 60); ++ int zero = 0; ++ for (int i = 0; i <= 15000; ++i) ++ resolv_response_add_data (b, &zero, sizeof (zero)); ++ resolv_response_close_record (b); ++ } ++ ++ for (int i = 0; i < 200; ++i) ++ { ++ resolv_response_open_record (b, qname, qclass, qtype, 60); ++ char ipv4[4] = {192, 0, 2, i + 1}; ++ resolv_response_add_data (b, &ipv4, sizeof (ipv4)); ++ resolv_response_close_record (b); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_test *obj = resolv_test_start ++ ((struct resolv_redirect_config) ++ { ++ .response_callback = response ++ }); ++ ++ _res.options |= RES_NOAAAA; ++ ++ for (int do_stuff_txt = 0; do_stuff_txt < 2; ++do_stuff_txt) ++ { ++ queries = 0; ++ stuff_txt = do_stuff_txt; ++ ++ struct addrinfo *ai = NULL; ++ int ret; ++ ret = getaddrinfo ("example.com", "80", ++ &(struct addrinfo) ++ { ++ .ai_family = AF_UNSPEC, ++ .ai_socktype = SOCK_STREAM, ++ }, &ai); ++ ++ char *expected_result; ++ { ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ for (int i = 0; i < 200; ++i) ++ fprintf (mem.out, "address: STREAM/TCP 192.0.2.%d 80\n", i + 1); ++ xfclose_memstream (&mem); ++ expected_result = mem.buffer; ++ } ++ ++ check_addrinfo ("example.com", ai, ret, expected_result); ++ ++ free (expected_result); ++ freeaddrinfo (ai); ++ } ++ ++ resolv_test_end (obj); ++ return 0; ++} ++ ++#include +diff --git a/scripts/dso-ordering-test.py b/scripts/dso-ordering-test.py +index 2dd6bfda18..b87cf2f809 100644 +--- a/scripts/dso-ordering-test.py ++++ b/scripts/dso-ordering-test.py +@@ -707,13 +707,12 @@ def process_testcase(t): + "\t$(compile.c) $(OUTPUT_OPTION)\n") + makefile.write (rule) + +- not_depended_objs = find_objs_not_depended_on(test_descr) +- if not_depended_objs: +- depstr = "" +- for dep in not_depended_objs: +- depstr += (" $(objpfx)" + test_subdir + "/" +- + test_name + "-" + dep + ".so") +- makefile.write("$(objpfx)%s.out:%s\n" % (base_test_name, depstr)) ++ # Ensure that all shared objects are built before running the ++ # test, whether there link-time dependencies or not. ++ depobjs = ["$(objpfx){}/{}-{}.so".format(test_subdir, test_name, dep) ++ for dep in test_descr.objs] ++ makefile.write("$(objpfx){}.out: {}\n".format( ++ base_test_name, " ".join(depobjs))) + + # Add main executable to test-srcs + makefile.write("test-srcs += %s/%s\n" % (test_subdir, test_name)) +diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py +index 43ab58ffe2..36d204c9b0 100644 +--- a/scripts/glibcextract.py ++++ b/scripts/glibcextract.py +@@ -17,6 +17,7 @@ + # License along with the GNU C Library; if not, see + # . + ++import collections + import os.path + import re + import subprocess +@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None, + if not allow_extra_2: + ret = 1 + return ret ++ ++CompileResult = collections.namedtuple("CompileResult", "returncode output") ++ ++def compile_c_snippet(snippet, cc, extra_cc_args=''): ++ """Compile and return whether the SNIPPET can be build with CC along ++ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE ++ being 0 for success, or the failure value and the compiler output. ++ """ ++ with tempfile.TemporaryDirectory() as temp_dir: ++ c_file_name = os.path.join(temp_dir, 'test.c') ++ obj_file_name = os.path.join(temp_dir, 'test.o') ++ with open(c_file_name, 'w') as c_file: ++ c_file.write(snippet + '\n') ++ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name, ++ c_file_name] ++ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT) ++ return CompileResult(r.returncode, r.stdout) +diff --git a/socket/Makefile b/socket/Makefile +index 156eec6c85..2bde78387f 100644 +--- a/socket/Makefile ++++ b/socket/Makefile +@@ -34,6 +34,7 @@ routines := accept bind connect getpeername getsockname getsockopt \ + tests := \ + tst-accept4 \ + tst-sockopt \ ++ tst-cmsghdr \ + # tests + + tests-internal := \ +diff --git a/socket/tst-cmsghdr-skeleton.c b/socket/tst-cmsghdr-skeleton.c +new file mode 100644 +index 0000000000..4c6898569b +--- /dev/null ++++ b/socket/tst-cmsghdr-skeleton.c +@@ -0,0 +1,92 @@ ++/* Test ancillary data header creation. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* We use the preprocessor to generate the function/macro tests instead of ++ using indirection because having all the macro expansions alongside ++ each other lets the compiler warn us about suspicious pointer ++ arithmetic across subsequent CMSG_{FIRST,NXT}HDR expansions. */ ++ ++#include ++ ++#define RUN_TEST_CONCAT(suffix) run_test_##suffix ++#define RUN_TEST_FUNCNAME(suffix) RUN_TEST_CONCAT (suffix) ++ ++static void ++RUN_TEST_FUNCNAME (CMSG_NXTHDR_IMPL) (void) ++{ ++ struct msghdr m = {0}; ++ struct cmsghdr *cmsg; ++ char cmsgbuf[3 * CMSG_SPACE (sizeof (PAYLOAD))] = {0}; ++ ++ m.msg_control = cmsgbuf; ++ m.msg_controllen = sizeof (cmsgbuf); ++ ++ /* First header should point to the start of the buffer. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ ++ /* If the first header length consumes the entire buffer, there is no ++ space remaining for additional headers. */ ++ cmsg->cmsg_len = sizeof (cmsgbuf); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ /* The first header length is so big, using it would cause an overflow. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len = SIZE_MAX; ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ /* The first header leaves just enough space to hold another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len = sizeof (cmsgbuf) - sizeof (struct cmsghdr); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ ++ /* The first header leaves space but not enough for another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len ++; ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ /* The second header leaves just enough space to hold another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg->cmsg_len = CMSG_LEN (sizeof (PAYLOAD)); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ cmsg->cmsg_len = sizeof (cmsgbuf) ++ - CMSG_SPACE (sizeof (PAYLOAD)) /* First header. */ ++ - sizeof (struct cmsghdr); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ ++ /* The second header leaves space but not enough for another header. */ ++ cmsg = CMSG_FIRSTHDR (&m); ++ TEST_VERIFY_EXIT ((char *) cmsg == cmsgbuf); ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg != NULL); ++ cmsg->cmsg_len ++; ++ cmsg = CMSG_NXTHDR_IMPL (&m, cmsg); ++ TEST_VERIFY_EXIT (cmsg == NULL); ++ ++ return; ++} +diff --git a/socket/tst-cmsghdr.c b/socket/tst-cmsghdr.c +new file mode 100644 +index 0000000000..68c96d3c9d +--- /dev/null ++++ b/socket/tst-cmsghdr.c +@@ -0,0 +1,56 @@ ++/* Test ancillary data header creation. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#define PAYLOAD "Hello, World!" ++ ++/* CMSG_NXTHDR is a macro that calls an inline function defined in ++ bits/socket.h. In case the function cannot be inlined, libc.so carries ++ a copy. Both versions need to be tested. */ ++ ++#define CMSG_NXTHDR_IMPL CMSG_NXTHDR ++#include "tst-cmsghdr-skeleton.c" ++#undef CMSG_NXTHDR_IMPL ++ ++static struct cmsghdr * (* cmsg_nxthdr) (struct msghdr *, struct cmsghdr *); ++ ++#define CMSG_NXTHDR_IMPL cmsg_nxthdr ++#include "tst-cmsghdr-skeleton.c" ++#undef CMSG_NXTHDR_IMPL ++ ++static int ++do_test (void) ++{ ++ static void *handle; ++ ++ run_test_CMSG_NXTHDR (); ++ ++ handle = xdlopen (LIBC_SO, RTLD_LAZY); ++ cmsg_nxthdr = (struct cmsghdr * (*) (struct msghdr *, struct cmsghdr *)) ++ xdlsym (handle, "__cmsg_nxthdr"); ++ ++ run_test_cmsg_nxthdr (); ++ ++ return 0; ++} ++ ++#include +diff --git a/stdlib/Makefile b/stdlib/Makefile +index f7b25c1981..3d49c4941a 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -171,6 +171,7 @@ tests := \ + test-a64l \ + test-at_quick_exit-race \ + test-atexit-race \ ++ test-atexit-recursive \ + test-bz22786 \ + test-canon \ + test-canon2 \ +diff --git a/stdlib/arc4random.c b/stdlib/arc4random.c +index e417ef624d..960a38f295 100644 +--- a/stdlib/arc4random.c ++++ b/stdlib/arc4random.c +@@ -34,7 +34,7 @@ void + __arc4random_buf (void *p, size_t n) + { + static int seen_initialized; +- size_t l; ++ ssize_t l; + int fd; + + if (n == 0) +diff --git a/stdlib/exit.c b/stdlib/exit.c +index bc46109f3e..dc12e212bc 100644 +--- a/stdlib/exit.c ++++ b/stdlib/exit.c +@@ -53,7 +53,10 @@ __run_exit_handlers (int status, struct exit_function_list **listp, + exit (). */ + while (true) + { +- struct exit_function_list *cur = *listp; ++ struct exit_function_list *cur; ++ ++ restart: ++ cur = *listp; + + if (cur == NULL) + { +@@ -118,7 +121,7 @@ __run_exit_handlers (int status, struct exit_function_list **listp, + if (__glibc_unlikely (new_exitfn_called != __new_exitfn_called)) + /* The last exit function, or another thread, has registered + more exit functions. Start the loop over. */ +- continue; ++ goto restart; + } + + *listp = cur->next; +diff --git a/stdlib/longlong.h b/stdlib/longlong.h +index 9b89469ac2..d8f76a43b5 100644 +--- a/stdlib/longlong.h ++++ b/stdlib/longlong.h +@@ -593,6 +593,18 @@ extern UDItype __umulsidi3 (USItype, USItype); + #define UMUL_TIME 14 + #endif + ++#ifdef __loongarch__ ++# if W_TYPE_SIZE == 32 ++# define count_leading_zeros(count, x) ((count) = __builtin_clz (x)) ++# define count_trailing_zeros(count, x) ((count) = __builtin_ctz (x)) ++# define COUNT_LEADING_ZEROS_0 32 ++# elif W_TYPE_SIZE == 64 ++# define count_leading_zeros(count, x) ((count) = __builtin_clzll (x)) ++# define count_trailing_zeros(count, x) ((count) = __builtin_ctzll (x)) ++# define COUNT_LEADING_ZEROS_0 64 ++# endif ++#endif ++ + #if defined (__M32R__) && W_TYPE_SIZE == 32 + #define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + /* The cmp clears the condition bit. */ \ +diff --git a/stdlib/test-atexit-recursive.c b/stdlib/test-atexit-recursive.c +new file mode 100644 +index 0000000000..0596b9763b +--- /dev/null ++++ b/stdlib/test-atexit-recursive.c +@@ -0,0 +1,75 @@ ++/* Support file for atexit/exit, etc. race tests (BZ #27749). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Check that atexit handler registed from another handler still called. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++atexit_cb (void) ++{ ++} ++ ++static void ++atexit_last (void) ++{ ++ _exit (1); ++} ++ ++static void ++atexit_recursive (void) ++{ ++ atexit (&atexit_cb); ++ atexit (&atexit_last); ++} ++ ++_Noreturn static void ++test_and_exit (int count) ++{ ++ for (int i = 0; i < count; ++i) ++ atexit (&atexit_cb); ++ atexit (&atexit_recursive); ++ exit (0); ++} ++ ++static int ++do_test (void) ++{ ++ for (int i = 0; i < 100; ++i) ++ if (xfork () == 0) ++ test_and_exit (i); ++ ++ for (int i = 0; i < 100; ++i) ++ { ++ int status; ++ xwaitpid (0, &status, 0); ++ if (!WIFEXITED (status)) ++ FAIL_EXIT1 ("Failed iterations %d", i); ++ TEST_COMPARE (WEXITSTATUS (status), 1); ++ } ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION do_test ++#include +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index f7fa74b2a6..5e0c79475f 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + + static char *tmpdir; +@@ -71,6 +72,20 @@ call_system (void *closure) + } + } + ++static void * ++sleep_and_check_sigchld (void *closure) ++{ ++ double *seconds = (double *) closure; ++ char cmd[namemax]; ++ sprintf (cmd, "sleep %lf" , *seconds); ++ TEST_COMPARE (system (cmd), 0); ++ ++ sigset_t blocked = {0}; ++ TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0); ++ TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0); ++ return NULL; ++} ++ + static int + do_test (void) + { +@@ -154,6 +169,17 @@ do_test (void) + xchmod (_PATH_BSHELL, st.st_mode); + } + ++ { ++ pthread_t long_sleep_thread = xpthread_create (NULL, ++ sleep_and_check_sigchld, ++ &(double) { 0.2 }); ++ pthread_t short_sleep_thread = xpthread_create (NULL, ++ sleep_and_check_sigchld, ++ &(double) { 0.1 }); ++ xpthread_join (short_sleep_thread); ++ xpthread_join (long_sleep_thread); ++ } ++ + TEST_COMPARE (system (""), 0); + + return 0; +diff --git a/string/test-strnlen.c b/string/test-strnlen.c +index 4a9375112a..5cbaf4b734 100644 +--- a/string/test-strnlen.c ++++ b/string/test-strnlen.c +@@ -73,7 +73,7 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char) + { + size_t i; + +- align &= 63; ++ align &= (getpagesize () / sizeof (CHAR) - 1); + if ((align + len) * sizeof (CHAR) >= page_size) + return; + +@@ -90,38 +90,50 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char) + static void + do_overflow_tests (void) + { +- size_t i, j, len; ++ size_t i, j, al_idx, repeats, len; + const size_t one = 1; + uintptr_t buf_addr = (uintptr_t) buf1; ++ const size_t alignments[] = { 0, 1, 7, 9, 31, 33, 63, 65, 95, 97, 127, 129 }; + +- for (i = 0; i < 750; ++i) ++ for (al_idx = 0; al_idx < sizeof (alignments) / sizeof (alignments[0]); ++ al_idx++) + { +- do_test (1, i, SIZE_MAX, BIG_CHAR); +- +- do_test (0, i, SIZE_MAX - i, BIG_CHAR); +- do_test (0, i, i - buf_addr, BIG_CHAR); +- do_test (0, i, -buf_addr - i, BIG_CHAR); +- do_test (0, i, SIZE_MAX - buf_addr - i, BIG_CHAR); +- do_test (0, i, SIZE_MAX - buf_addr + i, BIG_CHAR); +- +- len = 0; +- for (j = 8 * sizeof(size_t) - 1; j ; --j) +- { +- len |= one << j; +- do_test (0, i, len - i, BIG_CHAR); +- do_test (0, i, len + i, BIG_CHAR); +- do_test (0, i, len - buf_addr - i, BIG_CHAR); +- do_test (0, i, len - buf_addr + i, BIG_CHAR); +- +- do_test (0, i, ~len - i, BIG_CHAR); +- do_test (0, i, ~len + i, BIG_CHAR); +- do_test (0, i, ~len - buf_addr - i, BIG_CHAR); +- do_test (0, i, ~len - buf_addr + i, BIG_CHAR); +- +- do_test (0, i, -buf_addr, BIG_CHAR); +- do_test (0, i, j - buf_addr, BIG_CHAR); +- do_test (0, i, -buf_addr - j, BIG_CHAR); +- } ++ for (repeats = 0; repeats < 2; ++repeats) ++ { ++ size_t align = repeats ? (getpagesize () - alignments[al_idx]) ++ : alignments[al_idx]; ++ align /= sizeof (CHAR); ++ for (i = 0; i < 750; ++i) ++ { ++ do_test (align, i, SIZE_MAX, BIG_CHAR); ++ ++ do_test (align, i, SIZE_MAX - i, BIG_CHAR); ++ do_test (align, i, i - buf_addr, BIG_CHAR); ++ do_test (align, i, -buf_addr - i, BIG_CHAR); ++ do_test (align, i, SIZE_MAX - buf_addr - i, BIG_CHAR); ++ do_test (align, i, SIZE_MAX - buf_addr + i, BIG_CHAR); ++ ++ len = 0; ++ for (j = 8 * sizeof (size_t) - 1; j; --j) ++ { ++ len |= one << j; ++ do_test (align, i, len, BIG_CHAR); ++ do_test (align, i, len - i, BIG_CHAR); ++ do_test (align, i, len + i, BIG_CHAR); ++ do_test (align, i, len - buf_addr - i, BIG_CHAR); ++ do_test (align, i, len - buf_addr + i, BIG_CHAR); ++ ++ do_test (align, i, ~len - i, BIG_CHAR); ++ do_test (align, i, ~len + i, BIG_CHAR); ++ do_test (align, i, ~len - buf_addr - i, BIG_CHAR); ++ do_test (align, i, ~len - buf_addr + i, BIG_CHAR); ++ ++ do_test (align, i, -buf_addr, BIG_CHAR); ++ do_test (align, i, j - buf_addr, BIG_CHAR); ++ do_test (align, i, -buf_addr - j, BIG_CHAR); ++ } ++ } ++ } + } + } + +diff --git a/sunrpc/netname.c b/sunrpc/netname.c +index bf7f0b81c4..c1d1c43e50 100644 +--- a/sunrpc/netname.c ++++ b/sunrpc/netname.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "nsswitch.h" + +@@ -48,7 +49,12 @@ user2netname (char netname[MAXNETNAMELEN + 1], const uid_t uid, + if ((strlen (dfltdom) + OPSYS_LEN + 3 + MAXIPRINT) > (size_t) MAXNETNAMELEN) + return 0; + ++ /* GCC with -Os warns that sprint might overflow while handling dfltdom, ++ however the above test does check if an overflow would happen. */ ++ DIAG_PUSH_NEEDS_COMMENT; ++ DIAG_IGNORE_Os_NEEDS_COMMENT (8, "-Wformat-overflow"); + sprintf (netname, "%s.%d@%s", OPSYS, uid, dfltdom); ++ DIAG_POP_NEEDS_COMMENT; + i = strlen (netname); + if (netname[i - 1] == '.') + netname[i - 1] = '\0'; +diff --git a/support/Makefile b/support/Makefile +index 9b50eac117..2b661a7eb8 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -32,6 +32,8 @@ libsupport-routines = \ + check_hostent \ + check_netent \ + delayed_exit \ ++ dtotimespec \ ++ dtotimespec-time64 \ + ignore_stderr \ + next_to_fault \ + oom_error \ +diff --git a/support/dtotimespec-time64.c b/support/dtotimespec-time64.c +new file mode 100644 +index 0000000000..b3d5e351e3 +--- /dev/null ++++ b/support/dtotimespec-time64.c +@@ -0,0 +1,27 @@ ++/* Convert double to timespec. 64-bit time support. ++ Copyright (C) 2011-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library and is also part of gnulib. ++ Patches to this file should be submitted to both projects. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++ ++#if __TIMESIZE != 64 ++# define timespec __timespec64 ++# define time_t __time64_t ++# define dtotimespec dtotimespec_time64 ++# include "dtotimespec.c" ++#endif +diff --git a/support/dtotimespec.c b/support/dtotimespec.c +new file mode 100644 +index 0000000000..cde5b4d74c +--- /dev/null ++++ b/support/dtotimespec.c +@@ -0,0 +1,50 @@ ++/* Convert double to timespec. ++ Copyright (C) 2011-2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library and is also part of gnulib. ++ Patches to this file should be submitted to both projects. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Convert the double value SEC to a struct timespec. Round toward ++ positive infinity. On overflow, return an extremal value. */ ++ ++#include ++#include ++ ++struct timespec ++dtotimespec (double sec) ++{ ++ if (sec <= TYPE_MINIMUM (time_t)) ++ return make_timespec (TYPE_MINIMUM (time_t), 0); ++ else if (sec >= 1.0 + TYPE_MAXIMUM (time_t)) ++ return make_timespec (TYPE_MAXIMUM (time_t), TIMESPEC_HZ - 1); ++ else ++ { ++ time_t s = sec; ++ double frac = TIMESPEC_HZ * (sec - s); ++ long ns = frac; ++ ns += ns < frac; ++ s += ns / TIMESPEC_HZ; ++ ns %= TIMESPEC_HZ; ++ ++ if (ns < 0) ++ { ++ s--; ++ ns += TIMESPEC_HZ; ++ } ++ ++ return make_timespec (s, ns); ++ } ++} +diff --git a/support/shell-container.c b/support/shell-container.c +index 1c73666f0a..6698061b9b 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -39,6 +39,7 @@ + #include + + #include ++#include + + /* Design considerations + +@@ -171,6 +172,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 +208,7 @@ static struct { + { "cp", copy_func }, + { "exit", exit_func }, + { "kill", kill_func }, ++ { "sleep", sleep_func }, + { NULL, NULL } + }; + +diff --git a/support/timespec.h b/support/timespec.h +index 4d2ac2737d..1bba3a6837 100644 +--- a/support/timespec.h ++++ b/support/timespec.h +@@ -57,6 +57,8 @@ int support_timespec_check_in_range (struct timespec expected, + struct timespec observed, + double lower_bound, double upper_bound); + ++struct timespec dtotimespec (double sec) __attribute__((const)); ++ + #else + struct timespec __REDIRECT (timespec_add, (struct timespec, struct timespec), + timespec_add_time64); +@@ -82,6 +84,8 @@ int __REDIRECT (support_timespec_check_in_range, (struct timespec expected, + double lower_bound, + double upper_bound), + support_timespec_check_in_range_time64); ++ ++struct timespec __REDIRECT (dtotimespec, (double sec), dtotimespec_time64); + #endif + + /* Check that the timespec on the left represents a time before the +diff --git a/sysdeps/aarch64/dl-trampoline.S b/sysdeps/aarch64/dl-trampoline.S +index 909b208578..d66f0b9c45 100644 +--- a/sysdeps/aarch64/dl-trampoline.S ++++ b/sysdeps/aarch64/dl-trampoline.S +@@ -298,12 +298,11 @@ _dl_runtime_profile: + stp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] + stp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] + stp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] +- str x8, [x29, #OFFSET_RG + DL_OFFSET_RG_X0 + 16*4] + stp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] + stp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] + stp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] + stp q6, q7, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*3] +- str xzr, [X29, #OFFSET_RV + DL_OFFSET_RG_VPCS] ++ str xzr, [X29, #OFFSET_RV + DL_OFFSET_RV_VPCS] + + /* Setup call to pltexit */ + ldp x0, x1, [x29, #OFFSET_SAVED_CALL_X0] +@@ -315,7 +314,6 @@ _dl_runtime_profile: + ldp x2, x3, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*1] + ldp x4, x5, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*2] + ldp x6, x7, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*3] +- ldr x8, [x29, #OFFSET_RV + DL_OFFSET_RV_X0 + 16*4] + ldp q0, q1, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*0] + ldp q2, q3, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*1] + ldp q4, q5, [x29, #OFFSET_RV + DL_OFFSET_RV_V0 + 32*2] +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 050a3032de..c2627fced7 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -105,6 +105,9 @@ typedef struct link_map *lookup_t; + DT_PREINIT_ARRAY. */ + typedef void (*dl_init_t) (int, char **, char **); + ++/* Type of a constructor function, in DT_FINI, DT_FINI_ARRAY. */ ++typedef void (*fini_t) (void); ++ + /* On some architectures a pointer to a function is not just a pointer + to the actual code of the function but rather an architecture + specific descriptor. */ +@@ -1048,9 +1051,16 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv, + initializer functions have completed. */ + extern void _dl_fini (void) attribute_hidden; + +-/* Sort array MAPS according to dependencies of the contained objects. */ ++/* Invoke the DT_FINI_ARRAY and DT_FINI destructors for MAP, which ++ must be a struct link_map *. Can be used as an argument to ++ _dl_catch_exception. */ ++void _dl_call_fini (void *map) attribute_hidden; ++ ++/* Sort array MAPS according to dependencies of the contained objects. ++ If FORCE_FIRST, MAPS[0] keeps its place even if the dependencies ++ say otherwise. */ + extern void _dl_sort_maps (struct link_map **maps, unsigned int nmaps, +- unsigned int skip, bool for_fini) attribute_hidden; ++ bool force_first, bool for_fini) attribute_hidden; + + /* The dynamic linker calls this function before and having changing + any shared object mappings. The `r_state' member of `struct r_debug' +diff --git a/sysdeps/generic/libc-lock-arch.h b/sysdeps/generic/libc-lock-arch.h +new file mode 100644 +index 0000000000..4713b30a8a +--- /dev/null ++++ b/sysdeps/generic/libc-lock-arch.h +@@ -0,0 +1,25 @@ ++/* Private libc-internal arch-specific definitions. Generic version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of the ++ License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If ++ not, see . */ ++ ++#ifndef _LIBC_LOCK_ARCH_H ++#define _LIBC_LOCK_ARCH_H ++ ++/* The default definition uses the natural alignment from the lock type. */ ++#define __LIBC_LOCK_ALIGNMENT ++ ++#endif +diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h +index c865713be1..1d51948566 100644 +--- a/sysdeps/hppa/dl-machine.h ++++ b/sysdeps/hppa/dl-machine.h +@@ -347,6 +347,16 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[], + its return value is the user program's entry point. */ + + #define RTLD_START \ ++/* Set up dp for any non-PIC lib constructors that may be called. */ \ ++static struct link_map * __attribute__((used)) \ ++set_dp (struct link_map *map) \ ++{ \ ++ register Elf32_Addr dp asm ("%r27"); \ ++ dp = D_PTR (map, l_info[DT_PLTGOT]); \ ++ asm volatile ("" : : "r" (dp)); \ ++ return map; \ ++} \ ++ \ + asm ( \ + " .text\n" \ + " .globl _start\n" \ +@@ -426,6 +436,13 @@ asm ( \ + direct loader invocation. Thus, argc and argv must be \ + reloaded from from _dl_argc and _dl_argv. */ \ + \ ++ /* Load main_map from _rtld_local and setup dp. */ \ ++" addil LT'_rtld_local,%r19\n" \ ++" ldw RT'_rtld_local(%r1),%r26\n" \ ++" bl set_dp, %r2\n" \ ++" ldw 0(%r26),%r26\n" \ ++" copy %ret0,%r26\n" \ ++ \ + /* Load argc from _dl_argc. */ \ + " addil LT'_dl_argc,%r19\n" \ + " ldw RT'_dl_argc(%r1),%r20\n" \ +@@ -438,13 +455,10 @@ asm ( \ + " ldw 0(%r20),%r24\n" \ + " stw %r24,-44(%sp)\n" \ + \ +- /* Call _dl_init(main_map, argc, argv, envp). */ \ +-" addil LT'_rtld_local,%r19\n" \ +-" ldw RT'_rtld_local(%r1),%r26\n" \ +-" ldw 0(%r26),%r26\n" \ +- \ + /* envp = argv + argc + 1 */ \ + " sh2add %r25,%r24,%r23\n" \ ++ \ ++ /* Call _dl_init(main_map, argc, argv, envp). */ \ + " bl _dl_init,%r2\n" \ + " ldo 4(%r23),%r23\n" /* delay slot */ \ + \ +diff --git a/sysdeps/ieee754/ldbl-128/e_j1l.c b/sysdeps/ieee754/ldbl-128/e_j1l.c +index 54c457681a..9a9c5c6f00 100644 +--- a/sysdeps/ieee754/ldbl-128/e_j1l.c ++++ b/sysdeps/ieee754/ldbl-128/e_j1l.c +@@ -869,10 +869,13 @@ __ieee754_y1l (_Float128 x) + { + /* 0 <= x <= 2 */ + SET_RESTORE_ROUNDL (FE_TONEAREST); ++ xx = math_opt_barrier (xx); ++ x = math_opt_barrier (x); + z = xx * xx; + p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D); + p = -TWOOPI / xx + p; + p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p; ++ math_force_eval (p); + return p; + } + +diff --git a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c +index f85ba94466..0a5fe68342 100644 +--- a/sysdeps/ieee754/ldbl-128ibm/e_j1l.c ++++ b/sysdeps/ieee754/ldbl-128ibm/e_j1l.c +@@ -792,10 +792,13 @@ __ieee754_y1l (long double x) + { + /* 0 <= x <= 2 */ + SET_RESTORE_ROUNDL (FE_TONEAREST); ++ xx = math_opt_barrier (xx); ++ x = math_opt_barrier (x); + z = xx * xx; + p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D); + p = -TWOOPI / xx + p; + p = TWOOPI * __ieee754_logl (x) * __ieee754_j1l (x) + p; ++ math_force_eval (p); + return p; + } + +diff --git a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c +index d85154e73a..d8c0de1faf 100644 +--- a/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c ++++ b/sysdeps/ieee754/ldbl-128ibm/s_llroundl.c +@@ -66,38 +66,35 @@ __llroundl (long double x) + /* Peg at max/min values, assuming that the above conversions do so. + Strictly speaking, we can return anything for values that overflow, + but this is more useful. */ +- res = hi + lo; +- +- /* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */ +- if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0))) ++ if (__glibc_unlikely (__builtin_add_overflow (hi, lo, &res))) + goto overflow; + + xh -= lo; + ldbl_canonicalize (&xh, &xl); + +- hi = res; + if (xh > 0.5) + { +- res += 1; ++ if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res))) ++ goto overflow; + } + else if (xh == 0.5) + { + if (xl > 0.0 || (xl == 0.0 && res >= 0)) +- res += 1; ++ if (__glibc_unlikely (__builtin_add_overflow (res, 1, &res))) ++ goto overflow; + } + else if (-xh > 0.5) + { +- res -= 1; ++ if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res))) ++ goto overflow; + } + else if (-xh == 0.5) + { + if (xl < 0.0 || (xl == 0.0 && res <= 0)) +- res -= 1; ++ if (__glibc_unlikely (__builtin_add_overflow (res, -1, &res))) ++ goto overflow; + } + +- if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0))) +- goto overflow; +- + return res; + } + else +diff --git a/sysdeps/mach/hurd/bits/socket.h b/sysdeps/mach/hurd/bits/socket.h +index 5b35ea81ec..70fce4fb27 100644 +--- a/sysdeps/mach/hurd/bits/socket.h ++++ b/sysdeps/mach/hurd/bits/socket.h +@@ -249,6 +249,12 @@ struct cmsghdr + + CMSG_ALIGN (sizeof (struct cmsghdr))) + #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + ++/* Given a length, return the additional padding necessary such that ++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ ++#define __CMSG_PADDING(len) ((sizeof (size_t) \ ++ - ((len) & (sizeof (size_t) - 1))) \ ++ & (sizeof (size_t) - 1)) ++ + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + struct cmsghdr *__cmsg) __THROW; + #ifdef __USE_EXTERN_INLINES +@@ -258,18 +264,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + _EXTERN_INLINE struct cmsghdr * + __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) + { ++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and ++ __mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of __cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; ++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; ++ ++ size_t __size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (__cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ + return (struct cmsghdr *) 0; + ++ /* There isn't enough space between __cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) ++ < __size_needed) ++ || ((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr ++ - __size_needed) ++ < __cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; ++ ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); +- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control +- + __mhdr->msg_controllen) +- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) +- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) +- /* No more entries. */ +- return (struct cmsghdr *) 0; + return __cmsg; + } + #endif /* Use `extern inline'. */ +diff --git a/sysdeps/nptl/libc-lock.h b/sysdeps/nptl/libc-lock.h +index 5af476c48b..63b3f3d75c 100644 +--- a/sysdeps/nptl/libc-lock.h ++++ b/sysdeps/nptl/libc-lock.h +@@ -22,6 +22,7 @@ + #include + #define __need_NULL + #include ++#include + + + /* Mutex type. */ +@@ -29,7 +30,12 @@ + # if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC + typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; + # else +-typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t; ++typedef struct ++{ ++ int lock __LIBC_LOCK_ALIGNMENT; ++ int cnt; ++ void *owner; ++} __libc_lock_recursive_t; + # endif + #else + typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; +diff --git a/sysdeps/nptl/libc-lockP.h b/sysdeps/nptl/libc-lockP.h +index d3a6837fd2..425f514c5c 100644 +--- a/sysdeps/nptl/libc-lockP.h ++++ b/sysdeps/nptl/libc-lockP.h +@@ -32,9 +32,10 @@ + ld.so might be used on old kernels with a different libc.so. */ + #include + #include ++#include + + /* Mutex type. */ +-typedef int __libc_lock_t; ++typedef int __libc_lock_t __LIBC_LOCK_ALIGNMENT; + typedef struct { pthread_mutex_t mutex; } __rtld_lock_recursive_t; + typedef pthread_rwlock_t __libc_rwlock_t; + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index bcff909b2f..f975dcd2bc 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -120,6 +120,7 @@ struct gaih_result + { + struct gaih_addrtuple *at; + char *canon; ++ char *h_name; + bool free_at; + bool got_ipv6; + }; +@@ -165,6 +166,7 @@ gaih_result_reset (struct gaih_result *res) + if (res->free_at) + free (res->at); + free (res->canon); ++ free (res->h_name); + memset (res, 0, sizeof (*res)); + } + +@@ -203,9 +205,8 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + return 0; + } + +-/* Convert struct hostent to a list of struct gaih_addrtuple objects. h_name +- is not copied, and the struct hostent object must not be deallocated +- prematurely. The new addresses are appended to the tuple array in RES. */ ++/* Convert struct hostent to a list of struct gaih_addrtuple objects. The new ++ addresses are appended to the tuple array in RES. */ + static bool + convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + struct hostent *h, struct gaih_result *res) +@@ -238,6 +239,15 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + res->at = array; + res->free_at = true; + ++ /* Duplicate h_name because it may get reclaimed when the underlying storage ++ is freed. */ ++ if (res->h_name == NULL) ++ { ++ res->h_name = __strdup (h->h_name); ++ if (res->h_name == NULL) ++ return false; ++ } ++ + /* Update the next pointers on reallocation. */ + for (size_t i = 0; i < old; i++) + array[i].next = array + i + 1; +@@ -262,7 +272,6 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, int family, + } + array[i].next = array + i + 1; + } +- array[0].name = h->h_name; + array[count - 1].next = NULL; + + return true; +@@ -324,15 +333,15 @@ gethosts (nss_gethostbyname3_r fct, int family, const char *name, + memory allocation failure. The returned string is allocated on the + heap; the caller has to free it. */ + static char * +-getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name) ++getcanonname (nss_action_list nip, const char *hname, const char *name) + { + nss_getcanonname_r *cfct = __nss_lookup_function (nip, "getcanonname_r"); + char *s = (char *) name; + if (cfct != NULL) + { + char buf[256]; +- if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf), +- &s, &errno, &h_errno)) != NSS_STATUS_SUCCESS) ++ if (DL_CALL_FCT (cfct, (hname ?: name, buf, sizeof (buf), &s, &errno, ++ &h_errno)) != NSS_STATUS_SUCCESS) + /* If the canonical name cannot be determined, use the passed + string. */ + s = (char *) name; +@@ -540,11 +549,11 @@ get_nscd_addresses (const char *name, const struct addrinfo *req, + at[count].addr[2] = htonl (0xffff); + } + else if (req->ai_family == AF_UNSPEC +- || air->family[count] == req->ai_family) ++ || air->family[i] == req->ai_family) + { +- at[count].family = air->family[count]; ++ at[count].family = air->family[i]; + memcpy (at[count].addr, addrs, size); +- if (air->family[count] == AF_INET6) ++ if (air->family[i] == AF_INET6) + res->got_ipv6 = true; + } + at[count].next = at + count + 1; +@@ -771,7 +780,7 @@ get_nss_addresses (const char *name, const struct addrinfo *req, + if ((req->ai_flags & AI_CANONNAME) != 0 + && res->canon == NULL) + { +- char *canonbuf = getcanonname (nip, res->at, name); ++ char *canonbuf = getcanonname (nip, res->h_name, name); + if (canonbuf == NULL) + { + __resolv_context_put (res_ctx); +@@ -1187,9 +1196,7 @@ free_and_return: + if (malloc_name) + free ((char *) name); + free (addrmem); +- if (res.free_at) +- free (res.at); +- free (res.canon); ++ gaih_result_reset (&res); + + return result; + } +diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c +index 8014f63355..20c9420dd4 100644 +--- a/sysdeps/posix/system.c ++++ b/sysdeps/posix/system.c +@@ -179,16 +179,16 @@ do_system (const char *line) + as if the shell had terminated using _exit(127). */ + status = W_EXITCODE (127, 0); + ++ /* sigaction can not fail with SIGINT/SIGQUIT used with old ++ disposition. Same applies for sigprocmask. */ + DO_LOCK (); + if (SUB_REF () == 0) + { +- /* sigaction can not fail with SIGINT/SIGQUIT used with old +- disposition. Same applies for sigprocmask. */ + __sigaction (SIGINT, &intr, NULL); + __sigaction (SIGQUIT, &quit, NULL); +- __sigprocmask (SIG_SETMASK, &omask, NULL); + } + DO_UNLOCK (); ++ __sigprocmask (SIG_SETMASK, &omask, NULL); + + if (ret != 0) + __set_errno (ret); +diff --git a/sysdeps/powerpc/mod-tlsopt-powerpc.c b/sysdeps/powerpc/mod-tlsopt-powerpc.c +index 2a82e53baf..d941024963 100644 +--- a/sysdeps/powerpc/mod-tlsopt-powerpc.c ++++ b/sysdeps/powerpc/mod-tlsopt-powerpc.c +@@ -22,7 +22,11 @@ tls_get_addr_opt_test (void) + tls_index *tls_arg; + #ifdef __powerpc64__ + register unsigned long thread_pointer __asm__ ("r13"); +- asm ("addi %0,2,foo@got@tlsgd" : "=r" (tls_arg)); ++# ifdef __PCREL__ ++ asm ("paddi %0,0,foo@got@tlsgd@pcrel,1" : "=b" (tls_arg)); ++# else ++ asm ("addi %0,2,foo@got@tlsgd" : "=b" (tls_arg)); ++# endif + #else + register unsigned long thread_pointer __asm__ ("r2"); + asm ("bcl 20,31,1f\n1:\t" +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index a139a16532..d5d9af4de2 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -265,6 +265,14 @@ $(objpfx)tst-mount-consts.out: ../sysdeps/unix/sysv/linux/tst-mount-consts.py + < /dev/null > $@ 2>&1; $(evaluate-test) + $(objpfx)tst-mount-consts.out: $(sysdeps-linux-python-deps) + ++tests-special += $(objpfx)tst-mount-compile.out ++$(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py ++ $(sysdeps-linux-python) \ ++ ../sysdeps/unix/sysv/linux/tst-mount-compile.py \ ++ $(sysdeps-linux-python-cc) \ ++ < /dev/null > $@ 2>&1; $(evaluate-test) ++$(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps) ++ + tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0 + + endif # $(subdir) == misc +@@ -354,6 +362,8 @@ sysdep_headers += netinet/if_fddi.h netinet/if_tr.h \ + netrom/netrom.h netpacket/packet.h netrose/rose.h \ + neteconet/ec.h netiucv/iucv.h + sysdep_routines += netlink_assert_response ++ ++CFLAGS-check_pf.c += -fexceptions + endif + + # Don't compile the ctype glue code, since there is no old non-GNU C library. +diff --git a/sysdeps/unix/sysv/linux/alpha/brk_call.h b/sysdeps/unix/sysv/linux/alpha/brk_call.h +index b8088cf13f..0b851b6c86 100644 +--- a/sysdeps/unix/sysv/linux/alpha/brk_call.h ++++ b/sysdeps/unix/sysv/linux/alpha/brk_call.h +@@ -21,8 +21,7 @@ __brk_call (void *addr) + { + unsigned long int result = INTERNAL_SYSCALL_CALL (brk, addr); + if (result == -ENOMEM) +- /* Mimic the default error reporting behavior. */ +- return addr; +- else +- return (void *) result; ++ /* Mimic the generic error reporting behavior. */ ++ result = INTERNAL_SYSCALL_CALL (brk, 0); ++ return (void *) result; + } +diff --git a/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h +new file mode 100644 +index 0000000000..30ee6279d2 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/arm/bits/struct_stat.h +@@ -0,0 +1,139 @@ ++/* Definition for struct stat. Linux/arm version. ++ Copyright (C) 2020-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library. If not, see ++ . */ ++ ++#if !defined _SYS_STAT_H && !defined _FCNTL_H ++# error "Never include directly; use instead." ++#endif ++ ++#ifndef _BITS_STRUCT_STAT_H ++#define _BITS_STRUCT_STAT_H 1 ++ ++#include ++#include ++ ++struct stat ++ { ++#ifdef __USE_TIME_BITS64 ++# include ++#else ++ __dev_t st_dev; /* Device. */ ++ unsigned short int __pad1; ++# ifndef __USE_FILE_OFFSET64 ++ __ino_t st_ino; /* File serial number. */ ++# else ++ __ino_t __st_ino; /* 32bit file serial number. */ ++# endif ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned short int __pad2; ++# ifndef __USE_FILE_OFFSET64 ++ __off_t st_size; /* Size of file, in bytes. */ ++# else ++ __off64_t st_size; /* Size of file, in bytes. */ ++# endif ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++# ifndef __USE_FILE_OFFSET64 ++ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ ++# else ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# endif ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++# ifndef __USE_FILE_OFFSET64 ++ unsigned long int __glibc_reserved4; ++ unsigned long int __glibc_reserved5; ++# else ++ __ino64_t st_ino; /* File serial number. */ ++# endif ++#endif /* __USE_TIME_BITS64 */ ++ }; ++ ++#ifdef __USE_LARGEFILE64 ++struct stat64 ++ { ++# ifdef __USE_TIME_BITS64 ++# include ++# else ++ __dev_t st_dev; /* Device. */ ++ unsigned int __pad1; ++ ++ __ino_t __st_ino; /* 32bit file serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned int __pad2; ++ __off64_t st_size; /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++ __ino64_t st_ino; /* File serial number. */ ++# endif /* __USE_TIME_BITS64 */ ++ }; ++#endif ++ ++/* Tell code we have these members. */ ++#define _STATBUF_ST_BLKSIZE ++#define _STATBUF_ST_RDEV ++/* Nanosecond resolution time values are supported. */ ++#define _STATBUF_ST_NSEC ++ ++ ++#endif /* _BITS_STRUCT_STAT_H */ +diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h +index 33ff88ce59..bfc674235d 100644 +--- a/sysdeps/unix/sysv/linux/bits/fcntl-linux.h ++++ b/sysdeps/unix/sysv/linux/bits/fcntl-linux.h +@@ -101,7 +101,7 @@ + #endif + + #ifndef F_GETLK +-# ifndef __USE_FILE_OFFSET64 ++# if !defined __USE_FILE_OFFSET64 && __TIMESIZE != 64 + # define F_GETLK 5 /* Get record locking info. */ + # define F_SETLK 6 /* Set record locking info (non-blocking). */ + # define F_SETLKW 7 /* Set record locking info (blocking). */ +diff --git a/sysdeps/unix/sysv/linux/bits/socket.h b/sysdeps/unix/sysv/linux/bits/socket.h +index 4f1f810ea1..539b8d7716 100644 +--- a/sysdeps/unix/sysv/linux/bits/socket.h ++++ b/sysdeps/unix/sysv/linux/bits/socket.h +@@ -307,6 +307,12 @@ struct cmsghdr + + CMSG_ALIGN (sizeof (struct cmsghdr))) + #define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) + ++/* Given a length, return the additional padding necessary such that ++ len + __CMSG_PADDING(len) == CMSG_ALIGN (len). */ ++#define __CMSG_PADDING(len) ((sizeof (size_t) \ ++ - ((len) & (sizeof (size_t) - 1))) \ ++ & (sizeof (size_t) - 1)) ++ + extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + struct cmsghdr *__cmsg) __THROW; + #ifdef __USE_EXTERN_INLINES +@@ -316,18 +322,38 @@ extern struct cmsghdr *__cmsg_nxthdr (struct msghdr *__mhdr, + _EXTERN_INLINE struct cmsghdr * + __NTH (__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg)) + { ++ /* We may safely assume that __cmsg lies between __mhdr->msg_control and ++ __mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of __cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * __msg_control_ptr = (unsigned char *) __mhdr->msg_control; ++ unsigned char * __cmsg_ptr = (unsigned char *) __cmsg; ++ ++ size_t __size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (__cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ + return (struct cmsghdr *) 0; + ++ /* There isn't enough space between __cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr) ++ < __size_needed) ++ || ((size_t) ++ (__msg_control_ptr + __mhdr->msg_controllen - __cmsg_ptr ++ - __size_needed) ++ < __cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; ++ ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); +- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) __mhdr->msg_control +- + __mhdr->msg_controllen) +- || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) +- > ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) +- /* No more entries. */ +- return (struct cmsghdr *) 0; + return __cmsg; + } + #endif /* Use `extern inline'. */ +diff --git a/sysdeps/unix/sysv/linux/bits/struct_stat.h b/sysdeps/unix/sysv/linux/bits/struct_stat.h +index 25bd6cb638..fb11a3fba4 100644 +--- a/sysdeps/unix/sysv/linux/bits/struct_stat.h ++++ b/sysdeps/unix/sysv/linux/bits/struct_stat.h +@@ -26,37 +26,36 @@ + #include + #include + +-struct stat +- { +-#ifdef __USE_TIME_BITS64 +-# include +-#else +- __dev_t st_dev; /* Device. */ +- unsigned short int __pad1; +-# ifndef __USE_FILE_OFFSET64 +- __ino_t st_ino; /* File serial number. */ +-# else +- __ino_t __st_ino; /* 32bit file serial number. */ ++#if defined __USE_FILE_OFFSET64 ++# define __field64(type, type64, name) type64 name ++#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T ++# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T ++# error "ino_t and off_t must both be the same type" + # endif +- __mode_t st_mode; /* File mode. */ +- __nlink_t st_nlink; /* Link count. */ +- __uid_t st_uid; /* User ID of the file's owner. */ +- __gid_t st_gid; /* Group ID of the file's group.*/ +- __dev_t st_rdev; /* Device number, if device. */ +- unsigned short int __pad2; +-# ifndef __USE_FILE_OFFSET64 +- __off_t st_size; /* Size of file, in bytes. */ +-# else +- __off64_t st_size; /* Size of file, in bytes. */ +-# endif +- __blksize_t st_blksize; /* Optimal block size for I/O. */ ++# define __field64(type, type64, name) type name ++#elif __BYTE_ORDER == __LITTLE_ENDIAN ++# define __field64(type, type64, name) \ ++ type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad ++#else ++# define __field64(type, type64, name) \ ++ int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name ++#endif + +-# ifndef __USE_FILE_OFFSET64 +- __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ +-# else +- __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +-# endif +-# ifdef __USE_XOPEN2K8 ++struct stat ++ { ++ __dev_t st_dev; /* Device. */ ++ __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ __dev_t __pad1; ++ __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ int __pad2; ++ __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ ++#ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the +@@ -66,47 +65,38 @@ struct stat + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +-# define st_atime st_atim.tv_sec /* Backward compatibility. */ +-# define st_mtime st_mtim.tv_sec +-# define st_ctime st_ctim.tv_sec +-# else ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++#else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +-# endif +-# ifndef __USE_FILE_OFFSET64 +- unsigned long int __glibc_reserved4; +- unsigned long int __glibc_reserved5; +-# else +- __ino64_t st_ino; /* File serial number. */ +-# endif +-#endif /* __USE_TIME_BITS64 */ ++#endif ++ int __glibc_reserved[2]; + }; + ++#undef __field64 ++ + #ifdef __USE_LARGEFILE64 + struct stat64 + { +-# ifdef __USE_TIME_BITS64 +-# include +-# else +- __dev_t st_dev; /* Device. */ +- unsigned int __pad1; +- +- __ino_t __st_ino; /* 32bit file serial number. */ +- __mode_t st_mode; /* File mode. */ +- __nlink_t st_nlink; /* Link count. */ +- __uid_t st_uid; /* User ID of the file's owner. */ +- __gid_t st_gid; /* Group ID of the file's group.*/ +- __dev_t st_rdev; /* Device number, if device. */ +- unsigned int __pad2; +- __off64_t st_size; /* Size of file, in bytes. */ +- __blksize_t st_blksize; /* Optimal block size for I/O. */ +- +- __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ +-# ifdef __USE_XOPEN2K8 ++ __dev_t st_dev; /* Device. */ ++ __ino64_t st_ino; /* File serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ __dev_t __pad1; ++ __off64_t st_size; /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ int __pad2; ++ __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ ++#ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the +@@ -116,16 +106,15 @@ struct stat64 + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +-# else ++#else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +-# endif +- __ino64_t st_ino; /* File serial number. */ +-# endif /* __USE_TIME_BITS64 */ ++#endif ++ int __glibc_reserved[2]; + }; + #endif + +@@ -135,5 +124,4 @@ struct stat64 + /* Nanosecond resolution time values are supported. */ + #define _STATBUF_ST_NSEC + +- + #endif /* _BITS_STRUCT_STAT_H */ +diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c +index fe73fe3ba8..ca20043408 100644 +--- a/sysdeps/unix/sysv/linux/check_pf.c ++++ b/sysdeps/unix/sysv/linux/check_pf.c +@@ -292,6 +292,14 @@ make_request (int fd, pid_t pid) + return NULL; + } + ++#ifdef __EXCEPTIONS ++static void ++cancel_handler (void *arg __attribute__((unused))) ++{ ++ /* Release the lock. */ ++ __libc_lock_unlock (lock); ++} ++#endif + + void + attribute_hidden +@@ -304,6 +312,10 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6, + struct cached_data *olddata = NULL; + struct cached_data *data = NULL; + ++#ifdef __EXCEPTIONS ++ /* Make sure that lock is released when the thread is cancelled. */ ++ __libc_cleanup_push (cancel_handler, NULL); ++#endif + __libc_lock_lock (lock); + + if (cache_valid_p ()) +@@ -338,6 +350,9 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6, + } + } + ++#ifdef __EXCEPTIONS ++ __libc_cleanup_pop (0); ++#endif + __libc_lock_unlock (lock); + + if (data != NULL) +diff --git a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c +index 15b7a3a925..24f72b797a 100644 +--- a/sysdeps/unix/sysv/linux/cmsg_nxthdr.c ++++ b/sysdeps/unix/sysv/linux/cmsg_nxthdr.c +@@ -23,18 +23,38 @@ + struct cmsghdr * + __cmsg_nxthdr (struct msghdr *mhdr, struct cmsghdr *cmsg) + { ++ /* We may safely assume that cmsg lies between mhdr->msg_control and ++ mhdr->msg_controllen because the user is required to obtain the first ++ cmsg via CMSG_FIRSTHDR, set its length, then obtain subsequent cmsgs ++ via CMSG_NXTHDR, setting lengths along the way. However, we don't yet ++ trust the value of cmsg->cmsg_len and therefore do not use it in any ++ pointer arithmetic until we check its value. */ ++ ++ unsigned char * msg_control_ptr = (unsigned char *) mhdr->msg_control; ++ unsigned char * cmsg_ptr = (unsigned char *) cmsg; ++ ++ size_t size_needed = sizeof (struct cmsghdr) ++ + __CMSG_PADDING (cmsg->cmsg_len); ++ ++ /* The current header is malformed, too small to be a full header. */ + if ((size_t) cmsg->cmsg_len < sizeof (struct cmsghdr)) +- /* The kernel header does this so there may be a reason. */ +- return NULL; ++ return (struct cmsghdr *) 0; ++ ++ /* There isn't enough space between cmsg and the end of the buffer to ++ hold the current cmsg *and* the next one. */ ++ if (((size_t) ++ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr) ++ < size_needed) ++ || ((size_t) ++ (msg_control_ptr + mhdr->msg_controllen - cmsg_ptr ++ - size_needed) ++ < cmsg->cmsg_len)) ++ ++ return (struct cmsghdr *) 0; + ++ /* Now, we trust cmsg_len and can use it to find the next header. */ + cmsg = (struct cmsghdr *) ((unsigned char *) cmsg + + CMSG_ALIGN (cmsg->cmsg_len)); +- if ((unsigned char *) (cmsg + 1) > ((unsigned char *) mhdr->msg_control +- + mhdr->msg_controllen) +- || ((unsigned char *) cmsg + CMSG_ALIGN (cmsg->cmsg_len) +- > ((unsigned char *) mhdr->msg_control + mhdr->msg_controllen))) +- /* No more entries. */ +- return NULL; + return cmsg; + } + libc_hidden_def (__cmsg_nxthdr) +diff --git a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h +similarity index 92% +rename from sysdeps/unix/sysv/linux/generic/bits/struct_stat.h +rename to sysdeps/unix/sysv/linux/csky/bits/struct_stat.h +index fb11a3fba4..f0ee455748 100644 +--- a/sysdeps/unix/sysv/linux/generic/bits/struct_stat.h ++++ b/sysdeps/unix/sysv/linux/csky/bits/struct_stat.h +@@ -1,4 +1,4 @@ +-/* Definition for struct stat. ++/* Definition for struct stat. Linux/csky version. + Copyright (C) 2020-2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -43,6 +43,9 @@ + + struct stat + { ++#ifdef __USE_TIME_BITS64 ++# include ++#else + __dev_t st_dev; /* Device. */ + __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ + __mode_t st_mode; /* File mode. */ +@@ -55,7 +58,7 @@ struct stat + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ +-#ifdef __USE_XOPEN2K8 ++# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the +@@ -65,18 +68,19 @@ struct stat + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +-# define st_atime st_atim.tv_sec /* Backward compatibility. */ +-# define st_mtime st_mtim.tv_sec +-# define st_ctime st_ctim.tv_sec +-#else ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +-#endif ++# endif + int __glibc_reserved[2]; ++#endif + }; + + #undef __field64 +@@ -84,6 +88,9 @@ struct stat + #ifdef __USE_LARGEFILE64 + struct stat64 + { ++# ifdef __USE_TIME_BITS64 ++# include ++# else + __dev_t st_dev; /* Device. */ + __ino64_t st_ino; /* File serial number. */ + __mode_t st_mode; /* File mode. */ +@@ -96,7 +103,7 @@ struct stat64 + __blksize_t st_blksize; /* Optimal block size for I/O. */ + int __pad2; + __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ +-#ifdef __USE_XOPEN2K8 ++# ifdef __USE_XOPEN2K8 + /* Nanosecond resolution timestamps are stored in a format + equivalent to 'struct timespec'. This is the type used + whenever possible but the Unix namespace rules do not allow the +@@ -106,15 +113,16 @@ struct stat64 + struct timespec st_atim; /* Time of last access. */ + struct timespec st_mtim; /* Time of last modification. */ + struct timespec st_ctim; /* Time of last status change. */ +-#else ++# else + __time_t st_atime; /* Time of last access. */ + unsigned long int st_atimensec; /* Nscecs of last access. */ + __time_t st_mtime; /* Time of last modification. */ + unsigned long int st_mtimensec; /* Nsecs of last modification. */ + __time_t st_ctime; /* Time of last status change. */ + unsigned long int st_ctimensec; /* Nsecs of last status change. */ +-#endif ++# endif + int __glibc_reserved[2]; ++# endif + }; + #endif + +diff --git a/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h +new file mode 100644 +index 0000000000..38b6e13e68 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/hppa/bits/struct_stat.h +@@ -0,0 +1,139 @@ ++/* Definition for struct stat. Linux/hppa version. ++ Copyright (C) 2020-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library. If not, see ++ . */ ++ ++#if !defined _SYS_STAT_H && !defined _FCNTL_H ++# error "Never include directly; use instead." ++#endif ++ ++#ifndef _BITS_STRUCT_STAT_H ++#define _BITS_STRUCT_STAT_H 1 ++ ++#include ++#include ++ ++struct stat ++ { ++#ifdef __USE_TIME_BITS64 ++# include ++#else ++ __dev_t st_dev; /* Device. */ ++ unsigned short int __pad1; ++# ifndef __USE_FILE_OFFSET64 ++ __ino_t st_ino; /* File serial number. */ ++# else ++ __ino_t __st_ino; /* 32bit file serial number. */ ++# endif ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned short int __pad2; ++# ifndef __USE_FILE_OFFSET64 ++ __off_t st_size; /* Size of file, in bytes. */ ++# else ++ __off64_t st_size; /* Size of file, in bytes. */ ++# endif ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++# ifndef __USE_FILE_OFFSET64 ++ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ ++# else ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# endif ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++# ifndef __USE_FILE_OFFSET64 ++ unsigned long int __glibc_reserved4; ++ unsigned long int __glibc_reserved5; ++# else ++ __ino64_t st_ino; /* File serial number. */ ++# endif ++#endif /* __USE_TIME_BITS64 */ ++ }; ++ ++#ifdef __USE_LARGEFILE64 ++struct stat64 ++ { ++# ifdef __USE_TIME_BITS64 ++# include ++# else ++ __dev_t st_dev; /* Device. */ ++ unsigned int __pad1; ++ ++ __ino_t __st_ino; /* 32bit file serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned int __pad2; ++ __off64_t st_size; /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++ __ino64_t st_ino; /* File serial number. */ ++# endif /* __USE_TIME_BITS64 */ ++ }; ++#endif ++ ++/* Tell code we have these members. */ ++#define _STATBUF_ST_BLKSIZE ++#define _STATBUF_ST_RDEV ++/* Nanosecond resolution time values are supported. */ ++#define _STATBUF_ST_NSEC ++ ++ ++#endif /* _BITS_STRUCT_STAT_H */ +diff --git a/sysdeps/unix/sysv/linux/hppa/kernel-features.h b/sysdeps/unix/sysv/linux/hppa/kernel-features.h +index 0cd21ef0fa..079612e4aa 100644 +--- a/sysdeps/unix/sysv/linux/hppa/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/hppa/kernel-features.h +@@ -30,3 +30,6 @@ + + #undef __ASSUME_CLONE_DEFAULT + #define __ASSUME_CLONE_BACKWARDS 1 ++ ++/* QEMU does not support set_robust_list. */ ++#undef __ASSUME_SET_ROBUST_LIST +diff --git a/sysdeps/unix/sysv/linux/ipc_priv.h b/sysdeps/unix/sysv/linux/ipc_priv.h +index 87893a6757..2f50c31a8e 100644 +--- a/sysdeps/unix/sysv/linux/ipc_priv.h ++++ b/sysdeps/unix/sysv/linux/ipc_priv.h +@@ -63,4 +63,10 @@ struct __old_ipc_perm + # define __IPC_TIME64 0 + #endif + ++#if __IPC_TIME64 || defined __ASSUME_SYSVIPC_BROKEN_MODE_T ++# define IPC_CTL_NEED_TRANSLATION 1 ++#else ++# define IPC_CTL_NEED_TRANSLATION 0 ++#endif ++ + #include +diff --git a/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h +new file mode 100644 +index 0000000000..1844bbaf6f +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/m68k/libc-lock-arch.h +@@ -0,0 +1,25 @@ ++/* Private libc-internal arch-specific definitions. m68k version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of the ++ License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; see the file COPYING.LIB. If ++ not, see . */ ++ ++#ifndef _LIBC_LOCK_ARCH_H ++#define _LIBC_LOCK_ARCH_H ++ ++/* Linux enforces 4-bytes alignment on futex inputs. */ ++#define __LIBC_LOCK_ALIGNMENT __attribute__ ((__aligned__ (4))) ++ ++#endif +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c +new file mode 100644 +index 0000000000..fe6c3a0dda +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/fstatat.c +@@ -0,0 +1,51 @@ ++/* Get file status. Linux/MIPSn64 version. ++ Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++/* Different than other ABIs, mips64 has different layouts for non-LFS ++ and LFS struct stat. */ ++int ++__fstatat (int fd, const char *file, struct stat *buf, int flag) ++{ ++ struct __stat64_t64 st64; ++ int r = __fstatat64_time64 (fd, file, &st64, flag); ++ if (r == 0) ++ { ++ /* Clear internal pad and reserved fields. */ ++ memset (buf, 0, sizeof (*buf)); ++ ++ buf->st_dev = st64.st_dev; ++ buf->st_ino = st64.st_ino; ++ buf->st_mode = st64.st_mode; ++ buf->st_nlink = st64.st_nlink; ++ buf->st_uid = st64.st_uid; ++ buf->st_gid = st64.st_gid; ++ buf->st_rdev = st64.st_rdev; ++ buf->st_size = st64.st_size; ++ buf->st_blksize = st64.st_blksize; ++ buf->st_blocks = st64.st_blocks; ++ buf->st_atim = st64.st_atim; ++ buf->st_mtim = st64.st_mtim; ++ buf->st_ctim = st64.st_ctim; ++ } ++ return r; ++} ++ ++weak_alias (__fstatat, fstatat) +diff --git a/sysdeps/unix/sysv/linux/msgctl.c b/sysdeps/unix/sysv/linux/msgctl.c +index e824ebb095..2072205252 100644 +--- a/sysdeps/unix/sysv/linux/msgctl.c ++++ b/sysdeps/unix/sysv/linux/msgctl.c +@@ -85,11 +85,19 @@ msgctl_syscall (int msqid, int cmd, msgctl_arg_t *buf) + int + __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) + { +-#if __IPC_TIME64 ++#if IPC_CTL_NEED_TRANSLATION ++# if __IPC_TIME64 + struct kernel_msqid64_ds ksemid, *arg = NULL; +-#else ++# else + msgctl_arg_t *arg; +-#endif ++# endif ++ ++ /* Some applications pass the __IPC_64 flag in cmd, to invoke ++ previously unsupported commands back when there was no EINVAL ++ error checking in glibc. Mask the flag for the switch statements ++ below. msgctl_syscall adds back the __IPC_64 flag for the actual ++ system call. */ ++ cmd &= ~__IPC_64; + + switch (cmd) + { +@@ -101,19 +109,19 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) + case IPC_STAT: + case MSG_STAT: + case MSG_STAT_ANY: +-#if __IPC_TIME64 ++# if __IPC_TIME64 + if (buf != NULL) + { + msqid64_to_kmsqid64 (buf, &ksemid); + arg = &ksemid; + } +-# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T ++# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T + if (cmd == IPC_SET) + arg->msg_perm.mode *= 0x10000U; +-# endif +-#else ++# endif ++# else + arg = buf; +-#endif ++# endif + break; + + case IPC_INFO: +@@ -137,21 +145,25 @@ __msgctl64 (int msqid, int cmd, struct __msqid64_ds *buf) + case IPC_STAT: + case MSG_STAT: + case MSG_STAT_ANY: +-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T ++# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T + arg->msg_perm.mode >>= 16; +-#else ++# else + /* Old Linux kernel versions might not clear the mode padding. */ + if (sizeof ((struct msqid_ds){0}.msg_perm.mode) + != sizeof (__kernel_mode_t)) + arg->msg_perm.mode &= 0xFFFF; +-#endif ++# endif + +-#if __IPC_TIME64 ++# if __IPC_TIME64 + kmsqid64_to_msqid64 (arg, buf); +-#endif ++# endif + } + + return ret; ++ ++#else /* !IPC_CTL_NEED_TRANSLATION */ ++ return msgctl_syscall (msqid, cmd, buf); ++#endif + } + #if __TIMESIZE != 64 + libc_hidden_def (__msgctl64) +diff --git a/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h +new file mode 100644 +index 0000000000..e00e71173e +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/nios2/bits/struct_stat.h +@@ -0,0 +1,135 @@ ++/* Definition for struct stat. Linux/nios2 version. ++ Copyright (C) 2020-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library. If not, see ++ . */ ++ ++#if !defined _SYS_STAT_H && !defined _FCNTL_H ++# error "Never include directly; use instead." ++#endif ++ ++#ifndef _BITS_STRUCT_STAT_H ++#define _BITS_STRUCT_STAT_H 1 ++ ++#include ++#include ++ ++#if defined __USE_FILE_OFFSET64 ++# define __field64(type, type64, name) type64 name ++#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T ++# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T ++# error "ino_t and off_t must both be the same type" ++# endif ++# define __field64(type, type64, name) type name ++#elif __BYTE_ORDER == __LITTLE_ENDIAN ++# define __field64(type, type64, name) \ ++ type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad ++#else ++# define __field64(type, type64, name) \ ++ int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name ++#endif ++ ++struct stat ++ { ++#ifdef __USE_TIME_BITS64 ++# include ++#else ++ __dev_t st_dev; /* Device. */ ++ __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ __dev_t __pad1; ++ __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ int __pad2; ++ __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */ ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++ int __glibc_reserved[2]; ++#endif ++ }; ++ ++#undef __field64 ++ ++#ifdef __USE_LARGEFILE64 ++struct stat64 ++ { ++# ifdef __USE_TIME_BITS64 ++# include ++# else ++ __dev_t st_dev; /* Device. */ ++ __ino64_t st_ino; /* File serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ __dev_t __pad1; ++ __off64_t st_size; /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ int __pad2; ++ __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */ ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++ int __glibc_reserved[2]; ++# endif ++ }; ++#endif ++ ++/* Tell code we have these members. */ ++#define _STATBUF_ST_BLKSIZE ++#define _STATBUF_ST_RDEV ++/* Nanosecond resolution time values are supported. */ ++#define _STATBUF_ST_NSEC ++ ++#endif /* _BITS_STRUCT_STAT_H */ +diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h +index a263d294b1..cf35c8bfc9 100644 +--- a/sysdeps/unix/sysv/linux/not-cancel.h ++++ b/sysdeps/unix/sysv/linux/not-cancel.h +@@ -68,7 +68,7 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt) + INTERNAL_SYSCALL_CALL (writev, fd, iov, iovcnt); + } + +-static inline int ++static inline ssize_t + __getrandom_nocancel (void *buf, size_t buflen, unsigned int flags) + { + return INLINE_SYSCALL_CALL (getrandom, buf, buflen, flags); +diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h +index d7cf158b33..0ca6e69ee9 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h ++++ b/sysdeps/unix/sysv/linux/powerpc/bits/fcntl.h +@@ -33,6 +33,12 @@ + # define __O_LARGEFILE 0200000 + #endif + ++#if __WORDSIZE == 64 && !defined __USE_FILE_OFFSET64 ++# define F_GETLK 5 ++# define F_SETLK 6 ++# define F_SETLKW 7 ++#endif ++ + struct flock + { + short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */ +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +index bf4be80f8d..202520ee25 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +@@ -122,6 +122,7 @@ + #define __NR_mbind 235 + #define __NR_membarrier 283 + #define __NR_memfd_create 279 ++#define __NR_memfd_secret 447 + #define __NR_migrate_pages 238 + #define __NR_mincore 232 + #define __NR_mkdirat 34 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +index d656aedcc2..4e65f337d4 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +@@ -127,6 +127,7 @@ + #define __NR_mbind 235 + #define __NR_membarrier 283 + #define __NR_memfd_create 279 ++#define __NR_memfd_secret 447 + #define __NR_migrate_pages 238 + #define __NR_mincore 232 + #define __NR_mkdirat 34 +diff --git a/sysdeps/unix/sysv/linux/semctl.c b/sysdeps/unix/sysv/linux/semctl.c +index 77a8130c18..3458b018bc 100644 +--- a/sysdeps/unix/sysv/linux/semctl.c ++++ b/sysdeps/unix/sysv/linux/semctl.c +@@ -140,6 +140,13 @@ __semctl64 (int semid, int semnum, int cmd, ...) + union semun64 arg64 = { 0 }; + va_list ap; + ++ /* Some applications pass the __IPC_64 flag in cmd, to invoke ++ previously unsupported commands back when there was no EINVAL ++ error checking in glibc. Mask the flag for the switch statements ++ below. semctl_syscall adds back the __IPC_64 flag for the actual ++ system call. */ ++ cmd &= ~__IPC_64; ++ + /* Get the argument only if required. */ + switch (cmd) + { +diff --git a/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h +new file mode 100644 +index 0000000000..0f7c9cdc89 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/sh/bits/struct_stat.h +@@ -0,0 +1,139 @@ ++/* Definition for struct stat. Linux/sh version. ++ Copyright (C) 2020-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library. If not, see ++ . */ ++ ++#if !defined _SYS_STAT_H && !defined _FCNTL_H ++# error "Never include directly; use instead." ++#endif ++ ++#ifndef _BITS_STRUCT_STAT_H ++#define _BITS_STRUCT_STAT_H 1 ++ ++#include ++#include ++ ++struct stat ++ { ++#ifdef __USE_TIME_BITS64 ++# include ++#else ++ __dev_t st_dev; /* Device. */ ++ unsigned short int __pad1; ++# ifndef __USE_FILE_OFFSET64 ++ __ino_t st_ino; /* File serial number. */ ++# else ++ __ino_t __st_ino; /* 32bit file serial number. */ ++# endif ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned short int __pad2; ++# ifndef __USE_FILE_OFFSET64 ++ __off_t st_size; /* Size of file, in bytes. */ ++# else ++ __off64_t st_size; /* Size of file, in bytes. */ ++# endif ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++# ifndef __USE_FILE_OFFSET64 ++ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */ ++# else ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# endif ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# define st_atime st_atim.tv_sec /* Backward compatibility. */ ++# define st_mtime st_mtim.tv_sec ++# define st_ctime st_ctim.tv_sec ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++# ifndef __USE_FILE_OFFSET64 ++ unsigned long int __glibc_reserved4; ++ unsigned long int __glibc_reserved5; ++# else ++ __ino64_t st_ino; /* File serial number. */ ++# endif ++#endif /* __USE_TIME_BITS64 */ ++ }; ++ ++#ifdef __USE_LARGEFILE64 ++struct stat64 ++ { ++# ifdef __USE_TIME_BITS64 ++# include ++# else ++ __dev_t st_dev; /* Device. */ ++ unsigned int __pad1; ++ ++ __ino_t __st_ino; /* 32bit file serial number. */ ++ __mode_t st_mode; /* File mode. */ ++ __nlink_t st_nlink; /* Link count. */ ++ __uid_t st_uid; /* User ID of the file's owner. */ ++ __gid_t st_gid; /* Group ID of the file's group.*/ ++ __dev_t st_rdev; /* Device number, if device. */ ++ unsigned int __pad2; ++ __off64_t st_size; /* Size of file, in bytes. */ ++ __blksize_t st_blksize; /* Optimal block size for I/O. */ ++ ++ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */ ++# ifdef __USE_XOPEN2K8 ++ /* Nanosecond resolution timestamps are stored in a format ++ equivalent to 'struct timespec'. This is the type used ++ whenever possible but the Unix namespace rules do not allow the ++ identifier 'timespec' to appear in the header. ++ Therefore we have to handle the use of this header in strictly ++ standard-compliant sources special. */ ++ struct timespec st_atim; /* Time of last access. */ ++ struct timespec st_mtim; /* Time of last modification. */ ++ struct timespec st_ctim; /* Time of last status change. */ ++# else ++ __time_t st_atime; /* Time of last access. */ ++ unsigned long int st_atimensec; /* Nscecs of last access. */ ++ __time_t st_mtime; /* Time of last modification. */ ++ unsigned long int st_mtimensec; /* Nsecs of last modification. */ ++ __time_t st_ctime; /* Time of last status change. */ ++ unsigned long int st_ctimensec; /* Nsecs of last status change. */ ++# endif ++ __ino64_t st_ino; /* File serial number. */ ++# endif /* __USE_TIME_BITS64 */ ++ }; ++#endif ++ ++/* Tell code we have these members. */ ++#define _STATBUF_ST_BLKSIZE ++#define _STATBUF_ST_RDEV ++/* Nanosecond resolution time values are supported. */ ++#define _STATBUF_ST_NSEC ++ ++ ++#endif /* _BITS_STRUCT_STAT_H */ +diff --git a/sysdeps/unix/sysv/linux/shmctl.c b/sysdeps/unix/sysv/linux/shmctl.c +index ea38935497..f00817a6f6 100644 +--- a/sysdeps/unix/sysv/linux/shmctl.c ++++ b/sysdeps/unix/sysv/linux/shmctl.c +@@ -85,11 +85,19 @@ shmctl_syscall (int shmid, int cmd, shmctl_arg_t *buf) + int + __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) + { +-#if __IPC_TIME64 ++#if IPC_CTL_NEED_TRANSLATION ++# if __IPC_TIME64 + struct kernel_shmid64_ds kshmid, *arg = NULL; +-#else ++# else + shmctl_arg_t *arg; +-#endif ++# endif ++ ++ /* Some applications pass the __IPC_64 flag in cmd, to invoke ++ previously unsupported commands back when there was no EINVAL ++ error checking in glibc. Mask the flag for the switch statements ++ below. shmctl_syscall adds back the __IPC_64 flag for the actual ++ system call. */ ++ cmd &= ~__IPC_64; + + switch (cmd) + { +@@ -103,19 +111,19 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) + case IPC_STAT: + case SHM_STAT: + case SHM_STAT_ANY: +-#if __IPC_TIME64 ++# if __IPC_TIME64 + if (buf != NULL) + { + shmid64_to_kshmid64 (buf, &kshmid); + arg = &kshmid; + } +-# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T ++# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T + if (cmd == IPC_SET) + arg->shm_perm.mode *= 0x10000U; +-# endif +-#else ++# endif ++# else + arg = buf; +-#endif ++# endif + break; + + case IPC_INFO: +@@ -140,21 +148,25 @@ __shmctl64 (int shmid, int cmd, struct __shmid64_ds *buf) + case IPC_STAT: + case SHM_STAT: + case SHM_STAT_ANY: +-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T ++# ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T + arg->shm_perm.mode >>= 16; +-#else ++# else + /* Old Linux kernel versions might not clear the mode padding. */ + if (sizeof ((struct shmid_ds){0}.shm_perm.mode) + != sizeof (__kernel_mode_t)) + arg->shm_perm.mode &= 0xFFFF; +-#endif ++# endif + +-#if __IPC_TIME64 ++# if __IPC_TIME64 + kshmid64_to_shmid64 (arg, buf); +-#endif ++# endif + } + + return ret; ++ ++#else /* !IPC_CTL_NEED_TRANSLATION */ ++ return shmctl_syscall (shmid, cmd, buf); ++#endif + } + #if __TIMESIZE != 64 + libc_hidden_def (__shmctl64) +diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h +index f965986ba8..19841d0738 100644 +--- a/sysdeps/unix/sysv/linux/sys/mount.h ++++ b/sysdeps/unix/sysv/linux/sys/mount.h +@@ -27,77 +27,113 @@ + #include + #include + +-#define BLOCK_SIZE 1024 ++#ifdef __has_include ++# if __has_include ("linux/mount.h") ++# include "linux/mount.h" ++# endif ++#endif ++ ++ + #define BLOCK_SIZE_BITS 10 ++#define BLOCK_SIZE (1<. ++ ++import argparse ++import sys ++ ++import glibcextract ++ ++ ++def main(): ++ """The main entry point.""" ++ parser = argparse.ArgumentParser( ++ description='Check if glibc provided sys/mount.h can be ' ++ ' used along related kernel headers.') ++ parser.add_argument('--cc', metavar='CC', ++ help='C compiler (including options) to use') ++ args = parser.parse_args() ++ ++ if glibcextract.compile_c_snippet( ++ '#include ', ++ args.cc).returncode != 0: ++ sys.exit (77) ++ ++ def check(testname, snippet): ++ # Add -Werror to catch macro redefinitions and _ISOMAC to avoid ++ # internal glibc definitions. ++ r = glibcextract.compile_c_snippet(snippet, args.cc, ++ '-Werror -D_ISOMAC') ++ if r.returncode != 0: ++ print('error: test {}:\n{}'.format(testname, r.output.decode())) ++ return r.returncode ++ ++ status = max( ++ check("sys/mount.h + linux/mount.h", ++ "#include \n" ++ "#include "), ++ check("sys/mount.h + linux/fs.h", ++ "#include \n" ++ "#include "), ++ check("linux/mount.h + sys/mount.h", ++ "#include \n" ++ "#include "), ++ check("linux/fs.h + sys/mount.h", ++ "#include \n" ++ "#include ")) ++ sys.exit(status) ++ ++if __name__ == '__main__': ++ main() +diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py +index a62f803123..be2ef2daf1 100755 +--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py +@@ -33,6 +33,11 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + ++ if glibcextract.compile_c_snippet( ++ '#include ', ++ args.cc).returncode != 0: ++ sys.exit (77) ++ + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) + # Constants in glibc were updated to match Linux v5.16. When glibc + # constants are updated this value should be updated to match the +diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +index 90cbb9be64..d732173abd 100644 +--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +@@ -33,11 +33,13 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + +- linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- # Linux started to provide pidfd.h with 5.10. +- if linux_version_headers < (5, 10): ++ if glibcextract.compile_c_snippet( ++ '#include ', ++ args.cc).returncode != 0: + sys.exit (77) +- linux_version_glibc = (5, 18) ++ ++ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) ++ linux_version_glibc = (5, 19) + sys.exit(glibcextract.compare_macro_consts( + '#include \n', + '#include \n' +diff --git a/sysdeps/unix/sysv/linux/tst-pidfd.c b/sysdeps/unix/sysv/linux/tst-pidfd.c +index 037af22290..5711d1c312 100644 +--- a/sysdeps/unix/sysv/linux/tst-pidfd.c ++++ b/sysdeps/unix/sysv/linux/tst-pidfd.c +@@ -147,8 +147,11 @@ do_test (void) + may be denied if the process doesn't have CAP_SYS_PTRACE or + if a LSM security_ptrace_access_check denies access. */ + if (fd == -1 && errno == EPERM) +- FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, " +- "skipping test"); ++ { ++ TEST_COMPARE (pidfd_send_signal (pidfd, SIGKILL, NULL, 0), 0); ++ FAIL_UNSUPPORTED ("don't have permission to use pidfd_getfd on pidfd, " ++ "skipping test"); ++ } + TEST_VERIFY (fd > 0); + + char *path = xasprintf ("/proc/%d/fd/%d", pid, remote_fd); +diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h +index e9f3382108..d95c1efa2c 100644 +--- a/sysdeps/x86/dl-cacheinfo.h ++++ b/sysdeps/x86/dl-cacheinfo.h +@@ -478,7 +478,7 @@ handle_zhaoxin (int name) + } + + static void +-get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, ++get_common_cache_info (long int *shared_ptr, long int * shared_per_thread_ptr, unsigned int *threads_ptr, + long int core) + { + unsigned int eax; +@@ -497,6 +497,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, + unsigned int family = cpu_features->basic.family; + unsigned int model = cpu_features->basic.model; + long int shared = *shared_ptr; ++ long int shared_per_thread = *shared_per_thread_ptr; + unsigned int threads = *threads_ptr; + bool inclusive_cache = true; + bool support_count_mask = true; +@@ -512,6 +513,7 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, + /* Try L2 otherwise. */ + level = 2; + shared = core; ++ shared_per_thread = core; + threads_l2 = 0; + threads_l3 = -1; + } +@@ -668,29 +670,27 @@ get_common_cache_info (long int *shared_ptr, unsigned int *threads_ptr, + } + else + { +-intel_bug_no_cache_info: +- /* Assume that all logical threads share the highest cache +- level. */ +- threads +- = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16) +- & 0xff); +- } +- +- /* Cap usage of highest cache level to the number of supported +- threads. */ +- if (shared > 0 && threads > 0) +- shared /= threads; ++ intel_bug_no_cache_info: ++ /* Assume that all logical threads share the highest cache ++ level. */ ++ threads = ((cpu_features->features[CPUID_INDEX_1].cpuid.ebx >> 16) ++ & 0xff); ++ } ++ /* Get per-thread size of highest level cache. */ ++ if (shared_per_thread > 0 && threads > 0) ++ shared_per_thread /= threads; + } + + /* Account for non-inclusive L2 and L3 caches. */ + if (!inclusive_cache) + { +- if (threads_l2 > 0) +- core /= threads_l2; ++ long int core_per_thread = threads_l2 > 0 ? (core / threads_l2) : core; ++ shared_per_thread += core_per_thread; + shared += core; + } + + *shared_ptr = shared; ++ *shared_per_thread_ptr = shared_per_thread; + *threads_ptr = threads; + } + +@@ -704,6 +704,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + int max_cpuid_ex; + long int data = -1; + long int shared = -1; ++ long int shared_per_thread = -1; + long int core = -1; + unsigned int threads = 0; + unsigned long int level1_icache_size = -1; +@@ -724,6 +725,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features); + core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features); + shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features); ++ shared_per_thread = shared; + + level1_icache_size + = handle_intel (_SC_LEVEL1_ICACHE_SIZE, cpu_features); +@@ -747,13 +749,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + level4_cache_size + = handle_intel (_SC_LEVEL4_CACHE_SIZE, cpu_features); + +- get_common_cache_info (&shared, &threads, core); ++ get_common_cache_info (&shared, &shared_per_thread, &threads, core); + } + else if (cpu_features->basic.kind == arch_kind_zhaoxin) + { + data = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE); + core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE); + shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE); ++ shared_per_thread = shared; + + level1_icache_size = handle_zhaoxin (_SC_LEVEL1_ICACHE_SIZE); + level1_icache_linesize = handle_zhaoxin (_SC_LEVEL1_ICACHE_LINESIZE); +@@ -767,13 +770,14 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + level3_cache_assoc = handle_zhaoxin (_SC_LEVEL3_CACHE_ASSOC); + level3_cache_linesize = handle_zhaoxin (_SC_LEVEL3_CACHE_LINESIZE); + +- get_common_cache_info (&shared, &threads, core); ++ get_common_cache_info (&shared, &shared_per_thread, &threads, core); + } + else if (cpu_features->basic.kind == arch_kind_amd) + { + data = handle_amd (_SC_LEVEL1_DCACHE_SIZE); + core = handle_amd (_SC_LEVEL2_CACHE_SIZE); + shared = handle_amd (_SC_LEVEL3_CACHE_SIZE); ++ shared_per_thread = shared; + + level1_icache_size = handle_amd (_SC_LEVEL1_ICACHE_SIZE); + level1_icache_linesize = handle_amd (_SC_LEVEL1_ICACHE_LINESIZE); +@@ -791,8 +795,11 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx); + + if (shared <= 0) +- /* No shared L3 cache. All we have is the L2 cache. */ +- shared = core; ++ { ++ /* No shared L3 cache. All we have is the L2 cache. */ ++ shared = core; ++ shared_per_thread = core; ++ } + else + { + /* Figure out the number of logical threads that share L3. */ +@@ -816,7 +823,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + /* Cap usage of highest cache level to the number of + supported threads. */ + if (threads > 0) +- shared /= threads; ++ shared_per_thread /= threads; + + /* Get shared cache per ccx for Zen architectures. */ + if (cpu_features->basic.family >= 0x17) +@@ -827,12 +834,13 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx); + + unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1; +- shared *= threads_per_ccx; ++ shared_per_thread *= threads_per_ccx; + } + else + { + /* Account for exclusive L2 and L3 caches. */ + shared += core; ++ shared_per_thread += core; + } + } + } +@@ -850,17 +858,46 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + cpu_features->level3_cache_linesize = level3_cache_linesize; + cpu_features->level4_cache_size = level4_cache_size; + +- /* The default setting for the non_temporal threshold is 3/4 of one +- thread's share of the chip's cache. For most Intel and AMD processors +- with an initial release date between 2017 and 2020, a thread's typical +- share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4 +- threshold leaves 125 KBytes to 500 KBytes of the thread's data +- in cache after a maximum temporal copy, which will maintain +- in cache a reasonable portion of the thread's stack and other +- active data. If the threshold is set higher than one thread's +- share of the cache, it has a substantial risk of negatively +- impacting the performance of other threads running on the chip. */ +- unsigned long int non_temporal_threshold = shared * 3 / 4; ++ /* The default setting for the non_temporal threshold is 1/4 of size ++ of the chip's cache. For most Intel and AMD processors with an ++ initial release date between 2017 and 2023, a thread's typical ++ share of the cache is from 18-64MB. Using the 1/4 L3 is meant to ++ estimate the point where non-temporal stores begin out-competing ++ REP MOVSB. As well the point where the fact that non-temporal ++ stores are forced back to main memory would already occurred to the ++ majority of the lines in the copy. Note, concerns about the ++ entire L3 cache being evicted by the copy are mostly alleviated ++ by the fact that modern HW detects streaming patterns and ++ provides proper LRU hints so that the maximum thrashing ++ capped at 1/associativity. */ ++ unsigned long int non_temporal_threshold = shared / 4; ++ ++ /* If the computed non_temporal_threshold <= 3/4 * per-thread L3, we most ++ likely have incorrect/incomplete cache info in which case, default to ++ 3/4 * per-thread L3 to avoid regressions. */ ++ unsigned long int non_temporal_threshold_lowbound ++ = shared_per_thread * 3 / 4; ++ if (non_temporal_threshold < non_temporal_threshold_lowbound) ++ non_temporal_threshold = non_temporal_threshold_lowbound; ++ ++ /* If no ERMS, we use the per-thread L3 chunking. Normal cacheable stores run ++ a higher risk of actually thrashing the cache as they don't have a HW LRU ++ hint. As well, their performance in highly parallel situations is ++ noticeably worse. */ ++ if (!CPU_FEATURE_USABLE_P (cpu_features, ERMS)) ++ non_temporal_threshold = non_temporal_threshold_lowbound; ++ /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of ++ 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best ++ if that operation cannot overflow. Minimum of 0x4040 (16448) because the ++ L(large_memset_4x) loops need 64-byte to cache align and enough space for ++ at least 1 iteration of 4x PAGE_SIZE unrolled loop. Both values are ++ reflected in the manual. */ ++ unsigned long int maximum_non_temporal_threshold = SIZE_MAX >> 4; ++ unsigned long int minimum_non_temporal_threshold = 0x4040; ++ if (non_temporal_threshold < minimum_non_temporal_threshold) ++ non_temporal_threshold = minimum_non_temporal_threshold; ++ else if (non_temporal_threshold > maximum_non_temporal_threshold) ++ non_temporal_threshold = maximum_non_temporal_threshold; + + #if HAVE_TUNABLES + /* NB: The REP MOVSB threshold must be greater than VEC_SIZE * 8. */ +@@ -915,8 +952,8 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + shared = tunable_size; + + tunable_size = TUNABLE_GET (x86_non_temporal_threshold, long int, NULL); +- /* NB: Ignore the default value 0. */ +- if (tunable_size != 0) ++ if (tunable_size > minimum_non_temporal_threshold ++ && tunable_size <= maximum_non_temporal_threshold) + non_temporal_threshold = tunable_size; + + tunable_size = TUNABLE_GET (x86_rep_movsb_threshold, long int, NULL); +@@ -931,14 +968,9 @@ dl_init_cacheinfo (struct cpu_features *cpu_features) + + TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, data, 0, SIZE_MAX); + TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, shared, 0, SIZE_MAX); +- /* SIZE_MAX >> 4 because memmove-vec-unaligned-erms right-shifts the value of +- 'x86_non_temporal_threshold' by `LOG_4X_MEMCPY_THRESH` (4) and it is best +- if that operation cannot overflow. Minimum of 0x4040 (16448) because the +- L(large_memset_4x) loops need 64-byte to cache align and enough space for +- at least 1 iteration of 4x PAGE_SIZE unrolled loop. Both values are +- reflected in the manual. */ + TUNABLE_SET_WITH_BOUNDS (x86_non_temporal_threshold, non_temporal_threshold, +- 0x4040, SIZE_MAX >> 4); ++ minimum_non_temporal_threshold, ++ maximum_non_temporal_threshold); + TUNABLE_SET_WITH_BOUNDS (x86_rep_movsb_threshold, rep_movsb_threshold, + minimum_rep_movsb_threshold, SIZE_MAX); + TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1, +diff --git a/sysdeps/x86/get-isa-level.h b/sysdeps/x86/get-isa-level.h +index 1ade78ab73..5b4dd5f062 100644 +--- a/sysdeps/x86/get-isa-level.h ++++ b/sysdeps/x86/get-isa-level.h +@@ -47,6 +47,8 @@ get_isa_level (const struct cpu_features *cpu_features) + isa_level |= GNU_PROPERTY_X86_ISA_1_V2; + if (CPU_FEATURE_USABLE_P (cpu_features, AVX) + && CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI1) ++ && CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && CPU_FEATURE_USABLE_P (cpu_features, F16C) + && CPU_FEATURE_USABLE_P (cpu_features, FMA) + && CPU_FEATURE_USABLE_P (cpu_features, LZCNT) +diff --git a/sysdeps/x86/isa-level.h b/sysdeps/x86/isa-level.h +index 3c4480aba7..06f6c9663e 100644 +--- a/sysdeps/x86/isa-level.h ++++ b/sysdeps/x86/isa-level.h +@@ -79,7 +79,9 @@ + /* ISA level >= 3 guaranteed includes. */ + #define AVX_X86_ISA_LEVEL 3 + #define AVX2_X86_ISA_LEVEL 3 ++#define BMI1_X86_ISA_LEVEL 3 + #define BMI2_X86_ISA_LEVEL 3 ++#define LZCNT_X86_ISA_LEVEL 3 + #define MOVBE_X86_ISA_LEVEL 3 + + /* ISA level >= 2 guaranteed includes. */ +diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S +index 0db2cb4152..7619e743e1 100644 +--- a/sysdeps/x86_64/dl-tlsdesc.S ++++ b/sysdeps/x86_64/dl-tlsdesc.S +@@ -61,7 +61,7 @@ _dl_tlsdesc_return: + _dl_tlsdesc_undefweak: + _CET_ENDBR + movq 8(%rax), %rax +- subq %fs:0, %rax ++ sub %fs:0, %RAX_LP + ret + cfi_endproc + .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak +@@ -102,7 +102,7 @@ _dl_tlsdesc_dynamic: + /* Preserve call-clobbered registers that we modify. + We need two scratch regs anyway. */ + movq %rsi, -16(%rsp) +- movq %fs:DTV_OFFSET, %rsi ++ mov %fs:DTV_OFFSET, %RSI_LP + movq %rdi, -8(%rsp) + movq TLSDESC_ARG(%rax), %rdi + movq (%rsi), %rax +@@ -116,7 +116,7 @@ _dl_tlsdesc_dynamic: + addq TLSDESC_MODOFF(%rdi), %rax + .Lret: + movq -16(%rsp), %rsi +- subq %fs:0, %rax ++ sub %fs:0, %RAX_LP + movq -8(%rsp), %rdi + ret + .Lslow: +diff --git a/sysdeps/x86_64/fpu/fraiseexcpt.c b/sysdeps/x86_64/fpu/fraiseexcpt.c +index 864f4777a2..23446ff4ac 100644 +--- a/sysdeps/x86_64/fpu/fraiseexcpt.c ++++ b/sysdeps/x86_64/fpu/fraiseexcpt.c +@@ -33,7 +33,7 @@ __feraiseexcept (int excepts) + /* One example of an invalid operation is 0.0 / 0.0. */ + float f = 0.0; + +- __asm__ __volatile__ ("divss %0, %0 " : : "x" (f)); ++ __asm__ __volatile__ ("divss %0, %0 " : "+x" (f)); + (void) &f; + } + +@@ -43,7 +43,7 @@ __feraiseexcept (int excepts) + float f = 1.0; + float g = 0.0; + +- __asm__ __volatile__ ("divss %1, %0" : : "x" (f), "x" (g)); ++ __asm__ __volatile__ ("divss %1, %0" : "+x" (f) : "x" (g)); + (void) &f; + } + +diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h +index a57a9952f3..f2f5e8a211 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h ++++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h +@@ -36,7 +36,9 @@ IFUNC_SELECTOR (void) + const struct cpu_features *cpu_features = __get_cpu_features (); + + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI1) + && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, LZCNT) + && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, + AVX_Fast_Unaligned_Load, )) + { +diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +index a71444eccb..00a91123d3 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c ++++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c +@@ -69,10 +69,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __memchr_evex_rtm) + X86_IFUNC_IMPL_ADD_V3 (array, i, memchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __memchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, memchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __memchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -207,13 +209,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, memrchr, + X86_IFUNC_IMPL_ADD_V4 (array, i, memrchr, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (LZCNT)), + __memrchr_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (LZCNT)), + __memrchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, memrchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) ++ && CPU_FEATURE_USABLE (LZCNT) + && CPU_FEATURE_USABLE (RTM)), + __memrchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -335,10 +343,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __rawmemchr_evex_rtm) + X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __rawmemchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, rawmemchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __rawmemchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -448,13 +458,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcasecmp, + X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strcasecmp_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp, +@@ -470,13 +483,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strcasecmp_l, + X86_IFUNC_IMPL_ADD_V4 (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_l_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcasecmp_l_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strcasecmp_l_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strcasecmp_l, +@@ -562,13 +578,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strrchr, + X86_IFUNC_IMPL_ADD_V4 (array, i, strrchr, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2)), + __strrchr_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2)), + __strrchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strrchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strrchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -585,10 +607,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __strcmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strcmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strcmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strcmp_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strcmp, +@@ -638,13 +662,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncasecmp, + X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strncasecmp_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp, +@@ -660,13 +687,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncasecmp_l, + X86_IFUNC_IMPL_ADD_V4 (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ & CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_l_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncasecmp_l_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncasecmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strncasecmp_l_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strncasecmp_l, +@@ -773,13 +803,18 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + X86_IFUNC_IMPL_ADD_V4 (array, i, wcsrchr, + (CPU_FEATURE_USABLE (AVX512VL) + && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI1) + && CPU_FEATURE_USABLE (BMI2)), + __wcsrchr_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcsrchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcsrchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI1) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcsrchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -796,10 +831,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __wcscmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcscmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcscmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcscmp_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -816,10 +853,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __wcsncmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wcsncmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, wcsncmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wcsncmp_avx2_rtm) + /* ISA V2 wrapper for GENERIC implementation because the +@@ -909,10 +948,12 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + && CPU_FEATURE_USABLE (BMI2)), + __wmemchr_evex_rtm) + X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __wmemchr_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, wmemchr, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __wmemchr_avx2_rtm) + /* ISA V2 wrapper for SSE2 implementation because the SSE2 +@@ -1162,13 +1203,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + IFUNC_IMPL (i, name, strncmp, + X86_IFUNC_IMPL_ADD_V4 (array, i, strncmp, + (CPU_FEATURE_USABLE (AVX512VL) +- && CPU_FEATURE_USABLE (AVX512BW)), ++ && CPU_FEATURE_USABLE (AVX512BW) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncmp_evex) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp, +- CPU_FEATURE_USABLE (AVX2), ++ (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2)), + __strncmp_avx2) + X86_IFUNC_IMPL_ADD_V3 (array, i, strncmp, + (CPU_FEATURE_USABLE (AVX2) ++ && CPU_FEATURE_USABLE (BMI2) + && CPU_FEATURE_USABLE (RTM)), + __strncmp_avx2_rtm) + X86_IFUNC_IMPL_ADD_V2 (array, i, strncmp, +diff --git a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +index 68646ef199..7622af259c 100644 +--- a/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h ++++ b/sysdeps/x86_64/multiarch/ifunc-strcasecmp.h +@@ -34,6 +34,7 @@ IFUNC_SELECTOR (void) + const struct cpu_features *cpu_features = __get_cpu_features (); + + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, + AVX_Fast_Unaligned_Load, )) + { +diff --git a/sysdeps/x86_64/multiarch/memcmp-sse2.S b/sysdeps/x86_64/multiarch/memcmp-sse2.S +index afd450d020..51bc9344f0 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-sse2.S ++++ b/sysdeps/x86_64/multiarch/memcmp-sse2.S +@@ -308,7 +308,17 @@ L(ret_nonzero_vec_end_0): + setg %dl + leal -1(%rdx, %rdx), %eax + # else +- addl %edx, %eax ++ /* Use `addq` instead of `addl` here so that even if `rax` + `rdx` ++ is negative value of the sum will be usable as a 64-bit offset ++ (negative 32-bit numbers zero-extend to a large and often ++ out-of-bounds 64-bit offsets). Note that `rax` + `rdx` >= 0 is ++ an invariant when `memcmp` is used correctly, but if the input ++ strings `rsi`/`rdi` are concurrently modified as the function ++ runs (there is a Data-Race) it is possible for `rax` + `rdx` to ++ be negative. Given that there is virtually no extra to cost ++ using `addq` instead of `addl` we may as well protect the ++ data-race case. */ ++ addq %rdx, %rax + movzbl (VEC_SIZE * -1 + SIZE_OFFSET)(%rsi, %rax), %ecx + movzbl (VEC_SIZE * -1 + SIZE_OFFSET)(%rdi, %rax), %eax + subl %ecx, %eax +diff --git a/sysdeps/x86_64/multiarch/rtld-strcpy.S b/sysdeps/x86_64/multiarch/rtld-strcpy.S +new file mode 100644 +index 0000000000..19439c553d +--- /dev/null ++++ b/sysdeps/x86_64/multiarch/rtld-strcpy.S +@@ -0,0 +1,18 @@ ++/* Copyright (C) 2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include "../strcpy.S" +diff --git a/sysdeps/x86_64/multiarch/strcmp.c b/sysdeps/x86_64/multiarch/strcmp.c +index fdd5afe3af..9d6c9f66ba 100644 +--- a/sysdeps/x86_64/multiarch/strcmp.c ++++ b/sysdeps/x86_64/multiarch/strcmp.c +@@ -45,12 +45,12 @@ IFUNC_SELECTOR (void) + const struct cpu_features *cpu_features = __get_cpu_features (); + + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, + AVX_Fast_Unaligned_Load, )) + { + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) +- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) + return OPTIMIZE (evex); + + if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) +diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S +index 0593fb303b..b9b58ef599 100644 +--- a/sysdeps/x86_64/multiarch/strlen-avx2.S ++++ b/sysdeps/x86_64/multiarch/strlen-avx2.S +@@ -544,14 +544,11 @@ L(return_vzeroupper): + L(cross_page_less_vec): + tzcntl %eax, %eax + # ifdef USE_AS_WCSLEN +- /* NB: Multiply length by 4 to get byte count. */ +- sall $2, %esi ++ /* NB: Divide by 4 to convert from byte-count to length. */ ++ shrl $2, %eax + # endif + cmpq %rax, %rsi + cmovb %esi, %eax +-# ifdef USE_AS_WCSLEN +- shrl $2, %eax +-# endif + VZEROUPPER_RETURN + # endif + +diff --git a/sysdeps/x86_64/multiarch/strncmp.c b/sysdeps/x86_64/multiarch/strncmp.c +index 4ebe4bde30..c4f8b6bbb5 100644 +--- a/sysdeps/x86_64/multiarch/strncmp.c ++++ b/sysdeps/x86_64/multiarch/strncmp.c +@@ -41,12 +41,12 @@ IFUNC_SELECTOR (void) + const struct cpu_features *cpu_features = __get_cpu_features (); + + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2) + && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features, + AVX_Fast_Unaligned_Load, )) + { + if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL) +- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW) +- && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2)) ++ && X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)) + return OPTIMIZE (evex); + + if (CPU_FEATURE_USABLE_P (cpu_features, RTM)) +diff --git a/time/Makefile b/time/Makefile +index 470275b90c..2f4aa2d528 100644 +--- a/time/Makefile ++++ b/time/Makefile +@@ -50,7 +50,7 @@ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \ + tst-clock tst-clock2 tst-clock_nanosleep tst-cpuclock1 \ + tst-adjtime tst-ctime tst-difftime tst-mktime4 tst-clock_settime \ + tst-settimeofday tst-itimer tst-gmtime tst-timegm \ +- tst-timespec_get tst-timespec_getres ++ tst-timespec_get tst-timespec_getres tst-strftime4 + + tests-time64 := \ + tst-adjtime-time64 \ +@@ -65,6 +65,7 @@ tests-time64 := \ + tst-itimer-time64 \ + tst-mktime4-time64 \ + tst-settimeofday-time64 \ ++ tst-strftime4-time64 \ + tst-timegm-time64 \ + tst-timespec_get-time64 \ + tst-timespec_getres-time64 \ +diff --git a/time/mktime.c b/time/mktime.c +index 494c89bf54..e9a6006710 100644 +--- a/time/mktime.c ++++ b/time/mktime.c +@@ -429,8 +429,13 @@ __mktime_internal (struct tm *tp, + time with the right value, and use its UTC offset. + + Heuristic: probe the adjacent timestamps in both directions, +- looking for the desired isdst. This should work for all real +- time zone histories in the tz database. */ ++ looking for the desired isdst. If none is found within a ++ reasonable duration bound, assume a one-hour DST difference. ++ This should work for all real time zone histories in the tz ++ database. */ ++ ++ /* +1 if we wanted standard time but got DST, -1 if the reverse. */ ++ int dst_difference = (isdst == 0) - (tm.tm_isdst == 0); + + /* Distance between probes when looking for a DST boundary. In + tzdata2003a, the shortest period of DST is 601200 seconds +@@ -441,12 +446,14 @@ __mktime_internal (struct tm *tp, + periods when probing. */ + int stride = 601200; + +- /* The longest period of DST in tzdata2003a is 536454000 seconds +- (e.g., America/Jujuy starting 1946-10-01 01:00). The longest +- period of non-DST is much longer, but it makes no real sense +- to search for more than a year of non-DST, so use the DST +- max. */ +- int duration_max = 536454000; ++ /* In TZDB 2021e, the longest period of DST (or of non-DST), in ++ which the DST (or adjacent DST) difference is not one hour, ++ is 457243209 seconds: e.g., America/Cambridge_Bay with leap ++ seconds, starting 1965-10-31 00:00 in a switch from ++ double-daylight time (-05) to standard time (-07), and ++ continuing to 1980-04-27 02:00 in a switch from standard time ++ (-07) to daylight time (-06). */ ++ int duration_max = 457243209; + + /* Search in both directions, so the maximum distance is half + the duration; add the stride to avoid off-by-1 problems. */ +@@ -483,6 +490,11 @@ __mktime_internal (struct tm *tp, + } + } + ++ /* No unusual DST offset was found nearby. Assume one-hour DST. */ ++ t += 60 * 60 * dst_difference; ++ if (mktime_min <= t && t <= mktime_max && convert_time (convert, t, &tm)) ++ goto offset_found; ++ + __set_errno (EOVERFLOW); + return -1; + } +diff --git a/time/strftime_l.c b/time/strftime_l.c +index 75554fee7c..4d7c4ea828 100644 +--- a/time/strftime_l.c ++++ b/time/strftime_l.c +@@ -159,6 +159,10 @@ extern char *tzname[]; + #ifdef _LIBC + # define tzname __tzname + # define tzset __tzset ++ ++# define time_t __time64_t ++# define __gmtime_r(t, tp) __gmtime64_r (t, tp) ++# define mktime(tp) __mktime64 (tp) + #endif + + #if !HAVE_TM_GMTOFF +diff --git a/time/strptime_l.c b/time/strptime_l.c +index a3c5681fc2..f927448204 100644 +--- a/time/strptime_l.c ++++ b/time/strptime_l.c +@@ -30,8 +30,10 @@ + #ifdef _LIBC + # define HAVE_LOCALTIME_R 0 + # include "../locale/localeinfo.h" +-#endif + ++# define time_t __time64_t ++# define __localtime_r(t, tp) __localtime64_r (t, tp) ++#endif + + #if ! HAVE_LOCALTIME_R && ! defined localtime_r + # ifdef _LIBC +diff --git a/time/tst-strftime4-time64.c b/time/tst-strftime4-time64.c +new file mode 100644 +index 0000000000..4d47ee7d79 +--- /dev/null ++++ b/time/tst-strftime4-time64.c +@@ -0,0 +1 @@ ++#include "tst-strftime4.c" +diff --git a/time/tst-strftime4.c b/time/tst-strftime4.c +new file mode 100644 +index 0000000000..659716d0fa +--- /dev/null ++++ b/time/tst-strftime4.c +@@ -0,0 +1,52 @@ ++/* Test strftime and strptime after 2038-01-19 03:14:07 UTC (bug 30053). ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ TEST_VERIFY_EXIT (setenv ("TZ", "UTC0", 1) == 0); ++ tzset (); ++ if (sizeof (time_t) > 4) ++ { ++ time_t wrap = (time_t) 2147483648LL; ++ char buf[80]; ++ struct tm *tm = gmtime (&wrap); ++ TEST_VERIFY_EXIT (tm != NULL); ++ TEST_VERIFY_EXIT (strftime (buf, sizeof buf, "%s", tm) > 0); ++ puts (buf); ++ TEST_VERIFY (strcmp (buf, "2147483648") == 0); ++ ++ struct tm tm2; ++ char *p = strptime (buf, "%s", &tm2); ++ TEST_VERIFY_EXIT (p != NULL && *p == '\0'); ++ time_t t = mktime (&tm2); ++ printf ("%lld\n", (long long) t); ++ TEST_VERIFY (t == wrap); ++ } ++ else ++ FAIL_UNSUPPORTED ("32-bit time_t"); ++ return 0; ++} ++ ++#include +diff --git a/time/tzfile.c b/time/tzfile.c +index dd75848ba9..8bba4e5b8d 100644 +--- a/time/tzfile.c ++++ b/time/tzfile.c +@@ -32,7 +32,7 @@ + int __use_tzfile; + static dev_t tzfile_dev; + static ino64_t tzfile_ino; +-static time_t tzfile_mtime; ++static __time64_t tzfile_mtime; + + struct ttinfo + { +@@ -61,6 +61,10 @@ static size_t num_leaps; + static struct leap *leaps; + static char *tzspec; + ++/* Used to restore the daylight variable during time conversion, as if ++ tzset had been called. */ ++static int daylight_saved; ++ + #include + #include + +@@ -438,36 +442,35 @@ __tzfile_read (const char *file, size_t extra, char **extrap) + if (__tzname[1] == NULL) + __tzname[1] = __tzname[0]; + ++ daylight_saved = 0; + if (num_transitions == 0) + /* Use the first rule (which should also be the only one). */ + rule_stdoff = rule_dstoff = types[0].offset; + else + { +- int stdoff_set = 0, dstoff_set = 0; +- rule_stdoff = rule_dstoff = 0; ++ rule_stdoff = 0; ++ ++ /* Search for the last rule with a standard time offset. This ++ will be used for the global timezone variable. */ + i = num_transitions - 1; + do +- { +- if (!stdoff_set && !types[type_idxs[i]].isdst) +- { +- stdoff_set = 1; +- rule_stdoff = types[type_idxs[i]].offset; +- } +- else if (!dstoff_set && types[type_idxs[i]].isdst) +- { +- dstoff_set = 1; +- rule_dstoff = types[type_idxs[i]].offset; +- } +- if (stdoff_set && dstoff_set) ++ if (!types[type_idxs[i]].isdst) ++ { ++ rule_stdoff = types[type_idxs[i]].offset; + break; +- } ++ } ++ else ++ daylight_saved = 1; + while (i-- > 0); + +- if (!dstoff_set) +- rule_dstoff = rule_stdoff; ++ /* Keep searching to see if there is a DST rule. This ++ information will be used to set the global daylight ++ variable. */ ++ while (i-- > 0 && !daylight_saved) ++ daylight_saved = types[type_idxs[i]].isdst; + } + +- __daylight = rule_stdoff != rule_dstoff; ++ __daylight = daylight_saved; + __timezone = -rule_stdoff; + + done: +@@ -731,7 +734,7 @@ __tzfile_compute (__time64_t timer, int use_localtime, + } + + struct ttinfo *info = &types[i]; +- __daylight = rule_stdoff != rule_dstoff; ++ __daylight = daylight_saved; + __timezone = -rule_stdoff; + + if (__tzname[0] == NULL) +diff --git a/timezone/Makefile b/timezone/Makefile +index a789c22d26..5002de39ad 100644 +--- a/timezone/Makefile ++++ b/timezone/Makefile +@@ -23,7 +23,7 @@ subdir := timezone + include ../Makeconfig + + others := zdump zic +-tests := test-tz tst-timezone tst-tzset tst-bz28707 ++tests := test-tz tst-timezone tst-tzset tst-bz28707 tst-bz29951 + + generated-dirs += testdata + +@@ -86,11 +86,13 @@ $(objpfx)tst-timezone.out: $(addprefix $(testdata)/, \ + Europe/London) + $(objpfx)tst-tzset.out: $(addprefix $(testdata)/XT, 1 2 3 4) + $(objpfx)tst-bz28707.out: $(testdata)/XT5 ++$(objpfx)tst-bz29951.out: $(testdata)/XT6 + + test-tz-ENV = TZDIR=$(testdata) + tst-timezone-ENV = TZDIR=$(testdata) + tst-tzset-ENV = TZDIR=$(testdata) + tst-bz28707-ENV = TZDIR=$(testdata) ++tst-bz29951-ENV = TZDIR=$(testdata) + + # Note this must come second in the deps list for $(built-program-cmd) to work. + zic-deps = $(objpfx)zic $(leapseconds) yearistype +diff --git a/timezone/testdata/XT6 b/timezone/testdata/XT6 +new file mode 100644 +index 0000000000..07b393bb7d +Binary files /dev/null and b/timezone/testdata/XT6 differ +diff --git a/timezone/tst-bz29951.c b/timezone/tst-bz29951.c +new file mode 100644 +index 0000000000..abd334683b +--- /dev/null ++++ b/timezone/tst-bz29951.c +@@ -0,0 +1,68 @@ ++/* Check that daylight is set if the last DST transition did not change offset. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* Set the specified time zone with error checking. */ ++static void ++set_timezone (const char *name) ++{ ++ TEST_VERIFY (setenv ("TZ", name, 1) == 0); ++ errno = 0; ++ tzset (); ++ TEST_COMPARE (errno, 0); ++} ++ ++static int ++do_test (void) ++{ ++ /* Test zone based on tz-2022g version of Africa/Tripoli. The last ++ DST transition coincided with a change in the standard time ++ offset, effectively making it a no-op. ++ ++ Africa/Tripoli Thu Oct 24 23:59:59 2013 UT ++ = Fri Oct 25 01:59:59 2013 CEST isdst=1 gmtoff=7200 ++ Africa/Tripoli Fri Oct 25 00:00:00 2013 UT ++ = Fri Oct 25 02:00:00 2013 EET isdst=0 gmtoff=7200 ++ */ ++ set_timezone ("XT6"); ++ TEST_VERIFY (daylight != 0); ++ TEST_COMPARE (timezone, -7200); ++ ++ /* Check that localtime re-initializes the two variables. */ ++ daylight = timezone = 17; ++ time_t t = 844034401; ++ struct tm *tm = localtime (&t); ++ TEST_VERIFY (daylight != 0); ++ TEST_COMPARE (timezone, -7200); ++ TEST_COMPARE (tm->tm_year, 96); ++ TEST_COMPARE (tm->tm_mon, 8); ++ TEST_COMPARE (tm->tm_mday, 29); ++ TEST_COMPARE (tm->tm_hour, 23); ++ TEST_COMPARE (tm->tm_min, 0); ++ TEST_COMPARE (tm->tm_sec, 1); ++ TEST_COMPARE (tm->tm_gmtoff, 3600); ++ TEST_COMPARE (tm->tm_isdst, 0); ++ ++ return 0; ++} ++ ++#include +diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile +index e6b9e8743a..4af102a3f6 100644 +--- a/wcsmbs/Makefile ++++ b/wcsmbs/Makefile +@@ -22,8 +22,9 @@ subdir := wcsmbs + + include ../Makeconfig + +-headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar-ldbl.h uchar.h \ +- bits/types/__mbstate_t.h bits/types/mbstate_t.h bits/types/wint_t.h ++headers := wchar.h bits/wchar.h bits/wchar2.h bits/wchar2-decl.h \ ++ bits/wchar-ldbl.h uchar.h bits/types/__mbstate_t.h \ ++ bits/types/mbstate_t.h bits/types/wint_t.h + + routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ + wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \ +@@ -73,6 +74,8 @@ $(objpfx)tst-wcstol-locale.out: $(gen-locales) + $(objpfx)tst-wcstod-nan-locale.out: $(gen-locales) + $(objpfx)tst-c16-surrogate.out: $(gen-locales) + $(objpfx)tst-c32-state.out: $(gen-locales) ++$(objpfx)test-c8rtomb.out: $(gen-locales) ++$(objpfx)test-mbrtoc8.out: $(gen-locales) + endif + + $(objpfx)tst-wcstod-round: $(libm) +diff --git a/wcsmbs/bits/wchar2-decl.h b/wcsmbs/bits/wchar2-decl.h +new file mode 100644 +index 0000000000..8e1735c33b +--- /dev/null ++++ b/wcsmbs/bits/wchar2-decl.h +@@ -0,0 +1,124 @@ ++/* Checking macros for wchar functions. Declarations only. ++ Copyright (C) 2004-2022 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _BITS_WCHAR2_DECL_H ++#define _BITS_WCHAR2_DECL_H 1 ++ ++#ifndef _WCHAR_H ++# error "Never include directly; use instead." ++#endif ++ ++ ++extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1, ++ const wchar_t *__restrict __s2, size_t __n, ++ size_t __ns1) __THROW; ++extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2, ++ size_t __n, size_t __ns1) __THROW; ++ ++ ++#ifdef __USE_GNU ++ ++extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1, ++ const wchar_t *__restrict __s2, size_t __n, ++ size_t __ns1) __THROW; ++ ++#endif ++ ++ ++extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n, ++ size_t __ns) __THROW; ++extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __n) __THROW; ++extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, size_t __n, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, size_t __n, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __destlen) __THROW; ++extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest, ++ const wchar_t *__restrict __src, ++ size_t __n, size_t __destlen) __THROW; ++extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n, ++ int __flag, size_t __s_len, ++ const wchar_t *__restrict __format, ...) ++ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */; ++extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, ++ int __flag, size_t __s_len, ++ const wchar_t *__restrict __format, ++ __gnuc_va_list __arg) ++ __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; ++ ++#if __USE_FORTIFY_LEVEL > 1 ++ ++extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag, ++ const wchar_t *__restrict __format, ...); ++extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format, ++ ...); ++extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag, ++ const wchar_t *__restrict __format, ++ __gnuc_va_list __ap); ++extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format, ++ __gnuc_va_list __ap); ++ ++#endif ++ ++extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n, ++ __FILE *__restrict __stream) __wur; ++ ++#ifdef __USE_GNU ++ ++extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size, ++ int __n, __FILE *__restrict __stream) ++ __wur; ++ ++#endif ++ ++extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar, ++ mbstate_t *__restrict __p, ++ size_t __buflen) __THROW __wur; ++extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst, ++ const char **__restrict __src, ++ size_t __len, mbstate_t *__restrict __ps, ++ size_t __dstlen) __THROW; ++extern size_t __wcsrtombs_chk (char *__restrict __dst, ++ const wchar_t **__restrict __src, ++ size_t __len, mbstate_t *__restrict __ps, ++ size_t __dstlen) __THROW; ++ ++#ifdef __USE_XOPEN2K8 ++ ++extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, ++ const char **__restrict __src, size_t __nmc, ++ size_t __len, mbstate_t *__restrict __ps, ++ size_t __dstlen) __THROW; ++extern size_t __wcsnrtombs_chk (char *__restrict __dst, ++ const wchar_t **__restrict __src, ++ size_t __nwc, size_t __len, ++ mbstate_t *__restrict __ps, size_t __dstlen) ++ __THROW; ++ ++#endif ++ ++#endif /* bits/wchar2-decl.h. */ +diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h +index 0e017f458b..3f110efe57 100644 +--- a/wcsmbs/bits/wchar2.h ++++ b/wcsmbs/bits/wchar2.h +@@ -21,9 +21,6 @@ + #endif + + +-extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1, +- const wchar_t *__restrict __s2, size_t __n, +- size_t __ns1) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmemcpy_alias, + (wchar_t *__restrict __s1, + const wchar_t *__restrict __s2, size_t __n), +@@ -45,8 +42,6 @@ __NTH (wmemcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, + } + + +-extern wchar_t *__wmemmove_chk (wchar_t *__s1, const wchar_t *__s2, +- size_t __n, size_t __ns1) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmemmove_alias, (wchar_t *__s1, + const wchar_t *__s2, + size_t __n), wmemmove); +@@ -66,9 +61,6 @@ __NTH (wmemmove (wchar_t *__s1, const wchar_t *__s2, size_t __n)) + + + #ifdef __USE_GNU +-extern wchar_t *__wmempcpy_chk (wchar_t *__restrict __s1, +- const wchar_t *__restrict __s2, size_t __n, +- size_t __ns1) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmempcpy_alias, + (wchar_t *__restrict __s1, + const wchar_t *__restrict __s2, +@@ -91,8 +83,6 @@ __NTH (wmempcpy (wchar_t *__restrict __s1, const wchar_t *__restrict __s2, + #endif + + +-extern wchar_t *__wmemset_chk (wchar_t *__s, wchar_t __c, size_t __n, +- size_t __ns) __THROW; + extern wchar_t *__REDIRECT_NTH (__wmemset_alias, (wchar_t *__s, wchar_t __c, + size_t __n), wmemset); + extern wchar_t *__REDIRECT_NTH (__wmemset_chk_warn, +@@ -110,9 +100,6 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n)) + } + + +-extern wchar_t *__wcscpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __n) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcscpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src), wcscpy); +@@ -127,9 +114,6 @@ __NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + } + + +-extern wchar_t *__wcpcpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcpcpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src), wcpcpy); +@@ -144,9 +128,6 @@ __NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + } + + +-extern wchar_t *__wcsncpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, size_t __n, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcsncpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, +@@ -168,9 +149,6 @@ __NTH (wcsncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + } + + +-extern wchar_t *__wcpncpy_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, size_t __n, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcpncpy_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, +@@ -192,9 +170,6 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + } + + +-extern wchar_t *__wcscat_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcscat_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src), wcscat); +@@ -209,9 +184,6 @@ __NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src)) + } + + +-extern wchar_t *__wcsncat_chk (wchar_t *__restrict __dest, +- const wchar_t *__restrict __src, +- size_t __n, size_t __destlen) __THROW; + extern wchar_t *__REDIRECT_NTH (__wcsncat_alias, + (wchar_t *__restrict __dest, + const wchar_t *__restrict __src, +@@ -228,10 +200,6 @@ __NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src, + } + + +-extern int __swprintf_chk (wchar_t *__restrict __s, size_t __n, +- int __flag, size_t __s_len, +- const wchar_t *__restrict __format, ...) +- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 6))) */; + + extern int __REDIRECT_NTH_LDBL (__swprintf_alias, + (wchar_t *__restrict __s, size_t __n, +@@ -258,11 +226,6 @@ __NTH (swprintf (wchar_t *__restrict __s, size_t __n, + : swprintf (s, n, __VA_ARGS__)) + #endif + +-extern int __vswprintf_chk (wchar_t *__restrict __s, size_t __n, +- int __flag, size_t __s_len, +- const wchar_t *__restrict __format, +- __gnuc_va_list __arg) +- __THROW /* __attribute__ ((__format__ (__wprintf__, 5, 0))) */; + + extern int __REDIRECT_NTH_LDBL (__vswprintf_alias, + (wchar_t *__restrict __s, size_t __n, +@@ -283,16 +246,6 @@ __NTH (vswprintf (wchar_t *__restrict __s, size_t __n, + + #if __USE_FORTIFY_LEVEL > 1 + +-extern int __fwprintf_chk (__FILE *__restrict __stream, int __flag, +- const wchar_t *__restrict __format, ...); +-extern int __wprintf_chk (int __flag, const wchar_t *__restrict __format, +- ...); +-extern int __vfwprintf_chk (__FILE *__restrict __stream, int __flag, +- const wchar_t *__restrict __format, +- __gnuc_va_list __ap); +-extern int __vwprintf_chk (int __flag, const wchar_t *__restrict __format, +- __gnuc_va_list __ap); +- + # ifdef __va_arg_pack + __fortify_function int + wprintf (const wchar_t *__restrict __fmt, ...) +@@ -328,8 +281,6 @@ vfwprintf (__FILE *__restrict __stream, + + #endif + +-extern wchar_t *__fgetws_chk (wchar_t *__restrict __s, size_t __size, int __n, +- __FILE *__restrict __stream) __wur; + extern wchar_t *__REDIRECT (__fgetws_alias, + (wchar_t *__restrict __s, int __n, + __FILE *__restrict __stream), fgetws) __wur; +@@ -351,9 +302,6 @@ fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) + } + + #ifdef __USE_GNU +-extern wchar_t *__fgetws_unlocked_chk (wchar_t *__restrict __s, size_t __size, +- int __n, __FILE *__restrict __stream) +- __wur; + extern wchar_t *__REDIRECT (__fgetws_unlocked_alias, + (wchar_t *__restrict __s, int __n, + __FILE *__restrict __stream), fgetws_unlocked) +@@ -379,9 +327,6 @@ fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream) + #endif + + +-extern size_t __wcrtomb_chk (char *__restrict __s, wchar_t __wchar, +- mbstate_t *__restrict __p, +- size_t __buflen) __THROW __wur; + extern size_t __REDIRECT_NTH (__wcrtomb_alias, + (char *__restrict __s, wchar_t __wchar, + mbstate_t *__restrict __ps), wcrtomb) __wur; +@@ -404,10 +349,6 @@ __NTH (wcrtomb (char *__restrict __s, wchar_t __wchar, + } + + +-extern size_t __mbsrtowcs_chk (wchar_t *__restrict __dst, +- const char **__restrict __src, +- size_t __len, mbstate_t *__restrict __ps, +- size_t __dstlen) __THROW; + extern size_t __REDIRECT_NTH (__mbsrtowcs_alias, + (wchar_t *__restrict __dst, + const char **__restrict __src, +@@ -431,10 +372,6 @@ __NTH (mbsrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, + } + + +-extern size_t __wcsrtombs_chk (char *__restrict __dst, +- const wchar_t **__restrict __src, +- size_t __len, mbstate_t *__restrict __ps, +- size_t __dstlen) __THROW; + extern size_t __REDIRECT_NTH (__wcsrtombs_alias, + (char *__restrict __dst, + const wchar_t **__restrict __src, +@@ -458,10 +395,6 @@ __NTH (wcsrtombs (char *__restrict __dst, const wchar_t **__restrict __src, + + + #ifdef __USE_XOPEN2K8 +-extern size_t __mbsnrtowcs_chk (wchar_t *__restrict __dst, +- const char **__restrict __src, size_t __nmc, +- size_t __len, mbstate_t *__restrict __ps, +- size_t __dstlen) __THROW; + extern size_t __REDIRECT_NTH (__mbsnrtowcs_alias, + (wchar_t *__restrict __dst, + const char **__restrict __src, size_t __nmc, +@@ -485,11 +418,6 @@ __NTH (mbsnrtowcs (wchar_t *__restrict __dst, const char **__restrict __src, + } + + +-extern size_t __wcsnrtombs_chk (char *__restrict __dst, +- const wchar_t **__restrict __src, +- size_t __nwc, size_t __len, +- mbstate_t *__restrict __ps, size_t __dstlen) +- __THROW; + extern size_t __REDIRECT_NTH (__wcsnrtombs_alias, + (char *__restrict __dst, + const wchar_t **__restrict __src, +diff --git a/wcsmbs/uchar.h b/wcsmbs/uchar.h +index c37e8619a0..5f7139f279 100644 +--- a/wcsmbs/uchar.h ++++ b/wcsmbs/uchar.h +@@ -34,8 +34,16 @@ + /* Declare the C2x char8_t typedef in C2x modes, but only if the C++ + __cpp_char8_t feature test macro is not defined. */ + #if __GLIBC_USE (ISOC2X) && !defined __cpp_char8_t ++#if __GNUC_PREREQ (10, 0) && defined __cplusplus ++/* Suppress the diagnostic regarding char8_t being a keyword in C++20. */ ++# pragma GCC diagnostic push ++# pragma GCC diagnostic ignored "-Wc++20-compat" ++#endif + /* Define the 8-bit character type. */ + typedef unsigned char char8_t; ++#if __GNUC_PREREQ (10, 0) && defined __cplusplus ++# pragma GCC diagnostic pop ++#endif + #endif + + #ifndef __USE_ISOCXX11 +diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h +index 5d6a40853d..c1321c7518 100644 +--- a/wcsmbs/wchar.h ++++ b/wcsmbs/wchar.h +@@ -864,14 +864,21 @@ extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize, + + /* Define some macros helping to catch buffer overflows. */ + #if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function +-# include ++/* Declare all functions from bits/wchar2-decl.h first. */ ++# include + #endif + +-#include ++/* The following headers provide asm redirections. These redirections must ++ appear before the first usage of these functions, e.g. in bits/wchar.h. */ + #if defined __LDBL_COMPAT || __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI == 1 + # include + #endif + ++#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function ++/* Now include the function definitions and redirects too. */ ++# include ++#endif ++ + __END_DECLS + + #endif /* wchar.h */ diff --git a/glibc/glibc-std.patch b/glibc/glibc-std.patch new file mode 100644 index 00000000..22b776cf --- /dev/null +++ b/glibc/glibc-std.patch @@ -0,0 +1,32 @@ +diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure +--- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:02:32.741186019 +1000 ++++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/64/configure 2021-09-18 21:03:05.314302356 +1000 +@@ -4,10 +4,10 @@ + test -n "$libc_cv_slibdir" || + case "$prefix" in + /usr | /usr/) +- libc_cv_slibdir='/lib64' +- libc_cv_rtlddir='/lib64' ++ libc_cv_slibdir='/lib' ++ libc_cv_rtlddir='/lib' + if test "$libdir" = '${exec_prefix}/lib'; then +- libdir='${exec_prefix}/lib64'; ++ libdir='${exec_prefix}/lib'; + # Locale data can be shared between 32-bit and 64-bit libraries. + libc_cv_complocaledir='${exec_prefix}/lib/locale' + fi +diff -pruN glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h +--- glibc-2.32.orig/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:02:32.742186053 +1000 ++++ glibc-2.32/sysdeps/unix/sysv/linux/x86_64/ldconfig.h 2021-09-18 21:03:05.314302356 +1000 +@@ -18,9 +18,9 @@ + #include + + #define SYSDEP_KNOWN_INTERPRETER_NAMES \ +- { "/lib/ld-linux.so.2", FLAG_ELF_LIBC6 }, \ ++ { "/lib32/ld-linux.so.2", FLAG_ELF_LIBC6 }, \ + { "/libx32/ld-linux-x32.so.2", FLAG_ELF_LIBC6 }, \ +- { "/lib64/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 }, ++ { "/lib/ld-linux-x86-64.so.2", FLAG_ELF_LIBC6 }, + #define SYSDEP_KNOWN_LIBRARY_NAMES \ + { "libc.so.6", FLAG_ELF_LIBC6 }, \ + { "libm.so.6", FLAG_ELF_LIBC6 }, diff --git a/iana-etc/.signature b/iana-etc/.signature index 2980e20a..0e924b58 100644 --- a/iana-etc/.signature +++ b/iana-etc/.signature @@ -1,7 +1,7 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqjDbff0lqb1M2n7AIWBoZGw0eXSr2YuUPfzvRHEtUlbatBeMaSOIDh8N7kEOR4S4leAY6o4YeFGwI2S7goIQgAQ= -SHA256 (Pkgfile) = ffc6f84b91b1466863a53ead938a7b9cf79f12f2722f74b9b2f544196b3d56b6 +RWRJc1FUaeVeqiHraroDmVaAosofzLr5M7Qr1RYoMaR8D6n39kVgB2ZULEy6jubHZaqEr+FIHrUKHvXT5xjLD/BrqCPHS9RM4w0= +SHA256 (Pkgfile) = 1825ffbabace3e931eeb867d30fd64c14b9e91a5303b3c3ee86d8c0342b9d6b2 SHA256 (.footprint) = 20bee9bdc0754167b76a54dd3f5b32a38ac4075bb7d0936188d78809f9056c8b -SHA256 (services) = 4b2a68d0aeabaf2a08c2acf3fd8fa98bf2c614711296009dc4a30a7c6a258f39 -SHA256 (protocols) = 02a7cd8a71982c87e042bcb58d19cdb1ad38d609c4fa29b1aa78f77fd7956e0b +SHA256 (services) = da86379c21a9b9307cce8b78e9dfec71e76ad6e80ede6a5a1d52edd02f5e98dc +SHA256 (protocols) = 343320d33397ff488448ffc4fef1c44cf66378333dd0225265db83f41a99613b SHA256 (update.sh) = c0177c49b9ac29c4f8d89d5f26ca4dc8b1ca358c4e71efca562e61f71f9f3df0 diff --git a/iana-etc/Pkgfile b/iana-etc/Pkgfile index 99981084..e6263d8c 100644 --- a/iana-etc/Pkgfile +++ b/iana-etc/Pkgfile @@ -3,7 +3,7 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=iana-etc -version=20230606 +version=20240125 release=1 source=(services protocols update.sh) diff --git a/iana-etc/protocols b/iana-etc/protocols index 267fbb0a..5c93c110 100644 --- a/iana-etc/protocols +++ b/iana-etc/protocols @@ -1,4 +1,4 @@ -# /etc/protocols, created 2023-09-15T17:43:50+0200 +# /etc/protocols, created 2024-01-27T09:49:26+0100 # Source: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml hopopt 0 HOPOPT icmp 1 ICMP @@ -53,7 +53,7 @@ esp 50 ESP ah 51 AH i-nlsp 52 I-NLSP narp 54 NARP -mobile 55 MOBILE +min-ipv4 55 Min-IPv4 tlsp 56 TLSP skip 57 SKIP ipv6-icmp 58 IPv6-ICMP diff --git a/iana-etc/services b/iana-etc/services index 22e5812c..ea2b8992 100644 --- a/iana-etc/services +++ b/iana-etc/services @@ -1,4 +1,4 @@ -# /etc/services, created 2023-09-15T17:43:50+0200 +# /etc/services, created 2024-01-27T09:49:26+0100 # Source: https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml tcpmux 1/tcp tcpmux 1/udp @@ -527,8 +527,6 @@ bhevent 357/tcp bhevent 357/udp shrinkwrap 358/tcp shrinkwrap 358/udp -nsrmp 359/tcp -nsrmp 359/udp scoi2odialog 360/tcp scoi2odialog 360/udp semantix 361/tcp @@ -8695,6 +8693,7 @@ amc 5506/udp psl-management 5507/tcp matter 5540/tcp matter 5540/udp +qftest-licserve 5543/tcp cbus 5550/tcp sgi-eventmond 5553/tcp sgi-eventmond 5553/udp @@ -9864,7 +9863,6 @@ infi-async 8067/tcp ucs-isc 8070/tcp gadugadu 8074/tcp gadugadu 8074/udp -mles 8077/tcp http-alt 8080/tcp http-alt 8080/udp sunproxyadmin 8081/tcp @@ -10064,6 +10062,7 @@ canon-bjnp4 8614/udp imink 8615/tcp monetra 8665/tcp monetra-admin 8666/tcp +spartan 8668/tcp msi-cps-rm 8675/tcp msi-cps-rm-disc 8675/udp sun-as-jmxrmi 8686/tcp @@ -10571,7 +10570,6 @@ axis-wimp-port 10260/udp tile-ml 10261/tcp blocks 10288/tcp blocks 10288/udp -cosir 10321/tcp bngsync 10439/udp cirrossp 10443/tcp hip-nat-t 10500/udp diff --git a/inetutils/.signature b/inetutils/.signature index db27434d..269396a5 100644 --- a/inetutils/.signature +++ b/inetutils/.signature @@ -1,7 +1,7 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqjx97iuG7J2xnGtXW4fhgHjHN+ee8AngdwIzJdXegaQT78Fcso8dCAuRRtdSs5XA7S0ck8DQX9OJcg4tuMcOiQU= -SHA256 (Pkgfile) = 089e8dfd58c67ae46266d590319d98bb2a6f402e592645515993190243b48d48 +RWRJc1FUaeVeqg9h26+orsF25t0kAxocNvGlO0/Dy4qp1fd2Ro1G4QZtgFzoQMJeCQzb26OqP/VZOdc48etaaZS/rYXil8sb0Qo= +SHA256 (Pkgfile) = 08a9dd7ec075b656c2567966449765e60b8671ff20ae236f85c50289e113bd5f SHA256 (.footprint) = 3c2caa23d1149c4ef65d0217ce9e207327e8e03db865e49402d2ad44192d8937 -SHA256 (inetutils-2.4.tar.gz) = 76aee0c2f0954728600d510955d697a4ec29324318e784848db606ee3c09e365 +SHA256 (inetutils-2.5.tar.gz) = fa043bbbc426eae1869070d2b6e29a98069615ac00681cdb92e20911d9292260 SHA256 (inetd.conf) = 35c5c1d8b4d48cdd708440863fea126c82c8248f8b964e5cf454ee3dd19e40f9 SHA256 (inetd) = 47d33b64f477959aefa3241b5024f39fc9bee8b10888908418ff07f16bcc3be5 diff --git a/inetutils/Pkgfile b/inetutils/Pkgfile index 35ac2cfd..7a70adb6 100644 --- a/inetutils/Pkgfile +++ b/inetutils/Pkgfile @@ -4,8 +4,8 @@ # Depends on: libxcrypt readline name=inetutils -version=2.4 -release=2 +version=2.5 +release=1 source=(http://ftpmirror.gnu.org/gnu/inetutils/inetutils-$version.tar.gz inetd.conf inetd) diff --git a/iproute2/.footprint b/iproute2/.footprint index 14dac401..f69aa78e 100644 --- a/iproute2/.footprint +++ b/iproute2/.footprint @@ -29,16 +29,6 @@ drwxr-xr-x root/root usr/include/ drwxr-xr-x root/root usr/include/iproute2/ -rw-r--r-- root/root usr/include/iproute2/bpf_elf.h drwxr-xr-x root/root usr/lib/ -drwxr-xr-x root/root usr/lib/iproute2/ --rw-r--r-- root/root usr/lib/iproute2/bpf_pinning --rw-r--r-- root/root usr/lib/iproute2/ematch_map --rw-r--r-- root/root usr/lib/iproute2/group --rw-r--r-- root/root usr/lib/iproute2/nl_protos --rw-r--r-- root/root usr/lib/iproute2/rt_dsfield --rw-r--r-- root/root usr/lib/iproute2/rt_protos --rw-r--r-- root/root usr/lib/iproute2/rt_realms --rw-r--r-- root/root usr/lib/iproute2/rt_scopes --rw-r--r-- root/root usr/lib/iproute2/rt_tables drwxr-xr-x root/root usr/lib/tc/ -rw-r--r-- root/root usr/lib/tc/experimental.dist lrwxrwxrwx root/root usr/lib/tc/m_ipt.so -> m_xt.so @@ -51,6 +41,16 @@ drwxr-xr-x root/root usr/share/bash-completion/ drwxr-xr-x root/root usr/share/bash-completion/completions/ -rw-r--r-- root/root usr/share/bash-completion/completions/devlink -rw-r--r-- root/root usr/share/bash-completion/completions/tc +drwxr-xr-x root/root usr/share/iproute2/ +-rw-r--r-- root/root usr/share/iproute2/bpf_pinning +-rw-r--r-- root/root usr/share/iproute2/ematch_map +-rw-r--r-- root/root usr/share/iproute2/group +-rw-r--r-- root/root usr/share/iproute2/nl_protos +-rw-r--r-- root/root usr/share/iproute2/rt_dsfield +-rw-r--r-- root/root usr/share/iproute2/rt_protos +-rw-r--r-- root/root usr/share/iproute2/rt_realms +-rw-r--r-- root/root usr/share/iproute2/rt_scopes +-rw-r--r-- root/root usr/share/iproute2/rt_tables drwxr-xr-x root/root usr/share/man/ drwxr-xr-x root/root usr/share/man/man3/ -rw-r--r-- root/root usr/share/man/man3/libnetlink.3.gz diff --git a/iproute2/.signature b/iproute2/.signature index 27874fe5..76178266 100644 --- a/iproute2/.signature +++ b/iproute2/.signature @@ -1,7 +1,7 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqtmO9CupTIif7Zm8+lbiLjsKdHv+OXjgW1xgUBrG8nuEQRIvXg29JA5LWHGlkuy/rzokvNsh1psrxNG3mXbIhgo= -SHA256 (Pkgfile) = aefefcfc6046856e1bc4930d6388df2208044d20d7dc83d9f3dfb4e97224fc44 -SHA256 (.footprint) = b81350f0bca0370fa916e9abebe4cea92f2676a032e15b045a8c6e934e73cee4 -SHA256 (iproute2-6.6.0.tar.xz) = 8738c804afd09f0bf756937f0c3de23117832a98d8cbbf50386cf5005cd613ce +RWRJc1FUaeVeqs1mhtiSOrfdNNGXIj9cL6irWLn0b2Br6Gc7hWHVRIKMBsHm3GbGWbe/J8qVpqQ1Z3pq6FAuk6KBnGv0lopu4g4= +SHA256 (Pkgfile) = f16b45bc4a28e12c3d6a42e78973715f710b1c42fd4443b5e5aa48e4e8cf2061 +SHA256 (.footprint) = d9aa3c0b99a58485927ffc0dd4a8937b00cc1f1f89cd30c44b16f9b648ff9065 +SHA256 (iproute2-6.7.0.tar.xz) = ff942dd9828d7d1f867f61fe72ce433078c31e5d8e4a78e20f02cb5892e8841d SHA256 (lo.iproute2) = ce94fcf414aa11927a66a221af14180f125f4efbf985dd4db9a1b43dad9cbcc7 SHA256 (net.iproute2) = 0af62a6d674d159ec77ccb46c7ee189c1dc4db0213026d6c42c2b80ce01d231d diff --git a/iproute2/Pkgfile b/iproute2/Pkgfile index d0a000c7..b2799c5a 100644 --- a/iproute2/Pkgfile +++ b/iproute2/Pkgfile @@ -4,7 +4,7 @@ # Depends on: db elfutils iptables libcap name=iproute2 -version=6.6.0 +version=6.7.0 release=1 source=(https://www.kernel.org/pub/linux/utils/net/$name/$name-$version.tar.xz lo.iproute2 net.iproute2) diff --git a/libnghttp2/.footprint b/libnghttp2/.footprint index 7b7f70b2..2263095f 100644 --- a/libnghttp2/.footprint +++ b/libnghttp2/.footprint @@ -6,8 +6,8 @@ drwxr-xr-x root/root usr/include/nghttp2/ drwxr-xr-x root/root usr/lib/ -rw-r--r-- root/root usr/lib/libnghttp2.a -rwxr-xr-x root/root usr/lib/libnghttp2.la -lrwxrwxrwx root/root usr/lib/libnghttp2.so -> libnghttp2.so.14.25.1 -lrwxrwxrwx root/root usr/lib/libnghttp2.so.14 -> libnghttp2.so.14.25.1 --rwxr-xr-x root/root usr/lib/libnghttp2.so.14.25.1 +lrwxrwxrwx root/root usr/lib/libnghttp2.so -> libnghttp2.so.14.26.0 +lrwxrwxrwx root/root usr/lib/libnghttp2.so.14 -> libnghttp2.so.14.26.0 +-rwxr-xr-x root/root usr/lib/libnghttp2.so.14.26.0 drwxr-xr-x root/root usr/lib/pkgconfig/ -rw-r--r-- root/root usr/lib/pkgconfig/libnghttp2.pc diff --git a/libnghttp2/.signature b/libnghttp2/.signature index 1d433866..cf2d7c9c 100644 --- a/libnghttp2/.signature +++ b/libnghttp2/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqvMzMgV54oOAvaJVEoniR9sisg4EcQTyES1Z8aqyRMw7NNkI8l/qU0Juapoqzdi3A0E7EPRsIFa+0JGA30V0ugE= -SHA256 (Pkgfile) = e337abdc280b1fdd3ed1509a9f37653e8ea85ce44b7a89c044e269985746a27a -SHA256 (.footprint) = 447708a94f6aea4a5923a941773a90701e63573daf5c777224588feabe755dfd -SHA256 (nghttp2-1.58.0.tar.xz) = 4a68a3040da92fd9872c056d0f6b0cd60de8410de10b578f8ade9ecc14d297e0 +RWRJc1FUaeVeqqOJPDZX1ehckDGqYNHBFHelGmKwdBZmYBMThB2IJR2N6paFp1HVCr01LVXry9yy/y0o5hTb9EsoVXYW6CbROg4= +SHA256 (Pkgfile) = 5b222e33eb93c7299cafa017a11e9427946f53711756c6d92fdeebf269f25a8c +SHA256 (.footprint) = 0e1f1162b1c33725df52dab11bfdb80367375961bd3a85b790ef042aa49f9716 +SHA256 (nghttp2-1.59.0.tar.xz) = fdc9bd71f5cf8d3fdfb63066b89364c10eb2fdeab55f3c6755cd7917b2ec4ffb diff --git a/libnghttp2/Pkgfile b/libnghttp2/Pkgfile index 14e121c4..deabb582 100644 --- a/libnghttp2/Pkgfile +++ b/libnghttp2/Pkgfile @@ -3,7 +3,7 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=libnghttp2 -version=1.58.0 +version=1.59.0 release=1 source=(https://github.com/nghttp2/nghttp2/releases/download/v$version/nghttp2-$version.tar.xz) diff --git a/libusb/.footprint b/libusb/.footprint index 45c02ce1..8f87fa28 100644 --- a/libusb/.footprint +++ b/libusb/.footprint @@ -1,6 +1,6 @@ drwxr-xr-x root/root lib/ -lrwxrwxrwx root/root lib/libusb-1.0.so.0 -> libusb-1.0.so.0.3.0 --rwxr-xr-x root/root lib/libusb-1.0.so.0.3.0 +lrwxrwxrwx root/root lib/libusb-1.0.so.0 -> libusb-1.0.so.0.4.0 +-rwxr-xr-x root/root lib/libusb-1.0.so.0.4.0 drwxr-xr-x root/root usr/ drwxr-xr-x root/root usr/include/ drwxr-xr-x root/root usr/include/libusb-1.0/ @@ -8,6 +8,6 @@ drwxr-xr-x root/root usr/include/libusb-1.0/ drwxr-xr-x root/root usr/lib/ -rw-r--r-- root/root usr/lib/libusb-1.0.a -rwxr-xr-x root/root usr/lib/libusb-1.0.la -lrwxrwxrwx root/root usr/lib/libusb-1.0.so -> ../../lib/libusb-1.0.so.0.3.0 +lrwxrwxrwx root/root usr/lib/libusb-1.0.so -> ../../lib/libusb-1.0.so.0.4.0 drwxr-xr-x root/root usr/lib/pkgconfig/ -rw-r--r-- root/root usr/lib/pkgconfig/libusb-1.0.pc diff --git a/libusb/.signature b/libusb/.signature index de46bd22..79be6e46 100644 --- a/libusb/.signature +++ b/libusb/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqrxp0Lf+ebUABelMydsZC8IIbrUHaXE1yBa8lXbGQ4QqP34Iefw2IW5wS4kPkPHnoCRPsVp/Z9eiUnteLyKK3Qw= -SHA256 (Pkgfile) = 2af4483f0ef8f394e93ffabec6dc2f51981ea67a4ee9803048c3f37e1cb7ac8f -SHA256 (.footprint) = 3785e93a3e0db3d8a9078ab4491a7876f90891976df0466fcd3cec030ae29103 -SHA256 (libusb-1.0.26.tar.bz2) = 12ce7a61fc9854d1d2a1ffe095f7b5fac19ddba095c259e6067a46500381b5a5 +RWRJc1FUaeVeqv31S3bWXRNk/eJTWjK9BJ5eZJ3aI6H4ji+gffpPJOmljMjVoDC2eZqteqTweZmy9eknUn5R7jYlX9qRUMShpAk= +SHA256 (Pkgfile) = a02a17ac6069422694b65e339e462b515938b553f0e0392026075caba124558f +SHA256 (.footprint) = 9ea929ed5fd8e6e32d522d5cafde49ee47d1a598b14780d767409c29b484f1c0 +SHA256 (libusb-1.0.27.tar.bz2) = ffaa41d741a8a3bee244ac8e54a72ea05bf2879663c098c82fc5757853441575 diff --git a/libusb/Pkgfile b/libusb/Pkgfile index 55070c88..b11517ce 100644 --- a/libusb/Pkgfile +++ b/libusb/Pkgfile @@ -4,7 +4,7 @@ # Depends on: eudev name=libusb -version=1.0.26 +version=1.0.27 release=1 source=(https://github.com/libusb/libusb/releases/download/v$version/$name-$version.tar.bz2) diff --git a/linux-pam/.footprint b/linux-pam/.footprint index 9e25494a..4c0a7733 100644 --- a/linux-pam/.footprint +++ b/linux-pam/.footprint @@ -34,6 +34,8 @@ lrwxrwxrwx root/root lib/libpamc.so.0 -> libpamc.so.0.82.1 drwxr-xr-x root/root lib/security/ -rwxr-xr-x root/root lib/security/pam_access.la -rwxr-xr-x root/root lib/security/pam_access.so +-rwxr-xr-x root/root lib/security/pam_canonicalize_user.la +-rwxr-xr-x root/root lib/security/pam_canonicalize_user.so -rwxr-xr-x root/root lib/security/pam_debug.la -rwxr-xr-x root/root lib/security/pam_debug.so -rwxr-xr-x root/root lib/security/pam_deny.la @@ -201,6 +203,7 @@ drwxr-xr-x root/root usr/share/man/man8/ -rw-r--r-- root/root usr/share/man/man8/mkhomedir_helper.8.gz -rw-r--r-- root/root usr/share/man/man8/pam.8.gz -rw-r--r-- root/root usr/share/man/man8/pam_access.8.gz +-rw-r--r-- root/root usr/share/man/man8/pam_canonicalize_user.8.gz -rw-r--r-- root/root usr/share/man/man8/pam_debug.8.gz -rw-r--r-- root/root usr/share/man/man8/pam_deny.8.gz -rw-r--r-- root/root usr/share/man/man8/pam_echo.8.gz diff --git a/linux-pam/.signature b/linux-pam/.signature index 548e52cf..01d92805 100644 --- a/linux-pam/.signature +++ b/linux-pam/.signature @@ -1,8 +1,8 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqkC0o2MkNDsb93FnEkxzvpdE0EPoJqsHWAQHcldPaMI5nnRikRheV/nNcxlityrOK2+jNTeZMdXgIxugtq0PGAg= -SHA256 (Pkgfile) = 10f9181d58abfed9fda8521cb95450de91f0c97fa6dd4cb31eee8e4ff204dc74 -SHA256 (.footprint) = e821bafa2b55574efc1be8ae5637978630503fccda7b12751cf689b8fb540f14 -SHA256 (Linux-PAM-1.5.3.tar.xz) = 7ac4b50feee004a9fa88f1dfd2d2fa738a82896763050cd773b3c54b0a818283 +RWRJc1FUaeVeqoxUgi+hj1Kdm/aTi8Fz6nnByHuyIEJVQMWWr+94+7oF3M2ZSzG/D256xkrEOKUIDn1HTZEvK1560eJm8+XRJAY= +SHA256 (Pkgfile) = d6e9b0f2be5267d25c70192947303f86e9e62dc8177f01874af9e0bd85c628db +SHA256 (.footprint) = 2dc2275e9e9e7fd93a2c1aeb364d8db7336699b4577a43b1b728e98113cc890e +SHA256 (Linux-PAM-1.6.0.tar.xz) = fff4a34e5bbee77e2e8f1992f27631e2329bcbf8a0563ddeb5c3389b4e3169ad SHA256 (common-account) = 63b6d073e0a05d45260912fd900e27ccac3304ca23cd05df68ce88da34a5d832 SHA256 (common-auth) = c8f2c471572147fafddfe2062b763d360bbb6d21aa8017c725785f96667e9b02 SHA256 (common-password) = 999c19d97ab2a8408103304faa12252d11ab03d492880d78a0bd1a1335659258 diff --git a/linux-pam/Pkgfile b/linux-pam/Pkgfile index 21268c82..3a17f2c6 100644 --- a/linux-pam/Pkgfile +++ b/linux-pam/Pkgfile @@ -3,11 +3,11 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=linux-pam -version=1.5.3 -release=2 -source=(https://github.com/$name/$name/releases/download/v${version}/Linux-PAM-$version.tar.xz - common-account common-auth common-password common-session - other) +version=1.6.0 +release=1 +source=(https://github.com/$name/$name/releases/download/v${version}/Linux-PAM-$version.tar.xz \ + common-account common-auth common-password common-session \ + other) build() { cd Linux-PAM-$version diff --git a/lzlib/.signature b/lzlib/.signature index 34d0f805..69127d4f 100644 --- a/lzlib/.signature +++ b/lzlib/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqk+dqu5/zoS74ETB7z8FTRUjLbkHeRqhj20+aZ1K/Z9L+Yu9z5m+SUgz/tuKpZ4+dQkwE/707cucfKGd/4DTGwk= -SHA256 (Pkgfile) = 6f4b969661edc8b4783e847d988622329789567e619869eff9b45e9381a47c52 +RWRJc1FUaeVequFGEvBiGjbdhTPyl/8a0RxWbfcrkYzyxw3v4Nc82BxDRWW4Kui7Zryv2F7tQtyi260B9KZp6ew8z5ar8FyUtAc= +SHA256 (Pkgfile) = 8baebd7140ff796eaf2cebc05ab15a6ae21aea9a777e96a5ba436d68daa1e257 SHA256 (.footprint) = 492e1ee45f1c99d9b38f7536f98efe5822c6c24838508b019d2b4346d0c38179 -SHA256 (lzlib-1.13.tar.gz) = a1ab58f3148ba4b2674e938438166042137a9275bed747306641acfddc9ffb80 +SHA256 (lzlib-1.14.tar.gz) = 5acac8714ed4f306020bae660dddce706e5f8a795863679037da9fe6bf4dcf6f diff --git a/lzlib/Pkgfile b/lzlib/Pkgfile index 3bd0666b..cfe607c5 100644 --- a/lzlib/Pkgfile +++ b/lzlib/Pkgfile @@ -1,11 +1,11 @@ # Description: Data compression library -# URL: http://lzip.nongnu.org/lzlib.html +# URL: https://lzip.nongnu.org/lzlib.html # Maintainer: CRUX System Team, core-ports at crux dot nu name=lzlib -version=1.13 +version=1.14 release=1 -source=(http://download.savannah.gnu.org/releases/lzip/lzlib/lzlib-$version.tar.gz) +source=(https://download.savannah.gnu.org/releases/lzip/lzlib/lzlib-$version.tar.gz) build() { cd $name-$version diff --git a/meson/.footprint b/meson/.footprint index 243d37db..c4d4a03f 100644 --- a/meson/.footprint +++ b/meson/.footprint @@ -4,13 +4,13 @@ drwxr-xr-x root/root usr/bin/ drwxr-xr-x root/root usr/lib/ drwxr-xr-x root/root usr/lib/python3.12/ drwxr-xr-x root/root usr/lib/python3.12/site-packages/ -drwxr-xr-x root/root usr/lib/python3.12/site-packages/meson-1.3.0-py3.12.egg-info/ --rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.0-py3.12.egg-info/PKG-INFO --rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.0-py3.12.egg-info/SOURCES.txt --rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.0-py3.12.egg-info/dependency_links.txt --rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.0-py3.12.egg-info/entry_points.txt --rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.0-py3.12.egg-info/requires.txt --rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.0-py3.12.egg-info/top_level.txt +drwxr-xr-x root/root usr/lib/python3.12/site-packages/meson-1.3.1-py3.12.egg-info/ +-rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.1-py3.12.egg-info/PKG-INFO +-rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.1-py3.12.egg-info/SOURCES.txt +-rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.1-py3.12.egg-info/dependency_links.txt +-rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.1-py3.12.egg-info/entry_points.txt +-rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.1-py3.12.egg-info/requires.txt +-rw-r--r-- root/root usr/lib/python3.12/site-packages/meson-1.3.1-py3.12.egg-info/top_level.txt drwxr-xr-x root/root usr/lib/python3.12/site-packages/mesonbuild/ -rw-r--r-- root/root usr/lib/python3.12/site-packages/mesonbuild/__init__.py (EMPTY) drwxr-xr-x root/root usr/lib/python3.12/site-packages/mesonbuild/__pycache__/ diff --git a/meson/.signature b/meson/.signature index 601c7e21..a53573c7 100644 --- a/meson/.signature +++ b/meson/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqtNsqr0U9lS9s1mY4loDt8byOHq0ctx8VzgH8T7pnmdFpdEee/B2xGkhh8HdtYh4z68V6RDuI4rW+QPUlTthJA8= -SHA256 (Pkgfile) = 89e0751b4881af98fed77f2593b2a647c3a1591a29233c63eee778b157cb605f -SHA256 (.footprint) = cf0b31c17ba3e293c45da44b86f763cc28cdddc2e313a577b3f6f4c06464f42c -SHA256 (meson-1.3.0.tar.gz) = 4ba253ef60e454e23234696119cbafa082a0aead0bd3bbf6991295054795f5dc +RWRJc1FUaeVeqsbttncgitTua53Rq8wThLkyYyg7qydysOAOtsPwOYyaxNzap38x/Rw9x/7XtXUCOHW8y0XW41PMBqJAMsMZAQE= +SHA256 (Pkgfile) = 27a93726929da9d9b287963c147683c5db4cc916b89d2d6063ebd47a0d9e98c7 +SHA256 (.footprint) = 9ab65228de1f3bd56780c2f703097ceb876a2e273de56cd2a27d76f26b348585 +SHA256 (meson-1.3.1.tar.gz) = 6020568bdede1643d4fb41e28215be38eff5d52da28ac7d125457c59e0032ad7 diff --git a/meson/Pkgfile b/meson/Pkgfile index bd762c99..59150073 100644 --- a/meson/Pkgfile +++ b/meson/Pkgfile @@ -4,7 +4,7 @@ # Depends on: python3-setuptools name=meson -version=1.3.0 +version=1.3.1 release=1 source=(https://github.com/mesonbuild/meson/releases/download/$version/$name-$version.tar.gz) diff --git a/openssl/.footprint b/openssl/.footprint index 759d0af6..dec5eb3f 100644 --- a/openssl/.footprint +++ b/openssl/.footprint @@ -962,7 +962,27 @@ lrwxrwxrwx root/root usr/share/man/man3/CMS_set1_eContentType.3ssl.gz -> CMS_get -rw-r--r-- root/root usr/share/man/man3/CMS_sign.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/CMS_sign_ex.3ssl.gz -> CMS_sign.3ssl.gz -rw-r--r-- root/root usr/share/man/man3/CMS_sign_receipt.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_signed_add1_attr.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_signed_add1_attr_by_NID.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_signed_add1_attr_by_OBJ.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_signed_add1_attr_by_txt.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_signed_delete_attr.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_signed_get0_data_by_OBJ.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +-rw-r--r-- root/root usr/share/man/man3/CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_signed_get_attr_by_NID.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_signed_get_attr_by_OBJ.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_signed_get_attr_count.3ssl.gz -> CMS_signed_get_attr.3ssl.gz -rw-r--r-- root/root usr/share/man/man3/CMS_uncompress.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_unsigned_add1_attr.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_unsigned_add1_attr_by_NID.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_unsigned_add1_attr_by_OBJ.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_unsigned_add1_attr_by_txt.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_unsigned_delete_attr.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_unsigned_get0_data_by_OBJ.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_unsigned_get_attr.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_unsigned_get_attr_by_NID.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_unsigned_get_attr_by_OBJ.3ssl.gz -> CMS_signed_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/CMS_unsigned_get_attr_count.3ssl.gz -> CMS_signed_get_attr.3ssl.gz -rw-r--r-- root/root usr/share/man/man3/CMS_verify.3ssl.gz -rw-r--r-- root/root usr/share/man/man3/CMS_verify_receipt.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/COMP_CTX_free.3ssl.gz -> COMP_CTX_new.3ssl.gz @@ -2031,6 +2051,10 @@ lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_CTX_set_signature_md.3ssl.gz -> lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_CTX_settable_params.3ssl.gz -> EVP_PKEY_CTX_set_params.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_METHOD.3ssl.gz -> EVP_PKEY_meth_new.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_Q_keygen.3ssl.gz -> EVP_PKEY_keygen.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_add1_attr.3ssl.gz -> EVP_PKEY_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_add1_attr_by_NID.3ssl.gz -> EVP_PKEY_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_add1_attr_by_OBJ.3ssl.gz -> EVP_PKEY_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_add1_attr_by_txt.3ssl.gz -> EVP_PKEY_get_attr.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_asn1_add0.3ssl.gz -> EVP_PKEY_ASN1_METHOD.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_asn1_add_alias.3ssl.gz -> EVP_PKEY_ASN1_METHOD.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_asn1_copy.3ssl.gz -> EVP_PKEY_ASN1_METHOD.3ssl.gz @@ -2076,6 +2100,7 @@ lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_decapsulate_init.3ssl.gz -> EVP -rw-r--r-- root/root usr/share/man/man3/EVP_PKEY_decrypt.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_decrypt_init.3ssl.gz -> EVP_PKEY_decrypt.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_decrypt_init_ex.3ssl.gz -> EVP_PKEY_decrypt.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_delete_attr.3ssl.gz -> EVP_PKEY_get_attr.3ssl.gz -rw-r--r-- root/root usr/share/man/man3/EVP_PKEY_derive.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_derive_init.3ssl.gz -> EVP_PKEY_derive.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_derive_init_ex.3ssl.gz -> EVP_PKEY_derive.3ssl.gz @@ -2115,6 +2140,10 @@ lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_get1_EC_KEY.3ssl.gz -> EVP_PKEY lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_get1_RSA.3ssl.gz -> EVP_PKEY_set1_RSA.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_get1_encoded_public_key.3ssl.gz -> EVP_PKEY_set1_encoded_public_key.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_get1_tls_encodedpoint.3ssl.gz -> EVP_PKEY_set1_encoded_public_key.3ssl.gz +-rw-r--r-- root/root usr/share/man/man3/EVP_PKEY_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_get_attr_by_NID.3ssl.gz -> EVP_PKEY_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_get_attr_by_OBJ.3ssl.gz -> EVP_PKEY_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_get_attr_count.3ssl.gz -> EVP_PKEY_get_attr.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_get_base_id.3ssl.gz -> EVP_PKEY_set1_RSA.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_get_bits.3ssl.gz -> EVP_PKEY_get_size.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/EVP_PKEY_get_bn_param.3ssl.gz -> EVP_PKEY_gettable_params.3ssl.gz @@ -2706,13 +2735,16 @@ lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_doall_arg.3ssl.gz -> OPENSSL_ lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_error.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_flush.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_free.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_get_down_load.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_insert.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_new.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_node_stats.3ssl.gz -> OPENSSL_LH_stats.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_node_stats_bio.3ssl.gz -> OPENSSL_LH_stats.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_node_usage_stats.3ssl.gz -> OPENSSL_LH_stats.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_node_usage_stats_bio.3ssl.gz -> OPENSSL_LH_stats.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_num_items.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_retrieve.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_set_down_load.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz -rw-r--r-- root/root usr/share/man/man3/OPENSSL_LH_stats.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LH_stats_bio.3ssl.gz -> OPENSSL_LH_stats.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/OPENSSL_LINE.3ssl.gz -> OPENSSL_FILE.3ssl.gz @@ -4817,9 +4849,20 @@ lrwxrwxrwx root/root usr/share/man/man3/X509_ALGOR_it.3ssl.gz -> X509_dup.3ssl.g lrwxrwxrwx root/root usr/share/man/man3/X509_ALGOR_new.3ssl.gz -> X509_dup.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_ALGOR_set0.3ssl.gz -> X509_ALGOR_dup.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_ALGOR_set_md.3ssl.gz -> X509_ALGOR_dup.3ssl.gz +-rw-r--r-- root/root usr/share/man/man3/X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_count.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_create.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_create_by_NID.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_create_by_OBJ.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_create_by_txt.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_dup.3ssl.gz -> X509_dup.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_free.3ssl.gz -> X509_dup.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_get0_data.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_get0_object.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_get0_type.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_new.3ssl.gz -> X509_dup.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_set1_data.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_ATTRIBUTE_set1_object.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_CERT_AUX_free.3ssl.gz -> X509_dup.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_CERT_AUX_new.3ssl.gz -> X509_dup.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_CINF_free.3ssl.gz -> X509_dup.3ssl.gz @@ -4974,9 +5017,14 @@ lrwxrwxrwx root/root usr/share/man/man3/X509_PUBKEY_set0_param.3ssl.gz -> X509_P lrwxrwxrwx root/root usr/share/man/man3/X509_PUBKEY_set0_public_key.3ssl.gz -> X509_PUBKEY_new.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_INFO_free.3ssl.gz -> X509_dup.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_INFO_new.3ssl.gz -> X509_dup.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_add1_attr.3ssl.gz -> X509_REQ_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_add1_attr_by_NID.3ssl.gz -> X509_REQ_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_add1_attr_by_OBJ.3ssl.gz -> X509_REQ_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_add1_attr_by_txt.3ssl.gz -> X509_REQ_get_attr.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_add_extensions.3ssl.gz -> X509_REQ_get_extensions.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_add_extensions_nid.3ssl.gz -> X509_REQ_get_extensions.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_check_private_key.3ssl.gz -> X509_check_private_key.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_delete_attr.3ssl.gz -> X509_REQ_get_attr.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_digest.3ssl.gz -> X509_digest.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_dup.3ssl.gz -> X509_dup.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_free.3ssl.gz -> X509_dup.3ssl.gz @@ -4984,6 +5032,10 @@ lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_get0_distinguishing_id.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_get0_pubkey.3ssl.gz -> X509_get_pubkey.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_get0_signature.3ssl.gz -> X509_get0_signature.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_get_X509_PUBKEY.3ssl.gz -> X509_get_pubkey.3ssl.gz +-rw-r--r-- root/root usr/share/man/man3/X509_REQ_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_get_attr_by_NID.3ssl.gz -> X509_REQ_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_get_attr_by_OBJ.3ssl.gz -> X509_REQ_get_attr.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_get_attr_count.3ssl.gz -> X509_REQ_get_attr.3ssl.gz -rw-r--r-- root/root usr/share/man/man3/X509_REQ_get_extensions.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_get_pubkey.3ssl.gz -> X509_get_pubkey.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_REQ_get_signature_nid.3ssl.gz -> X509_get0_signature.3ssl.gz @@ -5274,6 +5326,16 @@ lrwxrwxrwx root/root usr/share/man/man3/X509_up_ref.3ssl.gz -> X509_new.3ssl.gz -rw-r--r-- root/root usr/share/man/man3/X509_verify.3ssl.gz -rw-r--r-- root/root usr/share/man/man3/X509_verify_cert.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509_verify_cert_error_string.3ssl.gz -> X509_STORE_CTX_get_error.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509at_add1_attr.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509at_add1_attr_by_NID.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509at_add1_attr_by_OBJ.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509at_add1_attr_by_txt.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509at_delete_attr.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509at_get0_data_by_OBJ.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509at_get_attr.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509at_get_attr_by_NID.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509at_get_attr_by_OBJ.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/X509at_get_attr_count.3ssl.gz -> X509_ATTRIBUTE.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509v3_add_ext.3ssl.gz -> X509v3_get_ext_by_NID.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509v3_delete_ext.3ssl.gz -> X509v3_get_ext_by_NID.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/X509v3_get_ext.3ssl.gz -> X509v3_get_ext_by_NID.3ssl.gz @@ -5746,9 +5808,12 @@ lrwxrwxrwx root/root usr/share/man/man3/lh_TYPE_doall_arg.3ssl.gz -> OPENSSL_LH_ lrwxrwxrwx root/root usr/share/man/man3/lh_TYPE_error.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/lh_TYPE_flush.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/lh_TYPE_free.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/lh_TYPE_get_down_load.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/lh_TYPE_insert.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/lh_TYPE_new.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/lh_TYPE_num_items.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/lh_TYPE_retrieve.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz +lrwxrwxrwx root/root usr/share/man/man3/lh_TYPE_set_down_load.3ssl.gz -> OPENSSL_LH_COMPFUNC.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/o2i_SCT.3ssl.gz -> o2i_SCT_LIST.3ssl.gz -rw-r--r-- root/root usr/share/man/man3/o2i_SCT_LIST.3ssl.gz lrwxrwxrwx root/root usr/share/man/man3/pem_password_cb.3ssl.gz -> PEM_read_bio_PrivateKey.3ssl.gz diff --git a/openssl/.signature b/openssl/.signature index a57456b1..ce9a2e47 100644 --- a/openssl/.signature +++ b/openssl/.signature @@ -1,6 +1,6 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqmm5k4RYnXMcdQx2t/qluhUo1Rou8cxOmr9Yp2ujss2n4/4zdYwKM+URVeEvXum4sddU8BwCls6dzPKaLfZAYAM= -SHA256 (Pkgfile) = dd3a373384ac0286faffd447bfd9efd046647b4c177e94fa0eddf7427c76f8c8 -SHA256 (.footprint) = 48337e4333ad0648de351e16eb6fd235955a27baabd823dae1f0f67f76554913 -SHA256 (openssl-3.2.0.tar.gz) = 14c826f07c7e433706fb5c69fa9e25dab95684844b4c962a2cf1bf183eb4690e +RWRJc1FUaeVeqreSN4LjbHL/qjiazwnMutg418DHwkWHr4Giq0sZ2E+95J8uhAFhB0evYLGjDMF88lpICTq5G5hxJzmcEaikcQA= +SHA256 (Pkgfile) = 4d60223b75efdc20f6a3d454b654d4a0444294472b468b13df30e1c6e9e86fa1 +SHA256 (.footprint) = ad4a91fee721a743b0a8a4de70820c0a136fa4a8db520136d8bb77e09ded35d1 +SHA256 (openssl-3.2.1.tar.gz) = 83c7329fe52c850677d75e5d0b0ca245309b97e8ecbcfdc1dfdc4ab9fac35b39 SHA256 (mksslcert.sh) = d01cfd061b792f4f7444429582c5c9e83aaa7fc63cafd05669fd3f2970dff779 diff --git a/openssl/Pkgfile b/openssl/Pkgfile index 818fa86f..67a84506 100644 --- a/openssl/Pkgfile +++ b/openssl/Pkgfile @@ -3,7 +3,7 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=openssl -version=3.2.0 +version=3.2.1 release=1 source=(https://www.openssl.org/source/$name-$version.tar.gz mksslcert.sh) diff --git a/readline/.signature b/readline/.signature index 18bb246c..4e3bbdb1 100644 --- a/readline/.signature +++ b/readline/.signature @@ -1,7 +1,7 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqn/cJRU6PPjDJcp+Og+iuavGzZ3mUv26HzLh8z4ubCGMgNd2BK6zY2rv4k1rynFHl/cRwsNqruBCt0GZftcGdwc= -SHA256 (Pkgfile) = f43767f2c8a5d2dbb31a4d9e97be664f5d142a18141ee7dd70debb41c602cec3 +RWRJc1FUaeVeqnJ4Ib5zVQo41S4HdsEvIu0IhLVcok6dfcF6lKZf3FcikOcaQp5Ok/wXobwVHRpcJIR9P3Ovtm63/jLr9+dpDwE= +SHA256 (Pkgfile) = 659b933429c55163077c55e120f8ea95d557b31aafe2229d9820ed700ca42dce SHA256 (.footprint) = ef47c205c60675d3bf1c17a08ea69427281b94b26fcf5528017f2ef901b5068f SHA256 (readline-8.2.tar.gz) = 3feb7171f16a84ee82ca18a36d7b9be109a52c04f492a053331d7d1095007c35 -SHA256 (readline-8.2.7.patch.gz) = 98bb0e1e51c7e4f63c1a92806a9e61a329b79dde6c272fb8e38805644fe03405 +SHA256 (readline-8.2.10.patch.gz) = 6df4fe2c902aa6e21f04947dcef2144ad10c3f45989897f25d4d7ce7d46f649e SHA256 (inputrc) = 9119a95d4b1407e3c4ad2b6fb92e840353e65ae9d7ec77fed75cab293cb81bcb diff --git a/readline/Pkgfile b/readline/Pkgfile index f9f81f2f..7865b4f2 100644 --- a/readline/Pkgfile +++ b/readline/Pkgfile @@ -4,7 +4,7 @@ # Depends on: ncurses name=readline -version=8.2.7 +version=8.2.10 release=1 source=(http://ftpmirror.gnu.org/gnu/$name/$name-${version:0:3}.tar.gz $name-$version.patch.gz inputrc) diff --git a/readline/readline-8.2.10.patch.gz b/readline/readline-8.2.10.patch.gz new file mode 100644 index 00000000..207e7f1b Binary files /dev/null and b/readline/readline-8.2.10.patch.gz differ diff --git a/readline/readline-8.2.7.patch.gz b/readline/readline-8.2.7.patch.gz deleted file mode 100644 index 5b736e43..00000000 Binary files a/readline/readline-8.2.7.patch.gz and /dev/null differ diff --git a/sqlite3/.signature b/sqlite3/.signature index d8dfcbd4..2278fadd 100644 --- a/sqlite3/.signature +++ b/sqlite3/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqiO9pHhsfG9alE0SBuPgzjlJKoQQKcPbWELPTSPUSv2EKixM3oBHcvgFosWWcgP1KgbfnWP2dcM1IEnluvsOiwo= -SHA256 (Pkgfile) = 96fbe4dfd5e528c2b23d7034b9411a30e5aae2764366d4fdf6e5a63928b3438d +RWRJc1FUaeVeqqC/OXJZ8+5HWGFT4mUaDo8kuRzIIYJMtRS7vK/+8zorRBmF/rgcUbHLVckwV4pu4bD5o9dhzAViGRF87yZVHwc= +SHA256 (Pkgfile) = 0d32c051a83c18d38d1eb53a42e9f7a00a7b01e84d22d6b004b82edb75f8811f SHA256 (.footprint) = 54d29bd72af140bd285f65d0e72b3ef8eb4279298c98354632552b41db701253 -SHA256 (sqlite-autoconf-3440200.tar.gz) = 1c6719a148bc41cf0f2bbbe3926d7ce3f5ca09d878f1246fcc20767b175bb407 +SHA256 (sqlite-autoconf-3450100.tar.gz) = cd9c27841b7a5932c9897651e20b86c701dd740556989b01ca596fcfa3d49a0a diff --git a/sqlite3/Pkgfile b/sqlite3/Pkgfile index c6a44acf..2a8b9b6c 100644 --- a/sqlite3/Pkgfile +++ b/sqlite3/Pkgfile @@ -4,11 +4,11 @@ # Depends on: readline zlib name=sqlite3 -version=3.44.2 +version=3.45.1 release=1 _version=$(printf "%i%.2i%.2i%.2i" ${version//./ }) -source=(https://www.sqlite.org/2023/sqlite-autoconf-${_version}.tar.gz) +source=(https://www.sqlite.org/2024/sqlite-autoconf-${_version}.tar.gz) build() { cd sqlite-autoconf-${_version} diff --git a/sudo/.signature b/sudo/.signature index 1d3fa686..87b9f51f 100644 --- a/sudo/.signature +++ b/sudo/.signature @@ -1,6 +1,6 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqpvgWOgUMe5OXZTacuP0/7Zc5Fn5v67aMuZcBJyqw4rj+966p0fyzm5qgqeAXk1h0nUo3j6nhjJS9OiMmPozmQ0= -SHA256 (Pkgfile) = 326157d5f3b954ec8296b7cdca7324a51acd0d6599843ad9805b295563857a7e +RWRJc1FUaeVequirDGrs/kkJTi7uoYKhq/w0DoeHoklav+0CAL5BqkalppLJYqBD+x+b65iRJUxO5ISm01YVNF8aKrMx4jnKgAQ= +SHA256 (Pkgfile) = 9fe9221a784c85049c943d4a3dbbfa129bc5833391f4e3f2e873353f6ab08a7c SHA256 (.footprint) = 5d9d7932c3f618220ae5e35cc5d5b200dcac584e692e02b896dfec8c7104186f -SHA256 (sudo-1.9.15p4.tar.gz) = 2e20ec9865eeeea1316c6f49ec6ac4678869b689d4d90b44243bf4887d6dd532 +SHA256 (sudo-1.9.15p5.tar.gz) = 558d10b9a1991fb3b9fa7fa7b07ec4405b7aefb5b3cb0b0871dbc81e3a88e558 SHA256 (sudo.pam) = d56499ea47e4c654032b278923ebee0caba4ca5b0fd242ea9c47204afc8a09e1 diff --git a/sudo/Pkgfile b/sudo/Pkgfile index d0981306..0c195ca1 100644 --- a/sudo/Pkgfile +++ b/sudo/Pkgfile @@ -4,7 +4,7 @@ # Depends on: zlib linux-pam name=sudo -version=1.9.15p4 +version=1.9.15p5 release=1 source=(https://www.sudo.ws/dist/$name-$version.tar.gz $name.pam) diff --git a/tzdata/.signature b/tzdata/.signature index 2823169d..a60659bd 100644 --- a/tzdata/.signature +++ b/tzdata/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqnbMFEgXGh3c/rhcHnC97XoakBUTOvf3MyISzFoBO/DmnSGF9cThGiMc3q78ii7ERZo6LuoAYyaM0uLpjNvvhgE= -SHA256 (Pkgfile) = 9237953747809432e099f4cb3219ae1fd25156113212328f74a1c952be304adf +RWRJc1FUaeVeqtecKg2QH2NTsg5vznwQbrWOuBsPLFh7F3Zww+bidbOwWVb13u7EBUZMd4SCrLql1UBs4zj+99C6LwqQuOlHVwo= +SHA256 (Pkgfile) = 1b729dc23e2f5847461397ee0c632b43461fcdbb9347e02303749929ee55ea37 SHA256 (.footprint) = 1bbb038a1d2a1135b69255d993a6473526b6a0b43aa9e67558e75fd49bcdbcf0 -SHA256 (tzdb-2023d.tar.lz) = 696849b454176ea8f52dd7e9001999d01f5bb594344190a0c4084aeaf7f86bd8 +SHA256 (tzdb-2024a.tar.lz) = 511af6b467f40b1ec9ac3684d1701793af470f3e29ddfb97b82be438e8601a7a diff --git a/tzdata/Pkgfile b/tzdata/Pkgfile index 6d97e94d..a05bc426 100644 --- a/tzdata/Pkgfile +++ b/tzdata/Pkgfile @@ -3,7 +3,7 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=tzdata -version=2023d +version=2024a release=1 source=(https://data.iana.org/time-zones/releases/tzdb-$version.tar.lz) diff --git a/vim/.footprint b/vim/.footprint index 5008c05c..68b9c7de 100644 --- a/vim/.footprint +++ b/vim/.footprint @@ -40,6 +40,7 @@ drwxr-xr-x root/root usr/share/vim/autoload/ -rw-r--r-- root/root usr/share/vim/autoload/decada.vim drwxr-xr-x root/root usr/share/vim/autoload/dist/ -rw-r--r-- root/root usr/share/vim/autoload/dist/ft.vim +-rw-r--r-- root/root usr/share/vim/autoload/dist/json.vim -rw-r--r-- root/root usr/share/vim/autoload/dist/man.vim -rw-r--r-- root/root usr/share/vim/autoload/dist/script.vim -rw-r--r-- root/root usr/share/vim/autoload/dist/vim.vim @@ -52,6 +53,7 @@ drwxr-xr-x root/root usr/share/vim/autoload/dist/ -rw-r--r-- root/root usr/share/vim/autoload/haskellcomplete.vim -rw-r--r-- root/root usr/share/vim/autoload/htmlcomplete.vim -rw-r--r-- root/root usr/share/vim/autoload/javascriptcomplete.vim +-rw-r--r-- root/root usr/share/vim/autoload/modula2.vim -rw-r--r-- root/root usr/share/vim/autoload/netrw.vim -rw-r--r-- root/root usr/share/vim/autoload/netrwFileHandlers.vim -rw-r--r-- root/root usr/share/vim/autoload/netrwSettings.vim @@ -61,6 +63,7 @@ drwxr-xr-x root/root usr/share/vim/autoload/dist/ -rw-r--r-- root/root usr/share/vim/autoload/python.vim -rw-r--r-- root/root usr/share/vim/autoload/python3complete.vim -rw-r--r-- root/root usr/share/vim/autoload/pythoncomplete.vim +-rw-r--r-- root/root usr/share/vim/autoload/racket.vim -rw-r--r-- root/root usr/share/vim/autoload/rubycomplete.vim -rw-r--r-- root/root usr/share/vim/autoload/rust.vim -rw-r--r-- root/root usr/share/vim/autoload/rustfmt.vim @@ -159,6 +162,7 @@ drwxr-xr-x root/root usr/share/vim/compiler/ -rw-r--r-- root/root usr/share/vim/compiler/gfortran.vim -rw-r--r-- root/root usr/share/vim/compiler/ghc.vim -rw-r--r-- root/root usr/share/vim/compiler/gjs.vim +-rw-r--r-- root/root usr/share/vim/compiler/gm2.vim -rw-r--r-- root/root usr/share/vim/compiler/gnat.vim -rw-r--r-- root/root usr/share/vim/compiler/go.vim -rw-r--r-- root/root usr/share/vim/compiler/haml.vim @@ -479,6 +483,7 @@ drwxr-xr-x root/root usr/share/vim/ftplugin/ -rw-r--r-- root/root usr/share/vim/ftplugin/gdb.vim -rw-r--r-- root/root usr/share/vim/ftplugin/gdscript.vim -rw-r--r-- root/root usr/share/vim/ftplugin/gdshader.vim +-rw-r--r-- root/root usr/share/vim/ftplugin/git.vim -rw-r--r-- root/root usr/share/vim/ftplugin/gitattributes.vim -rw-r--r-- root/root usr/share/vim/ftplugin/gitcommit.vim -rw-r--r-- root/root usr/share/vim/ftplugin/gitconfig.vim @@ -1350,6 +1355,11 @@ drwxr-xr-x root/root usr/share/vim/syntax/ -rw-r--r-- root/root usr/share/vim/syntax/model.vim -rw-r--r-- root/root usr/share/vim/syntax/modsim3.vim -rw-r--r-- root/root usr/share/vim/syntax/modula2.vim +drwxr-xr-x root/root usr/share/vim/syntax/modula2/ +drwxr-xr-x root/root usr/share/vim/syntax/modula2/opt/ +-rw-r--r-- root/root usr/share/vim/syntax/modula2/opt/iso.vim +-rw-r--r-- root/root usr/share/vim/syntax/modula2/opt/pim.vim +-rw-r--r-- root/root usr/share/vim/syntax/modula2/opt/r10.vim -rw-r--r-- root/root usr/share/vim/syntax/modula3.vim -rw-r--r-- root/root usr/share/vim/syntax/mojo.vim -rw-r--r-- root/root usr/share/vim/syntax/monk.vim @@ -1395,6 +1405,7 @@ drwxr-xr-x root/root usr/share/vim/syntax/ -rw-r--r-- root/root usr/share/vim/syntax/openvpn.vim -rw-r--r-- root/root usr/share/vim/syntax/opl.vim -rw-r--r-- root/root usr/share/vim/syntax/ora.vim +-rw-r--r-- root/root usr/share/vim/syntax/pacmanlog.vim -rw-r--r-- root/root usr/share/vim/syntax/pamconf.vim -rw-r--r-- root/root usr/share/vim/syntax/pamenv.vim -rw-r--r-- root/root usr/share/vim/syntax/papp.vim diff --git a/vim/.signature b/vim/.signature index 540efee9..9ea4ddb8 100644 --- a/vim/.signature +++ b/vim/.signature @@ -1,6 +1,6 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqi1wrTI5wRd1PhTv4ilYo+qjLP9E6au+hbciVxyZKr4r402qaIWJKm8m7s14rrAgVypXOhrs/yE+txj7Aw7taQU= -SHA256 (Pkgfile) = ffcfc0de6a2c56516b6d978c1b44c6faa275a77d916607ff2b9c9a70f99bcd82 -SHA256 (.footprint) = 02d0e251b20f3de6415a41655c51f01e09938d101e5760e410349eeabd2b87ae -SHA256 (vim-9.0.2130.tar.gz) = e748cbe3656587c8bb2316e2bcd0dcb38a6f191e7779bd715ec9300a551be6b0 +RWRJc1FUaeVeqmZd99d0njLGqnLE7yGjnQjnoeVkiC0ESCoeSj3/MuStGXhTUHv3rrzQAyY7L3WycHa58QWRowBhwMY/ER78OwQ= +SHA256 (Pkgfile) = 7afa7d3f9fe4f90941fa947dc1a422f690f1a2ca186c2a0501f656e53abb3b69 +SHA256 (.footprint) = 0aaf42e68e091a9b2ad33862a9820d62cacee45587b387b92ac1e53f5d651c34 +SHA256 (vim-9.1.0015.tar.gz) = 650cc777d03e6c89cec63256978249de05c66801d42f1b59881aaaf4d5b545df SHA256 (Pkgfile.vim.tar.gz) = 1f275a454fdd936b446518dbd6b60ea8e82895b4fb9759a2f5757e03e996b195 diff --git a/vim/Pkgfile b/vim/Pkgfile index 45ab11b0..e788df47 100644 --- a/vim/Pkgfile +++ b/vim/Pkgfile @@ -4,7 +4,7 @@ # Depends on: acl ncurses name=vim -version=9.0.2130 +version=9.1.0015 release=1 source=(https://github.com/vim/vim/archive/v${version}/$name-$version.tar.gz https://git.crux.nu:82/tb/Pkgfile.vim/archive/master.tar.gz) diff --git a/xz/.footprint b/xz/.footprint index 6277d4f5..e107f149 100644 --- a/xz/.footprint +++ b/xz/.footprint @@ -43,9 +43,9 @@ drwxr-xr-x root/root usr/include/lzma/ drwxr-xr-x root/root usr/lib/ -rw-r--r-- root/root usr/lib/liblzma.a -rwxr-xr-x root/root usr/lib/liblzma.la -lrwxrwxrwx root/root usr/lib/liblzma.so -> liblzma.so.5.4.5 -lrwxrwxrwx root/root usr/lib/liblzma.so.5 -> liblzma.so.5.4.5 --rwxr-xr-x root/root usr/lib/liblzma.so.5.4.5 +lrwxrwxrwx root/root usr/lib/liblzma.so -> liblzma.so.5.4.6 +lrwxrwxrwx root/root usr/lib/liblzma.so.5 -> liblzma.so.5.4.6 +-rwxr-xr-x root/root usr/lib/liblzma.so.5.4.6 drwxr-xr-x root/root usr/lib/pkgconfig/ -rw-r--r-- root/root usr/lib/pkgconfig/liblzma.pc drwxr-xr-x root/root usr/share/ diff --git a/xz/.signature b/xz/.signature index 448468b0..67ef4943 100644 --- a/xz/.signature +++ b/xz/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqnLeq83sy0VSfjSZ55NUFQA/BcGpuKBfukgKCpuxgeansLzHEubrixawaSD0pxYzmlhPpMRqmYcIqNEzk9Y0EgQ= -SHA256 (Pkgfile) = 619eaad641bc4d65aaa3279247114cc42fde0f1ac133199053cbdb6735c51bb5 -SHA256 (.footprint) = 666944876dd09a05614ec470edd458b789214dbc17e45a2634886c5bb5f60f63 -SHA256 (xz-5.4.5.tar.xz) = da9dec6c12cf2ecf269c31ab65b5de18e8e52b96f35d5bcd08c12b43e6878803 +RWRJc1FUaeVeqndox98HX65xZw5GY+lidLvbaesEOw/8cjhz4vX6KpjeT3if9E5J0zfRJAujwSwIhKuTNvdFtZRT9vR869AJ3wE= +SHA256 (Pkgfile) = 26eb88341b55f12b66fb6ca8f626ca11d255a5cc34d7eadd3f3b6b1538636df4 +SHA256 (.footprint) = 90bf085eac68b6ba5efac1b66a50892e1a90ee299c29347903c8789430b4576f +SHA256 (xz-5.4.6.tar.xz) = b92d4e3a438affcf13362a1305cd9d94ed47ddda22e456a42791e630a5644f5c diff --git a/xz/Pkgfile b/xz/Pkgfile index 8dd1e479..03269e38 100644 --- a/xz/Pkgfile +++ b/xz/Pkgfile @@ -3,9 +3,9 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=xz -version=5.4.5 +version=5.4.6 release=1 -source=(https://tukaani.org/xz/$name-$version.tar.xz) +source=(https://github.com/tukaani-project/xz/releases/download/v$version/$name-$version.tar.xz) build() { cd $name-$version diff --git a/zlib/.footprint b/zlib/.footprint index 0217cb2f..ea2a4ac5 100644 --- a/zlib/.footprint +++ b/zlib/.footprint @@ -1,13 +1,13 @@ drwxr-xr-x root/root lib/ -lrwxrwxrwx root/root lib/libz.so.1 -> libz.so.1.3 --rwxr-xr-x root/root lib/libz.so.1.3 +lrwxrwxrwx root/root lib/libz.so.1 -> libz.so.1.3.1 +-rwxr-xr-x root/root lib/libz.so.1.3.1 drwxr-xr-x root/root usr/ drwxr-xr-x root/root usr/include/ -rw-r--r-- root/root usr/include/zconf.h -rw-r--r-- root/root usr/include/zlib.h drwxr-xr-x root/root usr/lib/ -rw-r--r-- root/root usr/lib/libz.a -lrwxrwxrwx root/root usr/lib/libz.so -> ../../lib/libz.so.1.3 +lrwxrwxrwx root/root usr/lib/libz.so -> ../../lib/libz.so.1.3.1 drwxr-xr-x root/root usr/lib/pkgconfig/ -rw-r--r-- root/root usr/lib/pkgconfig/zlib.pc drwxr-xr-x root/root usr/share/ diff --git a/zlib/.signature b/zlib/.signature index 2390d649..87de4f41 100644 --- a/zlib/.signature +++ b/zlib/.signature @@ -1,5 +1,5 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqsYUWu2Vd8+voTOinj9CDZZ0siMTPTGyxfIDV2W7l2eT2xqKA0pA5pTtATtWWNo7Hg/R6OqoJRIZuTsRyHTlCQs= -SHA256 (Pkgfile) = f3f7ab39390967b6d7553a472c8bf131dcb396d55f0dbe5468bf4684ed9dc50b -SHA256 (.footprint) = 6875303186f75b695556ecb2d0d33b58b7aea981b98f56bd86e9e44c91dad841 -SHA256 (zlib-1.3.tar.gz) = ff0ba4c292013dbc27530b3a81e1f9a813cd39de01ca5e0f8bf355702efa593e +RWRJc1FUaeVeqoHEMnx3r+TrXMj4IqWG8wmyTMCjWbgR3oYW8mAZWOB/ywxVTIE1BgvUwt71CQusrW7ee8FucZf0lse8HdQXIgU= +SHA256 (Pkgfile) = a56633b99a58b88d4b6e692b660631fd8464a3ebf34a1eda87f264ab9ca500ed +SHA256 (.footprint) = fe4997e1bc53c02faca1111b1dbd8ff79d1b5714c8beee0f8c4d37b80b0bf9c1 +SHA256 (zlib-1.3.1.tar.gz) = 9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23 diff --git a/zlib/Pkgfile b/zlib/Pkgfile index b67ead3c..f4eeac63 100644 --- a/zlib/Pkgfile +++ b/zlib/Pkgfile @@ -3,7 +3,7 @@ # Maintainer: CRUX System Team, core-ports at crux dot nu name=zlib -version=1.3 +version=1.3.1 release=1 source=(https://www.zlib.net/$name-$version.tar.gz)