diff -Nru glibc-2.27/debian/changelog glibc-2.27/debian/changelog --- glibc-2.27/debian/changelog 2020-06-04 17:25:26.000000000 +0000 +++ glibc-2.27/debian/changelog 2022-01-24 12:53:44.000000000 +0000 @@ -1,3 +1,109 @@ +glibc (2.27-3ubuntu1.5) bionic-security; urgency=medium + + * SECURITY UPDATE: infinite loop in iconv + - debian/patches/any/CVE-2016-10228-pre1.patch: add xsetlocale function + in support/Makefile, support/support.h, support/xsetlocale.c. + - debian/patches/any/CVE-2016-10228-1.patch: rewrite iconv option + parsing in iconv/Makefile, iconv/Versions, iconv/gconv_charset.c, + iconv/gconv_charset.h, iconv/gconv_int.h, iconv/gconv_open.c, + iconv/iconv_open.c, iconv/iconv_prog.c, iconv/tst-iconv-opt.c, + iconv/tst-iconv_prog.sh, intl/dcigettext.c. + - debian/patches/any/CVE-2016-10228-2.patch: handle translation output + codesets with suffixes in iconv/Versions, iconv/gconv_charset.c, + iconv/gconv_charset.h, iconv/gconv_int.h, iconv/iconv_open.c, + iconv/iconv_prog.c, intl/dcigettext.c, intl/tst-codeset.c. + - CVE-2016-10228 + * SECURITY UPDATE: buffer over-read in iconv + - debian/patches/any/CVE-2019-25013.patch: fix buffer overrun in EUC-KR + conversion module in iconvdata/bug-iconv13.c, iconvdata/euc-kr.c, + iconvdata/ksc5601.h. + - CVE-2019-25013 + * SECURITY UPDATE: another infinite loop in iconv + - debian/patches/any/CVE-2020-27618.patch: fix issue in + iconvdata/ibm1364.c. + - CVE-2020-27618 + * SECURITY UPDATE: DoS via assert in iconv + - debian/patches/any/CVE-2020-29562.patch: fix incorrect UCS4 inner + loop bounds in iconv/Makefile, iconv/gconv_simple.c, + iconv/tst-iconv8.c. + - CVE-2020-29562 + * SECURITY UPDATE: signed comparison issue in ARMv7 memcpy + - debian/patches/any/CVE-2020-6096-3.patch: fix memcpy and memmove for + negative length in sysdeps/arm/memcpy.S, sysdeps/arm/memmove.S. + - debian/patches/any/CVE-2020-6096-4.patch: fix multiarch memcpy for + negative length in sysdeps/arm/armv7/multiarch/memcpy_impl.S. + - CVE-2020-6096 + * SECURITY UPDATE: assertion fail in iconv + - debian/patches/any/CVE-2021-3326.patch: fix assertion failure in + ISO-2022-JP-3 module in iconvdata/Makefile, iconvdata/bug-iconv14.c, + iconvdata/iso-2022-jp-3.c. + - CVE-2021-3326 + * SECURITY UPDATE: overflow in wordexp via crafted pattern + - debian/patches/any/CVE-2021-35942.patch: handle overflow in + positional parameter number in posix/wordexp-test.c, posix/wordexp.c. + - CVE-2021-35942 + * SECURITY UPDATE: Off-by-one buffer overflow/underflow in getcwd() + - debian/patches/any/CVE-2021-3999.patch: set errno to ERANGE for + size == 1 in sysdeps/posix/getcwd.c. + - CVE-2021-3999 + * SECURITY UPDATE: DoS via long svcunix_create path argument + - debian/patches/any/CVE-2022-23218-pre1.patch: add the + __sockaddr_un_set function in include/sys/un.h, socket/Makefile, + socket/sockaddr_un_set.c, socket/tst-sockaddr_un_set.c. + - debian/patches/any/CVE-2022-23218.patch: fix buffer overflow in + sunrpc/svc_unix.c. + - CVE-2022-23218 + * SECURITY UPDATE: DoS via long clnt_create hostname argument + - debian/patches/any/CVE-2022-23219.patch: fix buffer overflow in + sunrpc/clnt_gen.c. + - CVE-2022-23219 + * debian/patches/any/fix_test-errno-linux.patch: Handle EINVAL from + quotactl in newer kernels in + sysdeps/unix/sysv/linux/test-errno-linux.c. + + -- Marc Deslauriers Mon, 24 Jan 2022 07:53:44 -0500 + +glibc (2.27-3ubuntu1.4) bionic; urgency=medium + + [ Balint Reczey ] + * tests: XFAIL new tst-support_descriptors on armel, too. + The armhf build builds for armel, too, thus this fixes the armhf autopkgtest. + (LP: #1895920) + + [ Adam Conrad ] + * debian/patches/arm/unsubmitted-ldso-abi-check.diff: Fix rtld segv in dl_open() + introduced via merge with upstream at 2.28 and when backporting upstream's + 2.27/master changes. (LP: #1821677) + + -- Balint Reczey Mon, 07 Dec 2020 17:38:09 +0100 + +glibc (2.27-3ubuntu1.3) bionic; urgency=medium + + [ Balint Reczey ] + * debian/gbp.conf: Add initial configuration + * debian/control.in/main: Add Vcs-* pointing to Ubuntu packaging repository + * arm64: Enable searching shared libraries in atomics/ on LSE HW + * Ship arm64 variant with LSE support in libc6-lse (LP: #1885012) + * Run tests of libc6-lse on HW supporting LSE + * debian/patches/git-updates.diff: update from upstream stable branch + - pthread_cond_broadcast: Fix waiters-after-spinning case + - Fix SSe2-based memmove corrupting memory (CVE-2017-18269) + - Fix strstr() performance regression on Haswell processors + - Support Japanese new era "令和 (Reiwa)" + - io: Remove copy_file_range emulation + (LP: #1851263, #1858203, #1838327, #1797335, #1756209, #1853193) + * XFAIL stdlib/tst-getrandom (LP: #1891403) + * debian/testsuite-xfail-debian.mk: XFAIL new tst-support_descriptors + + [ Thadeu Lima de Souza Cascardo ] + * tests: Make preadwritev2 invalid flags tests unsupported (LP: #1770480) + + [ Andreas Hasenack ] + * branch-pthread_rwlock_trywrlock-hang-23844.patch: + nptl: Fix pthread_rwlock_try*lock stalls (Bug 23844) (LP: #1864864) + + -- Balint Reczey Wed, 02 Sep 2020 11:18:37 +0200 + glibc (2.27-3ubuntu1.2) bionic-security; urgency=medium * SECURITY UPDATE: integer overflow in realpath diff -Nru glibc-2.27/debian/control glibc-2.27/debian/control --- glibc-2.27/debian/control 2018-04-16 20:02:50.000000000 +0000 +++ glibc-2.27/debian/control 2020-12-07 16:38:09.000000000 +0000 @@ -18,8 +18,10 @@ XSBC-Original-Maintainer: GNU Libc Maintainers Uploaders: Clint Adams , Aurelien Jarno , Adam Conrad , Samuel Thibault Standards-Version: 4.1.3 -Vcs-Browser: https://salsa.debian.org/glibc-team/glibc -Vcs-Git: https://salsa.debian.org/glibc-team/glibc.git +Vcs-Browser: https://git.launchpad.net/~ubuntu-core-dev/ubuntu/+source/glibc +Vcs-Git: https://git.launchpad.net/~ubuntu-core-dev/ubuntu/+source/glibc +XSBC-Original-Vcs-Browser: https://salsa.debian.org/glibc-team/glibc +XSBC-Original-Vcs-Git: https://salsa.debian.org/glibc-team/glibc.git Homepage: https://www.gnu.org/software/libc/libc.html Package: libc-bin @@ -782,7 +784,7 @@ Architecture: armel Section: libdevel Priority: optional -Depends: libc6-armhf (= ${binary:Version}), libc6-dev (= ${binary:Version}), ${misc:Depends} +Depends: libc6-armhf (= ${binary:Version}) , libc6-dev (= ${binary:Version}), ${misc:Depends} Recommends: gcc-multilib Build-Profiles: Description: GNU C Library: ARM hard float development libraries for armel @@ -805,7 +807,7 @@ Architecture: armhf Section: libdevel Priority: optional -Depends: libc6-armel (= ${binary:Version}), libc6-dev (= ${binary:Version}), ${misc:Depends} +Depends: libc6-armel (= ${binary:Version}) , libc6-dev (= ${binary:Version}), ${misc:Depends} Recommends: gcc-multilib Build-Profiles: Description: GNU C Library: ARM softfp development libraries for armhf @@ -911,3 +913,20 @@ needs to be installed on Alpha EV67/68 and EV7 machines. If you install this on an older machine, it won't even be used. +Package: libc6-lse +Architecture: arm64 +Section: libs +Priority: optional +Multi-Arch: same +Depends: libc6 (= ${binary:Version}), ${misc:Depends} +Breaks: initramfs-tools (<< 0.130ubuntu3.10) +Build-Profiles: +Description: GNU C Library: Shared Libraries + Contains the standard libraries that are used by nearly all programs on + the system. This package includes shared versions of the standard C library + and the standard math library, as well as many others. + . + This set of libraries is optimized to support Large System Extensions (LSE). + It only needs to be installed on ARM machine supporting LSE. If you install + this on an machine without LSE support, it won't be used. + diff -Nru glibc-2.27/debian/control.in/main glibc-2.27/debian/control.in/main --- glibc-2.27/debian/control.in/main 2018-04-16 20:02:50.000000000 +0000 +++ glibc-2.27/debian/control.in/main 2020-12-07 16:38:09.000000000 +0000 @@ -18,8 +18,10 @@ XSBC-Original-Maintainer: GNU Libc Maintainers Uploaders: Clint Adams , Aurelien Jarno , Adam Conrad , Samuel Thibault Standards-Version: 4.1.3 -Vcs-Browser: https://salsa.debian.org/glibc-team/glibc -Vcs-Git: https://salsa.debian.org/glibc-team/glibc.git +Vcs-Browser: https://git.launchpad.net/~ubuntu-core-dev/ubuntu/+source/glibc +Vcs-Git: https://git.launchpad.net/~ubuntu-core-dev/ubuntu/+source/glibc +XSBC-Original-Vcs-Browser: https://salsa.debian.org/glibc-team/glibc +XSBC-Original-Vcs-Git: https://salsa.debian.org/glibc-team/glibc.git Homepage: https://www.gnu.org/software/libc/libc.html Package: libc-bin diff -Nru glibc-2.27/debian/control.in/opt glibc-2.27/debian/control.in/opt --- glibc-2.27/debian/control.in/opt 2017-09-03 20:41:15.000000000 +0000 +++ glibc-2.27/debian/control.in/opt 2020-12-07 16:38:09.000000000 +0000 @@ -47,3 +47,20 @@ needs to be installed on Alpha EV67/68 and EV7 machines. If you install this on an older machine, it won't even be used. +Package: libc6-lse +Architecture: arm64 +Section: libs +Priority: optional +Multi-Arch: same +Depends: libc6 (= ${binary:Version}), ${misc:Depends} +Breaks: initramfs-tools (<< 0.130ubuntu3.10) +Build-Profiles: +Description: GNU C Library: Shared Libraries + Contains the standard libraries that are used by nearly all programs on + the system. This package includes shared versions of the standard C library + and the standard math library, as well as many others. + . + This set of libraries is optimized to support Large System Extensions (LSE). + It only needs to be installed on ARM machine supporting LSE. If you install + this on an machine without LSE support, it won't be used. + diff -Nru glibc-2.27/debian/gbp.conf glibc-2.27/debian/gbp.conf --- glibc-2.27/debian/gbp.conf 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/gbp.conf 2020-12-07 16:38:09.000000000 +0000 @@ -0,0 +1,3 @@ +[buildpackage] +pristine-tar = False +overlay = True diff -Nru glibc-2.27/debian/patches/all/branch-pthread_rwlock_trywrlock-hang-23844.patch glibc-2.27/debian/patches/all/branch-pthread_rwlock_trywrlock-hang-23844.patch --- glibc-2.27/debian/patches/all/branch-pthread_rwlock_trywrlock-hang-23844.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/all/branch-pthread_rwlock_trywrlock-hang-23844.patch 2020-12-07 16:38:09.000000000 +0000 @@ -0,0 +1,647 @@ +From e8c13d5f7a6cd34bc2ac51a0c89fcbbfd2e5c043 Mon Sep 17 00:00:00 2001 +From: Carlos O'Donell +Date: Mon, 21 Jan 2019 22:50:12 -0500 +Subject: [PATCH] nptl: Fix pthread_rwlock_try*lock stalls (Bug 23844) + +For a full analysis of both the pthread_rwlock_tryrdlock() stall +and the pthread_rwlock_trywrlock() stall see: +https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14 + +In the pthread_rwlock_trydlock() function we fail to inspect for +PTHREAD_RWLOCK_FUTEX_USED in __wrphase_futex and wake the waiting +readers. + +In the pthread_rwlock_trywrlock() function we write 1 to +__wrphase_futex and loose the setting of the PTHREAD_RWLOCK_FUTEX_USED +bit, again failing to wake waiting readers during unlock. + +The fix in the case of pthread_rwlock_trydlock() is to check for +PTHREAD_RWLOCK_FUTEX_USED and wake the readers. + +The fix in the case of pthread_rwlock_trywrlock() is to only write +1 to __wrphase_futex if we installed the write phase, since all other +readers would be spinning waiting for this step. + +We add two new tests, one exercises the stall for +pthread_rwlock_trywrlock() which is easy to exercise, and one exercises +the stall for pthread_rwlock_trydlock() which is harder to exercise. + +The pthread_rwlock_trywrlock() test fails consistently without the fix, +and passes after. The pthread_rwlock_tryrdlock() test fails roughly +5-10% of the time without the fix, and passes all the time after. + +Signed-off-by: Carlos O'Donell +Signed-off-by: Torvald Riegel +Signed-off-by: Rik Prohaska +Co-authored-by: Torvald Riegel +Co-authored-by: Rik Prohaska +(cherry picked from commit 5fc9ed4c4058bfbdf51ad6e7aac7d209b580e8c4) +--- + ChangeLog | 17 ++ + NEWS | 1 + + nptl/Makefile | 3 +- + nptl/pthread_rwlock_tryrdlock.c | 25 ++- + nptl/pthread_rwlock_trywrlock.c | 9 +- + nptl/tst-rwlock-tryrdlock-stall.c | 355 ++++++++++++++++++++++++++++++ + nptl/tst-rwlock-trywrlock-stall.c | 108 +++++++++ + support/Makefile | 1 + + support/xpthread_rwlock_destroy.c | 26 +++ + support/xthread.h | 1 + + 10 files changed, 535 insertions(+), 11 deletions(-) + create mode 100644 nptl/tst-rwlock-tryrdlock-stall.c + create mode 100644 nptl/tst-rwlock-trywrlock-stall.c + create mode 100644 support/xpthread_rwlock_destroy.c + + Ubuntu notes: + - removed NEWS and ChangeLog hunks + - fixed conflict in nptl/Makefile + +Origin: backport, https://sourceware.org/git/?p=glibc.git;a=commit;h=e8c13d5f7a6cd34bc2ac51a0c89fcbbfd2e5c043 +Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=23844 +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1864864 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=952609 +Last-Update: 2020-03-09 + +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -310,7 +310,8 @@ + tst-robust-fork tst-create-detached tst-memstream \ + tst-thread-exit-clobber tst-minstack-cancel tst-minstack-exit \ + tst-minstack-throw \ +- tst-rwlock-pwn ++ tst-rwlock-pwn \ ++ tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall + + tests-internal := tst-rwlock19 tst-rwlock20 \ + tst-sem11 tst-sem12 tst-sem13 \ +--- a/nptl/pthread_rwlock_tryrdlock.c ++++ b/nptl/pthread_rwlock_tryrdlock.c +@@ -94,15 +94,22 @@ + /* Same as in __pthread_rwlock_rdlock_full: + We started the read phase, so we are also responsible for + updating the write-phase futex. Relaxed MO is sufficient. +- Note that there can be no other reader that we have to wake +- because all other readers will see the read phase started by us +- (or they will try to start it themselves); if a writer started +- the read phase, we cannot have started it. Furthermore, we +- cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will +- overwrite the value set by the most recent writer (or the readers +- before it in case of explicit hand-over) and we know that there +- are no waiting readers. */ +- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0); ++ We have to do the same steps as a writer would when handing over the ++ read phase to use because other readers cannot distinguish between ++ us and the writer. ++ Note that __pthread_rwlock_tryrdlock callers will not have to be ++ woken up because they will either see the read phase started by us ++ or they will try to start it themselves; however, callers of ++ __pthread_rwlock_rdlock_full just increase the reader count and then ++ check what state the lock is in, so they cannot distinguish between ++ us and a writer that acquired and released the lock in the ++ meantime. */ ++ if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) ++ & PTHREAD_RWLOCK_FUTEX_USED) != 0) ++ { ++ int private = __pthread_rwlock_get_private (rwlock); ++ futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); ++ } + } + + return 0; +--- a/nptl/pthread_rwlock_trywrlock.c ++++ b/nptl/pthread_rwlock_trywrlock.c +@@ -46,8 +46,15 @@ + &rwlock->__data.__readers, &r, + r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED)) + { ++ /* We have become the primary writer and we cannot have shared ++ the PTHREAD_RWLOCK_FUTEX_USED flag with someone else, so we ++ can simply enable blocking (see full wrlock code). */ + atomic_store_relaxed (&rwlock->__data.__writers_futex, 1); +- atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); ++ /* If we started a write phase, we need to enable readers to ++ wait. If we did not, we must not change it because other threads ++ may have set the PTHREAD_RWLOCK_FUTEX_USED in the meantime. */ ++ if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) ++ atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); + atomic_store_relaxed (&rwlock->__data.__cur_writer, + THREAD_GETMEM (THREAD_SELF, tid)); + return 0; +--- /dev/null ++++ b/nptl/tst-rwlock-tryrdlock-stall.c +@@ -0,0 +1,355 @@ ++/* Bug 23844: Test for pthread_rwlock_tryrdlock stalls. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* For a full analysis see comment: ++ https://sourceware.org/bugzilla/show_bug.cgi?id=23844#c14 ++ ++ Provided here for reference: ++ ++ --- Analysis of pthread_rwlock_tryrdlock() stall --- ++ A read lock begins to execute. ++ ++ In __pthread_rwlock_rdlock_full: ++ ++ We can attempt a read lock, but find that the lock is ++ in a write phase (PTHREAD_RWLOCK_WRPHASE, or WP-bit ++ is set), and the lock is held by a primary writer ++ (PTHREAD_RWLOCK_WRLOCKED is set). In this case we must ++ wait for explicit hand over from the writer to us or ++ one of the other waiters. The read lock threads are ++ about to execute: ++ ++ 341 r = (atomic_fetch_add_acquire (&rwlock->__data.__readers, ++ 342 (1 << PTHREAD_RWLOCK_READER_SHIFT)) ++ 343 + (1 << PTHREAD_RWLOCK_READER_SHIFT)); ++ ++ An unlock beings to execute. ++ ++ Then in __pthread_rwlock_wrunlock: ++ ++ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); ++ ... ++ 549 while (!atomic_compare_exchange_weak_release ++ 550 (&rwlock->__data.__readers, &r, ++ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED) ++ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 ++ 553 : PTHREAD_RWLOCK_WRPHASE)))) ++ 554 { ++ ... ++ 556 } ++ ++ We clear PTHREAD_RWLOCK_WRLOCKED, and if there are ++ no readers so we leave the lock in PTHRAD_RWLOCK_WRPHASE. ++ ++ Back in the read lock. ++ ++ The read lock adjusts __readres as above. ++ ++ 383 while ((r & PTHREAD_RWLOCK_WRPHASE) != 0 ++ 384 && (r & PTHREAD_RWLOCK_WRLOCKED) == 0) ++ 385 { ++ ... ++ 390 if (atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, &r, ++ 391 r ^ PTHREAD_RWLOCK_WRPHASE)) ++ 392 { ++ ++ And then attemps to start the read phase. ++ ++ Assume there happens to be a tryrdlock at this point, noting ++ that PTHREAD_RWLOCK_WRLOCKED is clear, and PTHREAD_RWLOCK_WRPHASE ++ is 1. So the try lock attemps to start the read phase. ++ ++ In __pthread_rwlock_tryrdlock: ++ ++ 44 if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) ++ 45 { ++ ... ++ 49 if (((r & PTHREAD_RWLOCK_WRLOCKED) != 0) ++ 50 && (rwlock->__data.__flags ++ 51 == PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)) ++ 52 return EBUSY; ++ 53 rnew = r + (1 << PTHREAD_RWLOCK_READER_SHIFT); ++ 54 } ++ ... ++ 89 while (!atomic_compare_exchange_weak_acquire (&rwlock->__data.__readers, ++ 90 &r, rnew)); ++ ++ And succeeds. ++ ++ Back in the write unlock: ++ ++ 557 if ((r >> PTHREAD_RWLOCK_READER_SHIFT) != 0) ++ 558 { ++ ... ++ 563 if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) ++ 564 & PTHREAD_RWLOCK_FUTEX_USED) != 0) ++ 565 futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); ++ 566 } ++ ++ We note that PTHREAD_RWLOCK_FUTEX_USED is non-zero ++ and don't wake anyone. This is OK because we handed ++ over to the trylock. It will be the trylock's responsibility ++ to wake any waiters. ++ ++ Back in the read lock: ++ ++ The read lock fails to install PTHRAD_REWLOCK_WRPHASE as 0 because ++ the __readers value was adjusted by the trylock, and so it falls through ++ to waiting on the lock for explicit handover from either a new writer ++ or a new reader. ++ ++ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, ++ 449 1 | PTHREAD_RWLOCK_FUTEX_USED, ++ 450 abstime, private); ++ ++ We use PTHREAD_RWLOCK_FUTEX_USED to indicate the futex ++ is in use. ++ ++ At this point we have readers waiting on the read lock ++ to unlock. The wrlock is done. The trylock is finishing ++ the installation of the read phase. ++ ++ 92 if ((r & PTHREAD_RWLOCK_WRPHASE) != 0) ++ 93 { ++ ... ++ 105 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0); ++ 106 } ++ ++ The trylock does note that we were the one that ++ installed the read phase, but the comments are not ++ correct, the execution ordering above shows that ++ readers might indeed be waiting, and they are. ++ ++ The atomic_store_relaxed throws away PTHREAD_RWLOCK_FUTEX_USED, ++ and the waiting reader is never worken becuase as noted ++ above it is conditional on the futex being used. ++ ++ The solution is for the trylock thread to inspect ++ PTHREAD_RWLOCK_FUTEX_USED and wake the waiting readers. ++ ++ --- Analysis of pthread_rwlock_trywrlock() stall --- ++ ++ A write lock begins to execute, takes the write lock, ++ and then releases the lock... ++ ++ In pthread_rwlock_wrunlock(): ++ ++ 547 unsigned int r = atomic_load_relaxed (&rwlock->__data.__readers); ++ ... ++ 549 while (!atomic_compare_exchange_weak_release ++ 550 (&rwlock->__data.__readers, &r, ++ 551 ((r ^ PTHREAD_RWLOCK_WRLOCKED) ++ 552 ^ ((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0 ? 0 ++ 553 : PTHREAD_RWLOCK_WRPHASE)))) ++ 554 { ++ ... ++ 556 } ++ ++ ... leaving it in the write phase with zero readers ++ (the case where we leave the write phase in place ++ during a write unlock). ++ ++ A write trylock begins to execute. ++ ++ In __pthread_rwlock_trywrlock: ++ ++ 40 while (((r & PTHREAD_RWLOCK_WRLOCKED) == 0) ++ 41 && (((r >> PTHREAD_RWLOCK_READER_SHIFT) == 0) ++ 42 || (prefer_writer && ((r & PTHREAD_RWLOCK_WRPHASE) != 0)))) ++ 43 { ++ ++ The lock is not locked. ++ ++ There are no readers. ++ ++ 45 if (atomic_compare_exchange_weak_acquire ( ++ 46 &rwlock->__data.__readers, &r, ++ 47 r | PTHREAD_RWLOCK_WRPHASE | PTHREAD_RWLOCK_WRLOCKED)) ++ ++ We atomically install the write phase and we take the ++ exclusive write lock. ++ ++ 48 { ++ 49 atomic_store_relaxed (&rwlock->__data.__writers_futex, 1); ++ ++ We get this far. ++ ++ A reader lock begins to execute. ++ ++ In pthread_rwlock_rdlock: ++ ++ 437 for (;;) ++ 438 { ++ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) ++ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) ++ 441 { ++ 442 int private = __pthread_rwlock_get_private (rwlock); ++ 443 if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) ++ 444 && (!atomic_compare_exchange_weak_relaxed ++ 445 (&rwlock->__data.__wrphase_futex, ++ 446 &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))) ++ 447 continue; ++ 448 int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, ++ 449 1 | PTHREAD_RWLOCK_FUTEX_USED, ++ 450 abstime, private); ++ ++ We are in a write phase, so the while() on line 439 is true. ++ ++ The value of wpf does not have PTHREAD_RWLOCK_FUTEX_USED set ++ since this is the first reader to lock. ++ ++ The atomic operation sets wpf with PTHREAD_RELOCK_FUTEX_USED ++ on the expectation that this reader will be woken during ++ the handoff. ++ ++ Back in pthread_rwlock_trywrlock: ++ ++ 50 atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); ++ 51 atomic_store_relaxed (&rwlock->__data.__cur_writer, ++ 52 THREAD_GETMEM (THREAD_SELF, tid)); ++ 53 return 0; ++ 54 } ++ ... ++ 57 } ++ ++ We write 1 to __wrphase_futex discarding PTHREAD_RWLOCK_FUTEX_USED, ++ and so in the unlock we will not awaken the waiting reader. ++ ++ The solution to this is to realize that if we did not start the write ++ phase we need not write 1 or any other value to __wrphase_futex. ++ This ensures that any readers (which saw __wrphase_futex != 0) can ++ set PTHREAD_RWLOCK_FUTEX_USED and this can be used at unlock to ++ wake them. ++ ++ If we installed the write phase then all other readers are looping ++ here: ++ ++ In __pthread_rwlock_rdlock_full: ++ ++ 437 for (;;) ++ 438 { ++ 439 while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) ++ 440 | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) ++ 441 { ++ ... ++ 508 } ++ ++ waiting for the write phase to be installed or removed before they ++ can begin waiting on __wrphase_futex (part of the algorithm), or ++ taking a concurrent read lock, and thus we can safely write 1 to ++ __wrphase_futex. ++ ++ If we did not install the write phase then the readers may already ++ be waiting on the futex, the original writer wrote 1 to __wrphase_futex ++ as part of starting the write phase, and we cannot also write 1 ++ without loosing the PTHREAD_RWLOCK_FUTEX_USED bit. ++ ++ --- ++ ++ Summary for the pthread_rwlock_tryrdlock() stall: ++ ++ The stall is caused by pthread_rwlock_tryrdlock failing to check ++ that PTHREAD_RWLOCK_FUTEX_USED is set in the __wrphase_futex futex ++ and then waking the futex. ++ ++ The fix for bug 23844 ensures that waiters on __wrphase_futex are ++ correctly woken. Before the fix the test stalls as readers can ++ wait forever on __wrphase_futex. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* We need only one lock to reproduce the issue. We will need multiple ++ threads to get the exact case where we have a read, try, and unlock ++ all interleaving to produce the case where the readers are waiting ++ and the try fails to wake them. */ ++pthread_rwlock_t onelock; ++ ++/* The number of threads is arbitrary but empirically chosen to have ++ enough threads that we see the condition where waiting readers are ++ not woken by a successful tryrdlock. */ ++#define NTHREADS 32 ++ ++_Atomic int do_exit; ++ ++void * ++run_loop (void *arg) ++{ ++ int i = 0, ret; ++ while (!do_exit) ++ { ++ /* Arbitrarily choose if we are the writer or reader. Choose a ++ high enough ratio of readers to writers to make it likely ++ that readers block (and eventually are susceptable to ++ stalling). ++ ++ If we are a writer, take the write lock, and then unlock. ++ If we are a reader, try the lock, then lock, then unlock. */ ++ if ((i % 8) != 0) ++ xpthread_rwlock_wrlock (&onelock); ++ else ++ { ++ if ((ret = pthread_rwlock_tryrdlock (&onelock)) != 0) ++ { ++ if (ret == EBUSY) ++ xpthread_rwlock_rdlock (&onelock); ++ else ++ exit (EXIT_FAILURE); ++ } ++ } ++ /* Thread does some work and then unlocks. */ ++ xpthread_rwlock_unlock (&onelock); ++ i++; ++ } ++ return NULL; ++} ++ ++int ++do_test (void) ++{ ++ int i; ++ pthread_t tids[NTHREADS]; ++ xpthread_rwlock_init (&onelock, NULL); ++ for (i = 0; i < NTHREADS; i++) ++ tids[i] = xpthread_create (NULL, run_loop, NULL); ++ /* Run for some amount of time. Empirically speaking exercising ++ the stall via pthread_rwlock_tryrdlock is much harder, and on ++ a 3.5GHz 4 core x86_64 VM system it takes somewhere around ++ 20-200s to stall, approaching 100% stall past 200s. We can't ++ wait that long for a regression test so we just test for 20s, ++ and expect the stall to happen with a 5-10% chance (enough for ++ developers to see). */ ++ sleep (20); ++ /* Then exit. */ ++ printf ("INFO: Exiting...\n"); ++ do_exit = 1; ++ /* If any readers stalled then we will timeout waiting for them. */ ++ for (i = 0; i < NTHREADS; i++) ++ xpthread_join (tids[i]); ++ printf ("INFO: Done.\n"); ++ xpthread_rwlock_destroy (&onelock); ++ printf ("PASS: No pthread_rwlock_tryrdlock stalls detected.\n"); ++ return 0; ++} ++ ++#define TIMEOUT 30 ++#include +--- /dev/null ++++ b/nptl/tst-rwlock-trywrlock-stall.c +@@ -0,0 +1,108 @@ ++/* Bug 23844: Test for pthread_rwlock_trywrlock stalls. ++ Copyright (C) 2019 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 ++ . */ ++ ++/* For a full analysis see comments in tst-rwlock-tryrdlock-stall.c. ++ ++ Summary for the pthread_rwlock_trywrlock() stall: ++ ++ The stall is caused by pthread_rwlock_trywrlock setting ++ __wrphase_futex futex to 1 and loosing the ++ PTHREAD_RWLOCK_FUTEX_USED bit. ++ ++ The fix for bug 23844 ensures that waiters on __wrphase_futex are ++ correctly woken. Before the fix the test stalls as readers can ++ wait forever on __wrphase_futex. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* We need only one lock to reproduce the issue. We will need multiple ++ threads to get the exact case where we have a read, try, and unlock ++ all interleaving to produce the case where the readers are waiting ++ and the try clears the PTHREAD_RWLOCK_FUTEX_USED bit and a ++ subsequent unlock fails to wake them. */ ++pthread_rwlock_t onelock; ++ ++/* The number of threads is arbitrary but empirically chosen to have ++ enough threads that we see the condition where waiting readers are ++ not woken by a successful unlock. */ ++#define NTHREADS 32 ++ ++_Atomic int do_exit; ++ ++void * ++run_loop (void *arg) ++{ ++ int i = 0, ret; ++ while (!do_exit) ++ { ++ /* Arbitrarily choose if we are the writer or reader. Choose a ++ high enough ratio of readers to writers to make it likely ++ that readers block (and eventually are susceptable to ++ stalling). ++ ++ If we are a writer, take the write lock, and then unlock. ++ If we are a reader, try the lock, then lock, then unlock. */ ++ if ((i % 8) != 0) ++ { ++ if ((ret = pthread_rwlock_trywrlock (&onelock)) != 0) ++ { ++ if (ret == EBUSY) ++ xpthread_rwlock_wrlock (&onelock); ++ else ++ exit (EXIT_FAILURE); ++ } ++ } ++ else ++ xpthread_rwlock_rdlock (&onelock); ++ /* Thread does some work and then unlocks. */ ++ xpthread_rwlock_unlock (&onelock); ++ i++; ++ } ++ return NULL; ++} ++ ++int ++do_test (void) ++{ ++ int i; ++ pthread_t tids[NTHREADS]; ++ xpthread_rwlock_init (&onelock, NULL); ++ for (i = 0; i < NTHREADS; i++) ++ tids[i] = xpthread_create (NULL, run_loop, NULL); ++ /* Run for some amount of time. The pthread_rwlock_tryrwlock stall ++ is very easy to trigger and happens in seconds under the test ++ conditions. */ ++ sleep (10); ++ /* Then exit. */ ++ printf ("INFO: Exiting...\n"); ++ do_exit = 1; ++ /* If any readers stalled then we will timeout waiting for them. */ ++ for (i = 0; i < NTHREADS; i++) ++ xpthread_join (tids[i]); ++ printf ("INFO: Done.\n"); ++ xpthread_rwlock_destroy (&onelock); ++ printf ("PASS: No pthread_rwlock_tryrwlock stalls detected.\n"); ++ return 0; ++} ++ ++#include +--- a/support/Makefile ++++ b/support/Makefile +@@ -122,6 +122,7 @@ + xpthread_mutexattr_settype \ + xpthread_once \ + xpthread_rwlock_init \ ++ xpthread_rwlock_destroy \ + xpthread_rwlock_rdlock \ + xpthread_rwlock_unlock \ + xpthread_rwlock_wrlock \ +--- /dev/null ++++ b/support/xpthread_rwlock_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_rwlock_destroy with error checking. ++ Copyright (C) 2019 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 ++ ++void ++xpthread_rwlock_destroy (pthread_rwlock_t *rwlock) ++{ ++ xpthread_check_return ("pthread_rwlock_destroy", ++ pthread_rwlock_destroy (rwlock)); ++} +--- a/support/xthread.h ++++ b/support/xthread.h +@@ -84,6 +84,7 @@ + void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock); + void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock); + void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock); ++void xpthread_rwlock_destroy (pthread_rwlock_t *rwlock); + + __END_DECLS + diff -Nru glibc-2.27/debian/patches/any/CVE-2016-10228-1.patch glibc-2.27/debian/patches/any/CVE-2016-10228-1.patch --- glibc-2.27/debian/patches/any/CVE-2016-10228-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2016-10228-1.patch 2022-01-24 12:53:44.000000000 +0000 @@ -0,0 +1,1356 @@ +Backport of: + +From 91927b7c76437db860cd86a7714476b56bb39d07 Mon Sep 17 00:00:00 2001 +From: Arjun Shankar +Date: Tue, 7 Jul 2020 20:31:48 +0200 +Subject: [PATCH] Rewrite iconv option parsing [BZ #19519] + +This commit replaces string manipulation during `iconv_open' and iconv_prog +option parsing with a structured, flag based conversion specification. In +doing so, it alters the internal `__gconv_open' interface and accordingly +adjusts its uses. + +This change fixes several hangs in the iconv program and therefore includes +a new test to exercise iconv_prog options that originally led to these hangs. +It also includes a new regression test for option handling in the iconv +function. + +Reviewed-by: Florian Weimer +Reviewed-by: Siddhesh Poyarekar +Reviewed-by: Carlos O'Donell +--- + iconv/Makefile | 17 +- + iconv/Versions | 1 + + iconv/gconv_charset.c | 218 +++++++++++++++++++++++++ + iconv/gconv_charset.h | 61 ++++++- + iconv/gconv_int.h | 19 ++- + iconv/gconv_open.c | 64 ++------ + iconv/iconv_open.c | 46 +----- + iconv/iconv_prog.c | 63 +++----- + iconv/tst-iconv-opt.c | 347 ++++++++++++++++++++++++++++++++++++++++ + iconv/tst-iconv_prog.sh | 280 ++++++++++++++++++++++++++++++++ + intl/dcigettext.c | 15 +- + 11 files changed, 988 insertions(+), 143 deletions(-) + create mode 100644 iconv/gconv_charset.c + create mode 100644 iconv/tst-iconv-opt.c + create mode 100644 iconv/tst-iconv_prog.sh + +--- a/iconv/Makefile ++++ b/iconv/Makefile +@@ -26,7 +26,7 @@ headers = iconv.h gconv.h + routines = iconv_open iconv iconv_close \ + gconv_open gconv gconv_close gconv_db gconv_conf \ + gconv_builtin gconv_simple gconv_trans gconv_cache +-routines += gconv_dl ++routines += gconv_dl gconv_charset + + vpath %.c ../locale/programs ../intl + +@@ -43,7 +43,7 @@ CFLAGS-charmap.c += -DCHARMAP_PATH='"$(i + CFLAGS-linereader.c += -DNO_TRANSLITERATION + CFLAGS-simple-hash.c += -I../locale + +-tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 ++tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 tst-iconv-opt + + others = iconv_prog iconvconfig + install-others-programs = $(inst_bindir)/iconv +@@ -60,6 +60,7 @@ include $(patsubst %,$(..)libof-iterator + + ifeq ($(run-built-tests),yes) + xtests-special += $(objpfx)test-iconvconfig.out ++tests-special += $(objpfx)tst-iconv_prog.out + endif + + # Make a copy of the file because gconv module names are constructed +@@ -78,6 +79,13 @@ endif + + include ../Rules + ++ifeq ($(run-built-tests),yes) ++LOCALES := en_US.UTF-8 ++include ../gen-locales.mk ++ ++$(objpfx)tst-iconv-opt.out: $(gen-locales) ++endif ++ + $(inst_bindir)/iconv: $(objpfx)iconv_prog $(+force) + $(do-install-program) + +@@ -92,3 +100,8 @@ $(objpfx)test-iconvconfig.out: /dev/null + cmp $$tmp $(inst_gconvdir)/gconv-modules.cache; \ + rm -f $$tmp) > $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog ++ $(BASH) $< $(common-objdir) '$(test-wrapper-env)' \ ++ '$(run-program-env)' > $@; \ ++ $(evaluate-test) +--- a/iconv/Versions ++++ b/iconv/Versions +@@ -6,6 +6,7 @@ libc { + GLIBC_PRIVATE { + # functions shared with iconv program + __gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db; ++ __gconv_open; __gconv_create_spec; + + # function used by the gconv modules + __gconv_transliterate; +--- /dev/null ++++ b/iconv/gconv_charset.c +@@ -0,0 +1,218 @@ ++/* Charset name normalization. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "gconv_int.h" ++#include "gconv_charset.h" ++ ++ ++/* This function returns a pointer to the last suffix in a conversion code ++ string. Valid suffixes matched by this function are of the form: '/' or ',' ++ followed by arbitrary text that doesn't contain '/' or ','. It does not ++ edit the string in any way. The caller is expected to parse the suffix and ++ remove it (by e.g. truncating the string) before the next call. */ ++static char * ++find_suffix (char *s) ++{ ++ /* The conversion code is in the form of a triplet, separated by '/' chars. ++ The third component of the triplet contains suffixes. If we don't have two ++ slashes, we don't have a suffix. */ ++ ++ int slash_count = 0; ++ char *suffix_term = NULL; ++ ++ for (int i = 0; s[i] != '\0'; i++) ++ switch (s[i]) ++ { ++ case '/': ++ slash_count++; ++ /* Fallthrough */ ++ case ',': ++ suffix_term = &s[i]; ++ } ++ ++ if (slash_count >= 2) ++ return suffix_term; ++ ++ return NULL; ++} ++ ++ ++struct gconv_parsed_code ++{ ++ char *code; ++ bool translit; ++ bool ignore; ++}; ++ ++ ++/* This function parses an iconv_open encoding PC.CODE, strips any suffixes ++ (such as TRANSLIT or IGNORE) from it and sets corresponding flags in it. */ ++static void ++gconv_parse_code (struct gconv_parsed_code *pc) ++{ ++ pc->translit = false; ++ pc->ignore = false; ++ ++ while (1) ++ { ++ /* First drop any trailing whitespaces and separators. */ ++ size_t len = strlen (pc->code); ++ while ((len > 0) ++ && (isspace (pc->code[len - 1]) ++ || pc->code[len - 1] == ',' ++ || pc->code[len - 1] == '/')) ++ len--; ++ ++ pc->code[len] = '\0'; ++ ++ if (len == 0) ++ return; ++ ++ char * suffix = find_suffix (pc->code); ++ if (suffix == NULL) ++ { ++ /* At this point, we have processed and removed all suffixes from the ++ code and what remains of the code is suffix free. */ ++ return; ++ } ++ else ++ { ++ /* A suffix is processed from the end of the code array going ++ backwards, one suffix at a time. The suffix is an index into the ++ code character array and points to: one past the end of the code ++ and any unprocessed suffixes, and to the beginning of the suffix ++ currently being processed during this iteration. We must process ++ this suffix and then drop it from the code by terminating the ++ preceding text with NULL. ++ ++ We want to allow and recognize suffixes such as: ++ ++ "/TRANSLIT" i.e. single suffix ++ "//TRANSLIT" i.e. single suffix and multiple separators ++ "//TRANSLIT/IGNORE" i.e. suffixes separated by "/" ++ "/TRANSLIT//IGNORE" i.e. suffixes separated by "//" ++ "//IGNORE,TRANSLIT" i.e. suffixes separated by "," ++ "//IGNORE," i.e. trailing "," ++ "//TRANSLIT/" i.e. trailing "/" ++ "//TRANSLIT//" i.e. trailing "//" ++ "/" i.e. empty suffix. ++ ++ Unknown suffixes are silently discarded and ignored. */ ++ ++ if ((__strcasecmp_l (suffix, ++ GCONV_TRIPLE_SEPARATOR ++ GCONV_TRANSLIT_SUFFIX, ++ _nl_C_locobj_ptr) == 0) ++ || (__strcasecmp_l (suffix, ++ GCONV_SUFFIX_SEPARATOR ++ GCONV_TRANSLIT_SUFFIX, ++ _nl_C_locobj_ptr) == 0)) ++ pc->translit = true; ++ ++ if ((__strcasecmp_l (suffix, ++ GCONV_TRIPLE_SEPARATOR ++ GCONV_IGNORE_ERRORS_SUFFIX, ++ _nl_C_locobj_ptr) == 0) ++ || (__strcasecmp_l (suffix, ++ GCONV_SUFFIX_SEPARATOR ++ GCONV_IGNORE_ERRORS_SUFFIX, ++ _nl_C_locobj_ptr) == 0)) ++ pc->ignore = true; ++ ++ /* We just processed this suffix. We can now drop it from the ++ code string by truncating it at the suffix's position. */ ++ suffix[0] = '\0'; ++ } ++ } ++} ++ ++ ++/* This function accepts the charset names of the source and destination of the ++ conversion and populates *conv_spec with an equivalent conversion ++ specification that may later be used by __gconv_open. The charset names ++ might contain options in the form of suffixes that alter the conversion, ++ e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring ++ and truncating any suffix options in fromcode, and processing and truncating ++ any suffix options in tocode. Supported suffix options ("TRANSLIT" or ++ "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec ++ to be set to true. Unrecognized suffix options are silently discarded. If ++ the function succeeds, it returns conv_spec back to the caller. It returns ++ NULL upon failure. conv_spec must be allocated and freed by the caller. */ ++struct gconv_spec * ++__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, ++ const char *tocode) ++{ ++ struct gconv_parsed_code pfc, ptc; ++ struct gconv_spec *ret = NULL; ++ ++ pfc.code = __strdup (fromcode); ++ ptc.code = __strdup (tocode); ++ ++ if ((pfc.code == NULL) ++ || (ptc.code == NULL)) ++ goto out; ++ ++ gconv_parse_code (&pfc); ++ gconv_parse_code (&ptc); ++ ++ /* We ignore suffixes in the fromcode because that is how the current ++ implementation has always handled them. Only suffixes in the tocode are ++ processed and handled. The reality is that invalid input in the input ++ character set should only be ignored if the fromcode specifies IGNORE. ++ The current implementation ignores invalid intput in the input character ++ set if the tocode contains IGNORE. We preserve this behavior for ++ backwards compatibility. In the future we may split the handling of ++ IGNORE to allow a finer grained specification of ignorning invalid input ++ and/or ignoring invalid output. */ ++ conv_spec->translit = ptc.translit; ++ conv_spec->ignore = ptc.ignore; ++ ++ /* 3 extra bytes because 1 extra for '\0', and 2 extra so strip might ++ be able to add one or two trailing '/' characters if necessary. */ ++ conv_spec->fromcode = malloc (strlen (fromcode) + 3); ++ if (conv_spec->fromcode == NULL) ++ goto out; ++ ++ conv_spec->tocode = malloc (strlen (tocode) + 3); ++ if (conv_spec->tocode == NULL) ++ { ++ free (conv_spec->fromcode); ++ conv_spec->fromcode = NULL; ++ goto out; ++ } ++ ++ /* Strip unrecognized characters and ensure that the code has two '/' ++ characters as per conversion code triplet specification. */ ++ strip (conv_spec->fromcode, pfc.code); ++ strip (conv_spec->tocode, ptc.code); ++ ret = conv_spec; ++ ++out: ++ free (pfc.code); ++ free (ptc.code); ++ ++ return ret; ++} ++libc_hidden_def (__gconv_create_spec) +--- a/iconv/gconv_charset.h ++++ b/iconv/gconv_charset.h +@@ -19,9 +19,68 @@ + + #include + #include ++#include ++#include ++#include ++#include ++#include "gconv_int.h" + + +-static void ++/* An iconv encoding is in the form of a triplet, with parts separated by ++ a '/' character. The first part is the standard name, the second part is ++ the character set, and the third part is the error handler. If the first ++ part is sufficient to identify both the standard and the character set ++ then the second part can be empty e.g. UTF-8//. If the first part is not ++ sufficient to identify both the standard and the character set then the ++ second part is required e.g. ISO-10646/UTF8/. If neither the first or ++ second parts are provided e.g. //, then the current locale is used. ++ The actual values used in the first and second parts are not entirely ++ relevant to the implementation. The values themselves are used in a hash ++ table to lookup modules and so the naming convention of the first two parts ++ is somewhat arbitrary and only helps locate the entries in the cache. ++ The third part is the error handler and is comprised of a ',' or '/' ++ separated list of suffixes. Currently, we support "TRANSLIT" for ++ transliteration and "IGNORE" for ignoring conversion errors due to ++ unrecognized input characters. */ ++#define GCONV_TRIPLE_SEPARATOR "/" ++#define GCONV_SUFFIX_SEPARATOR "," ++#define GCONV_TRANSLIT_SUFFIX "TRANSLIT" ++#define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE" ++ ++ ++/* This function accepts the charset names of the source and destination of the ++ conversion and populates *conv_spec with an equivalent conversion ++ specification that may later be used by __gconv_open. The charset names ++ might contain options in the form of suffixes that alter the conversion, ++ e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring ++ and truncating any suffix options in fromcode, and processing and truncating ++ any suffix options in tocode. Supported suffix options ("TRANSLIT" or ++ "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec ++ to be set to true. Unrecognized suffix options are silently discarded. If ++ the function succeeds, it returns conv_spec back to the caller. It returns ++ NULL upon failure. */ ++struct gconv_spec * ++__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, ++ const char *tocode); ++libc_hidden_proto (__gconv_create_spec) ++ ++ ++/* This function frees all heap memory allocated by __gconv_create_spec. */ ++static void __attribute__ ((unused)) ++gconv_destroy_spec (struct gconv_spec *conv_spec) ++{ ++ free (conv_spec->fromcode); ++ free (conv_spec->tocode); ++ return; ++} ++ ++ ++/* This function copies in-order, characters from the source 's' that are ++ either alpha-numeric or one in one of these: "_-.,:/" - into the destination ++ 'wp' while dropping all other characters. In the process, it converts all ++ alphabetical characters to upper case. It then appends up to two '/' ++ characters so that the total number of '/'es in the destination is 2. */ ++static inline void __attribute__ ((unused, always_inline)) + strip (char *wp, const char *s) + { + int slash_count = 0; +--- a/iconv/gconv_int.h ++++ b/iconv/gconv_int.h +@@ -92,6 +92,15 @@ struct gconv_module + }; + + ++/* The specification of the conversion that needs to be performed. */ ++struct gconv_spec ++{ ++ char *fromcode; ++ char *tocode; ++ bool translit; ++ bool ignore; ++}; ++ + /* Flags for `gconv_open'. */ + enum + { +@@ -154,10 +163,12 @@ __libc_lock_define (extern, __gconv_lock + }) + + +-/* Return in *HANDLE decriptor for transformation from FROMSET to TOSET. */ +-extern int __gconv_open (const char *toset, const char *fromset, +- __gconv_t *handle, int flags) +- attribute_hidden; ++/* Return in *HANDLE, a decriptor for the transformation. The function expects ++ the specification of the transformation in the structure pointed to by ++ CONV_SPEC. It only reads *CONV_SPEC and does not take ownership of it. */ ++extern int __gconv_open (struct gconv_spec *conv_spec, ++ __gconv_t *handle, int flags); ++libc_hidden_proto (__gconv_open) + + /* Free resources associated with transformation descriptor CD. */ + extern int __gconv_close (__gconv_t cd) +--- a/iconv/gconv_open.c ++++ b/iconv/gconv_open.c +@@ -27,7 +27,7 @@ + + + int +-__gconv_open (const char *toset, const char *fromset, __gconv_t *handle, ++__gconv_open (struct gconv_spec *conv_spec, __gconv_t *handle, + int flags) + { + struct __gconv_step *steps; +@@ -36,77 +36,38 @@ __gconv_open (const char *toset, const c + size_t cnt = 0; + int res; + int conv_flags = 0; +- const char *errhand; +- const char *ignore; + bool translit = false; ++ char *tocode, *fromcode; + + /* Find out whether any error handling method is specified. */ +- errhand = strchr (toset, '/'); +- if (errhand != NULL) +- errhand = strchr (errhand + 1, '/'); +- if (__glibc_likely (errhand != NULL)) +- { +- if (*++errhand == '\0') +- errhand = NULL; +- else +- { +- /* Make copy without the error handling description. */ +- char *newtoset = (char *) alloca (errhand - toset + 1); +- char *tok; +- char *ptr = NULL /* Work around a bogus warning */; +- +- newtoset[errhand - toset] = '\0'; +- toset = memcpy (newtoset, toset, errhand - toset); ++ translit = conv_spec->translit; + +- /* Find the appropriate transliteration handlers. */ +- tok = strdupa (errhand); ++ if (conv_spec->ignore) ++ conv_flags |= __GCONV_IGNORE_ERRORS; + +- tok = __strtok_r (tok, ",", &ptr); +- while (tok != NULL) +- { +- if (__strcasecmp_l (tok, "TRANSLIT", _nl_C_locobj_ptr) == 0) +- translit = true; +- else if (__strcasecmp_l (tok, "IGNORE", _nl_C_locobj_ptr) == 0) +- /* Set the flag to ignore all errors. */ +- conv_flags |= __GCONV_IGNORE_ERRORS; +- +- tok = __strtok_r (NULL, ",", &ptr); +- } +- } +- } +- +- /* For the source character set we ignore the error handler specification. +- XXX Is this really always the best? */ +- ignore = strchr (fromset, '/'); +- if (ignore != NULL && (ignore = strchr (ignore + 1, '/')) != NULL +- && *++ignore != '\0') +- { +- char *newfromset = (char *) alloca (ignore - fromset + 1); +- +- newfromset[ignore - fromset] = '\0'; +- fromset = memcpy (newfromset, fromset, ignore - fromset); +- } ++ tocode = conv_spec->tocode; ++ fromcode = conv_spec->fromcode; + + /* If the string is empty define this to mean the charset of the + currently selected locale. */ +- if (strcmp (toset, "//") == 0) ++ if (strcmp (tocode, "//") == 0) + { + const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET); + size_t len = strlen (codeset); + char *dest; +- toset = dest = (char *) alloca (len + 3); ++ tocode = dest = (char *) alloca (len + 3); + memcpy (__mempcpy (dest, codeset, len), "//", 3); + } +- if (strcmp (fromset, "//") == 0) ++ if (strcmp (fromcode, "//") == 0) + { + const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET); + size_t len = strlen (codeset); + char *dest; +- fromset = dest = (char *) alloca (len + 3); ++ fromcode = dest = (char *) alloca (len + 3); + memcpy (__mempcpy (dest, codeset, len), "//", 3); + } + +- res = __gconv_find_transform (toset, fromset, &steps, &nsteps, flags); ++ res = __gconv_find_transform (tocode, fromcode, &steps, &nsteps, flags); + if (res == __GCONV_OK) + { + /* Allocate room for handle. */ +@@ -205,3 +166,4 @@ __gconv_open (const char *toset, const c + *handle = result; + return res; + } ++libc_hidden_def (__gconv_open) +--- a/iconv/iconv_open.c ++++ b/iconv/iconv_open.c +@@ -31,49 +31,15 @@ + iconv_t + iconv_open (const char *tocode, const char *fromcode) + { +- /* Normalize the name. We remove all characters beside alpha-numeric, +- '_', '-', '/', '.', and ':'. */ +- size_t tocode_len = strlen (tocode) + 3; +- char *tocode_conv; +- bool tocode_usealloca = __libc_use_alloca (tocode_len); +- if (tocode_usealloca) +- tocode_conv = (char *) alloca (tocode_len); +- else +- { +- tocode_conv = (char *) malloc (tocode_len); +- if (tocode_conv == NULL) +- return (iconv_t) -1; +- } +- strip (tocode_conv, tocode); +- tocode = (tocode_conv[2] == '\0' && tocode[0] != '\0' +- ? upstr (tocode_conv, tocode) : tocode_conv); ++ __gconv_t cd; ++ struct gconv_spec conv_spec; + +- size_t fromcode_len = strlen (fromcode) + 3; +- char *fromcode_conv; +- bool fromcode_usealloca = __libc_use_alloca (fromcode_len); +- if (fromcode_usealloca) +- fromcode_conv = (char *) alloca (fromcode_len); +- else +- { +- fromcode_conv = (char *) malloc (fromcode_len); +- if (fromcode_conv == NULL) +- { +- if (! tocode_usealloca) +- free (tocode_conv); +- return (iconv_t) -1; +- } +- } +- strip (fromcode_conv, fromcode); +- fromcode = (fromcode_conv[2] == '\0' && fromcode[0] != '\0' +- ? upstr (fromcode_conv, fromcode) : fromcode_conv); ++ if (__gconv_create_spec (&conv_spec, fromcode, tocode) == NULL) ++ return (iconv_t) -1; + +- __gconv_t cd; +- int res = __gconv_open (tocode, fromcode, &cd, 0); ++ int res = __gconv_open (&conv_spec, &cd, 0); + +- if (! fromcode_usealloca) +- free (fromcode_conv); +- if (! tocode_usealloca) +- free (tocode_conv); ++ gconv_destroy_spec (&conv_spec); + + if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK) + { +--- a/iconv/iconv_prog.c ++++ b/iconv/iconv_prog.c +@@ -39,6 +39,7 @@ + #include + #include "iconv_prog.h" + #include "iconvconfig.h" ++#include "gconv_charset.h" + + /* Get libc version number. */ + #include "../version.h" +@@ -118,8 +119,7 @@ main (int argc, char *argv[]) + { + int status = EXIT_SUCCESS; + int remaining; +- iconv_t cd; +- const char *orig_to_code; ++ __gconv_t cd; + struct charmap_t *from_charmap = NULL; + struct charmap_t *to_charmap = NULL; + +@@ -139,39 +139,6 @@ main (int argc, char *argv[]) + exit (EXIT_SUCCESS); + } + +- /* If we have to ignore errors make sure we use the appropriate name for +- the to-character-set. */ +- orig_to_code = to_code; +- if (omit_invalid) +- { +- const char *errhand = strchrnul (to_code, '/'); +- int nslash = 2; +- char *newp; +- char *cp; +- +- if (*errhand == '/') +- { +- --nslash; +- errhand = strchrnul (errhand + 1, '/'); +- +- if (*errhand == '/') +- { +- --nslash; +- errhand = strchr (errhand, '\0'); +- } +- } +- +- newp = (char *) alloca (errhand - to_code + nslash + 7 + 1); +- cp = mempcpy (newp, to_code, errhand - to_code); +- while (nslash-- > 0) +- *cp++ = '/'; +- if (cp[-1] != '/') +- *cp++ = ','; +- memcpy (cp, "IGNORE", sizeof ("IGNORE")); +- +- to_code = newp; +- } +- + /* POSIX 1003.2b introduces a silly thing: the arguments to -t anf -f + can be file names of charmaps. In this case iconv will have to read + those charmaps and use them to do the conversion. But there are +@@ -184,10 +151,10 @@ main (int argc, char *argv[]) + file. */ + from_charmap = charmap_read (from_code, /*0, 1*/1, 0, 0, 0); + +- if (strchr (orig_to_code, '/') != NULL) ++ if (strchr (to_code, '/') != NULL) + /* The to-name might be a charmap file name. Try reading the + file. */ +- to_charmap = charmap_read (orig_to_code, /*0, 1,*/1, 0, 0, 0); ++ to_charmap = charmap_read (to_code, /*0, 1,*/1, 0, 0, 0); + + + /* At this point we have to handle two cases. The first one is +@@ -201,9 +168,25 @@ main (int argc, char *argv[]) + argc, remaining, argv, output_file); + else + { ++ struct gconv_spec conv_spec; ++ int res; ++ ++ if (__gconv_create_spec (&conv_spec, from_code, to_code) == NULL) ++ { ++ error (EXIT_FAILURE, errno, ++ _("failed to start conversion processing")); ++ exit (1); ++ } ++ ++ if (omit_invalid) ++ conv_spec.ignore = true; ++ + /* Let's see whether we have these coded character sets. */ +- cd = iconv_open (to_code, from_code); +- if (cd == (iconv_t) -1) ++ res = __gconv_open (&conv_spec, &cd, 0); ++ ++ gconv_destroy_spec (&conv_spec); ++ ++ if (res != __GCONV_OK) + { + if (errno == EINVAL) + { +@@ -221,7 +204,7 @@ main (int argc, char *argv[]) + const char *from_pretty = + (from_code[0] ? from_code : nl_langinfo (CODESET)); + const char *to_pretty = +- (orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET)); ++ (to_code[0] ? to_code : nl_langinfo (CODESET)); + + if (from_wrong) + { +--- /dev/null ++++ b/iconv/tst-iconv-opt.c +@@ -0,0 +1,347 @@ ++/* Test iconv's TRANSLIT and IGNORE option handling ++ ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* Run one iconv test. Arguments: ++ to: destination character set and options ++ from: source character set ++ input: input string to be converted ++ exp_in: expected number of bytes consumed ++ exp_ret: expected return value (error or number of irreversible conversions) ++ exp_out: expected output string ++ exp_err: expected value of `errno' after iconv returns. */ ++static void ++test_iconv (const char *to, const char *from, char *input, size_t exp_in, ++ size_t exp_ret, const char *exp_out, int exp_err) ++{ ++ iconv_t cd; ++ char outbuf[500]; ++ size_t inlen, outlen; ++ char *inptr, *outptr; ++ size_t n; ++ ++ cd = iconv_open (to, from); ++ TEST_VERIFY (cd != (iconv_t) -1); ++ ++ inlen = strlen (input); ++ outlen = sizeof (outbuf); ++ inptr = input; ++ outptr = outbuf; ++ ++ errno = 0; ++ n = iconv (cd, &inptr, &inlen, &outptr, &outlen); ++ ++ TEST_COMPARE (n, exp_ret); ++ TEST_VERIFY (inptr == input + exp_in); ++ TEST_COMPARE (errno, exp_err); ++ TEST_COMPARE_BLOB (outbuf, outptr - outbuf, exp_out, strlen (exp_out)); ++ TEST_VERIFY (iconv_close (cd) == 0); ++} ++ ++ ++/* We test option parsing by converting UTF-8 inputs to ASCII under various ++ option combinations. The UTF-8 inputs fall into three categories: ++ - ASCII-only, ++ - non-ASCII, ++ - non-ASCII with invalid UTF-8 characters. */ ++ ++/* 1. */ ++char ascii[] = "Just some ASCII text"; ++ ++/* 2. Valid UTF-8 input and some corresponding expected outputs with various ++ options. The two non-ASCII characters below are accented alphabets: ++ an `a' then an `o'. */ ++char utf8[] = "UTF-8 text with \u00E1 couple \u00F3f non-ASCII characters"; ++char u2a[] = "UTF-8 text with "; ++char u2a_translit[] = "UTF-8 text with a couple of non-ASCII characters"; ++char u2a_ignore[] = "UTF-8 text with couple f non-ASCII characters"; ++ ++/* 3. Invalid UTF-8 input and some corresponding expected outputs. \xff is ++ invalid UTF-8. It's followed by some valid but non-ASCII UTF-8. */ ++char iutf8[] = "Invalid UTF-8 \xff\u00B7text\u00B7"; ++char iu2a[] = "Invalid UTF-8 "; ++char iu2a_ignore[] = "Invalid UTF-8 text"; ++char iu2a_both[] = "Invalid UTF-8 .text."; ++ ++/* 4. Another invalid UTF-8 input and corresponding expected outputs. This time ++ the valid non-ASCII UTF-8 characters appear before the invalid \xff. */ ++char jutf8[] = "Invalid \u00B7UTF-8\u00B7 \xfftext"; ++char ju2a[] = "Invalid "; ++char ju2a_translit[] = "Invalid .UTF-8. "; ++char ju2a_ignore[] = "Invalid UTF-8 text"; ++char ju2a_both[] = "Invalid .UTF-8. text"; ++ ++/* We also test option handling for character set names that have the form ++ "A/B". In this test, we test conversions "ISO-10646/UTF-8", and either ++ ISO-8859-1 or ASCII. */ ++ ++/* 5. Accented 'A' and 'a' characters in ISO-8859-1 and UTF-8, and an ++ equivalent ASCII transliteration. */ ++char iso8859_1_a[] = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, /* Accented A's. */ ++ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, /* Accented a's. */ ++ 0x00}; ++char utf8_a[] = "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5" ++ "\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5"; ++char ascii_a[] = "AAAAAAaaaaaa"; ++ ++/* 6. An invalid ASCII string where [0] is invalid and [1] is '~'. */ ++char iascii [] = {0x80, '~', '\0'}; ++char empty[] = ""; ++char ia2u_ignore[] = "~"; ++ ++static int ++do_test (void) ++{ ++ xsetlocale (LC_ALL, "en_US.UTF-8"); ++ ++ ++ /* 0. iconv_open should gracefully fail for invalid character sets. */ ++ ++ TEST_VERIFY (iconv_open ("INVALID", "UTF-8") == (iconv_t) -1); ++ TEST_VERIFY (iconv_open ("UTF-8", "INVALID") == (iconv_t) -1); ++ TEST_VERIFY (iconv_open ("INVALID", "INVALID") == (iconv_t) -1); ++ ++ ++ /* 1. ASCII-only UTF-8 input should convert to ASCII with no changes: */ ++ ++ test_iconv ("ASCII", "UTF-8", ascii, strlen (ascii), 0, ascii, 0); ++ test_iconv ("ASCII//", "UTF-8", ascii, strlen (ascii), 0, ascii, 0); ++ test_iconv ("ASCII//TRANSLIT", "UTF-8", ascii, strlen (ascii), 0, ascii, 0); ++ test_iconv ("ASCII//TRANSLIT//", "UTF-8", ascii, strlen (ascii), 0, ascii, ++ 0); ++ test_iconv ("ASCII//IGNORE", "UTF-8", ascii, strlen (ascii), 0, ascii, 0); ++ test_iconv ("ASCII//IGNORE//", "UTF-8", ascii, strlen (ascii), 0, ascii, 0); ++ ++ ++ /* 2. Valid UTF-8 input with non-ASCII characters: */ ++ ++ /* EILSEQ when converted to ASCII. */ ++ test_iconv ("ASCII", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, EILSEQ); ++ ++ /* Converted without error with TRANSLIT enabled. */ ++ test_iconv ("ASCII//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, u2a_translit, ++ 0); ++ ++ /* EILSEQ with IGNORE enabled. Non-ASCII chars dropped from output. */ ++ test_iconv ("ASCII//IGNORE", "UTF-8", utf8, strlen (utf8), (size_t) -1, ++ u2a_ignore, EILSEQ); ++ ++ /* With TRANSLIT and IGNORE enabled, transliterated without error. We test ++ four combinations. */ ++ ++ test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */ ++ test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ ++ /* Misspellings of TRANSLIT and IGNORE are ignored, but conversion still ++ works while respecting any other correctly spelled options. */ ++ ++ test_iconv ("ASCII//T", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, ++ EILSEQ); ++ test_iconv ("ASCII//TRANSLITERATE", "UTF-8", utf8, strlen (u2a), (size_t) -1, ++ u2a, EILSEQ); ++ test_iconv ("ASCII//I", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, ++ EILSEQ); ++ test_iconv ("ASCII//IGNORED", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, ++ EILSEQ); ++ test_iconv ("ASCII//TRANSLITERATE//IGNORED", "UTF-8", utf8, strlen (u2a), ++ (size_t) -1, u2a, EILSEQ); ++ test_iconv ("ASCII//IGNORED,TRANSLITERATE", "UTF-8", utf8, strlen (u2a), ++ (size_t) -1, u2a, EILSEQ); ++ test_iconv ("ASCII//T//I", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, ++ EILSEQ); ++ ++ test_iconv ("ASCII//TRANSLIT//I", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */ ++ test_iconv ("ASCII//I//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ test_iconv ("ASCII//IGNORED,TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ test_iconv ("ASCII//TRANSLIT,IGNORED", "UTF-8", utf8, strlen (utf8), 2, ++ u2a_translit, 0); ++ ++ test_iconv ("ASCII//IGNORE,T", "UTF-8", utf8, strlen (utf8), (size_t) -1, ++ u2a_ignore, EILSEQ); ++ test_iconv ("ASCII//T,IGNORE", "UTF-8", utf8, strlen (utf8), (size_t) -1, ++ u2a_ignore, EILSEQ); ++ /* Due to bug 19519, iconv was ignoring IGNORE for the following input. */ ++ test_iconv ("ASCII//TRANSLITERATE//IGNORE", "UTF-8", utf8, strlen (utf8), ++ (size_t) -1, u2a_ignore, EILSEQ); ++ test_iconv ("ASCII//IGNORE//TRANSLITERATE", "UTF-8", utf8, strlen (utf8), ++ (size_t) -1, u2a_ignore, EILSEQ); ++ ++ ++ /* 3. Invalid UTF-8 followed by some valid non-ASCII UTF-8 characters: */ ++ ++ /* EILSEQ; output is truncated at the first invalid UTF-8 character. */ ++ test_iconv ("ASCII", "UTF-8", iutf8, strlen (iu2a), (size_t) -1, iu2a, ++ EILSEQ); ++ ++ /* With TRANSLIT enabled: EILSEQ; output still truncated at the first invalid ++ UTF-8 character. */ ++ test_iconv ("ASCII//TRANSLIT", "UTF-8", iutf8, strlen (iu2a), (size_t) -1, ++ iu2a, EILSEQ); ++ ++ /* With IGNORE enabled: EILSEQ; output omits invalid UTF-8 characters and ++ valid UTF-8 non-ASCII characters. */ ++ test_iconv ("ASCII//IGNORE", "UTF-8", iutf8, strlen (iutf8), (size_t) -1, ++ iu2a_ignore, EILSEQ); ++ ++ /* With TRANSLIT and IGNORE enabled, output omits only invalid UTF-8 ++ characters and transliterates valid non-ASCII UTF-8 characters. We test ++ four combinations. */ ++ ++ test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", iutf8, strlen (iutf8), 2, ++ iu2a_both, 0); ++ /* Due to bug 19519, iconv was ignoring IGNORE for the following input. */ ++ test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", iutf8, strlen (iutf8), 2, ++ iu2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", iutf8, strlen (iutf8), 2, ++ iu2a_both, 0); ++ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */ ++ test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", iutf8, strlen (iutf8), 2, ++ iu2a_both, 0); ++ ++ ++ /* 4. Invalid UTF-8 with valid non-ASCII UTF-8 chars appearing first: */ ++ ++ /* EILSEQ; output is truncated at the first non-ASCII character. */ ++ test_iconv ("ASCII", "UTF-8", jutf8, strlen (ju2a), (size_t) -1, ju2a, ++ EILSEQ); ++ ++ /* With TRANSLIT enabled: EILSEQ; output now truncated at the first invalid ++ UTF-8 character. */ ++ test_iconv ("ASCII//TRANSLIT", "UTF-8", jutf8, strlen (jutf8) - 5, ++ (size_t) -1, ju2a_translit, EILSEQ); ++ test_iconv ("ASCII//translit", "UTF-8", jutf8, strlen (jutf8) - 5, ++ (size_t) -1, ju2a_translit, EILSEQ); ++ ++ /* With IGNORE enabled: EILSEQ; output omits invalid UTF-8 characters and ++ valid UTF-8 non-ASCII characters. */ ++ test_iconv ("ASCII//IGNORE", "UTF-8", jutf8, strlen (jutf8), (size_t) -1, ++ ju2a_ignore, EILSEQ); ++ test_iconv ("ASCII//ignore", "UTF-8", jutf8, strlen (jutf8), (size_t) -1, ++ ju2a_ignore, EILSEQ); ++ ++ /* With TRANSLIT and IGNORE enabled, output omits only invalid UTF-8 ++ characters and transliterates valid non-ASCII UTF-8 characters. We test ++ several combinations. */ ++ ++ test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ /* Due to bug 19519, iconv was ignoring IGNORE for the following input. */ ++ test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */ ++ test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//translit,ignore", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ /* Trailing whitespace and separators should be ignored. */ ++ test_iconv ("ASCII//IGNORE,TRANSLIT ", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT/", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT//", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT,", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT,,", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ test_iconv ("ASCII//IGNORE,TRANSLIT /,", "UTF-8", jutf8, strlen (jutf8), 2, ++ ju2a_both, 0); ++ ++ /* TRANSLIT or IGNORE suffixes in fromcode should be ignored. */ ++ test_iconv ("ASCII", "UTF-8//TRANSLIT", jutf8, strlen (ju2a), (size_t) -1, ++ ju2a, EILSEQ); ++ test_iconv ("ASCII", "UTF-8//IGNORE", jutf8, strlen (ju2a), (size_t) -1, ++ ju2a, EILSEQ); ++ test_iconv ("ASCII", "UTF-8//TRANSLIT,IGNORE", jutf8, strlen (ju2a), ++ (size_t) -1, ju2a, EILSEQ); ++ ++ ++ /* 5. Charset names of the form "A/B/": */ ++ ++ /* ISO-8859-1 is converted to UTF-8 without needing transliteration. */ ++ test_iconv ("ISO-10646/UTF-8", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8/", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8/IGNORE", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8//IGNORE", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8/TRANSLIT", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8//TRANSLIT", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8//TRANSLIT/IGNORE", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8//TRANSLIT//IGNORE", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ test_iconv ("ISO-10646/UTF-8/TRANSLIT,IGNORE", "ISO-8859-1", iso8859_1_a, ++ strlen (iso8859_1_a), 0, utf8_a, 0); ++ ++ /* UTF-8 with accented A's is converted to ASCII with transliteration. */ ++ test_iconv ("ASCII", "ISO-10646/UTF-8", utf8_a, ++ 0, (size_t) -1, empty, EILSEQ); ++ test_iconv ("ASCII//IGNORE", "ISO-10646/UTF-8", utf8_a, ++ strlen (utf8_a), (size_t) -1, empty, EILSEQ); ++ test_iconv ("ASCII//TRANSLIT", "ISO-10646/UTF-8", utf8_a, ++ strlen (utf8_a), 12, ascii_a, 0); ++ ++ /* Invalid ASCII is converted to UTF-8 only with IGNORE. */ ++ test_iconv ("ISO-10646/UTF-8", "ASCII", iascii, strlen (empty), (size_t) -1, ++ empty, EILSEQ); ++ test_iconv ("ISO-10646/UTF-8/TRANSLIT", "ASCII", iascii, strlen (empty), ++ (size_t) -1, empty, EILSEQ); ++ test_iconv ("ISO-10646/UTF-8/IGNORE", "ASCII", iascii, strlen (iascii), ++ (size_t) -1, ia2u_ignore, EILSEQ); ++ test_iconv ("ISO-10646/UTF-8/TRANSLIT,IGNORE", "ASCII", iascii, ++ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ); ++ /* Due to bug 19519, iconv was ignoring IGNORE for the following three ++ inputs: */ ++ test_iconv ("ISO-10646/UTF-8/TRANSLIT/IGNORE", "ASCII", iascii, ++ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ); ++ test_iconv ("ISO-10646/UTF-8//TRANSLIT,IGNORE", "ASCII", iascii, ++ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ); ++ test_iconv ("ISO-10646/UTF-8//TRANSLIT//IGNORE", "ASCII", iascii, ++ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ); ++ ++ return 0; ++} ++ ++#include +--- /dev/null ++++ b/iconv/tst-iconv_prog.sh +@@ -0,0 +1,280 @@ ++#!/bin/bash ++# Test for some known iconv(1) hangs from bug 19519, and miscellaneous ++# iconv(1) program error conditions. ++# Copyright (C) 2020 Free Software Foundation, Inc. ++# This file is part of the GNU C Library. ++ ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++ ++# The GNU C Library is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# Lesser General Public License for more details. ++ ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# . ++ ++codir=$1 ++test_wrapper_env="$2" ++run_program_env="$3" ++ ++# We have to have some directories in the library path. ++LIBPATH=$codir:$codir/iconvdata ++ ++# How the start the iconv(1) program. $from is not defined/expanded yet. ++ICONV=' ++$codir/elf/ld.so --library-path $LIBPATH --inhibit-rpath ${from}.so ++$codir/iconv/iconv_prog ++' ++ICONV="$test_wrapper_env $run_program_env $ICONV" ++ ++# List of known hangs; ++# Gathered by running an exhaustive 2 byte input search against glibc-2.28 ++hangarray=( ++"\x00\x23;-c;ANSI_X3.110;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa1;-c;ARMSCII-8;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa1;-c;ASMO_449;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;BIG5;UTF-8//TRANSLIT//IGNORE" ++"\x00\xff;-c;BIG5HKSCS;UTF-8//TRANSLIT//IGNORE" ++"\x00\xff;-c;BRF;UTF-8//TRANSLIT//IGNORE" ++"\x00\xff;-c;BS_4730;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1250;UTF-8//TRANSLIT//IGNORE" ++"\x00\x98;-c;CP1251;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1252;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1253;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1254;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1255;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1257;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;CP1258;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;CP932;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;CSA_Z243.4-1985-1;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;CSA_Z243.4-1985-2;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;DEC-MCS;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;DIN_66003;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;DS_2089;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-AT-DE;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-AT-DE-A;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-CA-FR;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-DK-NO;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-DK-NO-A;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-ES;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-ES-A;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-ES-S;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-FI-SE;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-FI-SE-A;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-FR;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-IS-FRISS;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-IT;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-PT;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-UK;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;EBCDIC-US;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ES;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ES2;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-CN;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-JISX0213;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-JP;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-JP-MS;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-KR;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;EUC-TW;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GB18030;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GB_1988-80;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GBK;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GOST_19768-74;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GREEK7;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GREEK7-OLD;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;GREEK-CCITT;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;HP-GREEK8;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;HP-ROMAN8;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;HP-ROMAN9;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;HP-THAI8;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;HP-TURKISH8;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM038;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM1004;UTF-8//TRANSLIT//IGNORE" ++"\x00\xff;-c;IBM1008;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;IBM1046;UTF-8//TRANSLIT//IGNORE" ++"\x00\x51;-c;IBM1132;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa0;-c;IBM1133;UTF-8//TRANSLIT//IGNORE" ++"\x00\xce;-c;IBM1137;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE" ++"\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE" ++"\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE" ++# These are known hangs that are yet to be fixed: ++# "\x00\x0f;-c;IBM1364;UTF-8" ++# "\x00\x0f;-c;IBM1371;UTF-8" ++# "\x00\x0f;-c;IBM1388;UTF-8" ++# "\x00\x0f;-c;IBM1390;UTF-8" ++# "\x00\x0f;-c;IBM1399;UTF-8" ++"\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM281;UTF-8//TRANSLIT//IGNORE" ++"\x00\x57;-c;IBM290;UTF-8//TRANSLIT//IGNORE" ++"\x00\x45;-c;IBM420;UTF-8//TRANSLIT//IGNORE" ++"\x00\x68;-c;IBM423;UTF-8//TRANSLIT//IGNORE" ++"\x00\x70;-c;IBM424;UTF-8//TRANSLIT//IGNORE" ++"\x00\x53;-c;IBM4517;UTF-8//TRANSLIT//IGNORE" ++"\x00\x53;-c;IBM4899;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa5;-c;IBM4909;UTF-8//TRANSLIT//IGNORE" ++"\x00\xdc;-c;IBM4971;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM803;UTF-8//TRANSLIT//IGNORE" ++"\x00\x91;-c;IBM851;UTF-8//TRANSLIT//IGNORE" ++"\x00\x9b;-c;IBM856;UTF-8//TRANSLIT//IGNORE" ++"\x00\xd5;-c;IBM857;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;IBM864;UTF-8//TRANSLIT//IGNORE" ++"\x00\x94;-c;IBM868;UTF-8//TRANSLIT//IGNORE" ++"\x00\x94;-c;IBM869;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;IBM874;UTF-8//TRANSLIT//IGNORE" ++"\x00\x6a;-c;IBM875;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM880;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM891;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;IBM903;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;IBM904;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM905;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM9066;UTF-8//TRANSLIT//IGNORE" ++"\x00\x48;-c;IBM918;UTF-8//TRANSLIT//IGNORE" ++"\x00\x57;-c;IBM930;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM932;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM933;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM935;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM937;UTF-8//TRANSLIT//IGNORE" ++"\x00\x41;-c;IBM939;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IBM943;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;INIS;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;INIS-8;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;INIS-CYRILLIC;UTF-8//TRANSLIT//IGNORE" ++"\x00\xec;-c;ISIRI-3342;UTF-8//TRANSLIT//IGNORE" ++"\x00\xec;-c;ISO_10367-BOX;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-CN;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-CN-EXT;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-JP;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-JP-2;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-JP-3;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-2022-KR;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO_2033;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO_5427;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO_5427-EXT;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO_5428;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa4;-c;ISO_6937;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa0;-c;ISO_6937-2;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-8859-11;UTF-8//TRANSLIT//IGNORE" ++"\x00\xa5;-c;ISO-8859-3;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-8859-6;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-8859-7;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;ISO-8859-8;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;ISO-IR-197;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;ISO-IR-209;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;IT;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;JIS_C6220-1969-RO;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;JIS_C6229-1984-B;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;JOHAB;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;JUS_I.B1.002;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;KOI-8;UTF-8//TRANSLIT//IGNORE" ++"\x00\x88;-c;KOI8-T;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;KSC5636;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;LATIN-GREEK;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;LATIN-GREEK-1;UTF-8//TRANSLIT//IGNORE" ++"\x00\xf6;-c;MAC-IS;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;MSZ_7795.3;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NATS-DANO;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NATS-SEFI;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NC_NC00-10;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NF_Z_62-010;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NF_Z_62-010_1973;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NS_4551-1;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;NS_4551-2;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;PT;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;PT2;UTF-8//TRANSLIT//IGNORE" ++"\x00\x98;-c;RK1048;UTF-8//TRANSLIT//IGNORE" ++"\x00\x98;-c;SEN_850200_B;UTF-8//TRANSLIT//IGNORE" ++"\x00\x98;-c;SEN_850200_C;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;Shift_JISX0213;UTF-8//TRANSLIT//IGNORE" ++"\x00\x80;-c;SJIS;UTF-8//TRANSLIT//IGNORE" ++"\x00\x23;-c;T.61-8BIT;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;TIS-620;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;TSCII;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;UHC;UTF-8//TRANSLIT//IGNORE" ++"\x00\xd8;-c;UNICODE;UTF-8//TRANSLIT//IGNORE" ++"\x00\xdc;-c;UTF-16;UTF-8//TRANSLIT//IGNORE" ++"\xdc\x00;-c;UTF-16BE;UTF-8//TRANSLIT//IGNORE" ++"\x00\xdc;-c;UTF-16LE;UTF-8//TRANSLIT//IGNORE" ++"\xff\xff;-c;UTF-7;UTF-8//TRANSLIT//IGNORE" ++"\x00\x81;-c;WIN-SAMI-2;UTF-8//TRANSLIT//IGNORE" ++) ++ ++# List of option combinations that *should* lead to an error ++errorarray=( ++# Converting from/to invalid character sets should cause error ++"\x00\x00;;INVALID;INVALID" ++"\x00\x00;;INVALID;UTF-8" ++"\x00\x00;;UTF-8;INVALID" ++) ++ ++# Requires $twobyte input, $c flag, $from, and $to to be set; sets $ret ++execute_test () ++{ ++ eval PROG=\"$ICONV\" ++ echo -en "$twobyte" \ ++ | timeout -k 4 3 $PROG $c -f $from -t "$to" &>/dev/null ++ ret=$? ++} ++ ++check_hangtest_result () ++{ ++ if [ "$ret" -eq "124" ] || [ "$ret" -eq "137" ]; then # timeout/hang ++ result="HANG" ++ else ++ if [ "$ret" -eq "139" ]; then # segfault ++ result="SEGFAULT" ++ else ++ if [ "$ret" -gt "127" ]; then # unexpected error ++ result="UNEXPECTED" ++ else ++ result="OK" ++ fi ++ fi ++ fi ++ ++ echo -n "$result: from: \"$from\", to: \"$to\"," ++ echo " input \"$twobyte\", flags \"$c\"" ++ ++ if [ "$result" != "OK" ]; then ++ exit 1 ++ fi ++} ++ ++for hangcommand in "${hangarray[@]}"; do ++ twobyte="$(echo "$hangcommand" | cut -d";" -f 1)" ++ c="$(echo "$hangcommand" | cut -d";" -f 2)" ++ from="$(echo "$hangcommand" | cut -d";" -f 3)" ++ to="$(echo "$hangcommand" | cut -d";" -f 4)" ++ execute_test ++ check_hangtest_result ++done ++ ++check_errtest_result () ++{ ++ if [ "$ret" -eq "1" ]; then # we errored out as expected ++ result="PASS" ++ else ++ result="FAIL" ++ fi ++ echo -n "$result: from: \"$from\", to: \"$to\"," ++ echo " input \"$twobyte\", flags \"$c\", return code $ret" ++ ++ if [ "$result" != "PASS" ]; then ++ exit 1 ++ fi ++} ++ ++for errorcommand in "${errorarray[@]}"; do ++ twobyte="$(echo "$errorcommand" | cut -d";" -f 1)" ++ c="$(echo "$errorcommand" | cut -d";" -f 2)" ++ from="$(echo "$errorcommand" | cut -d";" -f 3)" ++ to="$(echo "$errorcommand" | cut -d";" -f 4)" ++ execute_test ++ check_errtest_result ++done +--- a/intl/dcigettext.c ++++ b/intl/dcigettext.c +@@ -1120,11 +1120,16 @@ _nl_find_msg (struct loaded_l10nfile *do + outcharset = encoding; + + # ifdef _LIBC +- /* We always want to use transliteration. */ +- outcharset = norm_add_slashes (outcharset, "TRANSLIT"); +- charset = norm_add_slashes (charset, ""); +- int r = __gconv_open (outcharset, charset, &convd->conv, +- GCONV_AVOID_NOCONV); ++ ++ struct gconv_spec conv_spec ++ = { .fromcode = norm_add_slashes (charset, ""), ++ .tocode = norm_add_slashes (outcharset, ""), ++ /* We always want to use transliteration. */ ++ .translit = true, ++ .ignore = false ++ }; ++ int r = __gconv_open (&conv_spec, &convd->conv, ++ GCONV_AVOID_NOCONV); + if (__builtin_expect (r != __GCONV_OK, 0)) + { + /* If the output encoding is the same there is diff -Nru glibc-2.27/debian/patches/any/CVE-2016-10228-2.patch glibc-2.27/debian/patches/any/CVE-2016-10228-2.patch --- glibc-2.27/debian/patches/any/CVE-2016-10228-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2016-10228-2.patch 2022-01-24 12:53:44.000000000 +0000 @@ -0,0 +1,224 @@ +Backport of: + +From 7d4ec75e111291851620c6aa2c4460647b7fd50d Mon Sep 17 00:00:00 2001 +From: Arjun Shankar +Date: Fri, 25 Sep 2020 14:47:06 +0200 +Subject: [PATCH] intl: Handle translation output codesets with suffixes [BZ + #26383] + +Commit 91927b7c7643 (Rewrite iconv option parsing [BZ #19519]) did not +handle cases where the output codeset for translations (via the `gettext' +family of functions) might have a caller specified encoding suffix such as +TRANSLIT or IGNORE. This led to a regression where translations did not +work when the codeset had a suffix. + +This commit fixes the above issue by parsing any suffixes passed to +__dcigettext and adds two new test-cases to intl/tst-codeset.c to +verify correct behaviour. The iconv-internal function __gconv_create_spec +and the static iconv-internal function gconv_destroy_spec are now visible +internally within glibc and used in intl/dcigettext.c. +--- + iconv/Versions | 4 +++- + iconv/gconv_charset.c | 10 ++++++++++ + iconv/gconv_charset.h | 27 --------------------------- + iconv/gconv_int.h | 21 +++++++++++++++++++++ + iconv/iconv_open.c | 2 +- + iconv/iconv_prog.c | 2 +- + intl/dcigettext.c | 17 ++++++++++------- + intl/tst-codeset.c | 34 ++++++++++++++-------------------- + 8 files changed, 60 insertions(+), 57 deletions(-) + +--- a/iconv/Versions ++++ b/iconv/Versions +@@ -6,7 +6,9 @@ libc { + GLIBC_PRIVATE { + # functions shared with iconv program + __gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db; +- __gconv_open; __gconv_create_spec; ++ ++ # functions used elsewhere in glibc ++ __gconv_open; __gconv_create_spec; __gconv_destroy_spec; + + # function used by the gconv modules + __gconv_transliterate; +--- a/iconv/gconv_charset.c ++++ b/iconv/gconv_charset.c +@@ -216,3 +216,13 @@ out: + return ret; + } + libc_hidden_def (__gconv_create_spec) ++ ++ ++void ++__gconv_destroy_spec (struct gconv_spec *conv_spec) ++{ ++ free (conv_spec->fromcode); ++ free (conv_spec->tocode); ++ return; ++} ++libc_hidden_def (__gconv_destroy_spec) +--- a/iconv/gconv_charset.h ++++ b/iconv/gconv_charset.h +@@ -48,33 +48,6 @@ + #define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE" + + +-/* This function accepts the charset names of the source and destination of the +- conversion and populates *conv_spec with an equivalent conversion +- specification that may later be used by __gconv_open. The charset names +- might contain options in the form of suffixes that alter the conversion, +- e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring +- and truncating any suffix options in fromcode, and processing and truncating +- any suffix options in tocode. Supported suffix options ("TRANSLIT" or +- "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec +- to be set to true. Unrecognized suffix options are silently discarded. If +- the function succeeds, it returns conv_spec back to the caller. It returns +- NULL upon failure. */ +-struct gconv_spec * +-__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, +- const char *tocode); +-libc_hidden_proto (__gconv_create_spec) +- +- +-/* This function frees all heap memory allocated by __gconv_create_spec. */ +-static void __attribute__ ((unused)) +-gconv_destroy_spec (struct gconv_spec *conv_spec) +-{ +- free (conv_spec->fromcode); +- free (conv_spec->tocode); +- return; +-} +- +- + /* This function copies in-order, characters from the source 's' that are + either alpha-numeric or one in one of these: "_-.,:/" - into the destination + 'wp' while dropping all other characters. In the process, it converts all +--- a/iconv/gconv_int.h ++++ b/iconv/gconv_int.h +@@ -170,6 +170,27 @@ extern int __gconv_open (struct gconv_sp + __gconv_t *handle, int flags); + libc_hidden_proto (__gconv_open) + ++/* This function accepts the charset names of the source and destination of the ++ conversion and populates *conv_spec with an equivalent conversion ++ specification that may later be used by __gconv_open. The charset names ++ might contain options in the form of suffixes that alter the conversion, ++ e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring ++ and truncating any suffix options in fromcode, and processing and truncating ++ any suffix options in tocode. Supported suffix options ("TRANSLIT" or ++ "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec ++ to be set to true. Unrecognized suffix options are silently discarded. If ++ the function succeeds, it returns conv_spec back to the caller. It returns ++ NULL upon failure. */ ++extern struct gconv_spec * ++__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode, ++ const char *tocode); ++libc_hidden_proto (__gconv_create_spec) ++ ++/* This function frees all heap memory allocated by __gconv_create_spec. */ ++extern void ++__gconv_destroy_spec (struct gconv_spec *conv_spec); ++libc_hidden_proto (__gconv_destroy_spec) ++ + /* Free resources associated with transformation descriptor CD. */ + extern int __gconv_close (__gconv_t cd) + attribute_hidden; +--- a/iconv/iconv_open.c ++++ b/iconv/iconv_open.c +@@ -39,7 +39,7 @@ iconv_open (const char *tocode, const ch + + int res = __gconv_open (&conv_spec, &cd, 0); + +- gconv_destroy_spec (&conv_spec); ++ __gconv_destroy_spec (&conv_spec); + + if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK) + { +--- a/iconv/iconv_prog.c ++++ b/iconv/iconv_prog.c +@@ -184,7 +184,7 @@ main (int argc, char *argv[]) + /* Let's see whether we have these coded character sets. */ + res = __gconv_open (&conv_spec, &cd, 0); + +- gconv_destroy_spec (&conv_spec); ++ __gconv_destroy_spec (&conv_spec); + + if (res != __GCONV_OK) + { +--- a/intl/dcigettext.c ++++ b/intl/dcigettext.c +@@ -1121,15 +1121,18 @@ _nl_find_msg (struct loaded_l10nfile *do + + # ifdef _LIBC + +- struct gconv_spec conv_spec +- = { .fromcode = norm_add_slashes (charset, ""), +- .tocode = norm_add_slashes (outcharset, ""), +- /* We always want to use transliteration. */ +- .translit = true, +- .ignore = false +- }; ++ struct gconv_spec conv_spec; ++ ++ __gconv_create_spec (&conv_spec, charset, outcharset); ++ ++ /* We always want to use transliteration. */ ++ conv_spec.translit = true; ++ + int r = __gconv_open (&conv_spec, &convd->conv, + GCONV_AVOID_NOCONV); ++ ++ __gconv_destroy_spec (&conv_spec); ++ + if (__builtin_expect (r != __GCONV_OK, 0)) + { + /* If the output encoding is the same there is +--- a/intl/tst-codeset.c ++++ b/intl/tst-codeset.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + static int + do_test (void) +@@ -43,9 +44,8 @@ do_test (void) + result = 1; + } + +- bind_textdomain_codeset ("codeset", "UTF-8"); +- + /* Here we expect output in UTF-8. */ ++ bind_textdomain_codeset ("codeset", "UTF-8"); + s = gettext ("cheese"); + if (strcmp (s, "K\303\244se")) + { +@@ -53,8 +53,25 @@ do_test (void) + result = 1; + } + ++ /* `a with umlaut' is transliterated to `ae'. */ ++ bind_textdomain_codeset ("codeset", "ASCII//TRANSLIT"); ++ s = gettext ("cheese"); ++ if (strcmp (s, "Kaese")) ++ { ++ printf ("call 3 returned: %s\n", s); ++ result = 1; ++ } ++ ++ /* Transliteration also works by default even if not set. */ ++ bind_textdomain_codeset ("codeset", "ASCII"); ++ s = gettext ("cheese"); ++ if (strcmp (s, "Kaese")) ++ { ++ printf ("call 4 returned: %s\n", s); ++ result = 1; ++ } ++ + return result; + } + +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include diff -Nru glibc-2.27/debian/patches/any/CVE-2016-10228-pre1.patch glibc-2.27/debian/patches/any/CVE-2016-10228-pre1.patch --- glibc-2.27/debian/patches/any/CVE-2016-10228-pre1.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2016-10228-pre1.patch 2022-01-24 12:53:44.000000000 +0000 @@ -0,0 +1,65 @@ +From cce35a50c1de0cec5cd1f6c18979ff6ee3ea1dd1 Mon Sep 17 00:00:00 2001 +From: Arjun Shankar +Date: Mon, 11 Nov 2019 14:57:23 +0100 +Subject: [PATCH] support: Add xsetlocale function + +--- + support/Makefile | 1 + + support/support.h | 1 + + support/xsetlocale.c | 30 ++++++++++++++++++++++++++++++ + 3 files changed, 32 insertions(+) + create mode 100644 support/xsetlocale.c + +--- a/support/Makefile ++++ b/support/Makefile +@@ -136,6 +136,7 @@ libsupport-routines = \ + xrealloc \ + xrecvfrom \ + xsendto \ ++ xsetlocale \ + xsetsockopt \ + xsigaction \ + xsignal \ +--- a/support/support.h ++++ b/support/support.h +@@ -80,6 +80,7 @@ char *xasprintf (const char *format, ... + __attribute__ ((format (printf, 1, 2), malloc)); + char *xstrdup (const char *); + char *xstrndup (const char *, size_t); ++char *xsetlocale (int category, const char *locale); + + __END_DECLS + +--- /dev/null ++++ b/support/xsetlocale.c +@@ -0,0 +1,30 @@ ++/* setlocale with error checking. ++ Copyright (C) 2019 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 ++ ++char * ++xsetlocale (int category, const char *locale) ++{ ++ char *p = setlocale (category, locale); ++ if (p == NULL) ++ FAIL_EXIT1 ("error: setlocale (%d, \"%s\")\n", category, locale); ++ return p; ++} diff -Nru glibc-2.27/debian/patches/any/CVE-2018-11236.patch glibc-2.27/debian/patches/any/CVE-2018-11236.patch --- glibc-2.27/debian/patches/any/CVE-2018-11236.patch 2019-07-03 12:05:39.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2018-11236.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,166 +0,0 @@ -From f19e67884c55c2dac6db3b146d80a769e322ecbe Mon Sep 17 00:00:00 2001 -From: Paul Pluzhnikov -Date: Tue, 8 May 2018 18:12:41 -0700 -Subject: [PATCH] Fix path length overflow in realpath [BZ #22786] - -Integer addition overflow may cause stack buffer overflow -when realpath() input length is close to SSIZE_MAX. - -2018-05-09 Paul Pluzhnikov - - [BZ #22786] - * stdlib/canonicalize.c (__realpath): Fix overflow in path length - computation. - * stdlib/Makefile (test-bz22786): New test. - * stdlib/test-bz22786.c: New test. - -(cherry picked from commit 5460617d1567657621107d895ee2dd83bc1f88f2) ---- - ChangeLog | 8 +++++ - stdlib/Makefile | 2 +- - stdlib/canonicalize.c | 2 +- - stdlib/test-bz22786.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 100 insertions(+), 2 deletions(-) - create mode 100644 stdlib/test-bz22786.c - -#diff --git a/ChangeLog b/ChangeLog -#index 14063a1..1419e89 100644 -#--- a/ChangeLog -#+++ b/ChangeLog -#@@ -1,3 +1,11 @@ -#+2018-05-09 Paul Pluzhnikov -#+ -#+ [BZ #22786] -#+ * stdlib/canonicalize.c (__realpath): Fix overflow in path length -#+ computation. -#+ * stdlib/Makefile (test-bz22786): New test. -#+ * stdlib/test-bz22786.c: New test. -#+ -# 2018-05-05 Paul Pluzhnikov -# -# [BZ #20419] -diff --git a/stdlib/Makefile b/stdlib/Makefile -index 7c363a6..a9ad849 100644 ---- a/stdlib/Makefile -+++ b/stdlib/Makefile -@@ -84,7 +84,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ - tst-cxa_atexit tst-on_exit test-atexit-race \ - test-at_quick_exit-race test-cxa_atexit-race \ - test-on_exit-race test-dlclose-exit-race \ -- tst-makecontext-align -+ tst-makecontext-align test-bz22786 - - tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ - tst-tls-atexit tst-tls-atexit-nodelete -diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c -index 30825a9..432fc82 100644 ---- a/stdlib/canonicalize.c -+++ b/stdlib/canonicalize.c -@@ -181,7 +181,7 @@ __realpath (const char *name, char *resolved) - extra_buf = __alloca (path_max); - - len = strlen (end); -- if ((long int) (n + len) >= path_max) -+ if (path_max - n <= len) - { - __set_errno (ENAMETOOLONG); - goto error; -diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c -new file mode 100644 -index 0000000..e7837f9 ---- /dev/null -+++ b/stdlib/test-bz22786.c -@@ -0,0 +1,90 @@ -+/* Bug 22786: test for buffer overflow in realpath. -+ Copyright (C) 2018 Free Software Foundation, Inc. -+ This file is part of the GNU C Library. -+ -+ The GNU C Library is free software; you can redistribute it and/or -+ modify it under the terms of the GNU Lesser General Public -+ License as published by the Free Software Foundation; either -+ version 2.1 of the License, or (at your option) any later version. -+ -+ The GNU C Library is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ Lesser General Public License for more details. -+ -+ You should have received a copy of the GNU Lesser General Public -+ License along with the GNU C Library; if not, see -+ . */ -+ -+/* This file must be run from within a directory called "stdlib". */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int -+do_test (void) -+{ -+ const char dir[] = "bz22786"; -+ const char lnk[] = "bz22786/symlink"; -+ -+ rmdir (dir); -+ if (mkdir (dir, 0755) != 0 && errno != EEXIST) -+ { -+ printf ("mkdir %s: %m\n", dir); -+ return EXIT_FAILURE; -+ } -+ if (symlink (".", lnk) != 0 && errno != EEXIST) -+ { -+ printf ("symlink (%s, %s): %m\n", dir, lnk); -+ return EXIT_FAILURE; -+ } -+ -+ const size_t path_len = (size_t) INT_MAX + 1; -+ -+ DIAG_PUSH_NEEDS_COMMENT; -+#if __GNUC_PREREQ (7, 0) -+ /* GCC 7 warns about too-large allocations; here we need such -+ allocation to succeed for the test to work. */ -+ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); -+#endif -+ char *path = malloc (path_len); -+ DIAG_POP_NEEDS_COMMENT; -+ -+ if (path == NULL) -+ { -+ printf ("malloc (%zu): %m\n", path_len); -+ return EXIT_UNSUPPORTED; -+ } -+ -+ /* Construct very long path = "bz22786/symlink/aaaa....." */ -+ char *p = mempcpy (path, lnk, sizeof (lnk) - 1); -+ *(p++) = '/'; -+ memset (p, 'a', path_len - (path - p) - 2); -+ p[path_len - (path - p) - 1] = '\0'; -+ -+ /* This call crashes before the fix for bz22786 on 32-bit platforms. */ -+ p = realpath (path, NULL); -+ -+ if (p != NULL || errno != ENAMETOOLONG) -+ { -+ printf ("realpath: %s (%m)", p); -+ return EXIT_FAILURE; -+ } -+ -+ /* Cleanup. */ -+ unlink (lnk); -+ rmdir (dir); -+ -+ return 0; -+} -+ -+#define TEST_FUNCTION do_test -+#include --- -2.9.3 - diff -Nru glibc-2.27/debian/patches/any/CVE-2018-11237-1.patch glibc-2.27/debian/patches/any/CVE-2018-11237-1.patch --- glibc-2.27/debian/patches/any/CVE-2018-11237-1.patch 2019-07-03 12:05:45.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2018-11237-1.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -From 9aaaab7c6e4176e61c59b0a63c6ba906d875dc0e Mon Sep 17 00:00:00 2001 -From: Andreas Schwab -Date: Tue, 22 May 2018 10:37:59 +0200 -Subject: [PATCH] Don't write beyond destination in - __mempcpy_avx512_no_vzeroupper (bug 23196) - -When compiled as mempcpy, the return value is the end of the destination -buffer, thus it cannot be used to refer to the start of it. ---- - ChangeLog | 9 +++++++++ - string/test-mempcpy.c | 1 + - sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S | 5 +++-- - 3 files changed, 13 insertions(+), 2 deletions(-) - -#diff --git a/ChangeLog b/ChangeLog -#index 252b099..8032adf 100644 -#--- a/ChangeLog -#+++ b/ChangeLog -#@@ -1,3 +1,12 @@ -#+2018-05-23 Andreas Schwab -#+ -#+ [BZ #23196] -#+ CVE-2018-11237 -#+ * sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S -#+ (L(preloop_large)): Save initial destination pointer in %r11 and -#+ use it instead of %rax after the loop. -#+ * string/test-mempcpy.c (MIN_PAGE_SIZE): Define. -#+ -# 2018-05-22 Joseph Myers -# -# * sysdeps/aarch64/Implies: Remove aarch64/soft-fp. -diff --git a/string/test-mempcpy.c b/string/test-mempcpy.c -index c08fba8..d98ecdd 100644 ---- a/string/test-mempcpy.c -+++ b/string/test-mempcpy.c -@@ -18,6 +18,7 @@ - . */ - - #define MEMCPY_RESULT(dst, len) (dst) + (len) -+#define MIN_PAGE_SIZE 131072 - #define TEST_MAIN - #define TEST_NAME "mempcpy" - #include "test-string.h" -diff --git a/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S b/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S -index 23c0f7a..effc3ac 100644 ---- a/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S -+++ b/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S -@@ -336,6 +336,7 @@ L(preloop_large): - vmovups (%rsi), %zmm4 - vmovups 0x40(%rsi), %zmm5 - -+ mov %rdi, %r11 - /* Align destination for access with non-temporal stores in the loop. */ - mov %rdi, %r8 - and $-0x80, %rdi -@@ -366,8 +367,8 @@ L(gobble_256bytes_nt_loop): - cmp $256, %rdx - ja L(gobble_256bytes_nt_loop) - sfence -- vmovups %zmm4, (%rax) -- vmovups %zmm5, 0x40(%rax) -+ vmovups %zmm4, (%r11) -+ vmovups %zmm5, 0x40(%r11) - jmp L(check) - - L(preloop_large_bkw): --- -2.9.3 - diff -Nru glibc-2.27/debian/patches/any/CVE-2018-11237-2.patch glibc-2.27/debian/patches/any/CVE-2018-11237-2.patch --- glibc-2.27/debian/patches/any/CVE-2018-11237-2.patch 2019-07-03 12:05:49.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2018-11237-2.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -From ed983107bbc62245b06b99f02e69acf36a0baa3e Mon Sep 17 00:00:00 2001 -From: "H.J. Lu" -Date: Wed, 23 May 2018 03:59:56 -0700 -Subject: [PATCH] Add a test case for [BZ #23196] - - [BZ #23196] - * string/test-memcpy.c (do_test1): New function. - (test_main): Call it. ---- - ChangeLog | 6 ++++++ - string/test-memcpy.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 53 insertions(+) - -#diff --git a/ChangeLog b/ChangeLog -#index 8032adf..8e69700 100644 -#--- a/ChangeLog -#+++ b/ChangeLog -#@@ -1,3 +1,9 @@ -#+2018-05-23 H.J. Lu -#+ -#+ [BZ #23196] -#+ * string/test-memcpy.c (do_test1): New function. -#+ (test_main): Call it. -#+ -# 2018-05-23 Andreas Schwab -# -# [BZ #23196] -diff --git a/string/test-memcpy.c b/string/test-memcpy.c -index 45f20a6..3c8066d 100644 ---- a/string/test-memcpy.c -+++ b/string/test-memcpy.c -@@ -212,6 +212,50 @@ do_random_tests (void) - } - } - -+static void -+do_test1 (void) -+{ -+ size_t size = 0x100000; -+ void *large_buf; -+ -+ large_buf = mmap (NULL, size * 2 + page_size, PROT_READ | PROT_WRITE, -+ MAP_PRIVATE | MAP_ANON, -1, 0); -+ if (large_buf == MAP_FAILED) -+ { -+ puts ("Failed to allocat large_buf, skipping do_test1"); -+ return; -+ } -+ -+ if (mprotect (large_buf + size, page_size, PROT_NONE)) -+ error (EXIT_FAILURE, errno, "mprotect failed"); -+ -+ size_t arrary_size = size / sizeof (uint32_t); -+ uint32_t *dest = large_buf; -+ uint32_t *src = large_buf + size + page_size; -+ size_t i; -+ -+ for (i = 0; i < arrary_size; i++) -+ src[i] = (uint32_t) i; -+ -+ FOR_EACH_IMPL (impl, 0) -+ { -+ memset (dest, -1, size); -+ CALL (impl, (char *) dest, (char *) src, size); -+ for (i = 0; i < arrary_size; i++) -+ if (dest[i] != src[i]) -+ { -+ error (0, 0, -+ "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"", -+ impl->name, dest, src, i); -+ ret = 1; -+ break; -+ } -+ } -+ -+ munmap ((void *) dest, size); -+ munmap ((void *) src, size); -+} -+ - int - test_main (void) - { -@@ -253,6 +297,9 @@ test_main (void) - do_test (0, 0, getpagesize ()); - - do_random_tests (); -+ -+ do_test1 (); -+ - return ret; - } - --- -2.9.3 - diff -Nru glibc-2.27/debian/patches/any/CVE-2018-19591.patch glibc-2.27/debian/patches/any/CVE-2018-19591.patch --- glibc-2.27/debian/patches/any/CVE-2018-19591.patch 2019-07-03 12:05:55.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2018-19591.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -From 9f433fc791ca4f9d678903ff45b504b524c886fb Mon Sep 17 00:00:00 2001 -From: Florian Weimer -Date: Tue, 27 Nov 2018 16:12:43 +0100 -Subject: [PATCH] CVE-2018-19591: if_nametoindex: Fix descriptor for overlong - name [BZ #23927] - -(cherry picked from commit d527c860f5a3f0ed687bd03f0cb464612dc23408) ---- - ChangeLog | 7 +++++++ - NEWS | 5 +++++ - sysdeps/unix/sysv/linux/if_index.c | 11 ++++++----- - 3 files changed, 18 insertions(+), 5 deletions(-) - -#diff --git a/ChangeLog b/ChangeLog -#index f150dbd..2f1e82b 100644 -#--- a/ChangeLog -#+++ b/ChangeLog -#@@ -1,3 +1,10 @@ -#+2018-11-27 Florian Weimer -#+ -#+ [BZ #23927] -#+ CVE-2018-19591 -#+ * sysdeps/unix/sysv/linux/if_index.c (__if_nametoindex): Avoid -#+ descriptor leak in case of ENODEV error. -#+ -# 2018-11-08 Alexandra Hájková -# -# [BZ #17630] -#diff --git a/NEWS b/NEWS -#index 5fef60b..e1a23f0 100644 -#--- a/NEWS -#+++ b/NEWS -#@@ -37,6 +37,10 @@ Security related changes: -# architecture could write beyond the target buffer, resulting in a buffer -# overflow. Reported by Andreas Schwab. -# -#+ CVE-2018-19591: A file descriptor leak in if_nametoindex can lead to a -#+ denial of service due to resource exhaustion when processing getaddrinfo -#+ calls with crafted host names. Reported by Guido Vranken. -#+ -# The following bugs are resolved with this release: -# -# [6889] 'PWD' mentioned but not specified -#@@ -97,6 +101,7 @@ The following bugs are resolved with this release: -# [23709] Fix CPU string flags for Haswell-type CPUs -# [23821] si_band in siginfo_t has wrong type long int on sparc64 -# [23822] ia64 static libm.a is missing exp2f, log2f and powf symbols -#+ [23927] Linux if_nametoindex() does not close descriptor (CVE-2018-19591) -# -# -# Version 2.27 -diff --git a/sysdeps/unix/sysv/linux/if_index.c b/sysdeps/unix/sysv/linux/if_index.c -index e3d0898..782fc5e 100644 ---- a/sysdeps/unix/sysv/linux/if_index.c -+++ b/sysdeps/unix/sysv/linux/if_index.c -@@ -38,11 +38,6 @@ __if_nametoindex (const char *ifname) - return 0; - #else - struct ifreq ifr; -- int fd = __opensock (); -- -- if (fd < 0) -- return 0; -- - if (strlen (ifname) >= IFNAMSIZ) - { - __set_errno (ENODEV); -@@ -50,6 +45,12 @@ __if_nametoindex (const char *ifname) - } - - strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); -+ -+ int fd = __opensock (); -+ -+ if (fd < 0) -+ return 0; -+ - if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0) - { - int saved_errno = errno; --- -2.9.3 - diff -Nru glibc-2.27/debian/patches/any/CVE-2019-25013.patch glibc-2.27/debian/patches/any/CVE-2019-25013.patch --- glibc-2.27/debian/patches/any/CVE-2019-25013.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2019-25013.patch 2022-01-24 12:48:32.000000000 +0000 @@ -0,0 +1,122 @@ +Backport of: + +From ee7a3144c9922808181009b7b3e50e852fb4999b Mon Sep 17 00:00:00 2001 +From: Andreas Schwab +Date: Mon, 21 Dec 2020 08:56:43 +0530 +Subject: [PATCH] Fix buffer overrun in EUC-KR conversion module (bz #24973) + +The byte 0xfe as input to the EUC-KR conversion denotes a user-defined +area and is not allowed. The from_euc_kr function used to skip two bytes +when told to skip over the unknown designation, potentially running over +the buffer end. +--- + iconvdata/Makefile | 3 ++- + iconvdata/bug-iconv13.c | 53 +++++++++++++++++++++++++++++++++++++++++ + iconvdata/euc-kr.c | 6 +---- + iconvdata/ksc5601.h | 6 ++--- + 4 files changed, 59 insertions(+), 9 deletions(-) + create mode 100644 iconvdata/bug-iconv13.c + +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -73,7 +73,7 @@ modules.so := $(addsuffix .so, $(modules + ifeq (yes,$(build-shared)) + tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ + tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ +- bug-iconv10 bug-iconv11 bug-iconv12 ++ bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 + ifeq ($(have-thread-library),yes) + tests += bug-iconv3 + endif +--- /dev/null ++++ b/iconvdata/bug-iconv13.c +@@ -0,0 +1,53 @@ ++/* bug 24973: Test EUC-KR module ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ iconv_t cd = iconv_open ("UTF-8//IGNORE", "EUC-KR"); ++ TEST_VERIFY_EXIT (cd != (iconv_t) -1); ++ ++ /* 0xfe (->0x7e : row 94) and 0xc9 (->0x49 : row 41) are user-defined ++ areas, which are not allowed and should be skipped over due to ++ //IGNORE. The trailing 0xfe also is an incomplete sequence, which ++ should be checked first. */ ++ char input[4] = { '\xc9', '\xa1', '\0', '\xfe' }; ++ char *inptr = input; ++ size_t insize = sizeof (input); ++ char output[4]; ++ char *outptr = output; ++ size_t outsize = sizeof (output); ++ ++ /* This used to crash due to buffer overrun. */ ++ TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == (size_t) -1); ++ TEST_VERIFY (errno == EINVAL); ++ /* The conversion should produce one character, the converted null ++ character. */ ++ TEST_VERIFY (sizeof (output) - outsize == 1); ++ ++ TEST_VERIFY_EXIT (iconv_close (cd) != -1); ++ ++ return 0; ++} ++ ++#include +--- a/iconvdata/euc-kr.c ++++ b/iconvdata/euc-kr.c +@@ -80,11 +80,7 @@ euckr_from_ucs4 (uint32_t ch, unsigned c + \ + if (ch <= 0x9f) \ + ++inptr; \ +- /* 0xfe(->0x7e : row 94) and 0xc9(->0x59 : row 41) are \ +- user-defined areas. */ \ +- else if (__builtin_expect (ch == 0xa0, 0) \ +- || __builtin_expect (ch > 0xfe, 0) \ +- || __builtin_expect (ch == 0xc9, 0)) \ ++ else if (__glibc_unlikely (ch == 0xa0)) \ + { \ + /* This is illegal. */ \ + STANDARD_FROM_LOOP_ERR_HANDLER (1); \ +--- a/iconvdata/ksc5601.h ++++ b/iconvdata/ksc5601.h +@@ -50,15 +50,15 @@ ksc5601_to_ucs4 (const unsigned char **s + unsigned char ch2; + int idx; + ++ if (avail < 2) ++ return 0; ++ + /* row 94(0x7e) and row 41(0x49) are user-defined area in KS C 5601 */ + + if (ch < offset || (ch - offset) <= 0x20 || (ch - offset) >= 0x7e + || (ch - offset) == 0x49) + return __UNKNOWN_10646_CHAR; + +- if (avail < 2) +- return 0; +- + ch2 = (*s)[1]; + if (ch2 < offset || (ch2 - offset) <= 0x20 || (ch2 - offset) >= 0x7f) + return __UNKNOWN_10646_CHAR; diff -Nru glibc-2.27/debian/patches/any/CVE-2020-27618.patch glibc-2.27/debian/patches/any/CVE-2020-27618.patch --- glibc-2.27/debian/patches/any/CVE-2020-27618.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2020-27618.patch 2022-01-24 12:53:44.000000000 +0000 @@ -0,0 +1,55 @@ +Backport of: + +From 9a99c682144bdbd40792ebf822fe9264e0376fb5 Mon Sep 17 00:00:00 2001 +From: Arjun Shankar +Date: Wed, 4 Nov 2020 12:19:38 +0100 +Subject: [PATCH] iconv: Accept redundant shift sequences in IBM1364 [BZ + #26224] + +The IBM1364, IBM1371, IBM1388, IBM1390 and IBM1399 character sets +share converter logic (iconvdata/ibm1364.c) which would reject +redundant shift sequences when processing input in these character +sets. This led to a hang in the iconv program (CVE-2020-27618). + +This commit adjusts the converter to ignore redundant shift sequences +and adds test cases for iconv_prog hangs that would be triggered upon +their rejection. This brings the implementation in line with other +converters that also ignore redundant shift sequences (e.g. IBM930 +etc., fixed in commit 692de4b3960d). + +Reviewed-by: Carlos O'Donell +--- + NEWS | 4 +++- + iconv/tst-iconv_prog.sh | 16 ++++++++++------ + iconvdata/ibm1364.c | 14 ++------------ + 3 files changed, 15 insertions(+), 19 deletions(-) + +--- a/iconvdata/ibm1364.c ++++ b/iconvdata/ibm1364.c +@@ -157,24 +157,14 @@ enum + \ + if (__builtin_expect (ch, 0) == SO) \ + { \ +- /* Shift OUT, change to DBCS converter. */ \ +- if (curcs == db) \ +- { \ +- result = __GCONV_ILLEGAL_INPUT; \ +- break; \ +- } \ ++ /* Shift OUT, change to DBCS converter (redundant escape okay). */ \ + curcs = db; \ + ++inptr; \ + continue; \ + } \ + if (__builtin_expect (ch, 0) == SI) \ + { \ +- /* Shift IN, change to SBCS converter. */ \ +- if (curcs == sb) \ +- { \ +- result = __GCONV_ILLEGAL_INPUT; \ +- break; \ +- } \ ++ /* Shift IN, change to SBCS converter (redundant escape okay). */ \ + curcs = sb; \ + ++inptr; \ + continue; \ diff -Nru glibc-2.27/debian/patches/any/CVE-2020-29562.patch glibc-2.27/debian/patches/any/CVE-2020-29562.patch --- glibc-2.27/debian/patches/any/CVE-2020-29562.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2020-29562.patch 2022-01-24 12:53:44.000000000 +0000 @@ -0,0 +1,141 @@ +From 228edd356f03bf62dcf2b1335f25d43c602ee68d Mon Sep 17 00:00:00 2001 +From: Michael Colavita +Date: Thu, 19 Nov 2020 11:44:40 -0500 +Subject: [PATCH] iconv: Fix incorrect UCS4 inner loop bounds (BZ#26923) + +Previously, in UCS4 conversion routines we limit the number of +characters we examine to the minimum of the number of characters in the +input and the number of characters in the output. This is not the +correct behavior when __GCONV_IGNORE_ERRORS is set, as we do not consume +an output character when we skip a code unit. Instead, track the input +and output pointers and terminate the loop when either reaches its +limit. + +This resolves assertion failures when resetting the input buffer in a step of +iconv, which assumes that the input will be fully consumed given sufficient +output space. +--- + iconv/Makefile | 2 +- + iconv/gconv_simple.c | 16 ++++---------- + iconv/tst-iconv8.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 55 insertions(+), 13 deletions(-) + create mode 100644 iconv/tst-iconv8.c + +--- a/iconv/Makefile ++++ b/iconv/Makefile +@@ -43,7 +43,7 @@ CFLAGS-charmap.c += -DCHARMAP_PATH='"$(i + CFLAGS-linereader.c += -DNO_TRANSLITERATION + CFLAGS-simple-hash.c += -I../locale + +-tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 tst-iconv-opt ++tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 tst-iconv-opt tst-iconv8 + + others = iconv_prog iconvconfig + install-others-programs = $(inst_bindir)/iconv +--- a/iconv/gconv_simple.c ++++ b/iconv/gconv_simple.c +@@ -237,11 +237,9 @@ ucs4_internal_loop (struct __gconv_step + int flags = step_data->__flags; + const unsigned char *inptr = *inptrp; + unsigned char *outptr = *outptrp; +- size_t n_convert = MIN (inend - inptr, outend - outptr) / 4; + int result; +- size_t cnt; + +- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4) ++ for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4) + { + uint32_t inval; + +@@ -304,11 +302,9 @@ ucs4_internal_loop_unaligned (struct __g + int flags = step_data->__flags; + const unsigned char *inptr = *inptrp; + unsigned char *outptr = *outptrp; +- size_t n_convert = MIN (inend - inptr, outend - outptr) / 4; + int result; +- size_t cnt; + +- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4) ++ for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4) + { + if (__glibc_unlikely (inptr[0] > 0x80)) + { +@@ -607,11 +603,9 @@ ucs4le_internal_loop (struct __gconv_ste + int flags = step_data->__flags; + const unsigned char *inptr = *inptrp; + unsigned char *outptr = *outptrp; +- size_t n_convert = MIN (inend - inptr, outend - outptr) / 4; + int result; +- size_t cnt; + +- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4) ++ for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4) + { + uint32_t inval; + +@@ -677,11 +671,9 @@ ucs4le_internal_loop_unaligned (struct _ + int flags = step_data->__flags; + const unsigned char *inptr = *inptrp; + unsigned char *outptr = *outptrp; +- size_t n_convert = MIN (inend - inptr, outend - outptr) / 4; + int result; +- size_t cnt; + +- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4) ++ for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4) + { + if (__glibc_unlikely (inptr[3] > 0x80)) + { +--- /dev/null ++++ b/iconv/tst-iconv8.c +@@ -0,0 +1,50 @@ ++/* Test iconv behavior on UCS4 conversions with //IGNORE. ++ Copyright (C) 2020 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Derived from BZ #26923 */ ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ iconv_t cd = iconv_open ("UTF-8//IGNORE", "ISO-10646/UCS4/"); ++ TEST_VERIFY_EXIT (cd != (iconv_t) -1); ++ ++ /* ++ * Convert sequence beginning with an irreversible character into buffer that ++ * is too small. ++ */ ++ char input[12] = "\xe1\x80\xa1" "AAAAAAAAA"; ++ char *inptr = input; ++ size_t insize = sizeof (input); ++ char output[6]; ++ char *outptr = output; ++ size_t outsize = sizeof (output); ++ ++ TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == -1); ++ TEST_VERIFY (errno == E2BIG); ++ ++ TEST_VERIFY_EXIT (iconv_close (cd) != -1); ++ ++ return 0; ++} ++ ++#include diff -Nru glibc-2.27/debian/patches/any/CVE-2020-6096-3.patch glibc-2.27/debian/patches/any/CVE-2020-6096-3.patch --- glibc-2.27/debian/patches/any/CVE-2020-6096-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2020-6096-3.patch 2022-01-24 12:51:20.000000000 +0000 @@ -0,0 +1,189 @@ +From 79a4fa341b8a89cb03f84564fd72abaa1a2db394 Mon Sep 17 00:00:00 2001 +From: Evgeny Eremin +Date: Wed, 8 Jul 2020 14:18:19 +0200 +Subject: [PATCH] arm: CVE-2020-6096: fix memcpy and memmove for negative + length [BZ #25620] + +Unsigned branch instructions could be used for r2 to fix the wrong +behavior when a negative length is passed to memcpy and memmove. +This commit fixes the generic arm implementation of memcpy amd memmove. +--- + sysdeps/arm/memcpy.S | 24 ++++++++++-------------- + sysdeps/arm/memmove.S | 24 ++++++++++-------------- + 2 files changed, 20 insertions(+), 28 deletions(-) + +diff --git a/sysdeps/arm/memcpy.S b/sysdeps/arm/memcpy.S +index 510e8adaf2..bcfbc51d99 100644 +--- a/sysdeps/arm/memcpy.S ++++ b/sysdeps/arm/memcpy.S +@@ -68,7 +68,7 @@ ENTRY(memcpy) + cfi_remember_state + + subs r2, r2, #4 +- blt 8f ++ blo 8f + ands ip, r0, #3 + PLD( pld [r1, #0] ) + bne 9f +@@ -82,7 +82,7 @@ ENTRY(memcpy) + cfi_rel_offset (r6, 4) + cfi_rel_offset (r7, 8) + cfi_rel_offset (r8, 12) +- blt 5f ++ blo 5f + + CALGN( ands ip, r1, #31 ) + CALGN( rsb r3, ip, #32 ) +@@ -98,9 +98,9 @@ ENTRY(memcpy) + #endif + + PLD( pld [r1, #0] ) +-2: PLD( subs r2, r2, #96 ) ++2: PLD( cmp r2, #96 ) + PLD( pld [r1, #28] ) +- PLD( blt 4f ) ++ PLD( blo 4f ) + PLD( pld [r1, #60] ) + PLD( pld [r1, #92] ) + +@@ -108,9 +108,7 @@ ENTRY(memcpy) + 4: ldmia r1!, {r3, r4, r5, r6, r7, r8, ip, lr} + subs r2, r2, #32 + stmia r0!, {r3, r4, r5, r6, r7, r8, ip, lr} +- bge 3b +- PLD( cmn r2, #96 ) +- PLD( bge 4b ) ++ bhs 3b + + 5: ands ip, r2, #28 + rsb ip, ip, #32 +@@ -222,7 +220,7 @@ ENTRY(memcpy) + strbge r4, [r0], #1 + subs r2, r2, ip + strb lr, [r0], #1 +- blt 8b ++ blo 8b + ands ip, r1, #3 + beq 1b + +@@ -236,7 +234,7 @@ ENTRY(memcpy) + .macro forward_copy_shift pull push + + subs r2, r2, #28 +- blt 14f ++ blo 14f + + CALGN( ands ip, r1, #31 ) + CALGN( rsb ip, ip, #32 ) +@@ -253,9 +251,9 @@ ENTRY(memcpy) + cfi_rel_offset (r10, 16) + + PLD( pld [r1, #0] ) +- PLD( subs r2, r2, #96 ) ++ PLD( cmp r2, #96 ) + PLD( pld [r1, #28] ) +- PLD( blt 13f ) ++ PLD( blo 13f ) + PLD( pld [r1, #60] ) + PLD( pld [r1, #92] ) + +@@ -280,9 +278,7 @@ ENTRY(memcpy) + mov ip, ip, PULL #\pull + orr ip, ip, lr, PUSH #\push + stmia r0!, {r3, r4, r5, r6, r7, r8, r10, ip} +- bge 12b +- PLD( cmn r2, #96 ) +- PLD( bge 13b ) ++ bhs 12b + + pop {r5 - r8, r10} + cfi_adjust_cfa_offset (-20) +diff --git a/sysdeps/arm/memmove.S b/sysdeps/arm/memmove.S +index 954037ef3a..0d07b76ee6 100644 +--- a/sysdeps/arm/memmove.S ++++ b/sysdeps/arm/memmove.S +@@ -85,7 +85,7 @@ ENTRY(memmove) + add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 +- blt 8f ++ blo 8f + ands ip, r0, #3 + PLD( pld [r1, #-4] ) + bne 9f +@@ -99,7 +99,7 @@ ENTRY(memmove) + cfi_rel_offset (r6, 4) + cfi_rel_offset (r7, 8) + cfi_rel_offset (r8, 12) +- blt 5f ++ blo 5f + + CALGN( ands ip, r1, #31 ) + CALGN( sbcsne r4, ip, r2 ) @ C is always set here +@@ -114,9 +114,9 @@ ENTRY(memmove) + #endif + + PLD( pld [r1, #-4] ) +-2: PLD( subs r2, r2, #96 ) ++2: PLD( cmp r2, #96 ) + PLD( pld [r1, #-32] ) +- PLD( blt 4f ) ++ PLD( blo 4f ) + PLD( pld [r1, #-64] ) + PLD( pld [r1, #-96] ) + +@@ -124,9 +124,7 @@ ENTRY(memmove) + 4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr} + subs r2, r2, #32 + stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr} +- bge 3b +- PLD( cmn r2, #96 ) +- PLD( bge 4b ) ++ bhs 3b + + 5: ands ip, r2, #28 + rsb ip, ip, #32 +@@ -237,7 +235,7 @@ ENTRY(memmove) + strbge r4, [r0, #-1]! + subs r2, r2, ip + strb lr, [r0, #-1]! +- blt 8b ++ blo 8b + ands ip, r1, #3 + beq 1b + +@@ -251,7 +249,7 @@ ENTRY(memmove) + .macro backward_copy_shift push pull + + subs r2, r2, #28 +- blt 14f ++ blo 14f + + CALGN( ands ip, r1, #31 ) + CALGN( rsb ip, ip, #32 ) +@@ -268,9 +266,9 @@ ENTRY(memmove) + cfi_rel_offset (r10, 16) + + PLD( pld [r1, #-4] ) +- PLD( subs r2, r2, #96 ) ++ PLD( cmp r2, #96 ) + PLD( pld [r1, #-32] ) +- PLD( blt 13f ) ++ PLD( blo 13f ) + PLD( pld [r1, #-64] ) + PLD( pld [r1, #-96] ) + +@@ -295,9 +293,7 @@ ENTRY(memmove) + mov r4, r4, PUSH #\push + orr r4, r4, r3, PULL #\pull + stmdb r0!, {r4 - r8, r10, ip, lr} +- bge 12b +- PLD( cmn r2, #96 ) +- PLD( bge 13b ) ++ bhs 12b + + pop {r5 - r8, r10} + cfi_adjust_cfa_offset (-20) +-- +2.27.0 + diff -Nru glibc-2.27/debian/patches/any/CVE-2020-6096-4.patch glibc-2.27/debian/patches/any/CVE-2020-6096-4.patch --- glibc-2.27/debian/patches/any/CVE-2020-6096-4.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2020-6096-4.patch 2022-01-24 12:51:24.000000000 +0000 @@ -0,0 +1,107 @@ +From beea361050728138b82c57dda0c4810402d342b9 Mon Sep 17 00:00:00 2001 +From: Alexander Anisimov +Date: Wed, 8 Jul 2020 14:18:31 +0200 +Subject: [PATCH] arm: CVE-2020-6096: Fix multiarch memcpy for negative length + [BZ #25620] + +Unsigned branch instructions could be used for r2 to fix the wrong +behavior when a negative length is passed to memcpy. +This commit fixes the armv7 version. +--- + sysdeps/arm/armv7/multiarch/memcpy_impl.S | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/sysdeps/arm/armv7/multiarch/memcpy_impl.S b/sysdeps/arm/armv7/multiarch/memcpy_impl.S +index bf4ac7077f..379bb56fc9 100644 +--- a/sysdeps/arm/armv7/multiarch/memcpy_impl.S ++++ b/sysdeps/arm/armv7/multiarch/memcpy_impl.S +@@ -268,7 +268,7 @@ ENTRY(memcpy) + + mov dst, dstin /* Preserve dstin, we need to return it. */ + cmp count, #64 +- bge .Lcpy_not_short ++ bhs .Lcpy_not_short + /* Deal with small copies quickly by dropping straight into the + exit block. */ + +@@ -351,10 +351,10 @@ ENTRY(memcpy) + + 1: + subs tmp2, count, #64 /* Use tmp2 for count. */ +- blt .Ltail63aligned ++ blo .Ltail63aligned + + cmp tmp2, #512 +- bge .Lcpy_body_long ++ bhs .Lcpy_body_long + + .Lcpy_body_medium: /* Count in tmp2. */ + #ifdef USE_VFP +@@ -378,7 +378,7 @@ ENTRY(memcpy) + add src, src, #64 + vstr d1, [dst, #56] + add dst, dst, #64 +- bge 1b ++ bhs 1b + tst tmp2, #0x3f + beq .Ldone + +@@ -412,7 +412,7 @@ ENTRY(memcpy) + ldrd A_l, A_h, [src, #64]! + strd A_l, A_h, [dst, #64]! + subs tmp2, tmp2, #64 +- bge 1b ++ bhs 1b + tst tmp2, #0x3f + bne 1f + ldr tmp2,[sp], #FRAME_SIZE +@@ -482,7 +482,7 @@ ENTRY(memcpy) + add src, src, #32 + + subs tmp2, tmp2, #prefetch_lines * 64 * 2 +- blt 2f ++ blo 2f + 1: + cpy_line_vfp d3, 0 + cpy_line_vfp d4, 64 +@@ -494,7 +494,7 @@ ENTRY(memcpy) + add dst, dst, #2 * 64 + add src, src, #2 * 64 + subs tmp2, tmp2, #prefetch_lines * 64 +- bge 1b ++ bhs 1b + + 2: + cpy_tail_vfp d3, 0 +@@ -615,8 +615,8 @@ ENTRY(memcpy) + 1: + pld [src, #(3 * 64)] + subs count, count, #64 +- ldrmi tmp2, [sp], #FRAME_SIZE +- bmi .Ltail63unaligned ++ ldrlo tmp2, [sp], #FRAME_SIZE ++ blo .Ltail63unaligned + pld [src, #(4 * 64)] + + #ifdef USE_NEON +@@ -633,7 +633,7 @@ ENTRY(memcpy) + neon_load_multi d0-d3, src + neon_load_multi d4-d7, src + subs count, count, #64 +- bmi 2f ++ blo 2f + 1: + pld [src, #(4 * 64)] + neon_store_multi d0-d3, dst +@@ -641,7 +641,7 @@ ENTRY(memcpy) + neon_store_multi d4-d7, dst + neon_load_multi d4-d7, src + subs count, count, #64 +- bpl 1b ++ bhs 1b + 2: + neon_store_multi d0-d3, dst + neon_store_multi d4-d7, dst +-- +2.27.0 + diff -Nru glibc-2.27/debian/patches/any/CVE-2021-3326.patch glibc-2.27/debian/patches/any/CVE-2021-3326.patch --- glibc-2.27/debian/patches/any/CVE-2021-3326.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2021-3326.patch 2022-01-24 12:51:45.000000000 +0000 @@ -0,0 +1,284 @@ +Backport of: + +From 7d88c6142c6efc160c0ee5e4f85cde382c072888 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Wed, 27 Jan 2021 13:36:12 +0100 +Subject: [PATCH] gconv: Fix assertion failure in ISO-2022-JP-3 module (bug + 27256) + +The conversion loop to the internal encoding does not follow +the interface contract that __GCONV_FULL_OUTPUT is only returned +after the internal wchar_t buffer has been filled completely. This +is enforced by the first of the two asserts in iconv/skeleton.c: + + /* We must run out of output buffer space in this + rerun. */ + assert (outbuf == outerr); + assert (nstatus == __GCONV_FULL_OUTPUT); + +This commit solves this issue by queuing a second wide character +which cannot be written immediately in the state variable, like +other converters already do (e.g., BIG5-HKSCS or TSCII). + +Reported-by: Tavis Ormandy +--- + iconvdata/Makefile | 4 +- + iconvdata/bug-iconv14.c | 127 ++++++++++++++++++++++++++++++++++++++ + iconvdata/iso-2022-jp-3.c | 67 ++++++++++++++------ + 3 files changed, 178 insertions(+), 20 deletions(-) + create mode 100644 iconvdata/bug-iconv14.c + +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -73,7 +73,7 @@ modules.so := $(addsuffix .so, $(modules + ifeq (yes,$(build-shared)) + tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ + tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ +- bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 ++ bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 bug-iconv14 + ifeq ($(have-thread-library),yes) + tests += bug-iconv3 + endif +@@ -316,6 +316,8 @@ $(objpfx)bug-iconv10.out: $(objpfx)gconv + $(addprefix $(objpfx),$(modules.so)) + $(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \ + $(addprefix $(objpfx),$(modules.so)) ++$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \ ++ $(addprefix $(objpfx),$(modules.so)) + + $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \ + $(addprefix $(objpfx),$(modules.so)) \ +--- /dev/null ++++ b/iconvdata/bug-iconv14.c +@@ -0,0 +1,127 @@ ++/* Assertion in ISO-2022-JP-3 due to two-character sequence (bug 27256). ++ Copyright (C) 2021 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++/* Use an escape sequence to return to the initial state. */ ++static void ++with_escape_sequence (void) ++{ ++ iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3"); ++ TEST_VERIFY_EXIT (c != (iconv_t) -1); ++ ++ char in[] = "\e$(O+D\e(B"; ++ char *inbuf = in; ++ size_t inleft = strlen (in); ++ char out[3]; /* Space for one output character. */ ++ char *outbuf; ++ size_t outleft; ++ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1); ++ TEST_COMPARE (errno, E2BIG); ++ TEST_COMPARE (inleft, 3); ++ TEST_COMPARE (inbuf - in, strlen (in) - 3); ++ TEST_COMPARE (outleft, sizeof (out) - 2); ++ TEST_COMPARE (outbuf - out, 2); ++ TEST_COMPARE (out[0] & 0xff, 0xc3); ++ TEST_COMPARE (out[1] & 0xff, 0xa6); ++ ++ /* Return to the initial shift state, producing the pending ++ character. */ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), 0); ++ TEST_COMPARE (inleft, 0); ++ TEST_COMPARE (inbuf - in, strlen (in)); ++ TEST_COMPARE (outleft, sizeof (out) - 2); ++ TEST_COMPARE (outbuf - out, 2); ++ TEST_COMPARE (out[0] & 0xff, 0xcc); ++ TEST_COMPARE (out[1] & 0xff, 0x80); ++ ++ /* Nothing should be flushed the second time. */ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); ++ TEST_COMPARE (outleft, sizeof (out)); ++ TEST_COMPARE (outbuf - out, 0); ++ TEST_COMPARE (out[0] & 0xff, 0xcc); ++ TEST_COMPARE (out[1] & 0xff, 0x80); ++ ++ TEST_COMPARE (iconv_close (c), 0); ++} ++ ++/* Use an explicit flush to return to the initial state. */ ++static void ++with_flush (void) ++{ ++ iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3"); ++ TEST_VERIFY_EXIT (c != (iconv_t) -1); ++ ++ char in[] = "\e$(O+D"; ++ char *inbuf = in; ++ size_t inleft = strlen (in); ++ char out[3]; /* Space for one output character. */ ++ char *outbuf; ++ size_t outleft; ++ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1); ++ TEST_COMPARE (errno, E2BIG); ++ TEST_COMPARE (inleft, 0); ++ TEST_COMPARE (inbuf - in, strlen (in)); ++ TEST_COMPARE (outleft, sizeof (out) - 2); ++ TEST_COMPARE (outbuf - out, 2); ++ TEST_COMPARE (out[0] & 0xff, 0xc3); ++ TEST_COMPARE (out[1] & 0xff, 0xa6); ++ ++ /* Flush the pending character. */ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); ++ TEST_COMPARE (outleft, sizeof (out) - 2); ++ TEST_COMPARE (outbuf - out, 2); ++ TEST_COMPARE (out[0] & 0xff, 0xcc); ++ TEST_COMPARE (out[1] & 0xff, 0x80); ++ ++ /* Nothing should be flushed the second time. */ ++ outbuf = out; ++ outleft = sizeof (out); ++ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0); ++ TEST_COMPARE (outleft, sizeof (out)); ++ TEST_COMPARE (outbuf - out, 0); ++ TEST_COMPARE (out[0] & 0xff, 0xcc); ++ TEST_COMPARE (out[1] & 0xff, 0x80); ++ ++ TEST_COMPARE (iconv_close (c), 0); ++} ++ ++static int ++do_test (void) ++{ ++ with_escape_sequence (); ++ with_flush (); ++ return 0; ++} ++ ++#include +--- a/iconvdata/iso-2022-jp-3.c ++++ b/iconvdata/iso-2022-jp-3.c +@@ -67,23 +67,34 @@ enum + CURRENT_SEL_MASK = 7 << 3 + }; + +-/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state +- also contains the last two bytes to be output, shifted by 6 bits, and a +- one-bit indicator whether they must be preceded by the shift sequence, +- in bit 22. */ ++/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the ++ state also contains the last two bytes to be output, shifted by 6 ++ bits, and a one-bit indicator whether they must be preceded by the ++ shift sequence, in bit 22. During ISO-2022-JP-3 to UCS-4 ++ conversion, COUNT may also contain a non-zero pending wide ++ character, shifted by six bits. This happens for certain inputs in ++ JISX0213_1_2004_set and JISX0213_2_set if the second wide character ++ in a combining sequence cannot be written because the buffer is ++ full. */ + + /* Since this is a stateful encoding we have to provide code which resets + the output state to the initial state. This has to be done during the + flushing. */ + #define EMIT_SHIFT_TO_INIT \ +- if ((data->__statep->__count & ~7) != ASCII_set) \ ++ if (data->__statep->__count != ASCII_set) \ + { \ + if (FROM_DIRECTION) \ + { \ +- /* It's easy, we don't have to emit anything, we just reset the \ +- state for the input. */ \ +- data->__statep->__count &= 7; \ +- data->__statep->__count |= ASCII_set; \ ++ if (__glibc_likely (outbuf + 4 <= outend)) \ ++ { \ ++ /* Write out the last character. */ \ ++ *((uint32_t *) outbuf) = data->__statep->__count >> 6; \ ++ outbuf += sizeof (uint32_t); \ ++ data->__statep->__count = ASCII_set; \ ++ } \ ++ else \ ++ /* We don't have enough room in the output buffer. */ \ ++ status = __GCONV_FULL_OUTPUT; \ + } \ + else \ + { \ +@@ -151,7 +162,21 @@ enum + #define LOOPFCT FROM_LOOP + #define BODY \ + { \ +- uint32_t ch = *inptr; \ ++ uint32_t ch; \ ++ \ ++ /* Output any pending character. */ \ ++ ch = set >> 6; \ ++ if (__glibc_unlikely (ch != 0)) \ ++ { \ ++ put32 (outptr, ch); \ ++ outptr += 4; \ ++ /* Remove the pending character, but preserve state bits. */ \ ++ set &= (1 << 6) - 1; \ ++ continue; \ ++ } \ ++ \ ++ /* Otherwise read the next input byte. */ \ ++ ch = *inptr; \ + \ + /* Recognize escape sequences. */ \ + if (__glibc_unlikely (ch == ESC)) \ +@@ -297,21 +322,25 @@ enum + uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0]; \ + uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1]; \ + \ ++ inptr += 2; \ ++ \ ++ put32 (outptr, u1); \ ++ outptr += 4; \ ++ \ + /* See whether we have room for two characters. */ \ +- if (outptr + 8 <= outend) \ ++ if (outptr + 4 <= outend) \ + { \ +- inptr += 2; \ +- put32 (outptr, u1); \ +- outptr += 4; \ + put32 (outptr, u2); \ + outptr += 4; \ + continue; \ + } \ +- else \ +- { \ +- result = __GCONV_FULL_OUTPUT; \ +- break; \ +- } \ ++ \ ++ /* Otherwise store only the first character now, and \ ++ put the second one into the queue. */ \ ++ set |= u2 << 6; \ ++ /* Tell the caller why we terminate the loop. */ \ ++ result = __GCONV_FULL_OUTPUT; \ ++ break; \ + } \ + \ + inptr += 2; \ diff -Nru glibc-2.27/debian/patches/any/CVE-2021-35942.patch glibc-2.27/debian/patches/any/CVE-2021-35942.patch --- glibc-2.27/debian/patches/any/CVE-2021-35942.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2021-35942.patch 2022-01-24 12:53:23.000000000 +0000 @@ -0,0 +1,33 @@ +From 5adda61f62b77384718b4c0d8336ade8f2b4b35c Mon Sep 17 00:00:00 2001 +From: Andreas Schwab +Date: Fri, 25 Jun 2021 15:02:47 +0200 +Subject: [PATCH] wordexp: handle overflow in positional parameter number (bug + 28011) + +Use strtoul instead of atoi so that overflow can be detected. +--- + posix/wordexp-test.c | 1 + + posix/wordexp.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +--- a/posix/wordexp-test.c ++++ b/posix/wordexp-test.c +@@ -200,6 +200,7 @@ struct test_case_struct + { 0, NULL, "$var", 0, 0, { NULL, }, IFS }, + { 0, NULL, "\"\\n\"", 0, 1, { "\\n", }, IFS }, + { 0, NULL, "", 0, 0, { NULL, }, IFS }, ++ { 0, NULL, "${1234567890123456789012}", 0, 0, { NULL, }, IFS }, + + /* Flags not already covered (testit() has special handling for these) */ + { 0, NULL, "one two", WRDE_DOOFFS, 2, { "one", "two", }, IFS }, +--- a/posix/wordexp.c ++++ b/posix/wordexp.c +@@ -1407,7 +1407,7 @@ envsubst: + /* Is it a numeric parameter? */ + else if (isdigit (env[0])) + { +- int n = atoi (env); ++ unsigned long n = strtoul (env, NULL, 10); + + if (n >= __libc_argc) + /* Substitute NULL. */ diff -Nru glibc-2.27/debian/patches/any/CVE-2021-3999.patch glibc-2.27/debian/patches/any/CVE-2021-3999.patch --- glibc-2.27/debian/patches/any/CVE-2021-3999.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2021-3999.patch 2022-01-24 12:53:44.000000000 +0000 @@ -0,0 +1,88 @@ +Backport of: + +From 472e799a5f2102bc0c3206dbd5a801765fceb39c Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Fri, 21 Jan 2022 23:32:56 +0530 +Subject: [PATCH] getcwd: Set errno to ERANGE for size == 1 (CVE-2021-3999) + +No valid path returned by getcwd would fit into 1 byte, so reject the +size early and return NULL with errno set to ERANGE. This change is +prompted by CVE-2021-3999, which describes a single byte buffer +underflow and overflow when all of the following conditions are met: + +- The buffer size (i.e. the second argument of getcwd) is 1 byte +- The current working directory is too long +- '/' is also mounted on the current working directory + +Sequence of events: + +- In sysdeps/unix/sysv/linux/getcwd.c, the syscall returns ENAMETOOLONG + because the linux kernel checks for name length before it checks + buffer size + +- The code falls back to the generic getcwd in sysdeps/posix + +- In the generic func, the buf[0] is set to '\0' on line 250 + +- this while loop on line 262 is bypassed: + + while (!(thisdev == rootdev && thisino == rootino)) + + since the rootfs (/) is bind mounted onto the directory and the flow + goes on to line 449, where it puts a '/' in the byte before the + buffer. + +- Finally on line 458, it moves 2 bytes (the underflowed byte and the + '\0') to the buf[0] and buf[1], resulting in a 1 byte buffer overflow. + +- buf is returned on line 469 and errno is not set. + +This resolves BZ #28769. + +Reviewed-by: Andreas Schwab +Reviewed-by: Adhemerval Zanella +Signed-off-by: Qualys Security Advisory +Signed-off-by: Siddhesh Poyarekar +(cherry picked from commit 23e0e8f5f1fb5ed150253d986ecccdc90c2dcd5e) +--- + NEWS | 6 + + sysdeps/posix/getcwd.c | 7 + + sysdeps/unix/sysv/linux/Makefile | 7 +- + .../unix/sysv/linux/tst-getcwd-smallbuff.c | 241 ++++++++++++++++++ + 4 files changed, 260 insertions(+), 1 deletion(-) + create mode 100644 sysdeps/unix/sysv/linux/tst-getcwd-smallbuff.c + +#diff --git a/NEWS b/NEWS +#index b4f81c2668..8d7467d2c1 100644 +#--- a/NEWS +#+++ b/NEWS +#@@ -20,6 +20,12 @@ Security related changes: +# function could result in a memory leak and potential access of +# uninitialized memory. Reported by Qualys. +# +#+ CVE-2021-3999: Passing a buffer of size exactly 1 byte to the getcwd +#+ function may result in an off-by-one buffer underflow and overflow +#+ when the current working directory is longer than PATH_MAX and also +#+ corresponds to the / directory through an unprivileged mount +#+ namespace. Reported by Qualys. +#+ +# The following bugs are resolved with this release: +# +# [12889] nptl: Fix race between pthread_kill and thread exit +--- a/sysdeps/posix/getcwd.c ++++ b/sysdeps/posix/getcwd.c +@@ -241,6 +241,14 @@ __getcwd (char *buf, size_t size) + char *path; + #ifndef NO_ALLOCATION + size_t allocated = size; ++ ++ /* A size of 1 byte is never useful. */ ++ if (allocated == 1) ++ { ++ __set_errno (ERANGE); ++ return NULL; ++ } ++ + if (size == 0) + { + if (buf != NULL) diff -Nru glibc-2.27/debian/patches/any/CVE-2022-23218.patch glibc-2.27/debian/patches/any/CVE-2022-23218.patch --- glibc-2.27/debian/patches/any/CVE-2022-23218.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2022-23218.patch 2022-01-24 12:53:44.000000000 +0000 @@ -0,0 +1,61 @@ +Backport of: + +From f545ad4928fa1f27a3075265182b38a4f939a5f7 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 17 Jan 2022 10:21:34 +0100 +Subject: [PATCH] CVE-2022-23218: Buffer overflow in sunrpc svcunix_create (bug + 28768) + +The sunrpc function svcunix_create suffers from a stack-based buffer +overflow with overlong pathname arguments. + +Reviewed-by: Siddhesh Poyarekar +--- + NEWS | 3 +++ + sunrpc/Makefile | 2 +- + sunrpc/svc_unix.c | 11 ++++------- + sunrpc/tst-bug28768.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 50 insertions(+), 8 deletions(-) + create mode 100644 sunrpc/tst-bug28768.c + +#diff --git a/NEWS b/NEWS +#index 38a9ddb2cf..38802f0673 100644 +#--- a/NEWS +#+++ b/NEWS +#@@ -160,6 +160,9 @@ Security related changes: +# legacy function could result in a stack-based buffer overflow when +# using the "unix" protocol. Reported by Martin Sebor. +# +#+ CVE-2022-23218: Passing an overlong file name to the svcunix_create +#+ legacy function could result in a stack-based buffer overflow. +#+ +# The following bugs are resolved with this release: +# +# [The release manager will add the list generated by +--- a/sunrpc/svc_unix.c ++++ b/sunrpc/svc_unix.c +@@ -154,7 +154,10 @@ svcunix_create (int sock, u_int sendsize + SVCXPRT *xprt; + struct unix_rendezvous *r; + struct sockaddr_un addr; +- socklen_t len = sizeof (struct sockaddr_in); ++ socklen_t len = sizeof (addr); ++ ++ if (__sockaddr_un_set (&addr, path) < 0) ++ return NULL; + + if (sock == RPC_ANYSOCK) + { +@@ -165,12 +168,6 @@ svcunix_create (int sock, u_int sendsize + } + madesock = TRUE; + } +- memset (&addr, '\0', sizeof (addr)); +- addr.sun_family = AF_UNIX; +- len = strlen (path) + 1; +- memcpy (addr.sun_path, path, len); +- len += sizeof (addr.sun_family); +- + __bind (sock, (struct sockaddr *) &addr, len); + + if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0 diff -Nru glibc-2.27/debian/patches/any/CVE-2022-23218-pre1.patch glibc-2.27/debian/patches/any/CVE-2022-23218-pre1.patch --- glibc-2.27/debian/patches/any/CVE-2022-23218-pre1.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2022-23218-pre1.patch 2022-01-24 12:53:44.000000000 +0000 @@ -0,0 +1,163 @@ +Backport of: + +From e368b12f6c16b6888dda99ba641e999b9c9643c8 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 17 Jan 2022 10:21:34 +0100 +Subject: [PATCH] socket: Add the __sockaddr_un_set function + +Reviewed-by: Siddhesh Poyarekar +--- + include/sys/un.h | 12 +++++++ + socket/Makefile | 6 +++- + socket/sockaddr_un_set.c | 41 ++++++++++++++++++++++++ + socket/tst-sockaddr_un_set.c | 62 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 120 insertions(+), 1 deletion(-) + create mode 100644 socket/sockaddr_un_set.c + create mode 100644 socket/tst-sockaddr_un_set.c + +--- a/include/sys/un.h ++++ b/include/sys/un.h +@@ -1 +1,13 @@ + #include ++ ++#ifndef _ISOMAC ++ ++/* Set ADDR->sun_family to AF_UNIX and ADDR->sun_path to PATHNAME. ++ Return 0 on success or -1 on failure (due to overlong PATHNAME). ++ The caller should always use sizeof (struct sockaddr_un) as the ++ socket address length, disregaring the length of PATHNAME. ++ Only concrete (non-abstract) pathnames are supported. */ ++int __sockaddr_un_set (struct sockaddr_un *addr, const char *pathname) ++ attribute_hidden; ++ ++#endif /* _ISOMAC */ +--- a/socket/Makefile ++++ b/socket/Makefile +@@ -29,10 +29,14 @@ headers := sys/socket.h sys/un.h bits/so + routines := accept bind connect getpeername getsockname getsockopt \ + listen recv recvfrom recvmsg send sendmsg sendto \ + setsockopt shutdown socket socketpair isfdtype opensock \ +- sockatmark accept4 recvmmsg sendmmsg ++ sockatmark accept4 recvmmsg sendmmsg sockaddr_un_set + + tests := tst-accept4 + ++tests-internal := \ ++ tst-sockaddr_un_set \ ++ # tests-internal ++ + aux := sa_len + + include ../Rules +--- /dev/null ++++ b/socket/sockaddr_un_set.c +@@ -0,0 +1,41 @@ ++/* Set the sun_path member of struct sockaddr_un. ++ 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 ++ ++int ++__sockaddr_un_set (struct sockaddr_un *addr, const char *pathname) ++{ ++ size_t name_length = strlen (pathname); ++ ++ /* The kernel supports names of exactly sizeof (addr->sun_path) ++ bytes, without a null terminator, but userspace does not; see the ++ SUN_LEN macro. */ ++ if (name_length >= sizeof (addr->sun_path)) ++ { ++ __set_errno (EINVAL); /* Error code used by the kernel. */ ++ return -1; ++ } ++ ++ addr->sun_family = AF_UNIX; ++ memcpy (addr->sun_path, pathname, name_length + 1); ++ return 0; ++} +--- /dev/null ++++ b/socket/tst-sockaddr_un_set.c +@@ -0,0 +1,65 @@ ++/* Test the __sockaddr_un_set 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 ++ . */ ++ ++/* Re-compile the function because the version in libc is not ++ exported. */ ++#include "sockaddr_un_set.c" ++ ++#include ++ ++static int ++do_test (void) ++{ ++ struct sockaddr_un sun; ++ int result = 0; ++ ++ memset (&sun, 0xcc, sizeof (sun)); ++ __sockaddr_un_set (&sun, ""); ++ TEST_COMPARE (sun.sun_family, AF_UNIX); ++ TEST_COMPARE (__sockaddr_un_set (&sun, ""), 0); ++ ++ memset (&sun, 0xcc, sizeof (sun)); ++ TEST_COMPARE (__sockaddr_un_set (&sun, "/example"), 0); ++ if (strcmp (sun.sun_path, "/example")) ++ result = 1; ++ ++ { ++ char pathname[108]; /* Length of sun_path (ABI constant). */ ++ memset (pathname, 'x', sizeof (pathname)); ++ pathname[sizeof (pathname) - 1] = '\0'; ++ memset (&sun, 0xcc, sizeof (sun)); ++ TEST_COMPARE (__sockaddr_un_set (&sun, pathname), 0); ++ TEST_COMPARE (sun.sun_family, AF_UNIX); ++ if (strcmp (sun.sun_path, pathname)) ++ result = 1; ++ } ++ ++ { ++ char pathname[109]; ++ memset (pathname, 'x', sizeof (pathname)); ++ pathname[sizeof (pathname) - 1] = '\0'; ++ memset (&sun, 0xcc, sizeof (sun)); ++ errno = 0; ++ TEST_COMPARE (__sockaddr_un_set (&sun, pathname), -1); ++ TEST_COMPARE (errno, EINVAL); ++ } ++ ++ return result; ++} ++ ++#include diff -Nru glibc-2.27/debian/patches/any/CVE-2022-23219.patch glibc-2.27/debian/patches/any/CVE-2022-23219.patch --- glibc-2.27/debian/patches/any/CVE-2022-23219.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/CVE-2022-23219.patch 2022-01-24 12:53:44.000000000 +0000 @@ -0,0 +1,54 @@ +From 226b46770c82899b555986583294b049c6ec9b40 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 17 Jan 2022 10:21:34 +0100 +Subject: [PATCH] CVE-2022-23219: Buffer overflow in sunrpc clnt_create for + "unix" (bug 22542) + +Processing an overlong pathname in the sunrpc clnt_create function +results in a stack-based buffer overflow. + +Reviewed-by: Siddhesh Poyarekar +--- + NEWS | 4 +++- + sunrpc/clnt_gen.c | 10 +++++++--- + 2 files changed, 10 insertions(+), 4 deletions(-) + +#diff --git a/NEWS b/NEWS +#index ddd95a8329..38a9ddb2cf 100644 +#--- a/NEWS +#+++ b/NEWS +#@@ -156,7 +156,9 @@ Changes to build and runtime requirements: +# +# Security related changes: +# +#- [Add security related changes here] +#+ CVE-2022-23219: Passing an overlong file name to the clnt_create +#+ legacy function could result in a stack-based buffer overflow when +#+ using the "unix" protocol. Reported by Martin Sebor. +# +# The following bugs are resolved with this release: +# +diff --git a/sunrpc/clnt_gen.c b/sunrpc/clnt_gen.c +index 13ced8994e..b44357cd88 100644 +--- a/sunrpc/clnt_gen.c ++++ b/sunrpc/clnt_gen.c +@@ -57,9 +57,13 @@ clnt_create (const char *hostname, u_long prog, u_long vers, + + if (strcmp (proto, "unix") == 0) + { +- memset ((char *)&sun, 0, sizeof (sun)); +- sun.sun_family = AF_UNIX; +- strcpy (sun.sun_path, hostname); ++ if (__sockaddr_un_set (&sun, hostname) < 0) ++ { ++ struct rpc_createerr *ce = &get_rpc_createerr (); ++ ce->cf_stat = RPC_SYSTEMERROR; ++ ce->cf_error.re_errno = errno; ++ return NULL; ++ } + sock = RPC_ANYSOCK; + client = clntunix_create (&sun, prog, vers, &sock, 0, 0); + if (client == NULL) +-- +2.27.0 + diff -Nru glibc-2.27/debian/patches/any/fix_test-errno-linux.patch glibc-2.27/debian/patches/any/fix_test-errno-linux.patch --- glibc-2.27/debian/patches/any/fix_test-errno-linux.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/any/fix_test-errno-linux.patch 2022-01-24 12:53:44.000000000 +0000 @@ -0,0 +1,35 @@ +From 6578d89c170cc7b524b9bccafffd5b4207bf646f Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 5 Dec 2019 17:29:42 +0100 +Subject: [PATCH] misc/test-errno-linux: Handle EINVAL from quotactl + +In commit 3dd4d40b420846dd35869ccc8f8627feef2cff32 ("xfs: Sanity check +flags of Q_XQUOTARM call"), Linux 5.4 added checking for the flags +argument, causing the test to fail due to too restrictive test +expectations. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 1f7525d924b608a3e43b10fcfb3d46b8a6e9e4f9) +--- + sysdeps/unix/sysv/linux/test-errno-linux.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/unix/sysv/linux/test-errno-linux.c b/sysdeps/unix/sysv/linux/test-errno-linux.c +index be1135351d..073e2fba64 100644 +--- a/sysdeps/unix/sysv/linux/test-errno-linux.c ++++ b/sysdeps/unix/sysv/linux/test-errno-linux.c +@@ -160,8 +160,9 @@ do_test (void) + fails |= test_wrp (EINVAL, poll, &pollfd, -1, 0); + /* quotactl returns ENOSYS for kernels not configured with + CONFIG_QUOTA, and may return EPERM if called within certain types +- of containers. */ +- fails |= test_wrp2 (LIST (ENODEV, ENOSYS, EPERM), ++ of containers. Linux 5.4 added additional argument validation ++ and can return EINVAL. */ ++ fails |= test_wrp2 (LIST (ENODEV, ENOSYS, EPERM, EINVAL), + quotactl, Q_GETINFO, NULL, -1, (caddr_t) &dqblk); + fails |= test_wrp (EINVAL, sched_getparam, -1, &sch_param); + fails |= test_wrp (EINVAL, sched_getscheduler, -1); +-- +2.27.0 + diff -Nru glibc-2.27/debian/patches/arm/unsubmitted-ldso-abi-check.diff glibc-2.27/debian/patches/arm/unsubmitted-ldso-abi-check.diff --- glibc-2.27/debian/patches/arm/unsubmitted-ldso-abi-check.diff 2016-01-27 14:17:05.000000000 +0000 +++ glibc-2.27/debian/patches/arm/unsubmitted-ldso-abi-check.diff 2020-12-07 16:38:09.000000000 +0000 @@ -4,7 +4,7 @@ --- a/elf/dl-load.c +++ b/elf/dl-load.c -@@ -1644,6 +1644,209 @@ +@@ -1438,6 +1438,209 @@ _dl_debug_printf_c ("\t\t(%s)\n", what); } @@ -214,7 +214,7 @@ /* Open a file and verify it is an ELF file for this architecture. We ignore only ELF files for other architectures. Non-ELF files and ELF files with different header information cause fatal errors since -@@ -1842,6 +2044,7 @@ +@@ -1676,6 +1879,7 @@ /* Check .note.ABI-tag if present. */ for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph) @@ -222,10 +222,10 @@ if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4) { ElfW(Addr) size = ph->p_filesz; -@@ -1890,6 +2093,21 @@ +@@ -1751,6 +1955,20 @@ + break; } - } + if (-1 != fd) + { + int error = arch_specific_checks(fd, name, ehdr); @@ -239,8 +239,7 @@ + goto call_lose; + } + } -+ -+ } ++ } + free (abi_note_malloced); + } - return fd; - } diff -Nru glibc-2.27/debian/patches/git-updates-2.diff glibc-2.27/debian/patches/git-updates-2.diff --- glibc-2.27/debian/patches/git-updates-2.diff 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/git-updates-2.diff 2020-12-07 16:38:09.000000000 +0000 @@ -0,0 +1,15498 @@ +GIT update of https://sourceware.org/git/glibc.git/release/2.27/master from glibc-2.27 + +Files manually omitted: manual/charset.texi manual/llio.texi manual/probes.texi manual/tunables.texi + +diff --git a/ChangeLog b/ChangeLog +index 536fcf1c4f..7e98e23cc4 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,880 @@ ++2018-07-06 Szabolcs Nagy ++ ++ * sysdeps/unix/sysv/linux/aarch64/dl-procinfo.h (HWCAP_IMPORTANT): Add ++ HWCAP_ATOMICS. ++ ++2018-07-06 Szabolcs Nagy ++ ++ * sysdeps/unix/sysv/linux/aarch64/cpu-features.c (init_cpu_features): ++ Use dl_hwcap without masking. ++ * sysdeps/unix/sysv/linux/aarch64/dl-procinfo.h (HWCAP_IMPORTANT): ++ Remove HWCAP_CPUID. ++ ++2019-09-13 Wilco Dijkstra ++ ++ * string/memmem.c (__memmem): Rewrite to improve performance. ++ ++2019-06-12 Wilco Dijkstra ++ ++ * string/str-two-way.h (two_way_short_needle): Add inline to avoid ++ warning. ++ (two_way_long_needle): Block inlining. ++ * string/strstr.c (strstr2): Add new function. ++ (strstr3): Likewise. ++ (STRSTR): Completely rewrite strstr to improve performance. ++ ++2019-09-13 Wilco Dijkstra ++ ++ [BZ #23637] ++ * string/test-strstr.c (pr23637): New function. ++ (test_main): Add tests with longer needles. ++ * string/strcasestr.c (AVAILABLE): Fix readahead distance. ++ * string/strstr.c (AVAILABLE): Likewise. ++ ++2019-09-13 Rajalakshmi Srinivasaraghavan ++ ++ * string/memmem.c: Use memcmp for first match. ++ ++2019-09-13 Wilco Dijkstra ++ ++ * string/strcasestr.c (STRCASESTR): Simplify and speedup first match. ++ * string/strstr.c (AVAILABLE): Likewise. ++ ++2019-09-13 Wilco Dijkstra ++ ++ * benchtests/bench-strcasestr.c: Rename __strnlen to strnlen. ++ * benchtests/bench-strstr.c: Likewise. ++ * string/memmem.c (FASTSEARCH): Define. ++ * string/str-two-way.h (two_way_short_needle): Minor cleanups. ++ Add support for FASTSEARCH. ++ * string/strcasestr.c (AVAILABLE): Use read-ahead __strnlen. ++ * string/strstr.c (AVAILABLE): Use read-ahead __strnlen. ++ (FASTSEARCH): Define. ++ * string/test-strcasestr.c: Rename __strnlen to strnlen. ++ * string/test-strstr.c: Likewise. ++ ++2019-09-06 Wilco Dijkstra ++ ++ * manual/tunables.texi (glibc.cpu.name): Add ares tunable. ++ * sysdeps/aarch64/multiarch/memcpy.c (__libc_memcpy): Use ++ __memcpy_falkor for ares. ++ * sysdeps/unix/sysv/linux/aarch64/cpu-features.h (IS_ARES): ++ Add new define. ++ * sysdeps/unix/sysv/linux/aarch64/cpu-features.c (cpu_list): ++ Add ares cpu. ++ ++2019-09-06 Siddhesh Poyarekar ++ ++ * sysdeps/aarch64/multiarch/memcpy_falkor.S (__memcpy_falkor): ++ Use vector registers. ++ ++2019-09-06 Siddhesh Poyarekar ++ ++ * sysdeps/aarch64/multiarch/memcpy_falkor.S (__memcpy_falkor): ++ Use multiple registers to copy data in loop tail. ++ ++2019-09-06 Siddhesh Poyarekar ++ ++ * sysdeps/aarch64/strncmp.S (strncmp): Use lsr instead of ++ mov + lsr. ++ ++2019-09-06 Siddhesh Poyarekar ++ ++ * sysdeps/aarch64/strncmp.S (strncmp): Use a separate shift ++ instruction to unbreak builds with binutils 2.26 and older. ++ ++2019-09-06 Siddhesh Poyarekar ++ ++ * sysdeps/aarch64/strncmp.S (count): New macro. ++ (strncmp): Store misaligned length in SRC1 in COUNT. ++ (mutual_align): Adjust. ++ (misaligned8): Load dword at a time when it is safe. ++ ++2019-09-06 Siddhesh Poyarekar ++ ++ * sysdeps/aarch64/strcmp.S (do_misaligned): Jump back to ++ do_misaligned, not misaligned8. ++ ++2019-09-06 Siddhesh Poyarekar ++ ++ * sysdeps/aarch64/strcmp.S (misaligned8): Compare dword at a ++ time whenever possible. ++ ++2019-09-06 Siddhesh Poyarekar ++ ++ * sysdeps/aarch64/memcmp.S: Widen comparison to 16 bytes at a ++ time. ++ ++2019-09-06 Siddhesh Poyarekar ++ ++ * sysdeps/aarch64/memcmp.S (more16): Fix loop16 branch target. ++ ++2019-09-06 Siddhesh Poyarekar ++ ++ * sysdeps/aarch64/memcmp.S: Use L() macro for labels. ++ ++2019-07-15 Adhemerval Zanella ++ ++ [BZ #24699] ++ * posix/tst-mmap-offset.c: Mention BZ #24699. ++ (do_test_bz21270): Rename to do_test_large_offset and use ++ mmap64_maximum_offset to check for maximum expected offset value. ++ * sysdeps/generic/mmap_info.h: New file. ++ * sysdeps/unix/sysv/linux/mips/mmap_info.h: Likewise. ++ * sysdeps/unix/sysv/linux/mmap64.c (MMAP_OFF_HIGH_MASK): Define iff ++ __NR_mmap2 is used. ++ ++2019-07-12 Szabolcs Nagy ++ ++ * sysdeps/aarch64/dl-machine.h (elf_machine_lazy_rel): Check ++ STO_AARCH64_VARIANT_PCS and bind such symbols at load time. ++ ++2019-06-13 Szabolcs Nagy ++ ++ * elf/elf.h (STO_AARCH64_VARIANT_PCS): Define. ++ (DT_AARCH64_VARIANT_PCS): Define. ++ ++2019-06-28 Florian Weimer ++ ++ [BZ #24744] ++ io: Remove the copy_file_range emulation. ++ * sysdeps/unix/sysv/linux/copy_file_range.c (copy_file_range): Do ++ not define and call copy_file_range_compat. ++ * io/Makefile (tests-static, tests-internal): Do not add ++ tst-copy_file_range-compat. ++ * io/copy_file_range-compat.c: Remove file. ++ * io/copy_file_range.c (copy_file_range): Define as stub. ++ * io/tst-copy_file_range-compat.c: Remove file. ++ * io/tst-copy_file_range.c (xdevfile): Remove variable. ++ (typical_sizes): Update comment. Remove 16K sizes. ++ (maximum_offset, maximum_offset_errno, maximum_offset_hard_limit): ++ Remove variables. ++ (find_maximum_offset, pipe_as_source, pipe_as_destination) ++ (delayed_write_failure_beginning, delayed_write_failure_end) ++ (cross_device_failure, enospc_failure_1, enospc_failure) ++ (oappend_failure): Remove functions. ++ (tests): Adjust test case list. ++ (do_test): Remove file system search code. Check for ENOSYS from ++ copy_file_range. Do not free xdevfile. ++ * manual/llio.texi (Copying File Data): Document ENOSYS error from ++ copy_file_range. Do not document the EXDEV error, which future ++ kernels may not report. Update the wording to reflect that ++ further errors are possible. ++ * sysdeps/unix/sysv/linux/kernel-features.h ++ [__LINUX_KERNEL_VERSION >= 0x040500] (__ASSUME_COPY_FILE_RANGE): ++ Remove definition. ++ * sysdeps/unix/sysv/linux/microblaze/kernel-features.h ++ [__LINUX_KERNEL_VERSION < 0x040A00] (__ASSUME_COPY_FILE_RANGE): Do ++ not undefine. ++ ++2019-06-20 Dmitry V. Levin ++ Florian Weimer ++ ++ [BZ #24228] ++ * libio/genops.c (_IO_unbuffer_all) ++ [SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)]: Do not attempt to free wide ++ buffers and access _IO_FILE_complete members of legacy libio streams. ++ * libio/tst-bz24228.c: New file. ++ * libio/tst-bz24228.map: Likewise. ++ * libio/Makefile [build-shared] (tests): Add tst-bz24228. ++ [build-shared] (generated): Add tst-bz24228.mtrace and ++ tst-bz24228.check. ++ [run-built-tests && build-shared] (tests-special): Add ++ $(objpfx)tst-bz24228-mem.out. ++ (LDFLAGS-tst-bz24228, tst-bz24228-ENV): New variables. ++ ($(objpfx)tst-bz24228-mem.out): New rule. ++ ++2019-05-22 Wilco Dijkstra ++ ++ [BZ #24531] ++ * malloc/malloc.c (MAX_TCACHE_COUNT): New define. ++ (do_set_tcache_count): Only update if count is small enough. ++ * manual/tunables.texi (glibc.malloc.tcache_count): Document max value. ++ ++2019-05-15 Andreas Schwab ++ ++ [BZ #20568] ++ * libio/wfileops.c (_IO_wfile_sync): Correct last argument to ++ __codecvt_do_length. ++ * libio/Makefile (tests): Add tst-wfile-sync. ++ ($(objpfx)tst-wfile-sync.out): Depend on $(gen-locales). ++ * libio/tst-wfile-sync.c: New file. ++ * libio/tst-wfile-sync.input: New file. ++ ++2019-04-23 Adhemerval Zanella ++ ++ [BZ #18035] ++ * elf/pldd-xx.c: Use _Static_assert in of pldd_assert. ++ (E(find_maps)): Avoid use alloca, use default read file operations ++ instead of explicit LFS names, and fix infinite loop. ++ * elf/pldd.c: Explicit set _FILE_OFFSET_BITS, cleanup headers. ++ (get_process_info): Use _Static_assert instead of assert, use default ++ directory operations instead of explicit LFS names, and free some ++ leadek pointers. ++ ++2019-04-02 TAMUKI Shoichi ++ ++ [BZ #22964] ++ * localedata/locales/ja_JP (LC_TIME): Add entry for the new Japanese ++ era. ++ ++2019-03-21 Stefan Liebler ++ ++ * sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT): ++ Add HWCAP_S390_VX and HWCAP_S390_VXE. ++ ++2019-02-07 Stefan Liebler ++ ++ [BZ #24180] ++ * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): ++ Add compiler barriers and comments. ++ ++2019-02-04 H.J. Lu ++ ++ [BZ #24155] ++ CVE-2019-7309 ++ * NEWS: Updated for CVE-2019-7309. ++ * sysdeps/x86_64/memcmp.S: Use RDX_LP for size. Clear the ++ upper 32 bits of RDX register for x32. Use unsigned Jcc ++ instructions, instead of signed. ++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp-2. ++ * sysdeps/x86_64/x32/tst-size_t-memcmp-2.c: New test. ++ ++2019-02-01 H.J. Lu ++ ++ [BZ #24097] ++ CVE-2019-6488 ++ * sysdeps/x86_64/multiarch/strlen-avx2.S: Use RSI_LP for length. ++ Clear the upper 32 bits of RSI register. ++ * sysdeps/x86_64/strlen.S: Use RSI_LP for length. ++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-strnlen ++ and tst-size_t-wcsnlen. ++ * sysdeps/x86_64/x32/tst-size_t-strnlen.c: New file. ++ * sysdeps/x86_64/x32/tst-size_t-wcsnlen.c: Likewise. ++ ++2019-02-01 H.J. Lu ++ ++ [BZ #24097] ++ CVE-2019-6488 ++ * sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: Use RDX_LP ++ for length. ++ * sysdeps/x86_64/multiarch/strcpy-ssse3.S: Likewise. ++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-strncpy. ++ * sysdeps/x86_64/x32/tst-size_t-strncpy.c: New file. ++ ++2019-02-01 H.J. Lu ++ ++ [BZ #24097] ++ CVE-2019-6488 ++ * sysdeps/x86_64/multiarch/strcmp-sse42.S: Use RDX_LP for length. ++ * sysdeps/x86_64/strcmp.S: Likewise. ++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-strncasecmp, ++ tst-size_t-strncmp and tst-size_t-wcsncmp. ++ * sysdeps/x86_64/x32/tst-size_t-strncasecmp.c: New file. ++ * sysdeps/x86_64/x32/tst-size_t-strncmp.c: Likewise. ++ * sysdeps/x86_64/x32/tst-size_t-wcsncmp.c: Likewise. ++ ++2019-02-01 H.J. Lu ++ ++ [BZ #24097] ++ CVE-2019-6488 ++ * sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S: Use ++ RDX_LP for length. Clear the upper 32 bits of RDX register. ++ * sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S: Likewise. ++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-wmemset. ++ * sysdeps/x86_64/x32/tst-size_t-memset.c: New file. ++ * sysdeps/x86_64/x32/tst-size_t-wmemset.c: Likewise. ++ ++2019-02-01 H.J. Lu ++ ++ [BZ #24097] ++ CVE-2019-6488 ++ * sysdeps/x86_64/memrchr.S: Use RDX_LP for length. ++ * sysdeps/x86_64/multiarch/memrchr-avx2.S: Likewise. ++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memrchr. ++ * sysdeps/x86_64/x32/tst-size_t-memrchr.c: New file. ++ ++2019-02-01 H.J. Lu ++ ++ [BZ #24097] ++ CVE-2019-6488 ++ * sysdeps/x86_64/multiarch/memcpy-ssse3-back.S: Use RDX_LP for ++ length. Clear the upper 32 bits of RDX register. ++ * sysdeps/x86_64/multiarch/memcpy-ssse3.S: Likewise. ++ * sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S: ++ Likewise. ++ * sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S: ++ Likewise. ++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcpy. ++ tst-size_t-wmemchr. ++ * sysdeps/x86_64/x32/tst-size_t-memcpy.c: New file. ++ ++2019-02-01 H.J. Lu ++ ++ [BZ #24097] ++ CVE-2019-6488 ++ * sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S: Use RDX_LP for ++ length. Clear the upper 32 bits of RDX register. ++ * sysdeps/x86_64/multiarch/memcmp-sse4.S: Likewise. ++ * sysdeps/x86_64/multiarch/memcmp-ssse3.S: Likewise. ++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memcmp and ++ tst-size_t-wmemcmp. ++ * sysdeps/x86_64/x32/tst-size_t-memcmp.c: New file. ++ * sysdeps/x86_64/x32/tst-size_t-wmemcmp.c: Likewise. ++ ++2019-02-01 H.J. Lu ++ ++ [BZ #24097] ++ CVE-2019-6488 ++ * sysdeps/x86_64/memchr.S: Use RDX_LP for length. Clear the ++ upper 32 bits of RDX register. ++ * sysdeps/x86_64/multiarch/memchr-avx2.S: Likewise. ++ * sysdeps/x86_64/x32/Makefile (tests): Add tst-size_t-memchr and ++ tst-size_t-wmemchr. ++ * sysdeps/x86_64/x32/test-size_t.h: New file. ++ * sysdeps/x86_64/x32/tst-size_t-memchr.c: Likewise. ++ * sysdeps/x86_64/x32/tst-size_t-wmemchr.c: Likewise. ++ ++2019-01-02 Florian Weimer ++ ++ [BZ #24018] ++ * intl/dcigettext.c (DCIGETTEXT): Do not return NULL on asprintf ++ failure. ++ ++2018-12-31 Florian Weimer ++ ++ [BZ #24027] ++ * malloc/malloc.c (_int_realloc): Always call memcpy for the ++ copying operation. (ncopies had the wrong type, resulting in an ++ integer wraparound and too few elements being copied.) ++ ++2018-12-13 Andreas Schwab ++ ++ [BZ #23861] ++ * nptl/pthread_rwlock_common.c: Reindent. Fix typos. ++ (__pthread_rwlock_rdlock_full): Update expected value for ++ __readers while waiting on PTHREAD_RWLOCK_RWAITING. ++ * nptl/tst-rwlock-pwn.c: New file. ++ * nptl/Makefile (tests): Add tst-rwlock-pwn. ++ ++2018-12-12 Tulio Magno Quites Machado Filho ++ ++ [BZ #23614] ++ * sysdeps/powerpc/powerpc64/addmul_1.S (FUNC): Add CFI offset for ++ registers saved in the stack frame. ++ * sysdeps/powerpc/powerpc64/lshift.S (__mpn_lshift): Likewise. ++ * sysdeps/powerpc/powerpc64/mul_1.S (__mpn_mul_1): Likewise. ++ ++2018-11-30 Tulio Magno Quites Machado Filho ++ ++ [BZ #23690] ++ * elf/dl-runtime.c (_dl_profile_fixup): Guarantee memory ++ modification order when accessing reloc_result->addr. ++ * include/link.h (reloc_result): Add field init. ++ * nptl/Makefile (tests): Add tst-audit-threads. ++ (modules-names): Add tst-audit-threads-mod1 and ++ tst-audit-threads-mod2. ++ Add rules to build tst-audit-threads. ++ * nptl/tst-audit-threads-mod1.c: New file. ++ * nptl/tst-audit-threads-mod2.c: Likewise. ++ * nptl/tst-audit-threads.c: Likewise. ++ * nptl/tst-audit-threads.h: Likewise. ++ ++2018-12-07 Florian Weimer ++ ++ [BZ #23927] ++ CVE-2018-19591 ++ * inet/tst-if_index-long.c: New file. ++ * inet/Makefile (tests): Add tst-if_index-long. ++ ++2018-12-07 Florian Weimer ++ ++ * support/check.h (support_record_failure_is_failed): Declare. ++ * support/descriptors.h: New file. ++ * support/support_descriptors.c: Likewise. ++ * support/tst-support_descriptors.c: Likewise. ++ * support/support_record_failure.c ++ (support_record_failure_is_failed): New function. ++ * support/Makefile (libsupport-routines): Add support_descriptors. ++ (tests): Add tst-support_descriptors. ++ ++2018-12-01 Florian Weimer ++ ++ * support/support_capture_subprocess.c ++ (support_capture_subprocess): Check that pipe descriptors have ++ expected values. Close original pipe descriptors in subprocess. ++ ++2018-11-28 Florian Weimer ++ ++ * support/support.h (support_quote_string): Do not use str ++ parameter name. ++ ++2018-11-27 Florian Weimer ++ ++ * support/support.h (support_quote_string): Declare. ++ * support/support_quote_string.c: New file. ++ * support/tst-support_quote_string.c: Likewise. ++ * support/Makefile (libsupport-routines): Add ++ support_quote_string. ++ (tests): Add tst-support_quote_string. ++ ++2018-12-07 DJ Delorie ++ ++ [BZ #23907] ++ * malloc/tst-tcfree3.c: New. ++ * malloc/Makefile: Add it. ++ ++2018-11-26 Florian Weimer ++ ++ [BZ #23907] ++ * malloc/malloc.c (_int_free): Validate tc_idx before checking for ++ double-frees. ++ ++ ++2018-11-20 DJ Delorie ++ ++ * malloc/malloc.c (tcache_entry): Add key field. ++ (tcache_put): Set it. ++ (tcache_get): Likewise. ++ (_int_free): Check for double free in tcache. ++ * malloc/tst-tcfree1.c: New. ++ * malloc/tst-tcfree2.c: New. ++ * malloc/Makefile: Run the new tests. ++ * manual/probes.texi: Document memory_tcache_double_free probe. ++ ++ * dlfcn/dlerror.c (check_free): Prevent double frees. ++ ++2018-11-27 Florian Weimer ++ ++ [BZ #23927] ++ CVE-2018-19591 ++ * sysdeps/unix/sysv/linux/if_index.c (__if_nametoindex): Avoid ++ descriptor leak in case of ENODEV error. ++ ++2018-11-08 Alexandra Hájková ++ ++ [BZ #17630] ++ * resolv/tst-resolv-network.c: Add test for getnetbyname. ++ ++2018-11-05 Andreas Schwab ++ ++ [BZ #22927] ++ * resolv/gai_misc.c (__gai_enqueue_request): Don't crash if ++ creating the first helper thread failed. ++ ++2018-10-23 Adhemerval Zanella ++ ++ [BZ #23709] ++ * sysdeps/x86/cpu-features.c (init_cpu_features): Set TSX bits ++ independently of other flags. ++ ++2018-10-26 Szabolcs Nagy ++ ++ [BZ #23822] ++ * sysdeps/ia64/fpu/e_exp2f.S (exp2f): Use WEAK_LIBM_ENTRY. ++ * sysdeps/ia64/fpu/e_log2f.S (log2f): Likewise. ++ * sysdeps/ia64/fpu/e_exp2f.S (powf): Likewise. ++ ++2018-10-25 Florian Weimer ++ ++ [BZ #23562] ++ [BZ #23821] ++ XFAIL siginfo_t si_band conform test on sparc64. ++ * sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h ++ (__SI_BAND_TYPE): Only override long int default type on sparc64. ++ * sysdeps/unix/sysv/linux/sparc/sparc64/Makefile ++ (conformtest-xfail-conds): Add sparc64-linux. ++ * conform/data/signal.h-data (siginfo_t): XFAIL si_band test on ++ sparc64. ++ * conform/data/sys/wait.h-data (siginfo_t): Likewise. ++ ++2018-10-19 Ilya Yu. Malakhov ++ ++ [BZ #23562] ++ * sysdeps/unix/sysv/linux/bits/types/siginfo_t.h ++ (struct siginfo_t): Use correct type for si_band. ++ ++2018-10-17 Stefan Liebler ++ ++ [BZ #23275] ++ * nptl/tst-mutex10.c: New File. ++ * nptl/Makefile (tests): Add tst-mutex10. ++ (tst-mutex10-ENV): New variable. ++ * sysdeps/unix/sysv/linux/s390/force-elision.h: (FORCE_ELISION): ++ Ensure that elision path is used if elision is available. ++ * sysdeps/unix/sysv/linux/powerpc/force-elision.h (FORCE_ELISION): ++ Likewise. ++ * sysdeps/unix/sysv/linux/x86/force-elision.h: (FORCE_ELISION): ++ Likewise. ++ * nptl/pthreadP.h (PTHREAD_MUTEX_TYPE, PTHREAD_MUTEX_TYPE_ELISION) ++ (PTHREAD_MUTEX_PSHARED): Use atomic_load_relaxed. ++ * nptl/pthread_mutex_consistent.c (pthread_mutex_consistent): Likewise. ++ * nptl/pthread_mutex_getprioceiling.c (pthread_mutex_getprioceiling): ++ Likewise. ++ * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full) ++ (__pthread_mutex_cond_lock_adjust): Likewise. ++ * nptl/pthread_mutex_setprioceiling.c (pthread_mutex_setprioceiling): ++ Likewise. ++ * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Likewise. ++ * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock): Likewise. ++ * nptl/pthread_mutex_unlock.c (__pthread_mutex_unlock_full): Likewise. ++ * sysdeps/nptl/bits/thread-shared-types.h (struct __pthread_mutex_s): ++ Add comments. ++ * nptl/pthread_mutex_destroy.c (__pthread_mutex_destroy): ++ Use atomic_load_relaxed and atomic_store_relaxed. ++ * nptl/pthread_mutex_init.c (__pthread_mutex_init): ++ Use atomic_store_relaxed. ++ ++2018-09-28 Adhemerval Zanella ++ ++ [BZ #23579] ++ * misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd, ++ do_test_with_invalid_iov): New tests. ++ * misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test): ++ Call do_test_with_invalid_fd and do_test_with_invalid_iov. ++ * sysdeps/unix/sysv/linux/preadv2.c (preadv2): Use fallback code iff ++ errno is ENOSYS. ++ * sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise. ++ * sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise. ++ * sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise. ++ * NEWS: Add bug fixed. ++ ++2018-09-28 Florian Weimer ++ ++ [BZ #22753] ++ * sysdeps/posix/preadv2.c (preadv2): Handle offset == -1. ++ * sysdeps/posix/preadv64v2.c (preadv64v2): Likewise. ++ * sysdeps/posix/pwritev2.c (pwritev2): Likewise. ++ * sysdeps/posix/pwritev64v2.c (pwritev64v2): Likweise. ++ * sysdeps/unix/sysv/linux/preadv2.c (preadv2): Likewise. ++ * sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise. ++ * sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise. ++ * sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likweise. ++ * manual/llio.texi (Scatter-Gather): Mention offset -1. ++ * misc/tst-preadvwritev-common.c (do_test_without_offset): New. ++ * misc/tst-preadvwritev2.c (do_test): Call it. ++ * misc/tst-preadvwritev64v2.c (do_test): Likewise. ++ * NEWS: Add bug fixed. ++ ++2018-09-06 Stefan Liebler ++ ++ * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute): ++ Increment size of new_argv by one. ++ ++2018-08-27 Martin Kuchta ++ Torvald Riegel ++ ++ [BZ #23538] ++ * nptl/pthread_cond_common.c (__condvar_quiesce_and_switch_g1): ++ Update r to include the set wake-request flag if waiters are ++ remaining after spinning. ++ ++2018-07-29 H.J. Lu ++ ++ [BZ #23459] ++ * sysdeps/x86/cpu-features.c (get_extended_indices): New ++ function. ++ (init_cpu_features): Call get_extended_indices for both Intel ++ and AMD CPUs. ++ * sysdeps/x86/cpu-features.h (COMMON_CPUID_INDEX_80000001): ++ Remove "for AMD" comment. ++ ++2018-07-29 H.J. Lu ++ ++ [BZ #23456] ++ * sysdeps/x86/cpu-features.h (index_cpu_LZCNT): Set to ++ COMMON_CPUID_INDEX_80000001. ++ ++2018-07-10 Florian Weimer ++ ++ [BZ #23036] ++ * posix/regexec.c (check_node_accept_bytes): When comparing ++ weights, do not compare an extra byte after the end of the ++ weights. ++ ++2018-06-29 Sylvain Lesage ++ ++ [BZ #22996] ++ * localedata/locales/es_BO (LC_PAPER): Change to “copy "en_US"”. ++ ++2018-07-06 Florian Weimer ++ ++ * conform/conformtest.pl (checknamespace): Escape literal braces ++ in regular expressions. ++ ++2018-06-21 Florian Weimer ++ ++ [BZ #23253] ++ * sysdeps/generic/math_private.h (default_libc_feholdsetround_ctx): ++ Renamed from libc_feholdsetround_ctx. ++ (default_libc_feresetround_ctx): Renamed from ++ libc_feresetround_ctx. ++ (default_libc_feholdsetround_noex_ctx): Renamed from ++ libc_feholdsetround_noex_ctx. ++ (default_libc_feresetround_noex_ctx): Renamed from ++ libc_feresetround_noex_ctx. ++ [!HAVE_RM_CTX] (libc_feholdsetround_ctx, libc_feresetround_ctx) ++ (libc_feholdsetround_noex_ctx, libc_feresetround_noex_ctx): Macros ++ forwardning to the old implementations under the new names. ++ * sysdeps/i386/fpu/fenv_private.h [__SSE_MATH__] ++ (libc_feholdexcept_setround_ctx, libc_fesetenv_ctx) ++ (libc_feupdateenv_ctx, libc_feholdsetround_ctx) ++ (libc_feresetround_ctx): Forward to default implements for i386 ++ and MATH_SET_BOTH_ROUNDING_MODES. ++ * sysdeps/i386/Makefile [$(subdir) == math] (CFLAGS-e_gamma_r.c): ++ Add -DMATH_SET_BOTH_ROUNDING_MODES. ++ ++2018-07-03 Florian Weimer ++ ++ [BZ #23363] ++ * stdio-common/tst-printf.c (DEC, INT, UNS, fp_test): Remove. ++ * stdio-common/tst-printf.sh: Adjust expected output. ++ * LICENSES: Update. ++ ++2018-06-26 Florian Weimer ++ ++ * libio/Makefile (tests-internal): Add tst-vtables, ++ tst-vtables-interposed. ++ * libio/tst-vtables.c: New file. ++ * libio/tst-vtables-common.c: Likewise. ++ * libio/tst-vtables-interposed.c: Likewise. ++ ++2018-06-26 Florian Weimer ++ ++ [BZ #23313] ++ * libio/vtables.c (check_stdfiles_vtables): New ELF constructor. ++ ++2018-06-29 Daniel Alvarez ++ Jakub Sitnicki ++ ++ [BZ #21812] ++ * sysdeps/unix/sysv/linux/ifaddrs.c (getifaddrs_internal): Retry ++ on NLM_F_DUMP_INTR. ++ ++2018-06-28 Florian Weimer ++ ++ [BZ #23349] ++ * time/bits/types/struct_timespec.h: Change header inclusion guard to ++ _STRUCT_TIMESPEC. ++ ++2018-05-24 Gabriel F. T. Gomes ++ ++ [BZ #23171] ++ * math/math.h [C++] (iseqsig): Fix parameter type for the long ++ double version. ++ ++2018-06-12 Carlos O'Donell ++ Andreas Schwab ++ Dmitry V. Levin ++ Florian Weimer ++ ++ [BZ #23102] ++ [BZ #21942] ++ [BZ #18018] ++ [BZ #23259] ++ CVE-2011-0536 ++ * elf/dl-dst.h: Remove DL_DST_COUNT. ++ * elf/dl-deps.c (expand_dst): Call _dl_dst_count. ++ * elf/dl-load.c (is_trusted_path_normalize): Don't handle colons. ++ (is_dst): Comment. Support ELF gABI. ++ (_dl_dst_count): Comment. Simplify and count DSTs. ++ (_dl_dst_substitute): Comment. Support __libc_enable_secure handling. ++ (expand_dybamic_string_token): Comment. Call _dl_dst_count. Rename ++ locals. ++ ++2018-06-12 Florian Weimer ++ ++ x86: Make strncmp usable from rtld. ++ * sysdeps/i386/i686/multiarch/strncmp-c.c: Only rename strncmp to ++ __strncmp_ia32 if in libc (and not in rtld). ++ * sysdeps/x86_64/multiarch/strncmp-sse2.S: Rename strcmp to ++ strncmp if not in libc (and not to __strncmp_sse2). ++ ++2018-06-01 Florian Weimer ++ ++ * sysdeps/i386/i686/fpu/multiarch/libm-test-ulps: Update from master ++ branch, commit e02c026f38505cd474ff1bdaa88fc671804f5805. ++ * sysdeps/i386/fpu/libm-test-ulps: Likewise. ++ ++2018-06-08 Adhemerval Zanella ++ ++ [BZ #23264] ++ * include/unistd.h (__execvpex): New prototype. ++ * posix/Makefile (tests): Add tst-spawn4. ++ (tests-internal): Add tst-spawn4-compat. ++ * posix/execvpe.c (__execvpe_common, __execvpex): New functions. ++ * posix/tst-spawn4-compat.c: New file. ++ * posix/tst-spawn4.c: Likewise. ++ * sysdeps/unix/sysv/linux/spawni.c (__spawni): Do not interpret invalid ++ binaries as shell scripts. ++ * sysdeps/posix/spawni.c (__spawni): Likewise. ++ * NEWS: Add BZ#22264. ++ ++2018-06-01 Florian Weimer ++ ++ [BZ #23236] ++ * libio/strfile.h (struct _IO_str_fields): Rename members to ++ discourage their use and add comment. ++ (_IO_STR_DYNAMIC): Remove unused macro. ++ * libio/strops.c (_IO_str_init_static_internal): Do not use ++ callback pointers. Call malloc and free. ++ (_IO_str_overflow): Do not use callback pointers. Call malloc ++ and free. ++ (enlarge_userbuf): Likewise. ++ (_IO_str_finish): Call free. ++ * libio/wstrops.c (_IO_wstr_init_static): Initialize ++ _allocate_buffer_unused. ++ (_IO_wstr_overflow): Do not use callback pointers. Call malloc ++ and free. ++ (enlarge_userbuf): Likewise. ++ (_IO_wstr_finish): Call free. ++ * debug/vasprintf_chk.c (__vasprintf_chk): Initialize ++ _allocate_buffer_unused, _free_buffer_unused. ++ * libio/memstream.c (__open_memstream): Likewise. ++ * libio/vasprintf.c (_IO_vasprintf): Likewise. ++ * libio/wmemstream.c (open_wmemstream): Likewise. ++ ++2018-05-23 H.J. Lu ++ ++ [BZ #23196] ++ * string/test-memcpy.c (do_test1): New function. ++ (test_main): Call it. ++ ++2018-05-23 Andreas Schwab ++ ++ [BZ #23196] ++ CVE-2018-11237 ++ * sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S ++ (L(preloop_large)): Save initial destination pointer in %r11 and ++ use it instead of %rax after the loop. ++ * string/test-mempcpy.c (MIN_PAGE_SIZE): Define. ++ ++2018-05-11 Florian Weimer ++ ++ [BZ #23166] ++ * include/rpc/clnt.h (rpc_createerr): Declare hidden alias. ++ * include/rpc/svc.h (svc_pollfd, svc_max_pollfd, svc_fdset): ++ Likewise. ++ * sunrpc/rpc_common.c (svc_fdset, rpc_createerr, svc_pollfd) ++ (svc_max_pollfd): Add nocommon attribute and hidden alias. Do not ++ export without --enable-obsolete-rpc. ++ * sunrpc/svcauth_des.c (svcauthdes_stats): Turn into compatibility ++ symbol. This should not have been exported, ever. ++ ++2018-05-11 Rafal Luzynski ++ ++ [BZ #23152] ++ * localedata/locales/gd_GB (abmon): Fix typo in May: ++ "Mhàrt" -> "Cèit". Adjust the comment according to the change. ++ ++2018-05-09 Paul Pluzhnikov ++ ++ [BZ #22786] ++ CVE-2018-11236 ++ * stdlib/canonicalize.c (__realpath): Fix overflow in path length ++ computation. ++ * stdlib/Makefile (test-bz22786): New test. ++ * stdlib/test-bz22786.c: New test. ++ ++2018-05-05 Paul Pluzhnikov ++ ++ [BZ #20419] ++ * elf/dl-load.c (open_verify): Fix stack overflow. ++ * elf/Makefile (tst-big-note): New test. ++ * elf/tst-big-note-lib.S: New. ++ * elf/tst-big-note.c: New. ++ ++2018-05-04 Stefan Liebler ++ ++ [BZ #23137] ++ * sysdeps/nptl/lowlevellock.h (lll_wait_tid): ++ Use atomic_load_acquire to load __tid. ++ ++2018-04-24 Joseph Myers ++ ++ * sysdeps/unix/sysv/linux/sys/ptrace.h ++ (PTRACE_SECCOMP_GET_METADATA): New enum value and macro. ++ * sysdeps/unix/sysv/linux/bits/ptrace-shared.h ++ (struct __ptrace_seccomp_metadata): New type. ++ * sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h ++ (PTRACE_SECCOMP_GET_METADATA): Likewise. ++ * sysdeps/unix/sysv/linux/arm/sys/ptrace.h ++ (PTRACE_SECCOMP_GET_METADATA): Likewise. ++ * sysdeps/unix/sysv/linux/ia64/sys/ptrace.h ++ (PTRACE_SECCOMP_GET_METADATA): Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h ++ (PTRACE_SECCOMP_GET_METADATA): Likewise. ++ * sysdeps/unix/sysv/linux/s390/sys/ptrace.h ++ (PTRACE_SECCOMP_GET_METADATA): Likewise. ++ * sysdeps/unix/sysv/linux/sparc/sys/ptrace.h ++ (PTRACE_SECCOMP_GET_METADATA): Likewise. ++ * sysdeps/unix/sysv/linux/tile/sys/ptrace.h ++ (PTRACE_SECCOMP_GET_METADATA): Likewise. ++ * sysdeps/unix/sysv/linux/x86/sys/ptrace.h ++ (PTRACE_SECCOMP_GET_METADATA): Likewise. ++ ++2018-04-09 Florian Weimer ++ ++ [BZ #23037] ++ * resolv/res_send.c (send_dg): Use designated initializers instead ++ of assignment to zero-initialize other fields of struct mmsghdr. ++ ++2018-04-06 Andreas Schwab ++ ++ * manual/charset.texi (Converting a Character): Fix typo. ++ ++2018-04-05 Florian Weimer ++ ++ * manual/examples/mbstouwcs.c (mbstouwcs): Fix loop termination, ++ integer overflow, memory leak on error, and indeterminate errno ++ value. Add a null wide character to terminate the result string. ++ * manual/charset.texi (Converting a Character): Mention embedded ++ null bytes in the mbrtowc input string. Explain what happens in ++ the -2 result case. Do not claim that mbrtowc is simple or ++ obvious to use. Adjust the description of the code example. Use ++ @code, not @var, for concrete variables. ++ ++2018-04-05 Florian Weimer ++ ++ * manual/examples/mbstouwcs.c: New file. ++ * manual/charset.texi (Converting a Character): Include it. ++ ++2018-04-03 H.J. Lu ++ ++ [BZ #22947] ++ * bits/uio-ext.h (RWF_APPEND): New. ++ * sysdeps/unix/sysv/linux/bits/uio-ext.h (RWF_APPEND): Likewise. ++ * manual/llio.texi: Document RWF_APPEND. ++ * misc/tst-preadvwritev2-common.c (RWF_APPEND): New. ++ (RWF_SUPPORTED): Add RWF_APPEND. ++ ++2018-03-27 Jesse Hathaway ++ ++ * sysdeps/unix/sysv/linux/getlogin_r.c (__getlogin_r_loginuid): Return ++ early when linux sentinel value is set. ++ ++2018-03-27 Andreas Schwab ++ ++ [BZ #23005] ++ * resolv/res_send.c (__res_context_send): Return ENOMEM if ++ allocation of private copy of nsaddr_list fails. ++ ++2018-03-20 Joseph Myers ++ ++ [BZ #17343] ++ * stdlib/random_r.c (__random_r): Use unsigned arithmetic for ++ possibly overflowing computations. ++ ++2018-04-26 Aurelien Jarno ++ ++ * signal/tst-sigaction.c: New file to test BZ #23069. ++ * signal/Makefile (tests): Fix indentation. Add tst-sigaction. ++ ++2018-04-28 Aurelien Jarno ++ ++ [BZ #23069] ++ * sysdeps/unix/sysv/linux/riscv/kernel_sigaction.h: New file. ++ + 2018-03-29 Florian Weimer + + * sysdeps/unix/sysv/linux/i386/tst-bz21269.c (do_test): Also +@@ -7,6 +884,7 @@ + Max Horn + + [BZ #22644] ++ CVE-2017-18269 + * sysdeps/i386/i686/multiarch/memcpy-sse2-unaligned.S: Fixed + branch conditions. + * string/test-memmove.c (do_test2): New testcase. +diff --git a/LICENSES b/LICENSES +index 80f7f14879..858076d9d3 100644 +--- a/LICENSES ++++ b/LICENSES +@@ -441,15 +441,6 @@ Permission to use, copy, modify, and distribute this + software is freely granted, provided that this notice + is preserved. + +-Part of stdio-common/tst-printf.c is copyright C E Chew: +- +-(C) Copyright C E Chew +- +-Feel free to copy, use and distribute this software provided: +- +- 1. you do not pretend that you wrote it +- 2. you leave this copyright notice intact. +- + Various long double libm functions are copyright Stephen L. Moshier: + + Copyright 2001 by Stephen L. Moshier +diff --git a/NEWS b/NEWS +index 4749f5f432..dcdfa74a99 100644 +--- a/NEWS ++++ b/NEWS +@@ -9,30 +9,150 @@ Version 2.27.1 + + Major new features: + ++* The entry for the new Japanese era has been added for ja_JP locale. ++ + * Nominative and genitive month names are now supported for the Catalan and + Czech languages. The Catalan and Greek languages now support abbreviated + alternative month names. + ++* Parsing of dynamic string tokens in DT_RPATH, DT_RUNPATH, DT_NEEDED, ++ DT_AUXILIARY, and DT_FILTER has been expanded to support the full ++ range of ELF gABI expressions including such constructs as ++ '$ORIGIN$ORIGIN' (if valid). For SUID/GUID applications the rules ++ have been further restricted, and where in the past a dynamic string ++ token sequence may have been interpreted as a literal string it will ++ now cause a load failure. These load failures were always considered ++ unspecified behaviour from the perspective of the dynamic loader, and ++ for safety are now load errors e.g. /foo/${ORIGIN}.so in DT_NEEDED ++ results in a load failure now. ++ ++Deprecated and removed features, and other changes affecting compatibility: ++ ++* The copy_file_range function fails with ENOSYS if the kernel does not ++ support the system call of the same name. Previously, user space ++ emulation was performed, but its behavior did not match the kernel ++ behavior, which was deemed too confusing. Applications which use the ++ copy_file_range function will have to be run on kernels which implement ++ the copy_file_range system call. Support for most architectures was added ++ in version 4.5 of the mainline Linux kernel. ++ ++Security related changes: ++ ++ CVE-2017-18269: An SSE2-based memmove implementation for the i386 ++ architecture could corrupt memory. Reported by Max Horn. ++ ++ CVE-2018-11236: Very long pathname arguments to realpath function could ++ result in an integer overflow and buffer overflow. Reported by Alexey ++ Izbyshev. ++ ++ CVE-2018-11237: The mempcpy implementation for the Intel Xeon Phi ++ architecture could write beyond the target buffer, resulting in a buffer ++ overflow. Reported by Andreas Schwab. ++ ++ CVE-2018-19591: A file descriptor leak in if_nametoindex can lead to a ++ denial of service due to resource exhaustion when processing getaddrinfo ++ calls with crafted host names. Reported by Guido Vranken. ++ ++ CVE-2019-6488: On x32, the size_t parameter may be passed in the lower ++ 32 bits of a 64-bit register with with non-zero upper 32 bit. When it ++ happened, accessing the 32-bit size_t value as the full 64-bit register ++ in the assembly string/memory functions would cause a buffer overflow. ++ Reported by H.J. Lu. ++ ++ CVE-2019-7309: x86-64 memcmp used signed Jcc instructions to check ++ size. For x86-64, memcmp on an object size larger than SSIZE_MAX ++ has undefined behavior. On x32, the size_t argument may be passed ++ in the lower 32 bits of the 64-bit RDX register with non-zero upper ++ 32 bits. When it happened with the sign bit of RDX register set, ++ memcmp gave the wrong result since it treated the size argument as ++ zero. Reported by H.J. Lu. ++ ++ CVE-2019-19126: ld.so failed to ignore the LD_PREFER_MAP_32BIT_EXEC ++ environment variable during program execution after a security ++ transition, allowing local attackers to restrict the possible mapping ++ addresses for loaded libraries and thus bypass ASLR for a setuid ++ program. Reported by Marcin Kościelnicki. ++ + The following bugs are resolved with this release: + + [6889] 'PWD' mentioned but not specified + [16335] Feature test macro documentation incomplete and out of date ++ [17343] Signed integer overflow in /stdlib/random_r.c ++ [18018] Additional $ORIGIN handling issues (CVE-2011-0536) ++ [18035] Fix pldd hang ++ [20419] files with large allocated notes crash in open_verify ++ [20568] Fix crash in _IO_wfile_sync + [21269] i386 sigaction sa_restorer handling is wrong ++ [21812] getifaddrs: Don't return ifa entries with NULL names ++ [21942] _dl_dst_substitute incorrectly handles $ORIGIN: with AT_SECURE=1 + [22342] NSCD not properly caching netgroup + [22638] sparc: static binaries are broken if glibc is built by gcc + configured with --enable-default-pie ++ [22644] memmove-sse2-unaligned on 32bit x86 produces garbage when crossing ++ 2GB threshold + [22735] Misleading typo in time.h source comment regarding CLOCKS_PER_SECOND ++ [22753] libc: preadv2/pwritev2 fallback code should handle offset=-1 ++ [22786] Stack buffer overflow in realpath() if input size is close ++ to SSIZE_MAX + [22797] Linux: use reserved name __key in pkey_get + [22807] PTRACE_* constants missing for powerpc + [22818] posix/tst-glob_lstat_compat failure on alpha + [22827] RISC-V ELF64 parser mis-reads flag in ldconfig + [22848] ca_ES: update date definitions from CLDR ++ [22884] RISCV fmax/fmin handle signalling NANs incorrectly + [22918] multiple common of `__nss_shadow_database' + [22919] sparc32: backtrace yields infinite backtrace with makecontext + [22926] FTBFS on powerpcspe ++ [22927] libanl: properly cleanup if first helper thread creation failed + [22932] lt_LT: Update of abbreviated month names from CLDR required + [22937] Greek (el_GR, el_CY) locales actually need ab_alt_mon ++ [22947] FAIL: misc/tst-preadvwritev2 + [22963] cs_CZ: Add alternative month names ++ [22964] The Japanese Era name will be changed on May 1, 2019 ++ [22996] localedata: change LC_PAPER to en_US in es_BO locale ++ [23005] Crash in __res_context_send after memory allocation failure ++ [23036] regexec: Fix off-by-one bug in weight comparison ++ [23037] initialize msg_flags to zero for sendmmsg() calls ++ [23069] sigaction broken on riscv64-linux-gnu ++ [23102] Incorrect parsing of consecutive $ variables in runpath entries ++ [23137] s390: pthread_join sometimes block indefinitely (on 31bit and libc ++ build with -Os) ++ [23152] gd_GB: Fix typo in "May" (abbreviated) ++ [23166] sunrpc: Remove stray exports without --enable-obsolete-rpc ++ [23171] Fix parameter type in C++ version of iseqsig ++ [23196] __mempcpy_avx512_no_vzeroupper mishandles large copies ++ [23236] Harden function pointers in _IO_str_fields ++ [23253] Set 387 and SSE2 rounding mode for tgamma on i386 ++ [23259] Unsubstituted ${ORIGIN} remains in DT_NEEDED for AT_SECURE ++ [23264] libc: posix_spawnp wrongly executes ENOEXEC in non compat mode ++ [23275] Race in pthread_mutex_lock while promoting to PTHREAD_MUTEX_ELISION_NP ++ [23313] libio: Disable vtable validation in case of interposition ++ [23349] Various glibc headers no longer compatible with ++ [23363] stdio-common/tst-printf.c has non-free license ++ [23456] Wrong index_cpu_LZCNT ++ [23459] COMMON_CPUID_INDEX_80000001 isn't populated for Intel processors ++ [23538] pthread_cond_broadcast: Fix waiters-after-spinning case ++ [23562] signal: Use correct type for si_band in siginfo_t ++ [23579] libc: Errors misreported in preadv2 ++ [23614] powerpc: missing CFI register information in __mpn_* functions ++ [23690] Fix _dl_profile_fixup data-dependency issue ++ [23709] Fix CPU string flags for Haswell-type CPUs ++ [23821] si_band in siginfo_t has wrong type long int on sparc64 ++ [23822] ia64 static libm.a is missing exp2f, log2f and powf symbols ++ [23861] rdlock stalls indefinitely on an unlocked pthread rwlock ++ [23907] Incorrect double-free malloc tcache check disregards tcache size ++ [23927] Linux if_nametoindex() does not close descriptor (CVE-2018-19591) ++ [24018] gettext may return NULL ++ [24027] malloc: Integer overflow in realloc ++ [24097] Can't use 64-bit register for size_t in assembly codes for x32 (CVE-2019-6488) ++ [24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309) ++ [24180] pthread_mutex_trylock does not use the correct order of instructions ++ while maintaining the robust mutex list due to missing compiler barriers ++ [24228] old x86 applications that use legacy libio crash on exit ++ [24531] Malloc tunables give tcache assertion failures ++ [24744] io: Remove the copy_file_range emulation ++ [25203] libio: Disable vtable validation for pre-2.1 interposed handles ++ [25204] Ignore LD_PREFER_MAP_32BIT_EXEC for SUID programs + + + Version 2.27 +diff --git a/benchtests/bench-strcasestr.c b/benchtests/bench-strcasestr.c +index e6659ea79e..4337e0c18d 100644 +--- a/benchtests/bench-strcasestr.c ++++ b/benchtests/bench-strcasestr.c +@@ -24,6 +24,7 @@ + #define STRCASESTR simple_strcasestr + #define NO_ALIAS + #define __strncasecmp strncasecmp ++#define __strnlen strnlen + #include "../string/strcasestr.c" + + +diff --git a/benchtests/bench-strstr.c b/benchtests/bench-strstr.c +index 86d5e829da..b7431de320 100644 +--- a/benchtests/bench-strstr.c ++++ b/benchtests/bench-strstr.c +@@ -22,6 +22,9 @@ + + + #define STRSTR simple_strstr ++#undef libc_hidden_builtin_def ++#define libc_hidden_builtin_def(X) ++#define __strnlen strnlen + #include "../string/strstr.c" + + +diff --git a/bits/uio-ext.h b/bits/uio-ext.h +index 8c15a05d9a..d5aa06fd08 100644 +--- a/bits/uio-ext.h ++++ b/bits/uio-ext.h +@@ -28,5 +28,6 @@ + #define RWF_DSYNC 0x00000002 /* per-IO O_DSYNC. */ + #define RWF_SYNC 0x00000004 /* per-IO O_SYNC. */ + #define RWF_NOWAIT 0x00000008 /* per-IO nonblocking mode. */ ++#define RWF_APPEND 0x00000010 /* per-IO O_APPEND. */ + + #endif /* sys/uio_ext.h */ +diff --git a/conform/conformtest.pl b/conform/conformtest.pl +index cb500f0e76..a4ef756105 100644 +--- a/conform/conformtest.pl ++++ b/conform/conformtest.pl +@@ -367,7 +367,7 @@ while ($#headers >= 0) { + s/^optional-//; + $optional = 1; + } +- if (/^element *({([^}]*)}|([^{ ]*)) *({([^}]*)}|([^{ ]*)) *([A-Za-z0-9_]*) *(.*)/) { ++ if (/^element *(\{([^}]*)\}|([^{ ]*)) *(\{([^}]*)\}|([^{ ]*)) *([A-Za-z0-9_]*) *(.*)/) { + my($struct) = "$2$3"; + my($type) = "$5$6"; + my($member) = "$7"; +@@ -556,7 +556,7 @@ while ($#headers >= 0) { + "Symbol \"$symbol\" has not the right value.", $res, + $xfail); + } +- } elsif (/^type *({([^}]*)|([a-zA-Z0-9_]*))/) { ++ } elsif (/^type *(\{([^}]*)|([a-zA-Z0-9_]*))/) { + my($type) = "$2$3"; + my($maybe_opaque) = 0; + +@@ -586,7 +586,7 @@ while ($#headers >= 0) { + ? "NOT AVAILABLE" + : "Type \"$type\" not available."), $missing, $optional, + $xfail); +- } elsif (/^tag *({([^}]*)|([a-zA-Z0-9_]*))/) { ++ } elsif (/^tag *(\{([^}]*)|([a-zA-Z0-9_]*))/) { + my($type) = "$2$3"; + + # Remember that this name is allowed. +@@ -607,7 +607,7 @@ while ($#headers >= 0) { + + compiletest ($fnamebase, "Testing for type $type", + "Type \"$type\" not available.", $missing, 0, $xfail); +- } elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) { ++ } elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) { + my($rettype) = "$2$3"; + my($fname) = "$4"; + my($args) = "$5"; +@@ -644,7 +644,7 @@ while ($#headers >= 0) { + "Function \"$fname\" has incorrect type.", $res, 0, + $xfail); + } +- } elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { ++ } elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { + my($rettype) = "$2$3"; + my($fname) = "$4"; + my($args) = "$5"; +@@ -681,7 +681,7 @@ while ($#headers >= 0) { + "Function \"$fname\" has incorrect type.", $res, 0, + $xfail); + } +- } elsif (/^variable *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) *(.*)/) { ++ } elsif (/^variable *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) *(.*)/) { + my($type) = "$2$3"; + my($vname) = "$4"; + my($rest) = "$5"; +@@ -713,7 +713,7 @@ while ($#headers >= 0) { + + compiletest ($fnamebase, "Test for type of variable $fname", + "Variable \"$vname\" has incorrect type.", $res, 0, $xfail); +- } elsif (/^macro-function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { ++ } elsif (/^macro-function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { + my($rettype) = "$2$3"; + my($fname) = "$4"; + my($args) = "$5"; +@@ -812,11 +812,11 @@ while ($#headers >= 0) { + + s/^xfail(\[([^\]]*)\])?-//; + s/^optional-//; +- if (/^element *({([^}]*)}|([^ ]*)) *({([^}]*)}|([^ ]*)) *([A-Za-z0-9_]*) *(.*)/) { ++ if (/^element *(\{([^}]*)\}|([^ ]*)) *(\{([^}]*)\}|([^ ]*)) *([A-Za-z0-9_]*) *(.*)/) { + push @allow, $7; + } elsif (/^(macro|constant|macro-constant|macro-int-constant) +([a-zA-Z0-9_]*) *(?:{([^}]*)} *)?(?:([>== 0) { + } else { + push @allow, $type; + } +- } elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) { ++ } elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) [(][*]([a-zA-Z0-9_]*) ([(].*[)])/) { + push @allow, $4; +- } elsif (/^function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { ++ } elsif (/^function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { + push @allow, $4; +- } elsif (/^variable *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*)/) { ++ } elsif (/^variable *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*)/) { + push @allow, $4; +- } elsif (/^macro-function *({([^}]*)}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { ++ } elsif (/^macro-function *(\{([^}]*)\}|([a-zA-Z0-9_]*)) ([a-zA-Z0-9_]*) ([(].*[)])/) { + push @allow, $4; + } elsif (/^symbol *([a-zA-Z0-9_]*) *([A-Za-z0-9_-]*)?/) { + push @allow, $1; +diff --git a/conform/data/signal.h-data b/conform/data/signal.h-data +index fa841cfdbe..88c1f5eba2 100644 +--- a/conform/data/signal.h-data ++++ b/conform/data/signal.h-data +@@ -170,7 +170,8 @@ element siginfo_t pid_t si_pid + element siginfo_t uid_t si_uid + element siginfo_t {void*} si_addr + element siginfo_t int si_status +-element siginfo_t long si_band ++// Bug 23821: si_band has type int on sparc64. ++xfail[sparc64-linux]-element siginfo_t long si_band + # endif + # ifndef XPG42 + element siginfo_t {union sigval} si_value +diff --git a/conform/data/sys/wait.h-data b/conform/data/sys/wait.h-data +index 559ebdf677..a6713461ea 100644 +--- a/conform/data/sys/wait.h-data ++++ b/conform/data/sys/wait.h-data +@@ -44,7 +44,8 @@ element siginfo_t pid_t si_pid + element siginfo_t uid_t si_uid + element siginfo_t {void*} si_addr + element siginfo_t int si_status +-element siginfo_t long si_band ++// Bug 23821: si_band has type int on sparc64. ++xfail[sparc64-linux]-element siginfo_t long si_band + # ifndef XPG42 + element siginfo_t {union sigval} si_value + # endif +diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c +index a00ef771e6..3eb64617fd 100644 +--- a/debug/vasprintf_chk.c ++++ b/debug/vasprintf_chk.c +@@ -55,8 +55,8 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format, + _IO_JUMPS (&sf._sbf) = &_IO_str_jumps; + _IO_str_init_static_internal (&sf, string, init_string_size, string); + sf._sbf._f._flags &= ~_IO_USER_BUF; +- sf._s._allocate_buffer = (_IO_alloc_type) malloc; +- sf._s._free_buffer = (_IO_free_type) free; ++ sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; ++ sf._s._free_buffer_unused = (_IO_free_type) free; + + /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n + can only come from read-only format strings. */ +diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c +index 04dce9ddc6..0fd1cf1adc 100644 +--- a/dlfcn/dlerror.c ++++ b/dlfcn/dlerror.c +@@ -197,7 +197,10 @@ check_free (struct dl_action_result *rec) + Dl_info info; + if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0) + #endif +- free ((char *) rec->errstring); ++ { ++ free ((char *) rec->errstring); ++ rec->errstring = NULL; ++ } + } + } + +diff --git a/elf/Makefile b/elf/Makefile +index 2a432d8bee..2d8fe88aa6 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -187,7 +187,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ + tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \ + tst-latepthread tst-tls-manydynamic tst-nodelete-dlclose \ +- tst-debug1 tst-main1 ++ tst-debug1 tst-main1 tst-big-note + # reldep9 + tests-internal += loadtest unload unload2 circleload1 \ + neededtest neededtest2 neededtest3 neededtest4 \ +@@ -272,7 +272,9 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \ + tst-latepthreadmod $(tst-tls-many-dynamic-modules) \ + tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin \ +- tst-main1mod tst-libc_dlvsym-dso ++ tst-main1mod tst-libc_dlvsym-dso \ ++ tst-big-note-lib ++ + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 + modules-names += tst-gnu2-tls1mod +@@ -1446,3 +1448,5 @@ $(objpfx)tst-libc_dlvsym-static: $(common-objpfx)dlfcn/libdl.a + tst-libc_dlvsym-static-ENV = \ + LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)dlfcn + $(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so ++ ++$(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so +diff --git a/elf/dl-deps.c b/elf/dl-deps.c +index c975fcffd7..20b8e94f2e 100644 +--- a/elf/dl-deps.c ++++ b/elf/dl-deps.c +@@ -100,7 +100,7 @@ struct list + ({ \ + const char *__str = (str); \ + const char *__result = __str; \ +- size_t __dst_cnt = DL_DST_COUNT (__str); \ ++ size_t __dst_cnt = _dl_dst_count (__str); \ + \ + if (__dst_cnt != 0) \ + { \ +diff --git a/elf/dl-dst.h b/elf/dl-dst.h +index 32de5d225a..859032be0d 100644 +--- a/elf/dl-dst.h ++++ b/elf/dl-dst.h +@@ -18,19 +18,6 @@ + + #include "trusted-dirs.h" + +-/* Determine the number of DST elements in the name. Only if IS_PATH is +- nonzero paths are recognized (i.e., multiple, ':' separated filenames). */ +-#define DL_DST_COUNT(name) \ +- ({ \ +- size_t __cnt = 0; \ +- const char *__sf = strchr (name, '$'); \ +- \ +- if (__glibc_unlikely (__sf != NULL)) \ +- __cnt = _dl_dst_count (__sf); \ +- \ +- __cnt; }) +- +- + #ifdef SHARED + # define IS_RTLD(l) (l) == &GL(dl_rtld_map) + #else +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 7554a99b5a..b20e2a46d0 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -122,12 +122,6 @@ is_trusted_path_normalize (const char *path, size_t len) + if (len == 0) + return false; + +- if (*path == ':') +- { +- ++path; +- --len; +- } +- + char *npath = (char *) alloca (len + 2); + char *wnp = npath; + while (*path != '\0') +@@ -178,114 +172,165 @@ is_trusted_path_normalize (const char *path, size_t len) + return false; + } + ++/* Given a substring starting at INPUT, just after the DST '$' start ++ token, determine if INPUT contains DST token REF, following the ++ ELF gABI rules for DSTs: ++ ++ * Longest possible sequence using the rules (greedy). + ++ * Must start with a $ (enforced by caller). ++ ++ * Must follow $ with one underscore or ASCII [A-Za-z] (caller ++ follows these rules for REF) or '{' (start curly quoted name). ++ ++ * Must follow first two characters with zero or more [A-Za-z0-9_] ++ (enforced by caller) or '}' (end curly quoted name). ++ ++ If the sequence is a DST matching REF then the length of the DST ++ (excluding the $ sign but including curly braces, if any) is ++ returned, otherwise 0. */ + static size_t +-is_dst (const char *start, const char *name, const char *str, int secure) ++is_dst (const char *input, const char *ref) + { +- size_t len; + bool is_curly = false; + +- if (name[0] == '{') ++ /* Is a ${...} input sequence? */ ++ if (input[0] == '{') + { + is_curly = true; +- ++name; +- } +- +- len = 0; +- while (name[len] == str[len] && name[len] != '\0') +- ++len; +- +- if (is_curly) +- { +- if (name[len] != '}') +- return 0; +- +- /* Point again at the beginning of the name. */ +- --name; +- /* Skip over closing curly brace and adjust for the --name. */ +- len += 2; ++ ++input; + } +- else if (name[len] != '\0' && name[len] != '/') +- return 0; + +- if (__glibc_unlikely (secure) +- && ((name[len] != '\0' && name[len] != '/') +- || (name != start + 1))) ++ /* Check for matching name, following closing curly brace (if ++ required), or trailing characters which are part of an ++ identifier. */ ++ size_t rlen = strlen (ref); ++ if (strncmp (input, ref, rlen) != 0 ++ || (is_curly && input[rlen] != '}') ++ || ((input[rlen] >= 'A' && input[rlen] <= 'Z') ++ || (input[rlen] >= 'a' && input[rlen] <= 'z') ++ || (input[rlen] >= '0' && input[rlen] <= '9') ++ || (input[rlen] == '_'))) + return 0; + +- return len; ++ if (is_curly) ++ /* Count the two curly braces. */ ++ return rlen + 2; ++ else ++ return rlen; + } + +- ++/* INPUT is the start of a DST sequence at the first '$' occurrence. ++ If there is a DST we call into _dl_dst_count to count the number of ++ DSTs. We count all known DSTs regardless of __libc_enable_secure; ++ the caller is responsible for enforcing the security of the ++ substitution rules (usually _dl_dst_substitute). */ + size_t +-_dl_dst_count (const char *name) ++_dl_dst_count (const char *input) + { +- const char *const start = name; + size_t cnt = 0; + ++ input = strchr (input, '$'); ++ ++ /* Most likely there is no DST. */ ++ if (__glibc_likely (input == NULL)) ++ return 0; ++ + do + { + size_t len; + +- /* $ORIGIN is not expanded for SUID/GUID programs (except if it +- is $ORIGIN alone) and it must always appear first in path. */ +- ++name; +- if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0 +- || (len = is_dst (start, name, "PLATFORM", 0)) != 0 +- || (len = is_dst (start, name, "LIB", 0)) != 0) ++ ++input; ++ /* All DSTs must follow ELF gABI rules, see is_dst (). */ ++ if ((len = is_dst (input, "ORIGIN")) != 0 ++ || (len = is_dst (input, "PLATFORM")) != 0 ++ || (len = is_dst (input, "LIB")) != 0) + ++cnt; + +- name = strchr (name + len, '$'); ++ /* There may be more than one DST in the input. */ ++ input = strchr (input + len, '$'); + } +- while (name != NULL); ++ while (input != NULL); + + return cnt; + } + +- ++/* Process INPUT for DSTs and store in RESULT using the information ++ from link map L to resolve the DSTs. This function only handles one ++ path at a time and does not handle colon-separated path lists (see ++ fillin_rpath ()). Lastly the size of result in bytes should be at ++ least equal to the value returned by DL_DST_REQUIRED. Note that it ++ is possible for a DT_NEEDED, DT_AUXILIARY, and DT_FILTER entries to ++ have colons, but we treat those as literal colons here, not as path ++ list delimeters. */ + char * +-_dl_dst_substitute (struct link_map *l, const char *name, char *result) ++_dl_dst_substitute (struct link_map *l, const char *input, char *result) + { +- const char *const start = name; +- +- /* Now fill the result path. While copying over the string we keep +- track of the start of the last path element. When we come across +- a DST we copy over the value or (if the value is not available) +- leave the entire path element out. */ ++ /* Copy character-by-character from input into the working pointer ++ looking for any DSTs. We track the start of input and if we are ++ going to check for trusted paths, all of which are part of $ORIGIN ++ handling in SUID/SGID cases (see below). In some cases, like when ++ a DST cannot be replaced, we may set result to an empty string and ++ return. */ + char *wp = result; +- char *last_elem = result; ++ const char *start = input; + bool check_for_trusted = false; + + do + { +- if (__glibc_unlikely (*name == '$')) ++ if (__glibc_unlikely (*input == '$')) + { + const char *repl = NULL; + size_t len; + +- ++name; +- if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0) ++ ++input; ++ if ((len = is_dst (input, "ORIGIN")) != 0) + { +- repl = l->l_origin; ++ /* For SUID/GUID programs we normally ignore the path with ++ $ORIGIN in DT_RUNPATH, or DT_RPATH. However, there is ++ one exception to this rule, and it is: ++ ++ * $ORIGIN appears as the first path element, and is ++ the only string in the path or is immediately ++ followed by a path separator and the rest of the ++ path. ++ ++ * The path is rooted in a trusted directory. ++ ++ This exception allows such programs to reference ++ shared libraries in subdirectories of trusted ++ directories. The use case is one of general ++ organization and deployment flexibility. ++ Trusted directories are usually such paths as "/lib64" ++ or "/usr/lib64", and the usual RPATHs take the form of ++ [$ORIGIN/../$LIB/somedir]. */ ++ if (__glibc_unlikely (__libc_enable_secure) ++ && !(input == start + 1 ++ && (input[len] == '\0' || input[len] == '/'))) ++ repl = (const char *) -1; ++ else ++ repl = l->l_origin; ++ + check_for_trusted = (__libc_enable_secure + && l->l_type == lt_executable); + } +- else if ((len = is_dst (start, name, "PLATFORM", 0)) != 0) ++ else if ((len = is_dst (input, "PLATFORM")) != 0) + repl = GLRO(dl_platform); +- else if ((len = is_dst (start, name, "LIB", 0)) != 0) ++ else if ((len = is_dst (input, "LIB")) != 0) + repl = DL_DST_LIB; + + if (repl != NULL && repl != (const char *) -1) + { + wp = __stpcpy (wp, repl); +- name += len; ++ input += len; + } +- else if (len > 1) ++ else if (len != 0) + { +- /* We cannot use this path element, the value of the +- replacement is unknown. */ +- wp = last_elem; +- break; ++ /* We found a valid DST that we know about, but we could ++ not find a replacement value for it, therefore we ++ cannot use this path and discard it. */ ++ *result = '\0'; ++ return result; + } + else + /* No DST we recognize. */ +@@ -293,16 +338,26 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result) + } + else + { +- *wp++ = *name++; ++ *wp++ = *input++; + } + } +- while (*name != '\0'); ++ while (*input != '\0'); + + /* In SUID/SGID programs, after $ORIGIN expansion the normalized +- path must be rooted in one of the trusted directories. */ ++ path must be rooted in one of the trusted directories. The $LIB ++ and $PLATFORM DST cannot in any way be manipulated by the caller ++ because they are fixed values that are set by the dynamic loader ++ and therefore any paths using just $LIB or $PLATFORM need not be ++ checked for trust, the authors of the binaries themselves are ++ trusted to have designed this correctly. Only $ORIGIN is tested in ++ this way because it may be manipulated in some ways with hard ++ links. */ + if (__glibc_unlikely (check_for_trusted) +- && !is_trusted_path_normalize (last_elem, wp - last_elem)) +- wp = last_elem; ++ && !is_trusted_path_normalize (result, wp - result)) ++ { ++ *result = '\0'; ++ return result; ++ } + + *wp = '\0'; + +@@ -310,13 +365,13 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result) + } + + +-/* Return copy of argument with all recognized dynamic string tokens +- ($ORIGIN and $PLATFORM for now) replaced. On some platforms it +- might not be possible to determine the path from which the object +- belonging to the map is loaded. In this case the path element +- containing $ORIGIN is left out. */ ++/* Return a malloc allocated copy of INPUT with all recognized DSTs ++ replaced. On some platforms it might not be possible to determine the ++ path from which the object belonging to the map is loaded. In this ++ case the path containing the DST is left out. On error NULL ++ is returned. */ + static char * +-expand_dynamic_string_token (struct link_map *l, const char *s) ++expand_dynamic_string_token (struct link_map *l, const char *input) + { + /* We make two runs over the string. First we determine how large the + resulting string is and then we copy it over. Since this is no +@@ -326,22 +381,22 @@ expand_dynamic_string_token (struct link_map *l, const char *s) + size_t total; + char *result; + +- /* Determine the number of DST elements. */ +- cnt = DL_DST_COUNT (s); ++ /* Determine the number of DSTs. */ ++ cnt = _dl_dst_count (input); + + /* If we do not have to replace anything simply copy the string. */ + if (__glibc_likely (cnt == 0)) +- return __strdup (s); ++ return __strdup (input); + + /* Determine the length of the substituted string. */ +- total = DL_DST_REQUIRED (l, s, strlen (s), cnt); ++ total = DL_DST_REQUIRED (l, input, strlen (input), cnt); + + /* Allocate the necessary memory. */ + result = (char *) malloc (total + 1); + if (result == NULL) + return NULL; + +- return _dl_dst_substitute (l, s, result); ++ return _dl_dst_substitute (l, input, result); + } + + +@@ -1469,6 +1524,7 @@ open_verify (const char *name, int fd, + ElfW(Ehdr) *ehdr; + ElfW(Phdr) *phdr, *ph; + ElfW(Word) *abi_note; ++ ElfW(Word) *abi_note_malloced = NULL; + unsigned int osversion; + size_t maplength; + +@@ -1640,10 +1696,25 @@ open_verify (const char *name, int fd, + abi_note = (void *) (fbp->buf + ph->p_offset); + else + { +- abi_note = alloca (size); ++ /* Note: __libc_use_alloca is not usable here, because ++ thread info may not have been set up yet. */ ++ if (size < __MAX_ALLOCA_CUTOFF) ++ abi_note = alloca (size); ++ else ++ { ++ /* There could be multiple PT_NOTEs. */ ++ abi_note_malloced = realloc (abi_note_malloced, size); ++ if (abi_note_malloced == NULL) ++ goto read_error; ++ ++ abi_note = abi_note_malloced; ++ } + __lseek (fd, ph->p_offset, SEEK_SET); + if (__libc_read (fd, (void *) abi_note, size) != size) +- goto read_error; ++ { ++ free (abi_note_malloced); ++ goto read_error; ++ } + } + + while (memcmp (abi_note, &expected_note, sizeof (expected_note))) +@@ -1678,6 +1749,7 @@ open_verify (const char *name, int fd, + + break; + } ++ free (abi_note_malloced); + } + + return fd; +diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c +index 61ef6d61ca..9ce488b673 100644 +--- a/elf/dl-runtime.c ++++ b/elf/dl-runtime.c +@@ -184,10 +184,36 @@ _dl_profile_fixup ( + /* This is the address in the array where we store the result of previous + relocations. */ + struct reloc_result *reloc_result = &l->l_reloc_result[reloc_index]; +- DL_FIXUP_VALUE_TYPE *resultp = &reloc_result->addr; + +- DL_FIXUP_VALUE_TYPE value = *resultp; +- if (DL_FIXUP_VALUE_CODE_ADDR (value) == 0) ++ /* CONCURRENCY NOTES: ++ ++ Multiple threads may be calling the same PLT sequence and with ++ LD_AUDIT enabled they will be calling into _dl_profile_fixup to ++ update the reloc_result with the result of the lazy resolution. ++ The reloc_result guard variable is reloc_init, and we use ++ acquire/release loads and store to it to ensure that the results of ++ the structure are consistent with the loaded value of the guard. ++ This does not fix all of the data races that occur when two or more ++ threads read reloc_result->reloc_init with a value of zero and read ++ and write to that reloc_result concurrently. The expectation is ++ generally that while this is a data race it works because the ++ threads write the same values. Until the data races are fixed ++ there is a potential for problems to arise from these data races. ++ The reloc result updates should happen in parallel but there should ++ be an atomic RMW which does the final update to the real result ++ entry (see bug 23790). ++ ++ The following code uses reloc_result->init set to 0 to indicate if it is ++ the first time this object is being relocated, otherwise 1 which ++ indicates the object has already been relocated. ++ ++ Reading/Writing from/to reloc_result->reloc_init must not happen ++ before previous writes to reloc_result complete as they could ++ end-up with an incomplete struct. */ ++ DL_FIXUP_VALUE_TYPE value; ++ unsigned int init = atomic_load_acquire (&reloc_result->init); ++ ++ if (init == 0) + { + /* This is the first time we have to relocate this object. */ + const ElfW(Sym) *const symtab +@@ -349,19 +375,31 @@ _dl_profile_fixup ( + + /* Store the result for later runs. */ + if (__glibc_likely (! GLRO(dl_bind_not))) +- *resultp = value; ++ { ++ reloc_result->addr = value; ++ /* Guarantee all previous writes complete before ++ init is updated. See CONCURRENCY NOTES earlier */ ++ atomic_store_release (&reloc_result->init, 1); ++ } ++ init = 1; + } ++ else ++ value = reloc_result->addr; + + /* By default we do not call the pltexit function. */ + long int framesize = -1; + ++ + #ifdef SHARED + /* Auditing checkpoint: report the PLT entering and allow the + auditors to change the value. */ +- if (DL_FIXUP_VALUE_CODE_ADDR (value) != 0 && GLRO(dl_naudit) > 0 ++ if (GLRO(dl_naudit) > 0 + /* Don't do anything if no auditor wants to intercept this call. */ + && (reloc_result->enterexit & LA_SYMB_NOPLTENTER) == 0) + { ++ /* Sanity check: DL_FIXUP_VALUE_CODE_ADDR (value) should have been ++ initialized earlier in this function or in another thread. */ ++ assert (DL_FIXUP_VALUE_CODE_ADDR (value) != 0); + ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound, + l_info[DT_SYMTAB]) + + reloc_result->boundndx); +diff --git a/elf/elf.h b/elf/elf.h +index 954f3266f7..f6ce814d43 100644 +--- a/elf/elf.h ++++ b/elf/elf.h +@@ -2835,6 +2835,13 @@ enum + #define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */ + #define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */ + ++/* AArch64 specific values for the Dyn d_tag field. */ ++#define DT_AARCH64_VARIANT_PCS (DT_LOPROC + 5) ++#define DT_AARCH64_NUM 6 ++ ++/* AArch64 specific values for the st_other field. */ ++#define STO_AARCH64_VARIANT_PCS 0x80 ++ + /* ARM relocs. */ + + #define R_ARM_NONE 0 /* No reloc */ +diff --git a/elf/pldd-xx.c b/elf/pldd-xx.c +index 2823dea662..f818d98582 100644 +--- a/elf/pldd-xx.c ++++ b/elf/pldd-xx.c +@@ -23,10 +23,6 @@ + #define EW_(e, w, t) EW__(e, w, _##t) + #define EW__(e, w, t) e##w##t + +-#define pldd_assert(name, exp) \ +- typedef int __assert_##name[((exp) != 0) - 1] +- +- + struct E(link_map) + { + EW(Addr) l_addr; +@@ -39,12 +35,12 @@ struct E(link_map) + EW(Addr) l_libname; + }; + #if CLASS == __ELF_NATIVE_CLASS +-pldd_assert (l_addr, (offsetof (struct link_map, l_addr) +- == offsetof (struct E(link_map), l_addr))); +-pldd_assert (l_name, (offsetof (struct link_map, l_name) +- == offsetof (struct E(link_map), l_name))); +-pldd_assert (l_next, (offsetof (struct link_map, l_next) +- == offsetof (struct E(link_map), l_next))); ++_Static_assert (offsetof (struct link_map, l_addr) ++ == offsetof (struct E(link_map), l_addr), "l_addr"); ++_Static_assert (offsetof (struct link_map, l_name) ++ == offsetof (struct E(link_map), l_name), "l_name"); ++_Static_assert (offsetof (struct link_map, l_next) ++ == offsetof (struct E(link_map), l_next), "l_next"); + #endif + + +@@ -54,10 +50,10 @@ struct E(libname_list) + EW(Addr) next; + }; + #if CLASS == __ELF_NATIVE_CLASS +-pldd_assert (name, (offsetof (struct libname_list, name) +- == offsetof (struct E(libname_list), name))); +-pldd_assert (next, (offsetof (struct libname_list, next) +- == offsetof (struct E(libname_list), next))); ++_Static_assert (offsetof (struct libname_list, name) ++ == offsetof (struct E(libname_list), name), "name"); ++_Static_assert (offsetof (struct libname_list, next) ++ == offsetof (struct E(libname_list), next), "next"); + #endif + + struct E(r_debug) +@@ -69,16 +65,17 @@ struct E(r_debug) + EW(Addr) r_map; + }; + #if CLASS == __ELF_NATIVE_CLASS +-pldd_assert (r_version, (offsetof (struct r_debug, r_version) +- == offsetof (struct E(r_debug), r_version))); +-pldd_assert (r_map, (offsetof (struct r_debug, r_map) +- == offsetof (struct E(r_debug), r_map))); ++_Static_assert (offsetof (struct r_debug, r_version) ++ == offsetof (struct E(r_debug), r_version), "r_version"); ++_Static_assert (offsetof (struct r_debug, r_map) ++ == offsetof (struct E(r_debug), r_map), "r_map"); + #endif + + + static int + +-E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) ++E(find_maps) (const char *exe, int memfd, pid_t pid, void *auxv, ++ size_t auxv_size) + { + EW(Addr) phdr = 0; + unsigned int phnum = 0; +@@ -104,12 +101,9 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + if (phdr == 0 || phnum == 0 || phent == 0) + error (EXIT_FAILURE, 0, gettext ("cannot find program header of process")); + +- EW(Phdr) *p = alloca (phnum * phent); +- if (pread64 (memfd, p, phnum * phent, phdr) != phnum * phent) +- { +- error (0, 0, gettext ("cannot read program header")); +- return EXIT_FAILURE; +- } ++ EW(Phdr) *p = xmalloc (phnum * phent); ++ if (pread (memfd, p, phnum * phent, phdr) != phnum * phent) ++ error (EXIT_FAILURE, 0, gettext ("cannot read program header")); + + /* Determine the load offset. We need this for interpreting the + other program header entries so we do this in a separate loop. +@@ -129,24 +123,18 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + if (p[i].p_type == PT_DYNAMIC) + { + EW(Dyn) *dyn = xmalloc (p[i].p_filesz); +- if (pread64 (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr) ++ if (pread (memfd, dyn, p[i].p_filesz, offset + p[i].p_vaddr) + != p[i].p_filesz) +- { +- error (0, 0, gettext ("cannot read dynamic section")); +- return EXIT_FAILURE; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read dynamic section")); + + /* Search for the DT_DEBUG entry. */ + for (unsigned int j = 0; j < p[i].p_filesz / sizeof (EW(Dyn)); ++j) + if (dyn[j].d_tag == DT_DEBUG && dyn[j].d_un.d_ptr != 0) + { + struct E(r_debug) r; +- if (pread64 (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr) ++ if (pread (memfd, &r, sizeof (r), dyn[j].d_un.d_ptr) + != sizeof (r)) +- { +- error (0, 0, gettext ("cannot read r_debug")); +- return EXIT_FAILURE; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read r_debug")); + + if (r.r_map != 0) + { +@@ -160,13 +148,10 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + } + else if (p[i].p_type == PT_INTERP) + { +- interp = alloca (p[i].p_filesz); +- if (pread64 (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr) ++ interp = xmalloc (p[i].p_filesz); ++ if (pread (memfd, interp, p[i].p_filesz, offset + p[i].p_vaddr) + != p[i].p_filesz) +- { +- error (0, 0, gettext ("cannot read program interpreter")); +- return EXIT_FAILURE; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read program interpreter")); + } + + if (list == 0) +@@ -174,14 +159,16 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + if (interp == NULL) + { + // XXX check whether the executable itself is the loader +- return EXIT_FAILURE; ++ exit (EXIT_FAILURE); + } + + // XXX perhaps try finding ld.so and _r_debug in it +- +- return EXIT_FAILURE; ++ exit (EXIT_FAILURE); + } + ++ free (p); ++ free (interp); ++ + /* Print the PID and program name first. */ + printf ("%lu:\t%s\n", (unsigned long int) pid, exe); + +@@ -192,47 +179,27 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + do + { + struct E(link_map) m; +- if (pread64 (memfd, &m, sizeof (m), list) != sizeof (m)) +- { +- error (0, 0, gettext ("cannot read link map")); +- status = EXIT_FAILURE; +- goto out; +- } ++ if (pread (memfd, &m, sizeof (m), list) != sizeof (m)) ++ error (EXIT_FAILURE, 0, gettext ("cannot read link map")); + + EW(Addr) name_offset = m.l_name; +- again: + while (1) + { +- ssize_t n = pread64 (memfd, tmpbuf.data, tmpbuf.length, name_offset); ++ ssize_t n = pread (memfd, tmpbuf.data, tmpbuf.length, name_offset); + if (n == -1) +- { +- error (0, 0, gettext ("cannot read object name")); +- status = EXIT_FAILURE; +- goto out; +- } ++ error (EXIT_FAILURE, 0, gettext ("cannot read object name")); + + if (memchr (tmpbuf.data, '\0', n) != NULL) + break; + + if (!scratch_buffer_grow (&tmpbuf)) +- { +- error (0, 0, gettext ("cannot allocate buffer for object name")); +- status = EXIT_FAILURE; +- goto out; +- } ++ error (EXIT_FAILURE, 0, ++ gettext ("cannot allocate buffer for object name")); + } + +- if (((char *)tmpbuf.data)[0] == '\0' && name_offset == m.l_name +- && m.l_libname != 0) +- { +- /* Try the l_libname element. */ +- struct E(libname_list) ln; +- if (pread64 (memfd, &ln, sizeof (ln), m.l_libname) == sizeof (ln)) +- { +- name_offset = ln.name; +- goto again; +- } +- } ++ /* The m.l_name and m.l_libname.name for loader linkmap points to same ++ values (since BZ#387 fix). Trying to use l_libname name as the ++ shared object name might lead to an infinite loop (BZ#18035). */ + + /* Skip over the executable. */ + if (((char *)tmpbuf.data)[0] != '\0') +@@ -242,7 +209,6 @@ E(find_maps) (pid_t pid, void *auxv, size_t auxv_size) + } + while (list != 0); + +- out: + scratch_buffer_free (&tmpbuf); + return status; + } +diff --git a/elf/pldd.c b/elf/pldd.c +index b8106fdc33..0bdfff450a 100644 +--- a/elf/pldd.c ++++ b/elf/pldd.c +@@ -17,23 +17,17 @@ + License along with the GNU C Library; if not, see + . */ + +-#include ++#define _FILE_OFFSET_BITS 64 ++ + #include +-#include + #include +-#include +-#include + #include + #include + #include +-#include +-#include + #include + #include +-#include + #include + #include +-#include + #include + #include + +@@ -76,14 +70,9 @@ static struct argp argp = + options, parse_opt, args_doc, doc, NULL, more_help, NULL + }; + +-// File descriptor of /proc/*/mem file. +-static int memfd; +- +-/* Name of the executable */ +-static char *exe; + + /* Local functions. */ +-static int get_process_info (int dfd, long int pid); ++static int get_process_info (const char *exe, int dfd, long int pid); + static void wait_for_ptrace_stop (long int pid); + + +@@ -102,8 +91,10 @@ main (int argc, char *argv[]) + return 1; + } + +- assert (sizeof (pid_t) == sizeof (int) +- || sizeof (pid_t) == sizeof (long int)); ++ _Static_assert (sizeof (pid_t) == sizeof (int) ++ || sizeof (pid_t) == sizeof (long int), ++ "sizeof (pid_t) != sizeof (int) or sizeof (long int)"); ++ + char *endp; + errno = 0; + long int pid = strtol (argv[remaining], &endp, 10); +@@ -119,25 +110,24 @@ main (int argc, char *argv[]) + if (dfd == -1) + error (EXIT_FAILURE, errno, gettext ("cannot open %s"), buf); + +- struct scratch_buffer exebuf; +- scratch_buffer_init (&exebuf); ++ /* Name of the executable */ ++ struct scratch_buffer exe; ++ scratch_buffer_init (&exe); + ssize_t nexe; + while ((nexe = readlinkat (dfd, "exe", +- exebuf.data, exebuf.length)) == exebuf.length) ++ exe.data, exe.length)) == exe.length) + { +- if (!scratch_buffer_grow (&exebuf)) ++ if (!scratch_buffer_grow (&exe)) + { + nexe = -1; + break; + } + } + if (nexe == -1) +- exe = (char *) ""; ++ /* Default stack allocation is at least 1024. */ ++ snprintf (exe.data, exe.length, ""); + else +- { +- exe = exebuf.data; +- exe[nexe] = '\0'; +- } ++ ((char*)exe.data)[nexe] = '\0'; + + /* Stop all threads since otherwise the list of loaded modules might + change while we are reading it. */ +@@ -155,8 +145,8 @@ main (int argc, char *argv[]) + error (EXIT_FAILURE, errno, gettext ("cannot prepare reading %s/task"), + buf); + +- struct dirent64 *d; +- while ((d = readdir64 (dir)) != NULL) ++ struct dirent *d; ++ while ((d = readdir (dir)) != NULL) + { + if (! isdigit (d->d_name[0])) + continue; +@@ -182,7 +172,7 @@ main (int argc, char *argv[]) + + wait_for_ptrace_stop (tid); + +- struct thread_list *newp = alloca (sizeof (*newp)); ++ struct thread_list *newp = xmalloc (sizeof (*newp)); + newp->tid = tid; + newp->next = thread_list; + thread_list = newp; +@@ -190,17 +180,22 @@ main (int argc, char *argv[]) + + closedir (dir); + +- int status = get_process_info (dfd, pid); ++ if (thread_list == NULL) ++ error (EXIT_FAILURE, 0, gettext ("no valid %s/task entries"), buf); ++ ++ int status = get_process_info (exe.data, dfd, pid); + +- assert (thread_list != NULL); + do + { + ptrace (PTRACE_DETACH, thread_list->tid, NULL, NULL); ++ struct thread_list *prev = thread_list; + thread_list = thread_list->next; ++ free (prev); + } + while (thread_list != NULL); + + close (dfd); ++ scratch_buffer_free (&exe); + + return status; + } +@@ -281,9 +276,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ + + + static int +-get_process_info (int dfd, long int pid) ++get_process_info (const char *exe, int dfd, long int pid) + { +- memfd = openat (dfd, "mem", O_RDONLY); ++ /* File descriptor of /proc//mem file. */ ++ int memfd = openat (dfd, "mem", O_RDONLY); + if (memfd == -1) + goto no_info; + +@@ -333,9 +329,9 @@ get_process_info (int dfd, long int pid) + + int retval; + if (e_ident[EI_CLASS] == ELFCLASS32) +- retval = find_maps32 (pid, auxv, auxv_size); ++ retval = find_maps32 (exe, memfd, pid, auxv, auxv_size); + else +- retval = find_maps64 (pid, auxv, auxv_size); ++ retval = find_maps64 (exe, memfd, pid, auxv, auxv_size); + + free (auxv); + close (memfd); +diff --git a/elf/tst-big-note-lib.S b/elf/tst-big-note-lib.S +new file mode 100644 +index 0000000000..6b514a03cc +--- /dev/null ++++ b/elf/tst-big-note-lib.S +@@ -0,0 +1,26 @@ ++/* Bug 20419: test for stack overflow in elf/dl-load.c open_verify() ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* This creates a .so with 8MiB PT_NOTE segment. ++ On a typical Linux system with 8MiB "ulimit -s", that was enough ++ to trigger stack overflow in open_verify. */ ++ ++.pushsection .note.big,"a" ++.balign 4 ++.fill 8*1024*1024, 1, 0 ++.popsection +diff --git a/io/tst-copy_file_range-compat.c b/elf/tst-big-note.c +similarity index 57% +rename from io/tst-copy_file_range-compat.c +rename to elf/tst-big-note.c +index 00c109a74d..fcd2b0ed82 100644 +--- a/io/tst-copy_file_range-compat.c ++++ b/elf/tst-big-note.c +@@ -1,5 +1,5 @@ +-/* Test the fallback implementation of copy_file_range. +- Copyright (C) 2017-2018 Free Software Foundation, Inc. ++/* Bug 20419: test for stack overflow in elf/dl-load.c open_verify() ++ Copyright (C) 2018 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 +@@ -16,15 +16,11 @@ + License along with the GNU C Library; if not, see + . */ + +-/* Get the declaration of the official copy_of_range function. */ +-#include ++/* This file must be run from within a directory called "elf". */ + +-/* Compile a local version of copy_file_range. */ +-#define COPY_FILE_RANGE_DECL static +-#define COPY_FILE_RANGE copy_file_range_compat +-#include +- +-/* Re-use the test, but run it against copy_file_range_compat defined +- above. */ +-#define copy_file_range copy_file_range_compat +-#include "tst-copy_file_range.c" ++int main (int argc, char *argv[]) ++{ ++ /* Nothing to do here: merely linking against tst-big-note-lib.so triggers ++ the bug. */ ++ return 0; ++} +diff --git a/include/link.h b/include/link.h +index 5924594548..83b1c34b7b 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -216,6 +216,10 @@ struct link_map + unsigned int boundndx; + uint32_t enterexit; + unsigned int flags; ++ /* CONCURRENCY NOTE: This is used to guard the concurrent initialization ++ of the relocation result across multiple threads. See the more ++ detailed notes in elf/dl-runtime.c. */ ++ unsigned int init; + } *l_reloc_result; + + /* Pointer to the version information if available. */ +diff --git a/include/rpc/clnt.h b/include/rpc/clnt.h +index a397023a93..80be0a9cec 100644 +--- a/include/rpc/clnt.h ++++ b/include/rpc/clnt.h +@@ -28,6 +28,7 @@ libc_hidden_proto (clntudp_create) + libc_hidden_proto (get_myaddress) + libc_hidden_proto (clntunix_create) + libc_hidden_proto (__libc_clntudp_bufcreate) ++libc_hidden_proto (rpc_createerr) + + # endif /* !_ISOMAC */ + #endif +diff --git a/include/rpc/svc.h b/include/rpc/svc.h +index 465bf4427d..40ba2546a9 100644 +--- a/include/rpc/svc.h ++++ b/include/rpc/svc.h +@@ -3,6 +3,10 @@ + + # ifndef _ISOMAC + ++libc_hidden_proto (svc_pollfd) ++libc_hidden_proto (svc_max_pollfd) ++libc_hidden_proto (svc_fdset) ++ + libc_hidden_proto (xprt_register) + libc_hidden_proto (xprt_unregister) + libc_hidden_proto (svc_register) +diff --git a/include/unistd.h b/include/unistd.h +index 0f91b8babc..a171b00326 100644 +--- a/include/unistd.h ++++ b/include/unistd.h +@@ -77,6 +77,8 @@ extern char *__getcwd (char *__buf, size_t __size) attribute_hidden; + extern int __rmdir (const char *__path) attribute_hidden; + extern int __execvpe (const char *file, char *const argv[], + char *const envp[]) attribute_hidden; ++extern int __execvpex (const char *file, char *const argv[], ++ char *const envp[]) attribute_hidden; + + /* Get the canonical absolute name of the named directory, and put it in SIZE + bytes of BUF. Returns NULL if the directory couldn't be determined or +diff --git a/inet/Makefile b/inet/Makefile +index f63c7e25ba..3274977bf6 100644 +--- a/inet/Makefile ++++ b/inet/Makefile +@@ -52,7 +52,7 @@ aux := check_pf check_native ifreq + tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \ + tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \ + tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \ +- tst-sockaddr test-hnto-types ++ tst-sockaddr test-hnto-types tst-if_index-long + + # tst-deadline must be linked statically so that we can access + # internal functions. +diff --git a/inet/tst-if_index-long.c b/inet/tst-if_index-long.c +new file mode 100644 +index 0000000000..3dc74874e5 +--- /dev/null ++++ b/inet/tst-if_index-long.c +@@ -0,0 +1,61 @@ ++/* Check for descriptor leak in if_nametoindex with a long interface name. ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* This test checks for a descriptor leak in case of a long interface ++ name (CVE-2018-19591, bug 23927). */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ struct support_descriptors *descrs = support_descriptors_list (); ++ ++ /* Prepare a name which is just as long as required for trigging the ++ bug. */ ++ char name[IFNAMSIZ + 1]; ++ memset (name, 'A', IFNAMSIZ); ++ name[IFNAMSIZ] = '\0'; ++ TEST_COMPARE (strlen (name), IFNAMSIZ); ++ struct ifreq ifr; ++ TEST_COMPARE (strlen (name), sizeof (ifr.ifr_name)); ++ ++ /* Test directly via if_nametoindex. */ ++ TEST_COMPARE (if_nametoindex (name), 0); ++ TEST_COMPARE (errno, ENODEV); ++ support_descriptors_check (descrs); ++ ++ /* Same test via getaddrinfo. */ ++ char *host = xasprintf ("fea0::%%%s", name); ++ struct addrinfo hints = { .ai_flags = AI_NUMERICHOST, }; ++ struct addrinfo *ai; ++ TEST_COMPARE (getaddrinfo (host, NULL, &hints, &ai), EAI_NONAME); ++ support_descriptors_check (descrs); ++ ++ support_descriptors_free (descrs); ++ ++ return 0; ++} ++ ++#include +diff --git a/intl/dcigettext.c b/intl/dcigettext.c +index 2a50369948..25f47c5bd3 100644 +--- a/intl/dcigettext.c ++++ b/intl/dcigettext.c +@@ -631,7 +631,7 @@ DCIGETTEXT (const char *domainname, const char *msgid1, const char *msgid2, + int ret = __asprintf (&xdirname, "%s/%s", cwd, dirname); + free (cwd); + if (ret < 0) +- return NULL; ++ goto return_untranslated; + dirname = xdirname; + } + #ifndef IN_LIBGLOCALE +diff --git a/io/Makefile b/io/Makefile +index 2117cb6b62..943833f8bd 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -73,11 +73,6 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ + tst-fts tst-fts-lfs tst-open-tmpfile \ + tst-copy_file_range tst-getcwd-abspath \ + +-# This test includes the compat implementation of copy_file_range, +-# which uses internal, unexported libc functions. +-tests-static += tst-copy_file_range-compat +-tests-internal += tst-copy_file_range-compat +- + ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)ftwtest.out + endif +diff --git a/io/copy_file_range-compat.c b/io/copy_file_range-compat.c +deleted file mode 100644 +index 4ab22cad19..0000000000 +--- a/io/copy_file_range-compat.c ++++ /dev/null +@@ -1,160 +0,0 @@ +-/* Emulation of copy_file_range. +- Copyright (C) 2017-2018 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 +- . */ +- +-/* The following macros should be defined before including this +- file: +- +- COPY_FILE_RANGE_DECL Declaration specifiers for the function below. +- COPY_FILE_RANGE Name of the function to define. */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-COPY_FILE_RANGE_DECL +-ssize_t +-COPY_FILE_RANGE (int infd, __off64_t *pinoff, +- int outfd, __off64_t *poutoff, +- size_t length, unsigned int flags) +-{ +- if (flags != 0) +- { +- __set_errno (EINVAL); +- return -1; +- } +- +- { +- struct stat64 instat; +- struct stat64 outstat; +- if (fstat64 (infd, &instat) != 0 || fstat64 (outfd, &outstat) != 0) +- return -1; +- if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode)) +- { +- __set_errno (EISDIR); +- return -1; +- } +- if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode)) +- { +- /* We need a regular input file so that the we can seek +- backwards in case of a write failure. */ +- __set_errno (EINVAL); +- return -1; +- } +- if (instat.st_dev != outstat.st_dev) +- { +- /* Cross-device copies are not supported. */ +- __set_errno (EXDEV); +- return -1; +- } +- } +- +- /* The output descriptor must not have O_APPEND set. */ +- { +- int flags = __fcntl (outfd, F_GETFL); +- if (flags & O_APPEND) +- { +- __set_errno (EBADF); +- return -1; +- } +- } +- +- /* Avoid an overflow in the result. */ +- if (length > SSIZE_MAX) +- length = SSIZE_MAX; +- +- /* Main copying loop. The buffer size is arbitrary and is a +- trade-off between stack size consumption, cache usage, and +- amortization of system call overhead. */ +- size_t copied = 0; +- char buf[8192]; +- while (length > 0) +- { +- size_t to_read = length; +- if (to_read > sizeof (buf)) +- to_read = sizeof (buf); +- +- /* Fill the buffer. */ +- ssize_t read_count; +- if (pinoff == NULL) +- read_count = read (infd, buf, to_read); +- else +- read_count = __libc_pread64 (infd, buf, to_read, *pinoff); +- if (read_count == 0) +- /* End of file reached prematurely. */ +- return copied; +- if (read_count < 0) +- { +- if (copied > 0) +- /* Report the number of bytes copied so far. */ +- return copied; +- return -1; +- } +- if (pinoff != NULL) +- *pinoff += read_count; +- +- /* Write the buffer part which was read to the destination. */ +- char *end = buf + read_count; +- for (char *p = buf; p < end; ) +- { +- ssize_t write_count; +- if (poutoff == NULL) +- write_count = write (outfd, p, end - p); +- else +- write_count = __libc_pwrite64 (outfd, p, end - p, *poutoff); +- if (write_count < 0) +- { +- /* Adjust the input read position to match what we have +- written, so that the caller can pick up after the +- error. */ +- size_t written = p - buf; +- /* NB: This needs to be signed so that we can form the +- negative value below. */ +- ssize_t overread = read_count - written; +- if (pinoff == NULL) +- { +- if (overread > 0) +- { +- /* We are on an error recovery path, so we +- cannot deal with failure here. */ +- int save_errno = errno; +- (void) __libc_lseek64 (infd, -overread, SEEK_CUR); +- __set_errno (save_errno); +- } +- } +- else /* pinoff != NULL */ +- *pinoff -= overread; +- +- if (copied + written > 0) +- /* Report the number of bytes copied so far. */ +- return copied + written; +- return -1; +- } +- p += write_count; +- if (poutoff != NULL) +- *poutoff += write_count; +- } /* Write loop. */ +- +- copied += read_count; +- length -= read_count; +- } +- return copied; +-} +diff --git a/io/copy_file_range.c b/io/copy_file_range.c +index 98bff8bd26..59fb979773 100644 +--- a/io/copy_file_range.c ++++ b/io/copy_file_range.c +@@ -1,5 +1,5 @@ +-/* Generic implementation of copy_file_range. +- Copyright (C) 2017-2018 Free Software Foundation, Inc. ++/* Stub implementation of copy_file_range. ++ Copyright (C) 2017-2019 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 +@@ -16,7 +16,15 @@ + License along with the GNU C Library; if not, see + . */ + +-#define COPY_FILE_RANGE_DECL +-#define COPY_FILE_RANGE copy_file_range ++#include ++#include + +-#include ++ssize_t ++copy_file_range (int infd, __off64_t *pinoff, ++ int outfd, __off64_t *poutoff, ++ size_t length, unsigned int flags) ++{ ++ __set_errno (ENOSYS); ++ return -1; ++} ++stub_warning (copy_file_range) +diff --git a/io/tst-copy_file_range.c b/io/tst-copy_file_range.c +index 3d531a1937..a9237cb384 100644 +--- a/io/tst-copy_file_range.c ++++ b/io/tst-copy_file_range.c +@@ -1,5 +1,5 @@ + /* Tests for copy_file_range. +- Copyright (C) 2017-2018 Free Software Foundation, Inc. ++ Copyright (C) 2017-2019 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 +@@ -20,22 +20,15 @@ + #include + #include + #include +-#include +-#include +-#include + #include + #include + #include + #include + #include +-#include + #include + #include + #include + #include +-#ifdef CLONE_NEWNS +-# include +-#endif + + /* Boolean flags which indicate whether to use pointers with explicit + output flags. */ +@@ -49,10 +42,6 @@ static int infd; + static char *outfile; + static int outfd; + +-/* Like the above, but on a different file system. xdevfile can be +- NULL if no suitable file system has been found. */ +-static char *xdevfile; +- + /* Input and output offsets. Set according to do_inoff and do_outoff + before the test. The offsets themselves are always set to + zero. */ +@@ -61,13 +50,10 @@ static off64_t *pinoff; + static off64_t outoff; + static off64_t *poutoff; + +-/* These are a collection of copy sizes used in tests. The selection +- takes into account that the fallback implementation uses an +- internal buffer of 8192 bytes. */ ++/* These are a collection of copy sizes used in tests. */ + enum { maximum_size = 99999 }; + static const int typical_sizes[] = +- { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, 16383, 16384, 16385, +- maximum_size }; ++ { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, maximum_size }; + + /* The random contents of this array can be used as a pattern to check + for correct write operations. */ +@@ -76,101 +62,6 @@ static unsigned char random_data[maximum_size]; + /* The size chosen by the test harness. */ + static int current_size; + +-/* Maximum writable file offset. Updated by find_maximum_offset +- below. */ +-static off64_t maximum_offset; +- +-/* Error code when crossing the offset. */ +-static int maximum_offset_errno; +- +-/* If true: Writes which cross the limit will fail. If false: Writes +- which cross the limit will result in a partial write. */ +-static bool maximum_offset_hard_limit; +- +-/* Fills maximum_offset etc. above. Truncates outfd as a side +- effect. */ +-static void +-find_maximum_offset (void) +-{ +- xftruncate (outfd, 0); +- if (maximum_offset != 0) +- return; +- +- uint64_t upper = -1; +- upper >>= 1; /* Maximum of off64_t. */ +- TEST_VERIFY ((off64_t) upper > 0); +- TEST_VERIFY ((off64_t) (upper + 1) < 0); +- if (lseek64 (outfd, upper, SEEK_SET) >= 0) +- { +- if (write (outfd, "", 1) == 1) +- FAIL_EXIT1 ("created a file larger than the off64_t range"); +- } +- +- uint64_t lower = 1024 * 1024; /* A reasonable minimum file size. */ +- /* Loop invariant: writing at lower succeeds, writing at upper fails. */ +- while (lower + 1 < upper) +- { +- uint64_t middle = (lower + upper) / 2; +- if (test_verbose > 0) +- printf ("info: %s: remaining test range %" PRIu64 " .. %" PRIu64 +- ", probe at %" PRIu64 "\n", __func__, lower, upper, middle); +- xftruncate (outfd, 0); +- if (lseek64 (outfd, middle, SEEK_SET) >= 0 +- && write (outfd, "", 1) == 1) +- lower = middle; +- else +- upper = middle; +- } +- TEST_VERIFY (lower + 1 == upper); +- maximum_offset = lower; +- printf ("info: maximum writable file offset: %" PRIu64 " (%" PRIx64 ")\n", +- lower, lower); +- +- /* Check that writing at the valid offset actually works. */ +- xftruncate (outfd, 0); +- xlseek (outfd, lower, SEEK_SET); +- TEST_COMPARE (write (outfd, "", 1), 1); +- +- /* Cross the boundary with a two-byte write. This can either result +- in a short write, or a failure. */ +- xlseek (outfd, lower, SEEK_SET); +- ssize_t ret = write (outfd, " ", 2); +- if (ret < 0) +- { +- maximum_offset_errno = errno; +- maximum_offset_hard_limit = true; +- } +- else +- maximum_offset_hard_limit = false; +- +- /* Check that writing at the next offset actually fails. This also +- obtains the expected errno value. */ +- xftruncate (outfd, 0); +- const char *action; +- if (lseek64 (outfd, lower + 1, SEEK_SET) != 0) +- { +- if (write (outfd, "", 1) != -1) +- FAIL_EXIT1 ("write to impossible offset %" PRIu64 " succeeded", +- lower + 1); +- action = "writing"; +- int errno_copy = errno; +- if (maximum_offset_hard_limit) +- TEST_COMPARE (errno_copy, maximum_offset_errno); +- else +- maximum_offset_errno = errno_copy; +- } +- else +- { +- action = "seeking"; +- maximum_offset_errno = errno; +- } +- printf ("info: %s out of range fails with %m (%d)\n", +- action, maximum_offset_errno); +- +- xftruncate (outfd, 0); +- xlseek (outfd, 0, SEEK_SET); +-} +- + /* Perform a copy of a file. */ + static void + simple_file_copy (void) +@@ -247,390 +138,6 @@ simple_file_copy (void) + free (bytes); + } + +-/* Test that reading from a pipe willfails. */ +-static void +-pipe_as_source (void) +-{ +- int pipefds[2]; +- xpipe (pipefds); +- +- for (int length = 0; length < 2; ++length) +- { +- if (test_verbose > 0) +- printf ("info: %s: length=%d\n", __func__, length); +- +- /* Make sure that there is something to copy in the pipe. */ +- xwrite (pipefds[1], "@", 1); +- +- TEST_COMPARE (copy_file_range (pipefds[0], pinoff, outfd, poutoff, +- length, 0), -1); +- /* Linux 4.10 and later return EINVAL. Older kernels return +- EXDEV. */ +- TEST_VERIFY (errno == EINVAL || errno == EXDEV); +- TEST_COMPARE (inoff, 0); +- TEST_COMPARE (outoff, 0); +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 0); +- +- /* Make sure that nothing was read. */ +- char buf = 'A'; +- TEST_COMPARE (read (pipefds[0], &buf, 1), 1); +- TEST_COMPARE (buf, '@'); +- } +- +- xclose (pipefds[0]); +- xclose (pipefds[1]); +-} +- +-/* Test that writing to a pipe fails. */ +-static void +-pipe_as_destination (void) +-{ +- /* Make sure that there is something to read in the input file. */ +- xwrite (infd, "abc", 3); +- xlseek (infd, 0, SEEK_SET); +- +- int pipefds[2]; +- xpipe (pipefds); +- +- for (int length = 0; length < 2; ++length) +- { +- if (test_verbose > 0) +- printf ("info: %s: length=%d\n", __func__, length); +- +- TEST_COMPARE (copy_file_range (infd, pinoff, pipefds[1], poutoff, +- length, 0), -1); +- /* Linux 4.10 and later return EINVAL. Older kernels return +- EXDEV. */ +- TEST_VERIFY (errno == EINVAL || errno == EXDEV); +- TEST_COMPARE (inoff, 0); +- TEST_COMPARE (outoff, 0); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- +- /* Make sure that nothing was written. */ +- struct pollfd pollfd = { .fd = pipefds[0], .events = POLLIN, }; +- TEST_COMPARE (poll (&pollfd, 1, 0), 0); +- } +- +- xclose (pipefds[0]); +- xclose (pipefds[1]); +-} +- +-/* Test a write failure after (potentially) writing some bytes. +- Failure occurs near the start of the buffer. */ +-static void +-delayed_write_failure_beginning (void) +-{ +- /* We need to write something to provoke the error. */ +- if (current_size == 0) +- return; +- xwrite (infd, random_data, sizeof (random_data)); +- xlseek (infd, 0, SEEK_SET); +- +- /* Write failure near the start. The actual error code varies among +- file systems. */ +- find_maximum_offset (); +- off64_t where = maximum_offset; +- +- if (current_size == 1) +- ++where; +- outoff = where; +- if (do_outoff) +- xlseek (outfd, 1, SEEK_SET); +- else +- xlseek (outfd, where, SEEK_SET); +- if (maximum_offset_hard_limit || where > maximum_offset) +- { +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0), -1); +- TEST_COMPARE (errno, maximum_offset_errno); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- TEST_COMPARE (inoff, 0); +- if (do_outoff) +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1); +- else +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where); +- TEST_COMPARE (outoff, where); +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, 0); +- } +- else +- { +- /* The offset is not a hard limit. This means we write one +- byte. */ +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0), 1); +- if (do_inoff) +- { +- TEST_COMPARE (inoff, 1); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- } +- else +- { +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 1); +- TEST_COMPARE (inoff, 0); +- } +- if (do_outoff) +- { +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1); +- TEST_COMPARE (outoff, where + 1); +- } +- else +- { +- TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where + 1); +- TEST_COMPARE (outoff, where); +- } +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, where + 1); +- } +-} +- +-/* Test a write failure after (potentially) writing some bytes. +- Failure occurs near the end of the buffer. */ +-static void +-delayed_write_failure_end (void) +-{ +- if (current_size <= 1) +- /* This would be same as the first test because there is not +- enough data to write to make a difference. */ +- return; +- xwrite (infd, random_data, sizeof (random_data)); +- xlseek (infd, 0, SEEK_SET); +- +- find_maximum_offset (); +- off64_t where = maximum_offset - current_size + 1; +- if (current_size == sizeof (random_data)) +- /* Otherwise we do not reach the non-writable byte. */ +- ++where; +- outoff = where; +- if (do_outoff) +- xlseek (outfd, 1, SEEK_SET); +- else +- xlseek (outfd, where, SEEK_SET); +- ssize_t ret = copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0); +- if (ret < 0) +- { +- TEST_COMPARE (ret, -1); +- TEST_COMPARE (errno, maximum_offset_errno); +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, 0); +- } +- else +- { +- /* The first copy succeeded. This happens in the emulation +- because the internal buffer of limited size does not +- necessarily cross the off64_t boundary on the first write +- operation. */ +- if (test_verbose > 0) +- printf ("info: copy_file_range (%zu) returned %zd\n", +- sizeof (random_data), ret); +- TEST_VERIFY (ret > 0); +- TEST_VERIFY (ret < maximum_size); +- struct stat64 st; +- xfstat (outfd, &st); +- TEST_COMPARE (st.st_size, where + ret); +- if (do_inoff) +- { +- TEST_COMPARE (inoff, ret); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- } +- else +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), ret); +- +- char *buffer = xmalloc (ret); +- TEST_COMPARE (pread64 (outfd, buffer, ret, where), ret); +- TEST_VERIFY (memcmp (buffer, random_data, ret) == 0); +- free (buffer); +- +- /* The second copy fails. */ +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- sizeof (random_data), 0), -1); +- TEST_COMPARE (errno, maximum_offset_errno); +- } +-} +- +-/* Test a write failure across devices. */ +-static void +-cross_device_failure (void) +-{ +- if (xdevfile == NULL) +- /* Subtest not supported due to missing cross-device file. */ +- return; +- +- /* We need something to write. */ +- xwrite (infd, random_data, sizeof (random_data)); +- xlseek (infd, 0, SEEK_SET); +- +- int xdevfd = xopen (xdevfile, O_RDWR | O_LARGEFILE, 0); +- TEST_COMPARE (copy_file_range (infd, pinoff, xdevfd, poutoff, +- current_size, 0), -1); +- TEST_COMPARE (errno, EXDEV); +- TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0); +- struct stat64 st; +- xfstat (xdevfd, &st); +- TEST_COMPARE (st.st_size, 0); +- +- xclose (xdevfd); +-} +- +-/* Try to exercise ENOSPC behavior with a tempfs file system (so that +- we do not have to fill up a regular file system to get the error). +- This function runs in a subprocess, so that we do not change the +- mount namespace of the actual test process. */ +-static void +-enospc_failure_1 (void *closure) +-{ +-#ifdef CLONE_NEWNS +- support_become_root (); +- +- /* Make sure that we do not alter the file system mounts of the +- parents. */ +- if (! support_enter_mount_namespace ()) +- { +- printf ("warning: ENOSPC test skipped\n"); +- return; +- } +- +- char *mountpoint = closure; +- if (mount ("none", mountpoint, "tmpfs", MS_NODEV | MS_NOEXEC, +- "size=500k") != 0) +- { +- printf ("warning: could not mount tmpfs at %s: %m\n", mountpoint); +- return; +- } +- +- /* The source file must reside on the same file system. */ +- char *intmpfsfile = xasprintf ("%s/%s", mountpoint, "in"); +- int intmpfsfd = xopen (intmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600); +- xwrite (intmpfsfd, random_data, sizeof (random_data)); +- xlseek (intmpfsfd, 1, SEEK_SET); +- inoff = 1; +- +- char *outtmpfsfile = xasprintf ("%s/%s", mountpoint, "out"); +- int outtmpfsfd = xopen (outtmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600); +- +- /* Fill the file with data until ENOSPC is reached. */ +- while (true) +- { +- ssize_t ret = write (outtmpfsfd, random_data, sizeof (random_data)); +- if (ret < 0 && errno != ENOSPC) +- FAIL_EXIT1 ("write to %s: %m", outtmpfsfile); +- if (ret < sizeof (random_data)) +- break; +- } +- TEST_COMPARE (write (outtmpfsfd, "", 1), -1); +- TEST_COMPARE (errno, ENOSPC); +- off64_t maxsize = xlseek (outtmpfsfd, 0, SEEK_CUR); +- TEST_VERIFY_EXIT (maxsize > sizeof (random_data)); +- +- /* Constructed the expected file contents. */ +- char *expected = xmalloc (maxsize); +- TEST_COMPARE (pread64 (outtmpfsfd, expected, maxsize, 0), maxsize); +- /* Go back a little, so some bytes can be written. */ +- enum { offset = 20000 }; +- TEST_VERIFY_EXIT (offset < maxsize); +- TEST_VERIFY_EXIT (offset < sizeof (random_data)); +- memcpy (expected + maxsize - offset, random_data + 1, offset); +- +- if (do_outoff) +- { +- outoff = maxsize - offset; +- xlseek (outtmpfsfd, 2, SEEK_SET); +- } +- else +- xlseek (outtmpfsfd, -offset, SEEK_CUR); +- +- /* First call is expected to succeed because we made room for some +- bytes. */ +- TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff, +- maximum_size, 0), offset); +- if (do_inoff) +- { +- TEST_COMPARE (inoff, 1 + offset); +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1); +- } +- else +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset); +- if (do_outoff) +- { +- TEST_COMPARE (outoff, maxsize); +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2); +- } +- else +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize); +- struct stat64 st; +- xfstat (outtmpfsfd, &st); +- TEST_COMPARE (st.st_size, maxsize); +- char *actual = xmalloc (st.st_size); +- TEST_COMPARE (pread64 (outtmpfsfd, actual, st.st_size, 0), st.st_size); +- TEST_VERIFY (memcmp (expected, actual, maxsize) == 0); +- +- /* Second call should fail with ENOSPC. */ +- TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff, +- maximum_size, 0), -1); +- TEST_COMPARE (errno, ENOSPC); +- +- /* Offsets should be unchanged. */ +- if (do_inoff) +- { +- TEST_COMPARE (inoff, 1 + offset); +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1); +- } +- else +- TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset); +- if (do_outoff) +- { +- TEST_COMPARE (outoff, maxsize); +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2); +- } +- else +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize); +- TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_END), maxsize); +- TEST_COMPARE (pread64 (outtmpfsfd, actual, maxsize, 0), maxsize); +- TEST_VERIFY (memcmp (expected, actual, maxsize) == 0); +- +- free (actual); +- free (expected); +- +- xclose (intmpfsfd); +- xclose (outtmpfsfd); +- free (intmpfsfile); +- free (outtmpfsfile); +- +-#else /* !CLONE_NEWNS */ +- puts ("warning: ENOSPC test skipped (no mount namespaces)"); +-#endif +-} +- +-/* Call enospc_failure_1 in a subprocess. */ +-static void +-enospc_failure (void) +-{ +- char *mountpoint +- = support_create_temp_directory ("tst-copy_file_range-enospc-"); +- support_isolate_in_subprocess (enospc_failure_1, mountpoint); +- free (mountpoint); +-} +- +-/* The target file descriptor must have O_APPEND enabled. */ +-static void +-oappend_failure (void) +-{ +- /* Add data, to make sure we do not fail because there is +- insufficient input data. */ +- xwrite (infd, random_data, current_size); +- xlseek (infd, 0, SEEK_SET); +- +- xclose (outfd); +- outfd = xopen (outfile, O_RDWR | O_APPEND, 0); +- TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff, +- current_size, 0), -1); +- TEST_COMPARE (errno, EBADF); +-} +- + /* Test that a short input file results in a shortened copy. */ + static void + short_copy (void) +@@ -721,14 +228,6 @@ struct test_case + static struct test_case tests[] = + { + { "simple_file_copy", simple_file_copy, .sizes = true }, +- { "pipe_as_source", pipe_as_source, }, +- { "pipe_as_destination", pipe_as_destination, }, +- { "delayed_write_failure_beginning", delayed_write_failure_beginning, +- .sizes = true }, +- { "delayed_write_failure_end", delayed_write_failure_end, .sizes = true }, +- { "cross_device_failure", cross_device_failure, .sizes = true }, +- { "enospc_failure", enospc_failure, }, +- { "oappend_failure", oappend_failure, .sizes = true }, + { "short_copy", short_copy, .sizes = true }, + }; + +@@ -739,53 +238,18 @@ do_test (void) + *p = rand () >> 24; + + infd = create_temp_file ("tst-copy_file_range-in-", &infile); +- xclose (create_temp_file ("tst-copy_file_range-out-", &outfile)); +- +- /* Try to find a different directory from the default input/output +- file. */ ++ outfd = create_temp_file ("tst-copy_file_range-out-", &outfile); + { +- struct stat64 instat; +- xfstat (infd, &instat); +- static const char *const candidates[] = +- { NULL, "/var/tmp", "/dev/shm" }; +- for (const char *const *c = candidates; c < array_end (candidates); ++c) +- { +- const char *path = *c; +- char *to_free = NULL; +- if (path == NULL) +- { +- to_free = xreadlink ("/proc/self/exe"); +- path = dirname (to_free); +- } +- +- struct stat64 cstat; +- xstat (path, &cstat); +- if (cstat.st_dev == instat.st_dev) +- { +- free (to_free); +- continue; +- } +- +- printf ("info: using alternate temporary files directory: %s\n", path); +- xdevfile = xasprintf ("%s/tst-copy_file_range-xdev-XXXXXX", path); +- free (to_free); +- break; +- } +- if (xdevfile != NULL) ++ ssize_t ret = copy_file_range (infd, NULL, outfd, NULL, 0, 0); ++ if (ret != 0) + { +- int xdevfd = mkstemp (xdevfile); +- if (xdevfd < 0) +- FAIL_EXIT1 ("mkstemp (\"%s\"): %m", xdevfile); +- struct stat64 xdevst; +- xfstat (xdevfd, &xdevst); +- TEST_VERIFY (xdevst.st_dev != instat.st_dev); +- add_temp_file (xdevfile); +- xclose (xdevfd); ++ if (errno == ENOSYS) ++ FAIL_UNSUPPORTED ("copy_file_range is not support on this system"); ++ FAIL_EXIT1 ("copy_file_range probing call: %m"); + } +- else +- puts ("warning: no alternate directory on different file system found"); + } + xclose (infd); ++ xclose (outfd); + + for (do_inoff = 0; do_inoff < 2; ++do_inoff) + for (do_outoff = 0; do_outoff < 2; ++do_outoff) +@@ -827,7 +291,6 @@ do_test (void) + + free (infile); + free (outfile); +- free (xdevfile); + + return 0; + } +diff --git a/libio/Makefile b/libio/Makefile +index 918a86bb74..2493a11ec2 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -63,11 +63,17 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ + bug-memstream1 bug-wmemstream1 \ + tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \ + tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \ +- tst-ftell-append tst-fputws tst-bz22415 ++ tst-ftell-append tst-fputws tst-bz22415 tst-wfile-sync ++ ++tests-internal = tst-vtables tst-vtables-interposed ++ + ifeq (yes,$(build-shared)) + # Add test-fopenloc only if shared library is enabled since it depends on + # shared localedata objects. + tests += tst-fopenloc ++# Add tst-bz24228 only if shared library is enabled since it can never meet its ++# objective with static linking because the relevant code just is not there. ++tests += tst-bz24228 + endif + test-srcs = test-freopen + +@@ -148,11 +154,14 @@ CFLAGS-oldtmpfile.c += -fexceptions + + CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\" + ++LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map ++ + tst_wprintf2-ARGS = "Some Text" + + test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace + tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace + tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace ++tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace + + generated += test-fmemopen.mtrace test-fmemopen.check + generated += tst-fopenloc.mtrace tst-fopenloc.check +@@ -161,6 +170,7 @@ generated += tst-bz22415.mtrace tst-bz22415.check + aux := fileops genops stdfiles stdio strops + + ifeq ($(build-shared),yes) ++generated += tst-bz24228.mtrace tst-bz24228.check + aux += oldfileops oldstdfiles + endif + +@@ -175,7 +185,8 @@ tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \ + ifeq (yes,$(build-shared)) + # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared + # library is enabled since they depend on tst-fopenloc.out. +-tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out ++tests-special += $(objpfx)tst-fopenloc-cmp.out $(objpfx)tst-fopenloc-mem.out \ ++ $(objpfx)tst-bz24228-mem.out + endif + endif + +@@ -203,6 +214,7 @@ $(objpfx)tst-ungetwc1.out: $(gen-locales) + $(objpfx)tst-ungetwc2.out: $(gen-locales) + $(objpfx)tst-widetext.out: $(gen-locales) + $(objpfx)tst_wprintf2.out: $(gen-locales) ++$(objpfx)tst-wfile-sync.out: $(gen-locales) + endif + + $(objpfx)test-freopen.out: test-freopen.sh $(objpfx)test-freopen +@@ -226,3 +238,7 @@ $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out + $(objpfx)tst-bz22415-mem.out: $(objpfx)tst-bz22415.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-bz22415.mtrace > $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-bz24228-mem.out: $(objpfx)tst-bz24228.out ++ $(common-objpfx)malloc/mtrace $(objpfx)tst-bz24228.mtrace > $@; \ ++ $(evaluate-test) +diff --git a/libio/genops.c b/libio/genops.c +index d6f8050669..32c7bfe2d0 100644 +--- a/libio/genops.c ++++ b/libio/genops.c +@@ -852,9 +852,16 @@ _IO_unbuffer_all (void) + + for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain) + { ++ int legacy = 0; ++ ++#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1) ++ if (__glibc_unlikely (_IO_vtable_offset (fp) != 0)) ++ legacy = 1; ++#endif ++ + if (! (fp->_flags & _IO_UNBUFFERED) + /* Iff stream is un-orientated, it wasn't used. */ +- && fp->_mode != 0) ++ && (legacy || fp->_mode != 0)) + { + #ifdef _IO_MTSAFE_IO + int cnt; +@@ -868,7 +875,7 @@ _IO_unbuffer_all (void) + __sched_yield (); + #endif + +- if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF)) ++ if (! legacy && ! dealloc_buffers && !(fp->_flags & _IO_USER_BUF)) + { + fp->_flags |= _IO_USER_BUF; + +@@ -879,7 +886,7 @@ _IO_unbuffer_all (void) + + _IO_SETBUF (fp, NULL, 0); + +- if (fp->_mode > 0) ++ if (! legacy && fp->_mode > 0) + _IO_wsetb (fp, NULL, NULL, 0); + + #ifdef _IO_MTSAFE_IO +@@ -890,7 +897,8 @@ _IO_unbuffer_all (void) + + /* Make sure that never again the wide char functions can be + used. */ +- fp->_mode = -1; ++ if (! legacy) ++ fp->_mode = -1; + } + + #ifdef _IO_MTSAFE_IO +diff --git a/libio/memstream.c b/libio/memstream.c +index d86befcc02..c5c7c2f6db 100644 +--- a/libio/memstream.c ++++ b/libio/memstream.c +@@ -90,8 +90,8 @@ __open_memstream (char **bufloc, _IO_size_t *sizeloc) + _IO_JUMPS_FILE_plus (&new_f->fp._sf._sbf) = &_IO_mem_jumps; + _IO_str_init_static_internal (&new_f->fp._sf, buf, _IO_BUFSIZ, buf); + new_f->fp._sf._sbf._f._flags &= ~_IO_USER_BUF; +- new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc; +- new_f->fp._sf._s._free_buffer = (_IO_free_type) free; ++ new_f->fp._sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; ++ new_f->fp._sf._s._free_buffer_unused = (_IO_free_type) free; + + new_f->fp.bufloc = bufloc; + new_f->fp.sizeloc = sizeloc; +diff --git a/libio/oldstdfiles.c b/libio/oldstdfiles.c +index 92d0f4a0d3..d6cbc9ffb7 100644 +--- a/libio/oldstdfiles.c ++++ b/libio/oldstdfiles.c +@@ -87,6 +87,11 @@ _IO_check_libio (void) + stdout->_vtable_offset = stderr->_vtable_offset = + ((int) sizeof (struct _IO_FILE) + - (int) sizeof (struct _IO_FILE_complete)); ++ ++ if (_IO_stdin_.vtable != &_IO_old_file_jumps ++ || _IO_stdout_.vtable != &_IO_old_file_jumps ++ || _IO_stderr_.vtable != &_IO_old_file_jumps) ++ IO_set_accept_foreign_vtables (&_IO_vtable_check); + } + } + +diff --git a/libio/strfile.h b/libio/strfile.h +index 68dfcbfe83..52a085e580 100644 +--- a/libio/strfile.h ++++ b/libio/strfile.h +@@ -31,8 +31,11 @@ typedef void (*_IO_free_type) (void*); + + struct _IO_str_fields + { +- _IO_alloc_type _allocate_buffer; +- _IO_free_type _free_buffer; ++ /* These members are preserved for ABI compatibility. The glibc ++ implementation always calls malloc/free for user buffers if ++ _IO_USER_BUF or _IO_FLAGS2_USER_WBUF are not set. */ ++ _IO_alloc_type _allocate_buffer_unused; ++ _IO_free_type _free_buffer_unused; + }; + + /* This is needed for the Irix6 N32 ABI, which has a 64 bit off_t type, +@@ -52,10 +55,6 @@ typedef struct _IO_strfile_ + struct _IO_str_fields _s; + } _IO_strfile; + +-/* dynamic: set when the array object is allocated (or reallocated) as +- necessary to hold a character sequence that can change in length. */ +-#define _IO_STR_DYNAMIC(FP) ((FP)->_s._allocate_buffer != (_IO_alloc_type)0) +- + /* frozen: set when the program has requested that the array object not + be altered, reallocated, or freed. */ + #define _IO_STR_FROZEN(FP) ((FP)->_f._IO_file_flags & _IO_USER_BUF) +diff --git a/libio/strops.c b/libio/strops.c +index ac995c830e..5fb38976e3 100644 +--- a/libio/strops.c ++++ b/libio/strops.c +@@ -61,7 +61,7 @@ _IO_str_init_static_internal (_IO_strfile *sf, char *ptr, _IO_size_t size, + fp->_IO_read_end = end; + } + /* A null _allocate_buffer function flags the strfile as being static. */ +- sf->_s._allocate_buffer = (_IO_alloc_type) 0; ++ sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0; + } + + void +@@ -103,8 +103,7 @@ _IO_str_overflow (_IO_FILE *fp, int c) + _IO_size_t new_size = 2 * old_blen + 100; + if (new_size < old_blen) + return EOF; +- new_buf +- = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size); ++ new_buf = malloc (new_size); + if (new_buf == NULL) + { + /* __ferror(fp) = 1; */ +@@ -113,7 +112,7 @@ _IO_str_overflow (_IO_FILE *fp, int c) + if (old_buf) + { + memcpy (new_buf, old_buf, old_blen); +- (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf); ++ free (old_buf); + /* Make sure _IO_setb won't try to delete _IO_buf_base. */ + fp->_IO_buf_base = NULL; + } +@@ -182,15 +181,14 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading) + + _IO_size_t newsize = offset + 100; + char *oldbuf = fp->_IO_buf_base; +- char *newbuf +- = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize); ++ char *newbuf = malloc (newsize); + if (newbuf == NULL) + return 1; + + if (oldbuf != NULL) + { + memcpy (newbuf, oldbuf, _IO_blen (fp)); +- (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf); ++ free (oldbuf); + /* Make sure _IO_setb won't try to delete + _IO_buf_base. */ + fp->_IO_buf_base = NULL; +@@ -346,7 +344,7 @@ void + _IO_str_finish (_IO_FILE *fp, int dummy) + { + if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF)) +- (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base); ++ free (fp->_IO_buf_base); + fp->_IO_buf_base = NULL; + + _IO_default_finish (fp, 0); +diff --git a/libio/tst-bz24228.c b/libio/tst-bz24228.c +new file mode 100644 +index 0000000000..6a74500d47 +--- /dev/null ++++ b/libio/tst-bz24228.c +@@ -0,0 +1,29 @@ ++/* BZ #24228 check for memory corruption in legacy libio ++ Copyright (C) 2019 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 int ++do_test (void) ++{ ++ mtrace (); ++ return 0; ++} ++ ++#include +diff --git a/libio/tst-bz24228.map b/libio/tst-bz24228.map +new file mode 100644 +index 0000000000..4383e0817d +--- /dev/null ++++ b/libio/tst-bz24228.map +@@ -0,0 +1,5 @@ ++# Hide the symbol from libc.so.6 to switch to the libio/oldfileops.c ++# implementation when it is available for the architecture. ++{ ++ local: _IO_stdin_used; ++}; +diff --git a/libio/tst-vtables-common.c b/libio/tst-vtables-common.c +new file mode 100644 +index 0000000000..dc8d89c195 +--- /dev/null ++++ b/libio/tst-vtables-common.c +@@ -0,0 +1,511 @@ ++/* Test for libio vtables and their validation. Common code. ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* This test provides some coverage for how various stdio functions ++ use the vtables in FILE * objects. The focus is mostly on which ++ functions call which methods, not so much on validating data ++ processing. An initial series of tests check that custom vtables ++ do not work without activation through _IO_init. ++ ++ Note: libio vtables are deprecated feature. Do not use this test ++ as a documentation source for writing custom vtables. See ++ fopencookie for a different way of creating custom stdio ++ streams. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Data shared between the test subprocess and the test driver in the ++ parent. Note that *shared is reset at the start of the check_call ++ function. */ ++struct shared ++{ ++ /* Expected file pointer for method calls. */ ++ FILE *fp; ++ ++ /* If true, assume that a call to _IO_init is needed to enable ++ custom vtables. */ ++ bool initially_disabled; ++ ++ /* Requested return value for the methods which have one. */ ++ int return_value; ++ ++ /* A value (usually a character) recorded by some of the methods ++ below. */ ++ int value; ++ ++ /* Likewise, for some data. */ ++ char buffer[16]; ++ size_t buffer_length; ++ ++ /* Total number of method calls. */ ++ unsigned int calls; ++ ++ /* Individual method call counts. */ ++ unsigned int calls_finish; ++ unsigned int calls_overflow; ++ unsigned int calls_underflow; ++ unsigned int calls_uflow; ++ unsigned int calls_pbackfail; ++ unsigned int calls_xsputn; ++ unsigned int calls_xsgetn; ++ unsigned int calls_seekoff; ++ unsigned int calls_seekpos; ++ unsigned int calls_setbuf; ++ unsigned int calls_sync; ++ unsigned int calls_doallocate; ++ unsigned int calls_read; ++ unsigned int calls_write; ++ unsigned int calls_seek; ++ unsigned int calls_close; ++ unsigned int calls_stat; ++ unsigned int calls_showmanyc; ++ unsigned int calls_imbue; ++} *shared; ++ ++/* Method implementations which increment the counters in *shared. */ ++ ++static void ++log_method (FILE *fp, const char *name) ++{ ++ if (test_verbose > 0) ++ printf ("info: %s (%p) called\n", name, fp); ++} ++ ++static void ++method_finish (FILE *fp, int dummy) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_finish; ++} ++ ++static int ++method_overflow (FILE *fp, int ch) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_overflow; ++ shared->value = ch; ++ return shared->return_value; ++} ++ ++static int ++method_underflow (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_underflow; ++ return shared->return_value; ++} ++ ++static int ++method_uflow (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_uflow; ++ return shared->return_value; ++} ++ ++static int ++method_pbackfail (FILE *fp, int ch) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_pbackfail; ++ shared->value = ch; ++ return shared->return_value; ++} ++ ++static size_t ++method_xsputn (FILE *fp, const void *data, size_t n) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_xsputn; ++ ++ size_t to_copy = n; ++ if (n > sizeof (shared->buffer)) ++ to_copy = sizeof (shared->buffer); ++ memcpy (shared->buffer, data, to_copy); ++ shared->buffer_length = to_copy; ++ return to_copy; ++} ++ ++static size_t ++method_xsgetn (FILE *fp, void *data, size_t n) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_xsgetn; ++ return 0; ++} ++ ++static off64_t ++method_seekoff (FILE *fp, off64_t offset, int dir, int mode) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_seekoff; ++ return shared->return_value; ++} ++ ++static off64_t ++method_seekpos (FILE *fp, off64_t offset, int mode) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_seekpos; ++ return shared->return_value; ++} ++ ++static FILE * ++method_setbuf (FILE *fp, char *buffer, ssize_t length) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_setbuf; ++ return fp; ++} ++ ++static int ++method_sync (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_sync; ++ return shared->return_value; ++} ++ ++static int ++method_doallocate (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_doallocate; ++ return shared->return_value; ++} ++ ++static ssize_t ++method_read (FILE *fp, void *data, ssize_t length) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_read; ++ return shared->return_value; ++} ++ ++static ssize_t ++method_write (FILE *fp, const void *data, ssize_t length) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_write; ++ return shared->return_value; ++} ++ ++static off64_t ++method_seek (FILE *fp, off64_t offset, int mode) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_seek; ++ return shared->return_value; ++} ++ ++static int ++method_close (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_close; ++ return shared->return_value; ++} ++ ++static int ++method_stat (FILE *fp, void *buffer) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_stat; ++ return shared->return_value; ++} ++ ++static int ++method_showmanyc (FILE *fp) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_showmanyc; ++ return shared->return_value; ++} ++ ++static void ++method_imbue (FILE *fp, void *locale) ++{ ++ log_method (fp, __func__); ++ TEST_VERIFY (fp == shared->fp); ++ ++shared->calls; ++ ++shared->calls_imbue; ++} ++ ++/* Our custom vtable. */ ++ ++static const struct _IO_jump_t jumps = ++{ ++ JUMP_INIT_DUMMY, ++ JUMP_INIT (finish, method_finish), ++ JUMP_INIT (overflow, method_overflow), ++ JUMP_INIT (underflow, method_underflow), ++ JUMP_INIT (uflow, method_uflow), ++ JUMP_INIT (pbackfail, method_pbackfail), ++ JUMP_INIT (xsputn, method_xsputn), ++ JUMP_INIT (xsgetn, method_xsgetn), ++ JUMP_INIT (seekoff, method_seekoff), ++ JUMP_INIT (seekpos, method_seekpos), ++ JUMP_INIT (setbuf, method_setbuf), ++ JUMP_INIT (sync, method_sync), ++ JUMP_INIT (doallocate, method_doallocate), ++ JUMP_INIT (read, method_read), ++ JUMP_INIT (write, method_write), ++ JUMP_INIT (seek, method_seek), ++ JUMP_INIT (close, method_close), ++ JUMP_INIT (stat, method_stat), ++ JUMP_INIT (showmanyc, method_showmanyc), ++ JUMP_INIT (imbue, method_imbue) ++}; ++ ++/* Our file implementation. */ ++ ++struct my_file ++{ ++ FILE f; ++ const struct _IO_jump_t *vtable; ++}; ++ ++struct my_file ++my_file_create (void) ++{ ++ return (struct my_file) ++ { ++ /* Disable locking, so that we do not have to set up a lock ++ pointer. */ ++ .f._flags = _IO_USER_LOCK, ++ ++ /* Copy the offset from the an initialized handle, instead of ++ figuring it out from scratch. */ ++ .f._vtable_offset = stdin->_vtable_offset, ++ ++ .vtable = &jumps, ++ }; ++} ++ ++/* Initial tests which do not enable vtable compatibility. */ ++ ++/* Inhibit GCC optimization of fprintf. */ ++typedef int (*fprintf_type) (FILE *, const char *, ...); ++static const volatile fprintf_type fprintf_ptr = &fprintf; ++ ++static void ++without_compatibility_fprintf (void *closure) ++{ ++ /* This call should abort. */ ++ fprintf_ptr (shared->fp, " "); ++ _exit (1); ++} ++ ++static void ++without_compatibility_fputc (void *closure) ++{ ++ /* This call should abort. */ ++ fputc (' ', shared->fp); ++ _exit (1); ++} ++ ++static void ++without_compatibility_fgetc (void *closure) ++{ ++ /* This call should abort. */ ++ fgetc (shared->fp); ++ _exit (1); ++} ++ ++static void ++without_compatibility_fflush (void *closure) ++{ ++ /* This call should abort. */ ++ fflush (shared->fp); ++ _exit (1); ++} ++ ++/* Exit status after abnormal termination. */ ++static int termination_status; ++ ++static void ++init_termination_status (void) ++{ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ abort (); ++ xwaitpid (pid, &termination_status, 0); ++ ++ TEST_VERIFY (WIFSIGNALED (termination_status)); ++ TEST_COMPARE (WTERMSIG (termination_status), SIGABRT); ++} ++ ++static void ++check_for_termination (const char *name, void (*callback) (void *)) ++{ ++ struct my_file file = my_file_create (); ++ shared->fp = &file.f; ++ shared->return_value = -1; ++ shared->calls = 0; ++ struct support_capture_subprocess proc ++ = support_capture_subprocess (callback, NULL); ++ support_capture_subprocess_check (&proc, name, termination_status, ++ sc_allow_stderr); ++ const char *message ++ = "Fatal error: glibc detected an invalid stdio handle\n"; ++ TEST_COMPARE_BLOB (proc.err.buffer, proc.err.length, ++ message, strlen (message)); ++ TEST_COMPARE (shared->calls, 0); ++ support_capture_subprocess_free (&proc); ++} ++ ++/* The test with vtable validation disabled. */ ++ ++/* This function does not have a prototype in libioP.h to prevent ++ accidental use from within the library (which would disable vtable ++ verification). */ ++void _IO_init (FILE *fp, int flags); ++ ++static void ++with_compatibility_fprintf (void *closure) ++{ ++ TEST_COMPARE (fprintf_ptr (shared->fp, "A%sCD", "B"), 4); ++ TEST_COMPARE (shared->calls, 3); ++ TEST_COMPARE (shared->calls_xsputn, 3); ++ TEST_COMPARE_BLOB (shared->buffer, shared->buffer_length, ++ "CD", 2); ++} ++ ++static void ++with_compatibility_fputc (void *closure) ++{ ++ shared->return_value = '@'; ++ TEST_COMPARE (fputc ('@', shared->fp), '@'); ++ TEST_COMPARE (shared->calls, 1); ++ TEST_COMPARE (shared->calls_overflow, 1); ++ TEST_COMPARE (shared->value, '@'); ++} ++ ++static void ++with_compatibility_fgetc (void *closure) ++{ ++ shared->return_value = 'X'; ++ TEST_COMPARE (fgetc (shared->fp), 'X'); ++ TEST_COMPARE (shared->calls, 1); ++ TEST_COMPARE (shared->calls_uflow, 1); ++} ++ ++static void ++with_compatibility_fflush (void *closure) ++{ ++ TEST_COMPARE (fflush (shared->fp), 0); ++ TEST_COMPARE (shared->calls, 1); ++ TEST_COMPARE (shared->calls_sync, 1); ++} ++ ++/* Call CALLBACK in a subprocess, after setting up a custom file ++ object and updating shared->fp. */ ++static void ++check_call (const char *name, void (*callback) (void *), ++ bool initially_disabled) ++{ ++ *shared = (struct shared) ++ { ++ .initially_disabled = initially_disabled, ++ }; ++ ++ /* Set up a custom file object. */ ++ struct my_file file = my_file_create (); ++ shared->fp = &file.f; ++ if (shared->initially_disabled) ++ _IO_init (shared->fp, file.f._flags); ++ ++ if (test_verbose > 0) ++ printf ("info: calling test %s\n", name); ++ support_isolate_in_subprocess (callback, NULL); ++} ++ ++/* Run the tests. INITIALLY_DISABLED indicates whether custom vtables ++ are disabled when the test starts. */ ++static int ++run_tests (bool initially_disabled) ++{ ++ /* The test relies on fatal error messages being printed to standard ++ error. */ ++ setenv ("LIBC_FATAL_STDERR_", "1", 1); ++ ++ shared = support_shared_allocate (sizeof (*shared)); ++ shared->initially_disabled = initially_disabled; ++ init_termination_status (); ++ ++ if (initially_disabled) ++ { ++ check_for_termination ("fprintf", without_compatibility_fprintf); ++ check_for_termination ("fputc", without_compatibility_fputc); ++ check_for_termination ("fgetc", without_compatibility_fgetc); ++ check_for_termination ("fflush", without_compatibility_fflush); ++ } ++ ++ check_call ("fprintf", with_compatibility_fprintf, initially_disabled); ++ check_call ("fputc", with_compatibility_fputc, initially_disabled); ++ check_call ("fgetc", with_compatibility_fgetc, initially_disabled); ++ check_call ("fflush", with_compatibility_fflush, initially_disabled); ++ ++ support_shared_free (shared); ++ shared = NULL; ++ ++ return 0; ++} +diff --git a/libio/tst-vtables-interposed.c b/libio/tst-vtables-interposed.c +new file mode 100644 +index 0000000000..c8f4e8c7c3 +--- /dev/null ++++ b/libio/tst-vtables-interposed.c +@@ -0,0 +1,37 @@ ++/* Test for libio vtables and their validation. Enabled through interposition. ++ Copyright (C) 2018 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 ++ . */ ++ ++/* Provide an interposed definition of the standard file handles with ++ our own vtable. stdout/stdin/stderr will not work as a result, but ++ a succesful test does not print anything, so this is fine. */ ++static const struct _IO_jump_t jumps; ++#define _IO_file_jumps jumps ++#include "stdfiles.c" ++ ++#include "tst-vtables-common.c" ++ ++static int ++do_test (void) ++{ ++ return run_tests (false); ++} ++ ++/* Calling setvbuf in the test driver is not supported with our ++ interposed file handles. */ ++#define TEST_NO_SETVBUF ++#include +diff --git a/libio/tst-vtables.c b/libio/tst-vtables.c +new file mode 100644 +index 0000000000..f16acf5d23 +--- /dev/null ++++ b/libio/tst-vtables.c +@@ -0,0 +1,29 @@ ++/* Test for libio vtables and their validation. Initially disabled case. ++ Copyright (C) 2018 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 "libioP.h" ++ ++#include "tst-vtables-common.c" ++ ++static int ++do_test (void) ++{ ++ return run_tests (true); ++} ++ ++#include +diff --git a/libio/tst-wfile-sync.c b/libio/tst-wfile-sync.c +new file mode 100644 +index 0000000000..618682064d +--- /dev/null ++++ b/libio/tst-wfile-sync.c +@@ -0,0 +1,39 @@ ++/* Test that _IO_wfile_sync does not crash (bug 20568). ++ Copyright (C) 2019 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 (setlocale (LC_ALL, "de_DE.UTF-8") != NULL); ++ /* Fill the stdio buffer and advance the read pointer. */ ++ TEST_VERIFY_EXIT (fgetwc (stdin) != WEOF); ++ /* This calls _IO_wfile_sync, it should not crash. */ ++ TEST_VERIFY_EXIT (setvbuf (stdin, NULL, _IONBF, 0) == 0); ++ /* Verify that the external file offset has been synchronized. */ ++ TEST_COMPARE (xlseek (0, 0, SEEK_CUR), 1); ++ ++ return 0; ++} ++ ++#include +diff --git a/libio/tst-wfile-sync.input b/libio/tst-wfile-sync.input +new file mode 100644 +index 0000000000..12d0958f7a +--- /dev/null ++++ b/libio/tst-wfile-sync.input +@@ -0,0 +1 @@ ++This is a test of _IO_wfile_sync. +diff --git a/libio/vasprintf.c b/libio/vasprintf.c +index 390a63d124..0bb217e46e 100644 +--- a/libio/vasprintf.c ++++ b/libio/vasprintf.c +@@ -54,8 +54,8 @@ _IO_vasprintf (char **result_ptr, const char *format, _IO_va_list args) + _IO_JUMPS (&sf._sbf) = &_IO_str_jumps; + _IO_str_init_static_internal (&sf, string, init_string_size, string); + sf._sbf._f._flags &= ~_IO_USER_BUF; +- sf._s._allocate_buffer = (_IO_alloc_type) malloc; +- sf._s._free_buffer = (_IO_free_type) free; ++ sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; ++ sf._s._free_buffer_unused = (_IO_free_type) free; + ret = _IO_vfprintf (&sf._sbf._f, format, args); + if (ret < 0) + { +diff --git a/libio/vtables.c b/libio/vtables.c +index 9fd4ccf642..9df75668c8 100644 +--- a/libio/vtables.c ++++ b/libio/vtables.c +@@ -71,3 +71,19 @@ _IO_vtable_check (void) + + __libc_fatal ("Fatal error: glibc detected an invalid stdio handle\n"); + } ++ ++/* Some variants of libstdc++ interpose _IO_2_1_stdin_ etc. and ++ install their own vtables directly, without calling _IO_init or ++ other functions. Detect this by looking at the vtables values ++ during startup, and disable vtable validation in this case. */ ++#ifdef SHARED ++__attribute__ ((constructor)) ++static void ++check_stdfiles_vtables (void) ++{ ++ if (_IO_2_1_stdin_.vtable != &_IO_file_jumps ++ || _IO_2_1_stdout_.vtable != &_IO_file_jumps ++ || _IO_2_1_stderr_.vtable != &_IO_file_jumps) ++ IO_set_accept_foreign_vtables (&_IO_vtable_check); ++} ++#endif +diff --git a/libio/wfileops.c b/libio/wfileops.c +index 2488821d54..dd010b4394 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -509,11 +509,12 @@ _IO_wfile_sync (_IO_FILE *fp) + generate the wide characters up to the current reading + position. */ + int nread; +- ++ size_t wnread = (fp->_wide_data->_IO_read_ptr ++ - fp->_wide_data->_IO_read_base); + fp->_wide_data->_IO_state = fp->_wide_data->_IO_last_state; + nread = (*cv->__codecvt_do_length) (cv, &fp->_wide_data->_IO_state, + fp->_IO_read_base, +- fp->_IO_read_end, delta); ++ fp->_IO_read_end, wnread); + fp->_IO_read_ptr = fp->_IO_read_base + nread; + delta = -(fp->_IO_read_end - fp->_IO_read_base - nread); + } +diff --git a/libio/wmemstream.c b/libio/wmemstream.c +index c962071d26..f4c6e75246 100644 +--- a/libio/wmemstream.c ++++ b/libio/wmemstream.c +@@ -92,8 +92,8 @@ open_wmemstream (wchar_t **bufloc, _IO_size_t *sizeloc) + _IO_wstr_init_static (&new_f->fp._sf._sbf._f, buf, + _IO_BUFSIZ / sizeof (wchar_t), buf); + new_f->fp._sf._sbf._f._flags2 &= ~_IO_FLAGS2_USER_WBUF; +- new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc; +- new_f->fp._sf._s._free_buffer = (_IO_free_type) free; ++ new_f->fp._sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc; ++ new_f->fp._sf._s._free_buffer_unused = (_IO_free_type) free; + + new_f->fp.bufloc = bufloc; + new_f->fp.sizeloc = sizeloc; +diff --git a/libio/wstrops.c b/libio/wstrops.c +index a3374a7b15..0839a70bfb 100644 +--- a/libio/wstrops.c ++++ b/libio/wstrops.c +@@ -63,7 +63,7 @@ _IO_wstr_init_static (_IO_FILE *fp, wchar_t *ptr, _IO_size_t size, + fp->_wide_data->_IO_read_end = end; + } + /* A null _allocate_buffer function flags the strfile as being static. */ +- (((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0; ++ (((_IO_strfile *) fp)->_s._allocate_buffer_unused) = (_IO_alloc_type)0; + } + + _IO_wint_t +@@ -95,9 +95,7 @@ _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c) + || __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t))) + return EOF; + +- new_buf +- = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size +- * sizeof (wchar_t)); ++ new_buf = malloc (new_size * sizeof (wchar_t)); + if (new_buf == NULL) + { + /* __ferror(fp) = 1; */ +@@ -106,7 +104,7 @@ _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c) + if (old_buf) + { + __wmemcpy (new_buf, old_buf, old_wblen); +- (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf); ++ free (old_buf); + /* Make sure _IO_setb won't try to delete _IO_buf_base. */ + fp->_wide_data->_IO_buf_base = NULL; + } +@@ -186,16 +184,14 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading) + return 1; + + wchar_t *oldbuf = wd->_IO_buf_base; +- wchar_t *newbuf +- = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize +- * sizeof (wchar_t)); ++ wchar_t *newbuf = malloc (newsize * sizeof (wchar_t)); + if (newbuf == NULL) + return 1; + + if (oldbuf != NULL) + { + __wmemcpy (newbuf, oldbuf, _IO_wblen (fp)); +- (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf); ++ free (oldbuf); + /* Make sure _IO_setb won't try to delete + _IO_buf_base. */ + wd->_IO_buf_base = NULL; +@@ -357,7 +353,7 @@ void + _IO_wstr_finish (_IO_FILE *fp, int dummy) + { + if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF)) +- (((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base); ++ free (fp->_wide_data->_IO_buf_base); + fp->_wide_data->_IO_buf_base = NULL; + + _IO_wdefault_finish (fp, 0); +diff --git a/localedata/locales/es_BO b/localedata/locales/es_BO +index 4202c5a0cf..5b6c6e2312 100644 +--- a/localedata/locales/es_BO ++++ b/localedata/locales/es_BO +@@ -124,7 +124,7 @@ first_weekday 2 + END LC_TIME + + LC_PAPER +-copy "i18n" ++copy "en_US" + END LC_PAPER + + LC_TELEPHONE +diff --git a/localedata/locales/gd_GB b/localedata/locales/gd_GB +index 676ee940c9..77d11e5977 100644 +--- a/localedata/locales/gd_GB ++++ b/localedata/locales/gd_GB +@@ -66,12 +66,12 @@ mon "Am Faoilleach";/ + "An Dmhair";/ + "An t-Samhain";/ + "An Dbhlachd" +-% Faoi, Gearr, Màrt, Gibl, Mhàrt, Ògmh, Iuch, Lùna, Sult, Dàmh, Samh, Dùbh ++% Faoi, Gearr, Màrt, Gibl, Cèit, Ògmh, Iuch, Lùna, Sult, Dàmh, Samh, Dùbh + abmon "Faoi";/ + "Gearr";/ + "Mrt";/ + "Gibl";/ +- "Mhrt";/ ++ "Cit";/ + "gmh";/ + "Iuch";/ + "Lna";/ +diff --git a/localedata/locales/ja_JP b/localedata/locales/ja_JP +index 1fd2fee44b..30190b6248 100644 +--- a/localedata/locales/ja_JP ++++ b/localedata/locales/ja_JP +@@ -14946,7 +14946,9 @@ am_pm "";"" + + t_fmt_ampm "%p%I%M%S" + +-era "+:2:1990//01//01:+*::%EC%Ey";/ ++era "+:2:2020//01//01:+*::%EC%Ey";/ ++ "+:1:2019//05//01:2019//12//31::%EC";/ ++ "+:2:1990//01//01:2019//04//30::%EC%Ey";/ + "+:1:1989//01//08:1989//12//31::%EC";/ + "+:2:1927//01//01:1989//01//07::%EC%Ey";/ + "+:1:1926//12//25:1926//12//31::%EC";/ +diff --git a/malloc/Makefile b/malloc/Makefile +index 17873e67c4..a23d370ff3 100644 +--- a/malloc/Makefile ++++ b/malloc/Makefile +@@ -37,6 +37,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ + tst-malloc-tcache-leak \ + tst-malloc_info \ + tst-malloc-too-large \ ++ tst-tcfree1 tst-tcfree2 tst-tcfree3 \ + + tests-static := \ + tst-interpose-static-nothread \ +diff --git a/malloc/malloc.c b/malloc/malloc.c +index f8e7250f70..6d6983d060 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -2904,6 +2904,8 @@ mremap_chunk (mchunkptr p, size_t new_size) + typedef struct tcache_entry + { + struct tcache_entry *next; ++ /* This field exists to detect double frees. */ ++ struct tcache_perthread_struct *key; + } tcache_entry; + + /* There is one of these for each thread, which contains the +@@ -2917,6 +2919,8 @@ typedef struct tcache_perthread_struct + tcache_entry *entries[TCACHE_MAX_BINS]; + } tcache_perthread_struct; + ++#define MAX_TCACHE_COUNT 127 /* Maximum value of counts[] entries. */ ++ + static __thread bool tcache_shutting_down = false; + static __thread tcache_perthread_struct *tcache = NULL; + +@@ -2927,6 +2931,11 @@ tcache_put (mchunkptr chunk, size_t tc_idx) + { + tcache_entry *e = (tcache_entry *) chunk2mem (chunk); + assert (tc_idx < TCACHE_MAX_BINS); ++ ++ /* Mark this chunk as "in the tcache" so the test in _int_free will ++ detect a double free. */ ++ e->key = tcache; ++ + e->next = tcache->entries[tc_idx]; + tcache->entries[tc_idx] = e; + ++(tcache->counts[tc_idx]); +@@ -2942,6 +2951,7 @@ tcache_get (size_t tc_idx) + assert (tcache->entries[tc_idx] > 0); + tcache->entries[tc_idx] = e->next; + --(tcache->counts[tc_idx]); ++ e->key = NULL; + return (void *) e; + } + +@@ -4165,13 +4175,33 @@ _int_free (mstate av, mchunkptr p, int have_lock) + #if USE_TCACHE + { + size_t tc_idx = csize2tidx (size); +- +- if (tcache +- && tc_idx < mp_.tcache_bins +- && tcache->counts[tc_idx] < mp_.tcache_count) ++ if (tcache != NULL && tc_idx < mp_.tcache_bins) + { +- tcache_put (p, tc_idx); +- return; ++ /* Check to see if it's already in the tcache. */ ++ tcache_entry *e = (tcache_entry *) chunk2mem (p); ++ ++ /* This test succeeds on double free. However, we don't 100% ++ trust it (it also matches random payload data at a 1 in ++ 2^ chance), so verify it's not an unlikely ++ coincidence before aborting. */ ++ if (__glibc_unlikely (e->key == tcache)) ++ { ++ tcache_entry *tmp; ++ LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx); ++ for (tmp = tcache->entries[tc_idx]; ++ tmp; ++ tmp = tmp->next) ++ if (tmp == e) ++ malloc_printerr ("free(): double free detected in tcache 2"); ++ /* If we get here, it was a coincidence. We've wasted a ++ few cycles, but don't abort. */ ++ } ++ ++ if (tcache->counts[tc_idx] < mp_.tcache_count) ++ { ++ tcache_put (p, tc_idx); ++ return; ++ } + } + } + #endif +@@ -4512,11 +4542,6 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + +- unsigned long copysize; /* bytes to copy */ +- unsigned int ncopies; /* INTERNAL_SIZE_T words to copy */ +- INTERNAL_SIZE_T* s; /* copy source */ +- INTERNAL_SIZE_T* d; /* copy destination */ +- + /* oldmem size */ + if (__builtin_expect (chunksize_nomask (oldp) <= 2 * SIZE_SZ, 0) + || __builtin_expect (oldsize >= av->system_mem, 0)) +@@ -4584,43 +4609,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, + } + else + { +- /* +- Unroll copy of <= 36 bytes (72 if 8byte sizes) +- We know that contents have an odd number of +- INTERNAL_SIZE_T-sized words; minimally 3. +- */ +- +- copysize = oldsize - SIZE_SZ; +- s = (INTERNAL_SIZE_T *) (chunk2mem (oldp)); +- d = (INTERNAL_SIZE_T *) (newmem); +- ncopies = copysize / sizeof (INTERNAL_SIZE_T); +- assert (ncopies >= 3); +- +- if (ncopies > 9) +- memcpy (d, s, copysize); +- +- else +- { +- *(d + 0) = *(s + 0); +- *(d + 1) = *(s + 1); +- *(d + 2) = *(s + 2); +- if (ncopies > 4) +- { +- *(d + 3) = *(s + 3); +- *(d + 4) = *(s + 4); +- if (ncopies > 6) +- { +- *(d + 5) = *(s + 5); +- *(d + 6) = *(s + 6); +- if (ncopies > 8) +- { +- *(d + 7) = *(s + 7); +- *(d + 8) = *(s + 8); +- } +- } +- } +- } +- ++ memcpy (newmem, chunk2mem (oldp), oldsize - SIZE_SZ); + _int_free (av, oldp, 1); + check_inuse_chunk (av, newp); + return chunk2mem (newp); +@@ -5118,8 +5107,11 @@ static inline int + __always_inline + do_set_tcache_count (size_t value) + { +- LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count); +- mp_.tcache_count = value; ++ if (value <= MAX_TCACHE_COUNT) ++ { ++ LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count); ++ mp_.tcache_count = value; ++ } + return 1; + } + +diff --git a/malloc/tst-tcfree1.c b/malloc/tst-tcfree1.c +new file mode 100644 +index 0000000000..bc29375ce7 +--- /dev/null ++++ b/malloc/tst-tcfree1.c +@@ -0,0 +1,42 @@ ++/* Test that malloc tcache catches double free. ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ /* Do one allocation of any size that fits in tcache. */ ++ char * volatile x = malloc (32); ++ ++ free (x); // puts in tcache ++ free (x); // should abort ++ ++ printf("FAIL: tcache double free not detected\n"); ++ return 1; ++} ++ ++#define TEST_FUNCTION do_test ++#define EXPECTED_SIGNAL SIGABRT ++#include +diff --git a/malloc/tst-tcfree2.c b/malloc/tst-tcfree2.c +new file mode 100644 +index 0000000000..17f06bacd4 +--- /dev/null ++++ b/malloc/tst-tcfree2.c +@@ -0,0 +1,48 @@ ++/* Test that malloc tcache catches double free. ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ char * volatile ptrs[20]; ++ int i; ++ ++ /* Allocate enough small chunks so that when we free them all, the tcache ++ is full, and the first one we freed is at the end of its linked list. */ ++#define COUNT 20 ++ for (i=0; i +diff --git a/malloc/tst-tcfree3.c b/malloc/tst-tcfree3.c +new file mode 100644 +index 0000000000..016d30ddd8 +--- /dev/null ++++ b/malloc/tst-tcfree3.c +@@ -0,0 +1,56 @@ ++/* Test that malloc tcache catches double free. ++ Copyright (C) 2018 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 ++ ++/* Prevent GCC from optimizing away any malloc/free pairs. */ ++#pragma GCC optimize ("O0") ++ ++static int ++do_test (void) ++{ ++ /* Do two allocation of any size that fit in tcache, and one that ++ doesn't. */ ++ int ** volatile a = malloc (32); ++ int ** volatile b = malloc (32); ++ /* This is just under the mmap threshold. */ ++ int ** volatile c = malloc (127 * 1024); ++ ++ /* The invalid "tcache bucket" we might dereference will likely end ++ up somewhere within this memory block, so make all the accidental ++ "next" pointers cause segfaults. BZ #23907. */ ++ memset (c, 0xff, 127 * 1024); ++ ++ free (a); // puts in tcache ++ ++ /* A is now free and contains the key we use to detect in-tcache. ++ Copy the key to the other chunks. */ ++ memcpy (b, a, 32); ++ memcpy (c, a, 32); ++ ++ /* This free tests the "are we in the tcache already" loop with a ++ VALID bin but "coincidental" matching key. */ ++ free (b); // should NOT abort ++ /* This free tests the "is it a valid tcache bin" test. */ ++ free (c); // should NOT abort ++ ++ return 0; ++} ++ ++#include +diff --git a/manual/examples/mbstouwcs.c b/manual/examples/mbstouwcs.c +new file mode 100644 +index 0000000000..c94e1fa790 +--- /dev/null ++++ b/manual/examples/mbstouwcs.c +@@ -0,0 +1,53 @@ ++#include ++#include ++#include ++#include ++ ++/* Do not include the above headers in the example. ++*/ ++wchar_t * ++mbstouwcs (const char *s) ++{ ++ /* Include the null terminator in the conversion. */ ++ size_t len = strlen (s) + 1; ++ wchar_t *result = reallocarray (NULL, len, sizeof (wchar_t)); ++ if (result == NULL) ++ return NULL; ++ ++ wchar_t *wcp = result; ++ mbstate_t state; ++ memset (&state, '\0', sizeof (state)); ++ ++ while (true) ++ { ++ wchar_t wc; ++ size_t nbytes = mbrtowc (&wc, s, len, &state); ++ if (nbytes == 0) ++ { ++ /* Terminate the result string. */ ++ *wcp = L'\0'; ++ break; ++ } ++ else if (nbytes == (size_t) -2) ++ { ++ /* Truncated input string. */ ++ errno = EILSEQ; ++ free (result); ++ return NULL; ++ } ++ else if (nbytes == (size_t) -1) ++ { ++ /* Some other error (including EILSEQ). */ ++ free (result); ++ return NULL; ++ } ++ else ++ { ++ /* A character was converted. */ ++ *wcp++ = towupper (wc); ++ len -= nbytes; ++ s += nbytes; ++ } ++ } ++ return result; ++} +diff --git a/math/math.h b/math/math.h +index 3c515f817f..0fcbd91366 100644 +--- a/math/math.h ++++ b/math/math.h +@@ -1223,7 +1223,7 @@ template<> struct __iseqsig_type + + template<> struct __iseqsig_type + { +- static int __call (double __x, double __y) throw () ++ static int __call (long double __x, long double __y) throw () + { + # ifndef __NO_LONG_DOUBLE_MATH + return __iseqsigl (__x, __y); +diff --git a/misc/tst-preadvwritev-common.c b/misc/tst-preadvwritev-common.c +index 560c8f89b6..b59a3de465 100644 +--- a/misc/tst-preadvwritev-common.c ++++ b/misc/tst-preadvwritev-common.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + #include + #include +@@ -25,6 +26,7 @@ + + #include + #include ++#include + + static char *temp_filename; + static int temp_fd; +@@ -50,6 +52,42 @@ do_prepare (int argc, char **argv) + pwritev (__fd, __iov, __iovcnt, __offset) + #endif + ++static __attribute__ ((unused)) void ++do_test_without_offset (void) ++{ ++ xftruncate (temp_fd, 0); ++ ++ xwrite (temp_fd, "123", 3); ++ xlseek (temp_fd, 2, SEEK_SET); ++ { ++ struct iovec iov[] = ++ { ++ { (void *) "abc", 3 }, ++ { (void *) "xyzt", 4 }, ++ }; ++ TEST_COMPARE (PWRITEV (temp_fd, iov, array_length (iov), -1), 7); ++ } ++ TEST_COMPARE (xlseek (temp_fd, 0, SEEK_CUR), 9); ++ ++ xlseek (temp_fd, 1, SEEK_SET); ++ char buf1[3]; ++ char buf2[2]; ++ { ++ struct iovec iov[] = ++ { ++ { buf1, sizeof (buf1) }, ++ { buf2, sizeof (buf2) }, ++ }; ++ TEST_COMPARE (PREADV (temp_fd, iov, array_length (iov), -1), ++ sizeof (buf1) + sizeof (buf2)); ++ TEST_COMPARE (memcmp ("2ab", buf1, sizeof (buf1)), 0); ++ TEST_COMPARE (memcmp ("cx", buf2, sizeof (buf2)), 0); ++ TEST_COMPARE (xlseek (temp_fd, 0, SEEK_CUR), 6); ++ } ++ ++ xftruncate (temp_fd, 0); ++} ++ + static int + do_test_with_offset (off_t offset) + { +diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c +index 89fd0a3ff5..50b9da3fea 100644 +--- a/misc/tst-preadvwritev2-common.c ++++ b/misc/tst-preadvwritev2-common.c +@@ -19,9 +19,6 @@ + #include + #include + +-static void +-do_test_with_invalid_flags (void) +-{ + #ifndef RWF_HIPRI + # define RWF_HIPRI 0 + #endif +@@ -34,7 +31,73 @@ do_test_with_invalid_flags (void) + #ifndef RWF_NOWAIT + # define RWF_NOWAIT 0 + #endif +-#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT) ++#ifndef RWF_APPEND ++# define RWF_APPEND 0 ++#endif ++#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \ ++ | RWF_APPEND) ++ ++static void ++do_test_with_invalid_fd (void) ++{ ++ char buf[256]; ++ struct iovec iov = { buf, sizeof buf }; ++ ++ /* Check with flag being 0 to use the fallback code which calls pwritev ++ or writev. */ ++ TEST_VERIFY (preadv2 (-1, &iov, 1, -1, 0) == -1); ++ TEST_COMPARE (errno, EBADF); ++ TEST_VERIFY (pwritev2 (-1, &iov, 1, -1, 0) == -1); ++ TEST_COMPARE (errno, EBADF); ++ ++ /* Same tests as before but with flags being different than 0. Since ++ there is no emulation for any flag value, fallback code returns ++ ENOTSUP. This is different running on a kernel with preadv2/pwritev2 ++ support, where EBADF is returned). */ ++ TEST_VERIFY (preadv2 (-1, &iov, 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EBADF || errno == ENOTSUP); ++ TEST_VERIFY (pwritev2 (-1, &iov, 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EBADF || errno == ENOTSUP); ++} ++ ++static void ++do_test_with_invalid_iov (void) ++{ ++ { ++ char buf[256]; ++ struct iovec iov; ++ ++ iov.iov_base = buf; ++ iov.iov_len = (size_t)SSIZE_MAX + 1; ++ ++ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, 0) == -1); ++ TEST_COMPARE (errno, EINVAL); ++ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, 0) == -1); ++ TEST_COMPARE (errno, EINVAL); ++ ++ /* Same as for invalid file descriptor tests, emulation fallback ++ first checks for flag value and return ENOTSUP. */ ++ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); ++ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); ++ } ++ ++ { ++ /* An invalid iovec buffer should trigger an invalid memory access ++ or an error (Linux for instance returns EFAULT). */ ++ struct iovec iov[IOV_MAX+1] = { 0 }; ++ ++ TEST_VERIFY (preadv2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); ++ TEST_VERIFY (pwritev2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1); ++ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP); ++ } ++} ++ ++static void ++do_test_with_invalid_flags (void) ++{ + /* Set the next bit from the mask of all supported flags. */ + int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2; + invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag); +diff --git a/misc/tst-preadvwritev2.c b/misc/tst-preadvwritev2.c +index d8a9daf66a..cb58cbe41e 100644 +--- a/misc/tst-preadvwritev2.c ++++ b/misc/tst-preadvwritev2.c +@@ -29,6 +29,9 @@ static int + do_test (void) + { + do_test_with_invalid_flags (); ++ do_test_without_offset (); ++ do_test_with_invalid_fd (); ++ do_test_with_invalid_iov (); + + return do_test_with_offset (0); + } +diff --git a/misc/tst-preadvwritev64v2.c b/misc/tst-preadvwritev64v2.c +index 2c656ae3d7..6a9de54c78 100644 +--- a/misc/tst-preadvwritev64v2.c ++++ b/misc/tst-preadvwritev64v2.c +@@ -31,6 +31,9 @@ static int + do_test (void) + { + do_test_with_invalid_flags (); ++ do_test_without_offset (); ++ do_test_with_invalid_fd (); ++ do_test_with_invalid_iov (); + + return do_test_with_offset (0); + } +diff --git a/nptl/Makefile b/nptl/Makefile +index 6fc2c8bb6a..8d88bf2514 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -235,9 +235,9 @@ LDLIBS-tst-minstack-throw = -lstdc++ + + tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \ +- tst-mutex7 tst-mutex9 tst-mutex5a tst-mutex7a tst-mutex7robust \ +- tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \ +- tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \ ++ tst-mutex7 tst-mutex9 tst-mutex10 tst-mutex5a tst-mutex7a \ ++ tst-mutex7robust tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 \ ++ tst-mutexpi5 tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a \ + tst-mutexpi9 \ + tst-spin1 tst-spin2 tst-spin3 tst-spin4 \ + tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \ +@@ -309,7 +309,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ + tst-thread_local1 tst-mutex-errorcheck tst-robust10 \ + tst-robust-fork tst-create-detached tst-memstream \ + tst-thread-exit-clobber tst-minstack-cancel tst-minstack-exit \ +- tst-minstack-throw ++ tst-minstack-throw \ ++ tst-rwlock-pwn + + tests-internal := tst-rwlock19 tst-rwlock20 \ + tst-sem11 tst-sem12 tst-sem13 \ +@@ -373,7 +374,8 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx5 \ + tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 \ + tst-oncex3 tst-oncex4 + ifeq ($(build-shared),yes) +-tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder ++tests += tst-atfork2 tst-tls4 tst-_res1 tst-fini1 tst-compat-forwarder \ ++ tst-audit-threads + tests-internal += tst-tls3 tst-tls3-malloc tst-tls5 tst-stackguard1 + tests-nolibpthread += tst-fini1 + ifeq ($(have-z-execstack),yes) +@@ -385,7 +387,8 @@ modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \ + tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \ + tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \ + tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod \ +- tst-join7mod tst-compat-forwarder-mod ++ tst-join7mod tst-compat-forwarder-mod tst-audit-threads-mod1 \ ++ tst-audit-threads-mod2 + extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) \ + tst-cleanup4aux.o tst-cleanupx4aux.o + test-extras += tst-cleanup4aux tst-cleanupx4aux +@@ -730,6 +733,16 @@ $(objpfx)tst-compat-forwarder: $(objpfx)tst-compat-forwarder-mod.so + # destroying a mutex. + tst-mutex8-ENV = GLIBC_TUNABLES=glibc.elision.enable=0 + ++tst-mutex10-ENV = GLIBC_TUNABLES=glibc.elision.enable=1 ++ ++# Protect against a build using -Wl,-z,now. ++LDFLAGS-tst-audit-threads-mod1.so = -Wl,-z,lazy ++LDFLAGS-tst-audit-threads-mod2.so = -Wl,-z,lazy ++LDFLAGS-tst-audit-threads = -Wl,-z,lazy ++$(objpfx)tst-audit-threads: $(objpfx)tst-audit-threads-mod2.so ++$(objpfx)tst-audit-threads.out: $(objpfx)tst-audit-threads-mod1.so ++tst-audit-threads-ENV = LD_AUDIT=$(objpfx)tst-audit-threads-mod1.so ++ + # The tests here better do not run in parallel + ifneq ($(filter %tests,$(MAKECMDGOALS)),) + .NOTPARALLEL: +diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h +index 583515ff48..ff51f452c6 100644 +--- a/nptl/pthreadP.h ++++ b/nptl/pthreadP.h +@@ -110,19 +110,23 @@ enum + }; + #define PTHREAD_MUTEX_PSHARED_BIT 128 + ++/* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ + #define PTHREAD_MUTEX_TYPE(m) \ +- ((m)->__data.__kind & 127) ++ (atomic_load_relaxed (&((m)->__data.__kind)) & 127) + /* Don't include NO_ELISION, as that type is always the same + as the underlying lock type. */ + #define PTHREAD_MUTEX_TYPE_ELISION(m) \ +- ((m)->__data.__kind & (127|PTHREAD_MUTEX_ELISION_NP)) ++ (atomic_load_relaxed (&((m)->__data.__kind)) \ ++ & (127 | PTHREAD_MUTEX_ELISION_NP)) + + #if LLL_PRIVATE == 0 && LLL_SHARED == 128 + # define PTHREAD_MUTEX_PSHARED(m) \ +- ((m)->__data.__kind & 128) ++ (atomic_load_relaxed (&((m)->__data.__kind)) & 128) + #else + # define PTHREAD_MUTEX_PSHARED(m) \ +- (((m)->__data.__kind & 128) ? LLL_SHARED : LLL_PRIVATE) ++ ((atomic_load_relaxed (&((m)->__data.__kind)) & 128) \ ++ ? LLL_SHARED : LLL_PRIVATE) + #endif + + /* The kernel when waking robust mutexes on exit never uses +diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c +index 8e425eb01e..479e54febb 100644 +--- a/nptl/pthread_cond_common.c ++++ b/nptl/pthread_cond_common.c +@@ -405,8 +405,12 @@ __condvar_quiesce_and_switch_g1 (pthread_cond_t *cond, uint64_t wseq, + { + /* There is still a waiter after spinning. Set the wake-request + flag and block. Relaxed MO is fine because this is just about +- this futex word. */ +- r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1); ++ this futex word. ++ ++ Update r to include the set wake-request flag so that the upcoming ++ futex_wait only blocks if the flag is still set (otherwise, we'd ++ violate the basic client-side futex protocol). */ ++ r = atomic_fetch_or_relaxed (cond->__data.__g_refs + g1, 1) | 1; + + if ((r >> 1) > 0) + futex_wait_simple (cond->__data.__g_refs + g1, r, private); +diff --git a/nptl/pthread_mutex_consistent.c b/nptl/pthread_mutex_consistent.c +index 85b8e1a6cb..4fbd875430 100644 +--- a/nptl/pthread_mutex_consistent.c ++++ b/nptl/pthread_mutex_consistent.c +@@ -23,8 +23,11 @@ + int + pthread_mutex_consistent (pthread_mutex_t *mutex) + { +- /* Test whether this is a robust mutex with a dead owner. */ +- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 ++ /* Test whether this is a robust mutex with a dead owner. ++ See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 + || mutex->__data.__owner != PTHREAD_MUTEX_INCONSISTENT) + return EINVAL; + +diff --git a/nptl/pthread_mutex_destroy.c b/nptl/pthread_mutex_destroy.c +index 5a22611541..713ea68496 100644 +--- a/nptl/pthread_mutex_destroy.c ++++ b/nptl/pthread_mutex_destroy.c +@@ -27,12 +27,17 @@ __pthread_mutex_destroy (pthread_mutex_t *mutex) + { + LIBC_PROBE (mutex_destroy, 1, mutex); + +- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0 + && mutex->__data.__nusers != 0) + return EBUSY; + +- /* Set to an invalid value. */ +- mutex->__data.__kind = -1; ++ /* Set to an invalid value. Relaxed MO is enough as it is undefined behavior ++ if the mutex is used after it has been destroyed. But you can reinitialize ++ it with pthread_mutex_init. */ ++ atomic_store_relaxed (&(mutex->__data.__kind), -1); + + return 0; + } +diff --git a/nptl/pthread_mutex_getprioceiling.c b/nptl/pthread_mutex_getprioceiling.c +index efa37b0d99..ee85949578 100644 +--- a/nptl/pthread_mutex_getprioceiling.c ++++ b/nptl/pthread_mutex_getprioceiling.c +@@ -24,7 +24,9 @@ + int + pthread_mutex_getprioceiling (const pthread_mutex_t *mutex, int *prioceiling) + { +- if (__builtin_expect ((mutex->__data.__kind ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if (__builtin_expect ((atomic_load_relaxed (&(mutex->__data.__kind)) + & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0, 0)) + return EINVAL; + +diff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c +index d8fe473728..5cf290c272 100644 +--- a/nptl/pthread_mutex_init.c ++++ b/nptl/pthread_mutex_init.c +@@ -101,7 +101,7 @@ __pthread_mutex_init (pthread_mutex_t *mutex, + memset (mutex, '\0', __SIZEOF_PTHREAD_MUTEX_T); + + /* Copy the values from the attribute. */ +- mutex->__data.__kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS; ++ int mutex_kind = imutexattr->mutexkind & ~PTHREAD_MUTEXATTR_FLAG_BITS; + + if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0) + { +@@ -111,17 +111,17 @@ __pthread_mutex_init (pthread_mutex_t *mutex, + return ENOTSUP; + #endif + +- mutex->__data.__kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ mutex_kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP; + } + + switch (imutexattr->mutexkind & PTHREAD_MUTEXATTR_PROTOCOL_MASK) + { + case PTHREAD_PRIO_INHERIT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: +- mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP; ++ mutex_kind |= PTHREAD_MUTEX_PRIO_INHERIT_NP; + break; + + case PTHREAD_PRIO_PROTECT << PTHREAD_MUTEXATTR_PROTOCOL_SHIFT: +- mutex->__data.__kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; ++ mutex_kind |= PTHREAD_MUTEX_PRIO_PROTECT_NP; + + int ceiling = (imutexattr->mutexkind + & PTHREAD_MUTEXATTR_PRIO_CEILING_MASK) +@@ -145,7 +145,11 @@ __pthread_mutex_init (pthread_mutex_t *mutex, + FUTEX_PRIVATE_FLAG FUTEX_WAKE. */ + if ((imutexattr->mutexkind & (PTHREAD_MUTEXATTR_FLAG_PSHARED + | PTHREAD_MUTEXATTR_FLAG_ROBUST)) != 0) +- mutex->__data.__kind |= PTHREAD_MUTEX_PSHARED_BIT; ++ mutex_kind |= PTHREAD_MUTEX_PSHARED_BIT; ++ ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ atomic_store_relaxed (&(mutex->__data.__kind), mutex_kind); + + /* Default values: mutex not used yet. */ + // mutex->__count = 0; already done by memset +diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c +index 1519c142bd..29cc143e6c 100644 +--- a/nptl/pthread_mutex_lock.c ++++ b/nptl/pthread_mutex_lock.c +@@ -62,6 +62,8 @@ static int __pthread_mutex_lock_full (pthread_mutex_t *mutex) + int + __pthread_mutex_lock (pthread_mutex_t *mutex) + { ++ /* See concurrency notes regarding mutex type which is loaded from __kind ++ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ + unsigned int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); + + LIBC_PROBE (mutex_entry, 1, mutex); +@@ -350,8 +352,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: + case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; +- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ int kind, robust; ++ { ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); ++ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ } + + if (robust) + { +@@ -502,7 +510,10 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_PP_NORMAL_NP: + case PTHREAD_MUTEX_PP_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int kind = atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_KIND_MASK_NP; + + oldval = mutex->__data.__lock; + +@@ -607,15 +618,18 @@ hidden_def (__pthread_mutex_lock) + void + __pthread_mutex_cond_lock_adjust (pthread_mutex_t *mutex) + { +- assert ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0); +- assert ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0); +- assert ((mutex->__data.__kind & PTHREAD_MUTEX_PSHARED_BIT) == 0); ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); ++ assert ((mutex_kind & PTHREAD_MUTEX_PRIO_INHERIT_NP) != 0); ++ assert ((mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) == 0); ++ assert ((mutex_kind & PTHREAD_MUTEX_PSHARED_BIT) == 0); + + /* Record the ownership. */ + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + mutex->__data.__owner = id; + +- if (mutex->__data.__kind == PTHREAD_MUTEX_PI_RECURSIVE_NP) ++ if (mutex_kind == PTHREAD_MUTEX_PI_RECURSIVE_NP) + ++mutex->__data.__count; + } + #endif +diff --git a/nptl/pthread_mutex_setprioceiling.c b/nptl/pthread_mutex_setprioceiling.c +index 8594874f85..8306cabcf4 100644 +--- a/nptl/pthread_mutex_setprioceiling.c ++++ b/nptl/pthread_mutex_setprioceiling.c +@@ -27,9 +27,10 @@ int + pthread_mutex_setprioceiling (pthread_mutex_t *mutex, int prioceiling, + int *old_ceiling) + { +- /* The low bits of __kind aren't ever changed after pthread_mutex_init, +- so we don't need a lock yet. */ +- if ((mutex->__data.__kind & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0) ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_PRIO_PROTECT_NP) == 0) + return EINVAL; + + /* See __init_sched_fifo_prio. */ +diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c +index 66efd3989f..40b559f517 100644 +--- a/nptl/pthread_mutex_timedlock.c ++++ b/nptl/pthread_mutex_timedlock.c +@@ -53,6 +53,8 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, + /* We must not check ABSTIME here. If the thread does not block + abstime must not be checked for a valid value. */ + ++ /* See concurrency notes regarding mutex type which is loaded from __kind ++ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ + switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex), + PTHREAD_MUTEX_TIMED_NP)) + { +@@ -338,8 +340,14 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, + case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: + case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; +- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ int kind, robust; ++ { ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); ++ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ } + + if (robust) + { +@@ -509,7 +517,10 @@ __pthread_mutex_timedlock (pthread_mutex_t *mutex, + case PTHREAD_MUTEX_PP_NORMAL_NP: + case PTHREAD_MUTEX_PP_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int kind = atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_KIND_MASK_NP; + + oldval = mutex->__data.__lock; + +diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c +index 7de61f4f68..8e01113b0f 100644 +--- a/nptl/pthread_mutex_trylock.c ++++ b/nptl/pthread_mutex_trylock.c +@@ -36,6 +36,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + int oldval; + pid_t id = THREAD_GETMEM (THREAD_SELF, tid); + ++ /* See concurrency notes regarding mutex type which is loaded from __kind ++ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ + switch (__builtin_expect (PTHREAD_MUTEX_TYPE_ELISION (mutex), + PTHREAD_MUTEX_TIMED_NP)) + { +@@ -92,6 +94,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP: + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + &mutex->__data.__list.__next); ++ /* We need to set op_pending before starting the operation. Also ++ see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + + oldval = mutex->__data.__lock; + do +@@ -117,7 +122,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + /* But it is inconsistent unless marked otherwise. */ + mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Note that we deliberately exist here. If we fall +@@ -133,6 +143,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + int kind = PTHREAD_MUTEX_TYPE (mutex); + if (kind == PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. Also see comments at ENQUEUE_MUTEX. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + NULL); + return EDEADLK; +@@ -140,6 +152,8 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + + if (kind == PTHREAD_MUTEX_ROBUST_RECURSIVE_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, + NULL); + +@@ -158,6 +172,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + id, 0); + if (oldval != 0 && (oldval & FUTEX_OWNER_DIED) == 0) + { ++ /* We haven't acquired the lock as it is already acquired by ++ another owner. We do not need to ensure ordering wrt another ++ memory access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; +@@ -171,13 +188,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + if (oldval == id) + lll_unlock (mutex->__data.__lock, + PTHREAD_ROBUST_MUTEX_PSHARED (mutex)); ++ /* FIXME This violates the mutex destruction requirements. See ++ __pthread_mutex_unlock_full. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return ENOTRECOVERABLE; + } + } + while ((oldval & FUTEX_OWNER_DIED) != 0); + ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + mutex->__data.__owner = id; +@@ -199,14 +223,25 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_PI_ROBUST_NORMAL_NP: + case PTHREAD_MUTEX_PI_ROBUST_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; +- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ int kind, robust; ++ { ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int mutex_kind = atomic_load_relaxed (&(mutex->__data.__kind)); ++ kind = mutex_kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ robust = mutex_kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ } + + if (robust) +- /* Note: robust PI futexes are signaled by setting bit 0. */ +- THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, +- (void *) (((uintptr_t) &mutex->__data.__list.__next) +- | 1)); ++ { ++ /* Note: robust PI futexes are signaled by setting bit 0. */ ++ THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, ++ (void *) (((uintptr_t) &mutex->__data.__list.__next) ++ | 1)); ++ /* We need to set op_pending before starting the operation. Also ++ see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); ++ } + + oldval = mutex->__data.__lock; + +@@ -215,12 +250,16 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + { + if (kind == PTHREAD_MUTEX_ERRORCHECK_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return EDEADLK; + } + + if (kind == PTHREAD_MUTEX_RECURSIVE_NP) + { ++ /* We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Just bump the counter. */ +@@ -242,6 +281,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + { + if ((oldval & FUTEX_OWNER_DIED) == 0) + { ++ /* We haven't acquired the lock as it is already acquired by ++ another owner. We do not need to ensure ordering wrt another ++ memory access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; +@@ -262,6 +304,9 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + if (INTERNAL_SYSCALL_ERROR_P (e, __err) + && INTERNAL_SYSCALL_ERRNO (e, __err) == EWOULDBLOCK) + { ++ /* The kernel has not yet finished the mutex owner death. ++ We do not need to ensure ordering wrt another memory ++ access. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + return EBUSY; +@@ -279,7 +324,12 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + /* But it is inconsistent unless marked otherwise. */ + mutex->__data.__owner = PTHREAD_MUTEX_INCONSISTENT; + ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + + /* Note that we deliberately exit here. If we fall +@@ -302,13 +352,20 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + PTHREAD_ROBUST_MUTEX_PSHARED (mutex)), + 0, 0); + ++ /* To the kernel, this will be visible after the kernel has ++ acquired the mutex in the syscall. */ + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + return ENOTRECOVERABLE; + } + + if (robust) + { ++ /* We must not enqueue the mutex before we have acquired it. ++ Also see comments at ENQUEUE_MUTEX. */ ++ __asm ("" ::: "memory"); + ENQUEUE_MUTEX_PI (mutex); ++ /* We need to clear op_pending after we enqueue the mutex. */ ++ __asm ("" ::: "memory"); + THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending, NULL); + } + +@@ -325,7 +382,10 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex) + case PTHREAD_MUTEX_PP_NORMAL_NP: + case PTHREAD_MUTEX_PP_ADAPTIVE_NP: + { +- int kind = mutex->__data.__kind & PTHREAD_MUTEX_KIND_MASK_NP; ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int kind = atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_KIND_MASK_NP; + + oldval = mutex->__data.__lock; + +diff --git a/nptl/pthread_mutex_unlock.c b/nptl/pthread_mutex_unlock.c +index 9ea62943b7..68d04d5395 100644 +--- a/nptl/pthread_mutex_unlock.c ++++ b/nptl/pthread_mutex_unlock.c +@@ -35,6 +35,8 @@ int + attribute_hidden + __pthread_mutex_unlock_usercnt (pthread_mutex_t *mutex, int decr) + { ++ /* See concurrency notes regarding mutex type which is loaded from __kind ++ in struct __pthread_mutex_s in sysdeps/nptl/bits/thread-shared-types.h. */ + int type = PTHREAD_MUTEX_TYPE_ELISION (mutex); + if (__builtin_expect (type & + ~(PTHREAD_MUTEX_KIND_MASK_NP|PTHREAD_MUTEX_ELISION_FLAGS_NP), 0)) +@@ -222,13 +224,19 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) + /* If the previous owner died and the caller did not succeed in + making the state consistent, mark the mutex as unrecoverable + and make all waiters. */ +- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0 + && __builtin_expect (mutex->__data.__owner + == PTHREAD_MUTEX_INCONSISTENT, 0)) + pi_notrecoverable: + newowner = PTHREAD_MUTEX_NOTRECOVERABLE; + +- if ((mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ if ((atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP) != 0) + { + continue_pi_robust: + /* Remove mutex from the list. +@@ -251,7 +259,10 @@ __pthread_mutex_unlock_full (pthread_mutex_t *mutex, int decr) + /* Unlock. Load all necessary mutex data before releasing the mutex + to not violate the mutex destruction requirements (see + lll_unlock). */ +- int robust = mutex->__data.__kind & PTHREAD_MUTEX_ROBUST_NORMAL_NP; ++ /* See concurrency notes regarding __kind in struct __pthread_mutex_s ++ in sysdeps/nptl/bits/thread-shared-types.h. */ ++ int robust = atomic_load_relaxed (&(mutex->__data.__kind)) ++ & PTHREAD_MUTEX_ROBUST_NORMAL_NP; + private = (robust + ? PTHREAD_ROBUST_MUTEX_PSHARED (mutex) + : PTHREAD_MUTEX_PSHARED (mutex)); +diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c +index a290d08332..9ce36d1026 100644 +--- a/nptl/pthread_rwlock_common.c ++++ b/nptl/pthread_rwlock_common.c +@@ -314,8 +314,8 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, + harmless because the flag is just about the state of + __readers, and all threads set the flag under the same + conditions. */ +- while ((atomic_load_relaxed (&rwlock->__data.__readers) +- & PTHREAD_RWLOCK_RWAITING) != 0) ++ while (((r = atomic_load_relaxed (&rwlock->__data.__readers)) ++ & PTHREAD_RWLOCK_RWAITING) != 0) + { + int private = __pthread_rwlock_get_private (rwlock); + int err = futex_abstimed_wait (&rwlock->__data.__readers, +diff --git a/nptl/tst-audit-threads-mod1.c b/nptl/tst-audit-threads-mod1.c +new file mode 100644 +index 0000000000..615d5ee512 +--- /dev/null ++++ b/nptl/tst-audit-threads-mod1.c +@@ -0,0 +1,74 @@ ++/* Dummy audit library for test-audit-threads. ++ ++ Copyright (C) 2018 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 ++ ++/* We must use a dummy LD_AUDIT module to force the dynamic loader to ++ *not* update the real PLT, and instead use a cached value for the ++ lazy resolution result. It is the update of that cached value that ++ we are testing for correctness by doing this. */ ++ ++/* Library to be audited. */ ++#define LIB "tst-audit-threads-mod2.so" ++/* CALLNUM is the number of retNum functions. */ ++#define CALLNUM 7999 ++ ++#define CONCATX(a, b) __CONCAT (a, b) ++ ++static int previous = 0; ++ ++unsigned int ++la_version (unsigned int ver) ++{ ++ return 1; ++} ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ return LA_FLG_BINDTO | LA_FLG_BINDFROM; ++} ++ ++uintptr_t ++CONCATX(la_symbind, __ELF_NATIVE_CLASS) (ElfW(Sym) *sym, ++ unsigned int ndx, ++ uintptr_t *refcook, ++ uintptr_t *defcook, ++ unsigned int *flags, ++ const char *symname) ++{ ++ const char * retnum = "retNum"; ++ char * num = strstr (symname, retnum); ++ int n; ++ /* Validate if the symbols are getting called in the correct order. ++ This code is here to verify binutils does not optimize out the PLT ++ entries that require the symbol binding. */ ++ if (num != NULL) ++ { ++ n = atoi (num); ++ assert (n >= previous); ++ assert (n <= CALLNUM); ++ previous = n; ++ } ++ return sym->st_value; ++} +diff --git a/nptl/tst-audit-threads-mod2.c b/nptl/tst-audit-threads-mod2.c +new file mode 100644 +index 0000000000..f9817dd3dc +--- /dev/null ++++ b/nptl/tst-audit-threads-mod2.c +@@ -0,0 +1,22 @@ ++/* Shared object with a huge number of functions for test-audit-threads. ++ ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* Define all the retNumN functions in a library. */ ++#define definenum ++#include "tst-audit-threads.h" +diff --git a/nptl/tst-audit-threads.c b/nptl/tst-audit-threads.c +new file mode 100644 +index 0000000000..e4bf433bd8 +--- /dev/null ++++ b/nptl/tst-audit-threads.c +@@ -0,0 +1,97 @@ ++/* Test multi-threading using LD_AUDIT. ++ ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* This test uses a dummy LD_AUDIT library (test-audit-threads-mod1) and a ++ library with a huge number of functions in order to validate lazy symbol ++ binding with an audit library. We use one thread per CPU to test that ++ concurrent lazy resolution does not have any defects which would cause ++ the process to fail. We use an LD_AUDIT library to force the testing of ++ the relocation resolution caching code in the dynamic loader i.e. ++ _dl_runtime_profile and _dl_profile_fixup. */ ++ ++#include ++#include ++#include ++#include ++ ++static int do_test (void); ++ ++/* This test usually takes less than 3s to run. However, there are cases that ++ take up to 30s. */ ++#define TIMEOUT 60 ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" ++ ++/* Declare the functions we are going to call. */ ++#define externnum ++#include "tst-audit-threads.h" ++#undef externnum ++ ++int num_threads; ++pthread_barrier_t barrier; ++ ++void ++sync_all (int num) ++{ ++ pthread_barrier_wait (&barrier); ++} ++ ++void ++call_all_ret_nums (void) ++{ ++ /* Call each function one at a time from all threads. */ ++#define callnum ++#include "tst-audit-threads.h" ++#undef callnum ++} ++ ++void * ++thread_main (void *unused) ++{ ++ call_all_ret_nums (); ++ return NULL; ++} ++ ++#define STR2(X) #X ++#define STR(X) STR2(X) ++ ++static int ++do_test (void) ++{ ++ int i; ++ pthread_t *threads; ++ ++ num_threads = get_nprocs (); ++ if (num_threads <= 1) ++ num_threads = 2; ++ ++ /* Used to synchronize all the threads after calling each retNumN. */ ++ xpthread_barrier_init (&barrier, NULL, num_threads); ++ ++ threads = (pthread_t *) xcalloc (num_threads, sizeof(pthread_t)); ++ for (i = 0; i < num_threads; i++) ++ threads[i] = xpthread_create(NULL, thread_main, NULL); ++ ++ for (i = 0; i < num_threads; i++) ++ xpthread_join(threads[i]); ++ ++ free (threads); ++ ++ return 0; ++} +diff --git a/nptl/tst-audit-threads.h b/nptl/tst-audit-threads.h +new file mode 100644 +index 0000000000..1c9ecc08df +--- /dev/null ++++ b/nptl/tst-audit-threads.h +@@ -0,0 +1,92 @@ ++/* Helper header for test-audit-threads. ++ ++ Copyright (C) 2018 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 this helper to create a large number of functions, all of ++ which will be resolved lazily and thus have their PLT updated. ++ This is done to provide enough functions that we can statistically ++ observe a thread vs. PLT resolution failure if one exists. */ ++ ++#define CONCAT(a, b) a ## b ++#define NUM(x, y) CONCAT (x, y) ++ ++#define FUNC10(x) \ ++ FUNC (NUM (x, 0)); \ ++ FUNC (NUM (x, 1)); \ ++ FUNC (NUM (x, 2)); \ ++ FUNC (NUM (x, 3)); \ ++ FUNC (NUM (x, 4)); \ ++ FUNC (NUM (x, 5)); \ ++ FUNC (NUM (x, 6)); \ ++ FUNC (NUM (x, 7)); \ ++ FUNC (NUM (x, 8)); \ ++ FUNC (NUM (x, 9)) ++ ++#define FUNC100(x) \ ++ FUNC10 (NUM (x, 0)); \ ++ FUNC10 (NUM (x, 1)); \ ++ FUNC10 (NUM (x, 2)); \ ++ FUNC10 (NUM (x, 3)); \ ++ FUNC10 (NUM (x, 4)); \ ++ FUNC10 (NUM (x, 5)); \ ++ FUNC10 (NUM (x, 6)); \ ++ FUNC10 (NUM (x, 7)); \ ++ FUNC10 (NUM (x, 8)); \ ++ FUNC10 (NUM (x, 9)) ++ ++#define FUNC1000(x) \ ++ FUNC100 (NUM (x, 0)); \ ++ FUNC100 (NUM (x, 1)); \ ++ FUNC100 (NUM (x, 2)); \ ++ FUNC100 (NUM (x, 3)); \ ++ FUNC100 (NUM (x, 4)); \ ++ FUNC100 (NUM (x, 5)); \ ++ FUNC100 (NUM (x, 6)); \ ++ FUNC100 (NUM (x, 7)); \ ++ FUNC100 (NUM (x, 8)); \ ++ FUNC100 (NUM (x, 9)) ++ ++#define FUNC7000() \ ++ FUNC1000 (1); \ ++ FUNC1000 (2); \ ++ FUNC1000 (3); \ ++ FUNC1000 (4); \ ++ FUNC1000 (5); \ ++ FUNC1000 (6); \ ++ FUNC1000 (7); ++ ++#ifdef FUNC ++# undef FUNC ++#endif ++ ++#ifdef externnum ++# define FUNC(x) extern int CONCAT (retNum, x) (void) ++#endif ++ ++#ifdef definenum ++# define FUNC(x) int CONCAT (retNum, x) (void) { return x; } ++#endif ++ ++#ifdef callnum ++# define FUNC(x) CONCAT (retNum, x) (); sync_all (x) ++#endif ++ ++/* A value of 7000 functions is chosen as an arbitrarily large ++ number of functions that will allow us enough attempts to ++ verify lazy resolution operation. */ ++FUNC7000 (); +diff --git a/nptl/tst-mutex10.c b/nptl/tst-mutex10.c +new file mode 100644 +index 0000000000..e1113ca60a +--- /dev/null ++++ b/nptl/tst-mutex10.c +@@ -0,0 +1,109 @@ ++/* Testing race while enabling lock elision. ++ Copyright (C) 2018 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 ++ ++static pthread_barrier_t barrier; ++static pthread_mutex_t mutex; ++static long long int iteration_count = 1000000; ++static unsigned int thread_count = 3; ++ ++static void * ++thr_func (void *arg) ++{ ++ long long int i; ++ for (i = 0; i < iteration_count; i++) ++ { ++ if ((uintptr_t) arg == 0) ++ { ++ xpthread_mutex_destroy (&mutex); ++ xpthread_mutex_init (&mutex, NULL); ++ } ++ ++ xpthread_barrier_wait (&barrier); ++ ++ /* Test if enabling lock elision works if it is enabled concurrently. ++ There was a race in FORCE_ELISION macro which leads to either ++ pthread_mutex_destroy returning EBUSY as the owner was recorded ++ by pthread_mutex_lock - in "normal mutex" code path - but was not ++ resetted in pthread_mutex_unlock - in "elision" code path. ++ Or it leads to the assertion in nptl/pthread_mutex_lock.c: ++ assert (mutex->__data.__owner == 0); ++ Please ensure that the test is run with lock elision: ++ export GLIBC_TUNABLES=glibc.elision.enable=1 */ ++ xpthread_mutex_lock (&mutex); ++ xpthread_mutex_unlock (&mutex); ++ ++ xpthread_barrier_wait (&barrier); ++ } ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ unsigned int i; ++ printf ("Starting %d threads to run %lld iterations.\n", ++ thread_count, iteration_count); ++ ++ pthread_t *threads = xmalloc (thread_count * sizeof (pthread_t)); ++ xpthread_barrier_init (&barrier, NULL, thread_count); ++ xpthread_mutex_init (&mutex, NULL); ++ ++ for (i = 0; i < thread_count; i++) ++ threads[i] = xpthread_create (NULL, thr_func, (void *) (uintptr_t) i); ++ ++ for (i = 0; i < thread_count; i++) ++ xpthread_join (threads[i]); ++ ++ xpthread_barrier_destroy (&barrier); ++ free (threads); ++ ++ return EXIT_SUCCESS; ++} ++ ++#define OPT_ITERATIONS 10000 ++#define OPT_THREADS 10001 ++#define CMDLINE_OPTIONS \ ++ { "iterations", required_argument, NULL, OPT_ITERATIONS }, \ ++ { "threads", required_argument, NULL, OPT_THREADS }, ++static void ++cmdline_process (int c) ++{ ++ long long int arg = strtoll (optarg, NULL, 0); ++ switch (c) ++ { ++ case OPT_ITERATIONS: ++ if (arg > 0) ++ iteration_count = arg; ++ break; ++ case OPT_THREADS: ++ if (arg > 0 && arg < 100) ++ thread_count = arg; ++ break; ++ } ++} ++#define CMDLINE_PROCESS cmdline_process ++#define TIMEOUT 50 ++#include +diff --git a/nptl/tst-rwlock-pwn.c b/nptl/tst-rwlock-pwn.c +new file mode 100644 +index 0000000000..c39dd70973 +--- /dev/null ++++ b/nptl/tst-rwlock-pwn.c +@@ -0,0 +1,87 @@ ++/* Test rwlock with PREFER_WRITER_NONRECURSIVE_NP (bug 23861). ++ Copyright (C) 2018 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 ++ ++/* We choose 10 iterations because this happens to be able to trigger the ++ stall on contemporary hardware. */ ++#define LOOPS 10 ++/* We need 3 threads to trigger bug 23861. One thread as a writer, and ++ two reader threads. The test verifies that the second-to-last reader ++ is able to notify the *last* reader that it should be done waiting. ++ If the second-to-last reader fails to notify the last reader or does ++ so incorrectly then the last reader may stall indefinitely. */ ++#define NTHREADS 3 ++ ++_Atomic int do_exit; ++pthread_rwlockattr_t mylock_attr; ++pthread_rwlock_t mylock; ++ ++void * ++run_loop (void *a) ++{ ++ while (!do_exit) ++ { ++ if (random () & 1) ++ { ++ xpthread_rwlock_wrlock (&mylock); ++ xpthread_rwlock_unlock (&mylock); ++ } ++ else ++ { ++ xpthread_rwlock_rdlock (&mylock); ++ xpthread_rwlock_unlock (&mylock); ++ } ++ } ++ return NULL; ++} ++ ++int ++do_test (void) ++{ ++ xpthread_rwlockattr_init (&mylock_attr); ++ xpthread_rwlockattr_setkind_np (&mylock_attr, ++ PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); ++ xpthread_rwlock_init (&mylock, &mylock_attr); ++ ++ for (int n = 0; n < LOOPS; n++) ++ { ++ pthread_t tids[NTHREADS]; ++ do_exit = 0; ++ for (int i = 0; i < NTHREADS; i++) ++ tids[i] = xpthread_create (NULL, run_loop, NULL); ++ /* Let the threads run for some time. */ ++ sleep (1); ++ printf ("Exiting..."); ++ fflush (stdout); ++ do_exit = 1; ++ for (int i = 0; i < NTHREADS; i++) ++ xpthread_join (tids[i]); ++ printf ("done.\n"); ++ } ++ pthread_rwlock_destroy (&mylock); ++ pthread_rwlockattr_destroy (&mylock_attr); ++ return 0; ++} ++ ++#define TIMEOUT (DEFAULT_TIMEOUT + 3 * LOOPS) ++#include +diff --git a/posix/Makefile b/posix/Makefile +index 83b3d7418c..0fb280ba69 100644 +--- a/posix/Makefile ++++ b/posix/Makefile +@@ -95,10 +95,10 @@ tests := test-errno tstgetopt testfnm runtests runptests \ + tst-posix_spawn-fd tst-posix_spawn-setsid \ + tst-posix_fadvise tst-posix_fadvise64 \ + tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \ +- tst-glob-tilde ++ tst-glob-tilde tst-spawn4 + tests-internal := bug-regex5 bug-regex20 bug-regex33 \ + tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \ +- tst-glob_lstat_compat ++ tst-glob_lstat_compat tst-spawn4-compat + xtests := bug-ga2 tst-getaddrinfo4 tst-getaddrinfo5 + ifeq (yes,$(build-shared)) + test-srcs := globtest +diff --git a/posix/execvpe.c b/posix/execvpe.c +index 859c0f69bf..ea67d19fcd 100644 +--- a/posix/execvpe.c ++++ b/posix/execvpe.c +@@ -67,11 +67,9 @@ maybe_script_execute (const char *file, char *const argv[], char *const envp[]) + __execve (new_argv[0], new_argv, envp); + } + +- +-/* Execute FILE, searching in the `PATH' environment variable if it contains +- no slashes, with arguments ARGV and environment from ENVP. */ +-int +-__execvpe (const char *file, char *const argv[], char *const envp[]) ++static int ++__execvpe_common (const char *file, char *const argv[], char *const envp[], ++ bool exec_script) + { + /* We check the simple case first. */ + if (*file == '\0') +@@ -85,7 +83,7 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) + { + __execve (file, argv, envp); + +- if (errno == ENOEXEC) ++ if (errno == ENOEXEC && exec_script) + maybe_script_execute (file, argv, envp); + + return -1; +@@ -137,7 +135,7 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) + + __execve (buffer, argv, envp); + +- if (errno == ENOEXEC) ++ if (errno == ENOEXEC && exec_script) + /* This has O(P*C) behavior, where P is the length of the path and C + is the argument count. A better strategy would be allocate the + substitute argv and reuse it each time through the loop (so it +@@ -184,4 +182,18 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) + return -1; + } + ++/* Execute FILE, searching in the `PATH' environment variable if it contains ++ no slashes, with arguments ARGV and environment from ENVP. */ ++int ++__execvpe (const char *file, char *const argv[], char *const envp[]) ++{ ++ return __execvpe_common (file, argv, envp, true); ++} + weak_alias (__execvpe, execvpe) ++ ++/* Same as __EXECVPE, but does not try to execute NOEXEC files. */ ++int ++__execvpex (const char *file, char *const argv[], char *const envp[]) ++{ ++ return __execvpe_common (file, argv, envp, false); ++} +diff --git a/posix/regexec.c b/posix/regexec.c +index 4b1ab4ecff..21129432d1 100644 +--- a/posix/regexec.c ++++ b/posix/regexec.c +@@ -3848,30 +3848,27 @@ check_node_accept_bytes (const re_dfa_t *dfa, int node_idx, + indirect = (const int32_t *) + _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); + int32_t idx = findidx (table, indirect, extra, &cp, elem_len); ++ int32_t rule = idx >> 24; ++ idx &= 0xffffff; + if (idx > 0) +- for (i = 0; i < cset->nequiv_classes; ++i) +- { +- int32_t equiv_class_idx = cset->equiv_classes[i]; +- size_t weight_len = weights[idx & 0xffffff]; +- if (weight_len == weights[equiv_class_idx & 0xffffff] +- && (idx >> 24) == (equiv_class_idx >> 24)) +- { +- int cnt = 0; +- +- idx &= 0xffffff; +- equiv_class_idx &= 0xffffff; +- +- while (cnt <= weight_len +- && (weights[equiv_class_idx + 1 + cnt] +- == weights[idx + 1 + cnt])) +- ++cnt; +- if (cnt > weight_len) +- { +- match_len = elem_len; +- goto check_node_accept_bytes_match; +- } +- } +- } ++ { ++ size_t weight_len = weights[idx]; ++ for (i = 0; i < cset->nequiv_classes; ++i) ++ { ++ int32_t equiv_class_idx = cset->equiv_classes[i]; ++ int32_t equiv_class_rule = equiv_class_idx >> 24; ++ equiv_class_idx &= 0xffffff; ++ if (weights[equiv_class_idx] == weight_len ++ && equiv_class_rule == rule ++ && memcmp (weights + idx + 1, ++ weights + equiv_class_idx + 1, ++ weight_len) == 0) ++ { ++ match_len = elem_len; ++ goto check_node_accept_bytes_match; ++ } ++ } ++ } + } + } + else +diff --git a/posix/tst-mmap-offset.c b/posix/tst-mmap-offset.c +index 92ea794c5a..cf17ba077c 100644 +--- a/posix/tst-mmap-offset.c ++++ b/posix/tst-mmap-offset.c +@@ -1,4 +1,4 @@ +-/* BZ #18877 and #21270 mmap offset test. ++/* BZ #18877, BZ #21270, and BZ #24699 mmap offset test. + + Copyright (C) 2015-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #include + +@@ -76,7 +77,7 @@ do_test_bz18877 (void) + + /* Check if invalid offset are handled correctly by mmap. */ + static int +-do_test_bz21270 (void) ++do_test_large_offset (void) + { + /* For architectures with sizeof (off_t) < sizeof (off64_t) mmap is + implemented with __SYS_mmap2 syscall and the offset is represented in +@@ -90,7 +91,7 @@ do_test_bz21270 (void) + const size_t length = 4096; + + void *addr = mmap64 (NULL, length, prot, flags, fd, offset); +- if (sizeof (off_t) < sizeof (off64_t)) ++ if (mmap64_maximum_offset (page_shift) < UINT64_MAX) + { + if ((addr != MAP_FAILED) && (errno != EINVAL)) + FAIL_RET ("mmap succeed"); +@@ -110,7 +111,7 @@ do_test (void) + int ret = 0; + + ret += do_test_bz18877 (); +- ret += do_test_bz21270 (); ++ ret += do_test_large_offset (); + + return ret; + } +diff --git a/posix/tst-spawn4-compat.c b/posix/tst-spawn4-compat.c +new file mode 100644 +index 0000000000..11f654b913 +--- /dev/null ++++ b/posix/tst-spawn4-compat.c +@@ -0,0 +1,77 @@ ++/* Check if posix_spawn does handle correctly ENOEXEC files. ++ Copyright (C) 2018 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 ++#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_15) ++ ++compat_symbol_reference (libc, posix_spawn, posix_spawn, GLIBC_2_2); ++compat_symbol_reference (libc, posix_spawnp, posix_spawnp, GLIBC_2_2); ++ ++static int ++do_test (void) ++{ ++ char *scriptname; ++ int fd = create_temp_file ("tst-spawn4.", &scriptname); ++ TEST_VERIFY_EXIT (fd >= 0); ++ ++ const char script[] = "exit 65"; ++ xwrite (fd, script, sizeof (script) - 1); ++ xclose (fd); ++ ++ TEST_VERIFY_EXIT (chmod (scriptname, 0x775) == 0); ++ ++ pid_t pid; ++ int status; ++ ++ /* For compat symbol it verifies that trying to issued a shell script ++ without a shebang is correctly executed. */ ++ status = posix_spawn (&pid, scriptname, NULL, NULL, (char *[]) { 0 }, ++ (char *[]) { 0 }); ++ TEST_VERIFY_EXIT (status == 0); ++ ++ TEST_VERIFY_EXIT (waitpid (pid, &status, 0) == pid); ++ TEST_VERIFY_EXIT (WIFEXITED (status) == 1 && WEXITSTATUS (status) == 65); ++ ++ status = posix_spawnp (&pid, scriptname, NULL, NULL, (char *[]) { 0 }, ++ (char *[]) { 0 }); ++ TEST_VERIFY_EXIT (status == 0); ++ ++ TEST_VERIFY_EXIT (waitpid (pid, &status, 0) == pid); ++ TEST_VERIFY_EXIT (WIFEXITED (status) == 1 && WEXITSTATUS (status) == 65); ++ ++ return 0; ++} ++#else ++static int ++do_test (void) ++{ ++ return 77; ++} ++#endif ++ ++#include +diff --git a/posix/tst-spawn4.c b/posix/tst-spawn4.c +new file mode 100644 +index 0000000000..e4a1fa3f00 +--- /dev/null ++++ b/posix/tst-spawn4.c +@@ -0,0 +1,56 @@ ++/* Check if posix_spawn does handle correctly ENOEXEC files. ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ char *scriptname; ++ int fd = create_temp_file ("tst-spawn4.", &scriptname); ++ TEST_VERIFY_EXIT (fd >= 0); ++ ++ const char script[] = "echo it should not happen"; ++ xwrite (fd, script, sizeof (script) - 1); ++ xclose (fd); ++ ++ TEST_VERIFY_EXIT (chmod (scriptname, 0x775) == 0); ++ ++ pid_t pid; ++ int status; ++ ++ /* Check if scripts without shebang are correctly not executed. */ ++ status = posix_spawn (&pid, scriptname, NULL, NULL, (char *[]) { 0 }, ++ (char *[]) { 0 }); ++ TEST_VERIFY_EXIT (status == ENOEXEC); ++ ++ status = posix_spawnp (&pid, scriptname, NULL, NULL, (char *[]) { 0 }, ++ (char *[]) { 0 }); ++ TEST_VERIFY_EXIT (status == ENOEXEC); ++ ++ return 0; ++} ++ ++#include +diff --git a/resolv/gai_misc.c b/resolv/gai_misc.c +index e7c3b63cc5..80a2cff835 100644 +--- a/resolv/gai_misc.c ++++ b/resolv/gai_misc.c +@@ -261,8 +261,11 @@ __gai_enqueue_request (struct gaicb *gaicbp) + /* We cannot create a thread in the moment and there is + also no thread running. This is a problem. `errno' is + set to EAGAIN if this is only a temporary problem. */ +- assert (lastp->next == newp); +- lastp->next = NULL; ++ assert (requests == newp || lastp->next == newp); ++ if (lastp != NULL) ++ lastp->next = NULL; ++ else ++ requests = NULL; + requests_tail = lastp; + + newp->next = freelist; +diff --git a/resolv/res_send.c b/resolv/res_send.c +index dde0425a33..9e9541789b 100644 +--- a/resolv/res_send.c ++++ b/resolv/res_send.c +@@ -471,6 +471,11 @@ __res_context_send (struct resolv_context *ctx, + '\0', + sizeof (struct sockaddr_in6) + - sizeof (struct sockaddr_in)); ++ else ++ { ++ __set_errno (ENOMEM); ++ return -1; ++ } + } + EXT(statp).nscount = statp->nscount; + } +@@ -1152,25 +1157,27 @@ send_dg(res_state statp, + if (have_sendmmsg >= 0 && nwritten == 0 && buf2 != NULL + && !single_request) + { +- struct iovec iov[2]; +- struct mmsghdr reqs[2]; +- reqs[0].msg_hdr.msg_name = NULL; +- reqs[0].msg_hdr.msg_namelen = 0; +- reqs[0].msg_hdr.msg_iov = &iov[0]; +- reqs[0].msg_hdr.msg_iovlen = 1; +- iov[0].iov_base = (void *) buf; +- iov[0].iov_len = buflen; +- reqs[0].msg_hdr.msg_control = NULL; +- reqs[0].msg_hdr.msg_controllen = 0; +- +- reqs[1].msg_hdr.msg_name = NULL; +- reqs[1].msg_hdr.msg_namelen = 0; +- reqs[1].msg_hdr.msg_iov = &iov[1]; +- reqs[1].msg_hdr.msg_iovlen = 1; +- iov[1].iov_base = (void *) buf2; +- iov[1].iov_len = buflen2; +- reqs[1].msg_hdr.msg_control = NULL; +- reqs[1].msg_hdr.msg_controllen = 0; ++ struct iovec iov = ++ { .iov_base = (void *) buf, .iov_len = buflen }; ++ struct iovec iov2 = ++ { .iov_base = (void *) buf2, .iov_len = buflen2 }; ++ struct mmsghdr reqs[2] = ++ { ++ { ++ .msg_hdr = ++ { ++ .msg_iov = &iov, ++ .msg_iovlen = 1, ++ }, ++ }, ++ { ++ .msg_hdr = ++ { ++ .msg_iov = &iov2, ++ .msg_iovlen = 1, ++ } ++ }, ++ }; + + int ndg = __sendmmsg (pfd[0].fd, reqs, 2, MSG_NOSIGNAL); + if (__glibc_likely (ndg == 2)) +diff --git a/resolv/tst-resolv-network.c b/resolv/tst-resolv-network.c +index 4b862d57e6..735e38d0f8 100644 +--- a/resolv/tst-resolv-network.c ++++ b/resolv/tst-resolv-network.c +@@ -149,6 +149,9 @@ handle_code (const struct resolv_response_context *ctx, + resolv_response_add_data (b, &rrtype, sizeof (rrtype)); + } + break; ++ case 104: ++ send_ptr (b, qname, qclass, qtype, "host.example"); ++ break; + default: + FAIL_EXIT1 ("invalid QNAME: %s (code %d)", qname, code); + } +@@ -257,6 +260,9 @@ do_test (void) + "error: TRY_AGAIN\n"); + check_netent ("code103.example", getnetbyname ("code103.example"), + "error: NO_RECOVERY\n"); ++ /* Test bug #17630. */ ++ check_netent ("code104.example", getnetbyname ("code104.example"), ++ "error: TRY_AGAIN\n"); + + /* Lookup by address, success cases. */ + check_reverse (1, +diff --git a/signal/Makefile b/signal/Makefile +index a9b99a20be..aa63434f47 100644 +--- a/signal/Makefile ++++ b/signal/Makefile +@@ -46,7 +46,7 @@ routines := signal raise killpg \ + sighold sigrelse sigignore sigset + + tests := tst-signal tst-sigset tst-sigsimple tst-raise tst-sigset2 \ +- tst-sigwait-eintr \ ++ tst-sigwait-eintr tst-sigaction \ + + include ../Rules + +diff --git a/signal/tst-sigaction.c b/signal/tst-sigaction.c +new file mode 100644 +index 0000000000..c908e8f6f6 +--- /dev/null ++++ b/signal/tst-sigaction.c +@@ -0,0 +1,56 @@ ++/* Test sigaction regression for BZ #23069. ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++#include ++ ++static void ++my_sig_handler (int signum) ++{ ++} ++ ++static int ++do_test (void) ++{ ++ /* Define a simple signal handler */ ++ struct sigaction act; ++ act.sa_handler = my_sig_handler; ++ act.sa_flags = 0; ++ sigemptyset (&act.sa_mask); ++ ++ /* Set it as SIGUSR1 signal handler */ ++ TEST_VERIFY_EXIT (sigaction (SIGUSR1, &act, NULL) == 0); ++ ++ /* Get SIGUSR1 signal handler */ ++ TEST_VERIFY_EXIT (sigaction (SIGUSR1, NULL, &act) == 0); ++ ++ /* Check it is consistent with the defined one */ ++ TEST_VERIFY (act.sa_handler == my_sig_handler); ++ TEST_VERIFY (!(act.sa_flags & SA_RESETHAND)); ++ ++ for (int i = 1; i < _NSIG; i++) ++ { ++ TEST_VERIFY (!sigismember (&act.sa_mask, i)); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/stdio-common/tst-printf.c b/stdio-common/tst-printf.c +index d73f0cc34e..70d9e584b3 100644 +--- a/stdio-common/tst-printf.c ++++ b/stdio-common/tst-printf.c +@@ -69,77 +69,7 @@ fmtst2chk (const char *fmt) + (void) printf(fmt, 4, 4, 0x12); + (void) printf("'\n"); + } +- +-/* This page is covered by the following copyright: */ +- +-/* (C) Copyright C E Chew +- * +- * Feel free to copy, use and distribute this software provided: +- * +- * 1. you do not pretend that you wrote it +- * 2. you leave this copyright notice intact. +- */ +- +-/* +- * Extracted from exercise.c for glibc-1.05 bug report by Bruce Evans. +- */ +- +-#define DEC -123 +-#define INT 255 +-#define UNS (~0) + +-/* Formatted Output Test +- * +- * This exercises the output formatting code. +- */ +- +-static void +-fp_test (void) +-{ +- int i, j, k, l; +- char buf[7]; +- char *prefix = buf; +- char tp[20]; +- +- puts("\nFormatted output test"); +- printf("prefix 6d 6o 6x 6X 6u\n"); +- strcpy(prefix, "%"); +- for (i = 0; i < 2; i++) { +- for (j = 0; j < 2; j++) { +- for (k = 0; k < 2; k++) { +- for (l = 0; l < 2; l++) { +- strcpy(prefix, "%"); +- if (i == 0) strcat(prefix, "-"); +- if (j == 0) strcat(prefix, "+"); +- if (k == 0) strcat(prefix, "#"); +- if (l == 0) strcat(prefix, "0"); +- printf("%5s |", prefix); +- strcpy(tp, prefix); +- strcat(tp, "6d |"); +- printf(tp, DEC); +- strcpy(tp, prefix); +- strcat(tp, "6o |"); +- printf(tp, INT); +- strcpy(tp, prefix); +- strcat(tp, "6x |"); +- printf(tp, INT); +- strcpy(tp, prefix); +- strcat(tp, "6X |"); +- printf(tp, INT); +- strcpy(tp, prefix); +- strcat(tp, "6u |"); +- printf(tp, UNS); +- printf("\n"); +- } +- } +- } +- } +- printf("%10s\n", (char *) NULL); +- printf("%-10s\n", (char *) NULL); +- printf("%.8f\n", DBL_MAX); +- printf("%.8f\n", -DBL_MAX); +-} +- + static int + do_test (void) + { +@@ -239,8 +169,8 @@ I am ready for my first lesson today."; + snprintf(buf2, sizeof(buf2), "%.999999u", 10)); + } + +- fp_test (); +- ++ printf("%.8f\n", DBL_MAX); ++ printf("%.8f\n", -DBL_MAX); + printf ("%e should be 1.234568e+06\n", 1234567.8); + printf ("%f should be 1234567.800000\n", 1234567.8); + printf ("%g should be 1.23457e+06\n", 1234567.8); +diff --git a/stdio-common/tst-printf.sh b/stdio-common/tst-printf.sh +index 93bfe03c6f..b543cc646c 100644 +--- a/stdio-common/tst-printf.sh ++++ b/stdio-common/tst-printf.sh +@@ -105,27 +105,6 @@ something really insane: 1.00000000000000000000000000000000000000000000000000000 + | 123456.0000| 1.2346e+05| 1.235e+05| + snprintf ("%30s", "foo") == 30, " " + snprintf ("%.999999u", 10) == 999999 +- +-Formatted output test +-prefix 6d 6o 6x 6X 6u +-%-+#0 |-123 |0377 |0xff |0XFF |4294967295 | +- %-+# |-123 |0377 |0xff |0XFF |4294967295 | +- %-+0 |-123 |377 |ff |FF |4294967295 | +- %-+ |-123 |377 |ff |FF |4294967295 | +- %-#0 |-123 |0377 |0xff |0XFF |4294967295 | +- %-# |-123 |0377 |0xff |0XFF |4294967295 | +- %-0 |-123 |377 |ff |FF |4294967295 | +- %- |-123 |377 |ff |FF |4294967295 | +- %+#0 |-00123 |000377 |0x00ff |0X00FF |4294967295 | +- %+# | -123 | 0377 | 0xff | 0XFF |4294967295 | +- %+0 |-00123 |000377 |0000ff |0000FF |4294967295 | +- %+ | -123 | 377 | ff | FF |4294967295 | +- %#0 |-00123 |000377 |0x00ff |0X00FF |4294967295 | +- %# | -123 | 0377 | 0xff | 0XFF |4294967295 | +- %0 |-00123 |000377 |0000ff |0000FF |4294967295 | +- % | -123 | 377 | ff | FF |4294967295 | +- (null) +-(null) + 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.00000000 + -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.00000000 + 1.234568e+06 should be 1.234568e+06 +@@ -225,27 +204,6 @@ something really insane: 1.00000000000000000000000000000000000000000000000000000 + | 123456.0000| 1.2346e+05| 1.235e+05| + snprintf ("%30s", "foo") == 30, " " + snprintf ("%.999999u", 10) == 999999 +- +-Formatted output test +-prefix 6d 6o 6x 6X 6u +-%-+#0 |-123 |0377 |0xff |0XFF |4294967295 | +- %-+# |-123 |0377 |0xff |0XFF |4294967295 | +- %-+0 |-123 |377 |ff |FF |4294967295 | +- %-+ |-123 |377 |ff |FF |4294967295 | +- %-#0 |-123 |0377 |0xff |0XFF |4294967295 | +- %-# |-123 |0377 |0xff |0XFF |4294967295 | +- %-0 |-123 |377 |ff |FF |4294967295 | +- %- |-123 |377 |ff |FF |4294967295 | +- %+#0 |-00123 |000377 |0x00ff |0X00FF |4294967295 | +- %+# | -123 | 0377 | 0xff | 0XFF |4294967295 | +- %+0 |-00123 |000377 |0000ff |0000FF |4294967295 | +- %+ | -123 | 377 | ff | FF |4294967295 | +- %#0 |-00123 |000377 |0x00ff |0X00FF |4294967295 | +- %# | -123 | 0377 | 0xff | 0XFF |4294967295 | +- %0 |-00123 |000377 |0000ff |0000FF |4294967295 | +- % | -123 | 377 | ff | FF |4294967295 | +- (null) +-(null) + 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.00000000 + -179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.00000000 + 1.234568e+06 should be 1.234568e+06 +diff --git a/stdlib/Makefile b/stdlib/Makefile +index 7c363a6e4d..a9ad849531 100644 +--- a/stdlib/Makefile ++++ b/stdlib/Makefile +@@ -84,7 +84,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ + tst-cxa_atexit tst-on_exit test-atexit-race \ + test-at_quick_exit-race test-cxa_atexit-race \ + test-on_exit-race test-dlclose-exit-race \ +- tst-makecontext-align ++ tst-makecontext-align test-bz22786 + + tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \ + tst-tls-atexit tst-tls-atexit-nodelete +diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c +index 30825a91b8..432fc82b4a 100644 +--- a/stdlib/canonicalize.c ++++ b/stdlib/canonicalize.c +@@ -181,7 +181,7 @@ __realpath (const char *name, char *resolved) + extra_buf = __alloca (path_max); + + len = strlen (end); +- if ((long int) (n + len) >= path_max) ++ if (path_max - n <= len) + { + __set_errno (ENAMETOOLONG); + goto error; +diff --git a/stdlib/random_r.c b/stdlib/random_r.c +index 4d2f0d472f..b47c65c6d7 100644 +--- a/stdlib/random_r.c ++++ b/stdlib/random_r.c +@@ -361,8 +361,7 @@ __random_r (struct random_data *buf, int32_t *result) + + if (buf->rand_type == TYPE_0) + { +- int32_t val = state[0]; +- val = ((state[0] * 1103515245) + 12345) & 0x7fffffff; ++ int32_t val = ((state[0] * 1103515245U) + 12345U) & 0x7fffffff; + state[0] = val; + *result = val; + } +@@ -371,11 +370,11 @@ __random_r (struct random_data *buf, int32_t *result) + int32_t *fptr = buf->fptr; + int32_t *rptr = buf->rptr; + int32_t *end_ptr = buf->end_ptr; +- int32_t val; ++ uint32_t val; + +- val = *fptr += *rptr; ++ val = *fptr += (uint32_t) *rptr; + /* Chucking least random bit. */ +- *result = (val >> 1) & 0x7fffffff; ++ *result = val >> 1; + ++fptr; + if (fptr >= end_ptr) + { +diff --git a/stdlib/test-bz22786.c b/stdlib/test-bz22786.c +new file mode 100644 +index 0000000000..e7837f98c1 +--- /dev/null ++++ b/stdlib/test-bz22786.c +@@ -0,0 +1,90 @@ ++/* Bug 22786: test for buffer overflow in realpath. ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++/* This file must be run from within a directory called "stdlib". */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ const char dir[] = "bz22786"; ++ const char lnk[] = "bz22786/symlink"; ++ ++ rmdir (dir); ++ if (mkdir (dir, 0755) != 0 && errno != EEXIST) ++ { ++ printf ("mkdir %s: %m\n", dir); ++ return EXIT_FAILURE; ++ } ++ if (symlink (".", lnk) != 0 && errno != EEXIST) ++ { ++ printf ("symlink (%s, %s): %m\n", dir, lnk); ++ return EXIT_FAILURE; ++ } ++ ++ const size_t path_len = (size_t) INT_MAX + 1; ++ ++ DIAG_PUSH_NEEDS_COMMENT; ++#if __GNUC_PREREQ (7, 0) ++ /* GCC 7 warns about too-large allocations; here we need such ++ allocation to succeed for the test to work. */ ++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than="); ++#endif ++ char *path = malloc (path_len); ++ DIAG_POP_NEEDS_COMMENT; ++ ++ if (path == NULL) ++ { ++ printf ("malloc (%zu): %m\n", path_len); ++ return EXIT_UNSUPPORTED; ++ } ++ ++ /* Construct very long path = "bz22786/symlink/aaaa....." */ ++ char *p = mempcpy (path, lnk, sizeof (lnk) - 1); ++ *(p++) = '/'; ++ memset (p, 'a', path_len - (path - p) - 2); ++ p[path_len - (path - p) - 1] = '\0'; ++ ++ /* This call crashes before the fix for bz22786 on 32-bit platforms. */ ++ p = realpath (path, NULL); ++ ++ if (p != NULL || errno != ENAMETOOLONG) ++ { ++ printf ("realpath: %s (%m)", p); ++ return EXIT_FAILURE; ++ } ++ ++ /* Cleanup. */ ++ unlink (lnk); ++ rmdir (dir); ++ ++ return 0; ++} ++ ++#define TEST_FUNCTION do_test ++#include +diff --git a/string/memmem.c b/string/memmem.c +index c17e1cf6a6..7fbe1cb5d6 100644 +--- a/string/memmem.c ++++ b/string/memmem.c +@@ -15,67 +15,115 @@ + License along with the GNU C Library; if not, see + . */ + +-/* This particular implementation was written by Eric Blake, 2008. */ +- + #ifndef _LIBC + # include + #endif + +-/* Specification of memmem. */ + #include + + #ifndef _LIBC +-# define __builtin_expect(expr, val) (expr) + # define __memmem memmem + #endif + + #define RETURN_TYPE void * + #define AVAILABLE(h, h_l, j, n_l) ((j) <= (h_l) - (n_l)) ++#define FASTSEARCH(S,C,N) (void*) memchr ((void *)(S), (C), (N)) + #include "str-two-way.h" + + #undef memmem + +-/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK +- if NEEDLE_LEN is 0, otherwise NULL if NEEDLE is not found in +- HAYSTACK. */ ++/* Hash character pairs so a small shift table can be used. All bits of ++ p[0] are included, but not all bits from p[-1]. So if two equal hashes ++ match on p[-1], p[0] matches too. Hash collisions are harmless and result ++ in smaller shifts. */ ++#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift)) ++ ++/* Fast memmem algorithm with guaranteed linear-time performance. ++ Small needles up to size 2 use a dedicated linear search. Longer needles ++ up to size 256 use a novel modified Horspool algorithm. It hashes pairs ++ of characters to quickly skip past mismatches. The main search loop only ++ exits if the last 2 characters match, avoiding unnecessary calls to memcmp ++ and allowing for a larger skip if there is no match. A self-adapting ++ filtering check is used to quickly detect mismatches in long needles. ++ By limiting the needle length to 256, the shift table can be reduced to 8 ++ bits per entry, lowering preprocessing overhead and minimizing cache effects. ++ The limit also implies worst-case performance is linear. ++ Needles larger than 256 characters use the linear-time Two-Way algorithm. */ + void * +-__memmem (const void *haystack_start, size_t haystack_len, +- const void *needle_start, size_t needle_len) ++__memmem (const void *haystack, size_t hs_len, ++ const void *needle, size_t ne_len) + { +- /* Abstract memory is considered to be an array of 'unsigned char' values, +- not an array of 'char' values. See ISO C 99 section 6.2.6.1. */ +- const unsigned char *haystack = (const unsigned char *) haystack_start; +- const unsigned char *needle = (const unsigned char *) needle_start; +- +- if (needle_len == 0) +- /* The first occurrence of the empty string is deemed to occur at +- the beginning of the string. */ +- return (void *) haystack; +- +- /* Sanity check, otherwise the loop might search through the whole +- memory. */ +- if (__glibc_unlikely (haystack_len < needle_len)) ++ const unsigned char *hs = (const unsigned char *) haystack; ++ const unsigned char *ne = (const unsigned char *) needle; ++ ++ if (ne_len == 0) ++ return (void *) hs; ++ if (ne_len == 1) ++ return (void *) memchr (hs, ne[0], hs_len); ++ ++ /* Ensure haystack length is >= needle length. */ ++ if (hs_len < ne_len) + return NULL; + +- /* Use optimizations in memchr when possible, to reduce the search +- size of haystack using a linear algorithm with a smaller +- coefficient. However, avoid memchr for long needles, since we +- can often achieve sublinear performance. */ +- if (needle_len < LONG_NEEDLE_THRESHOLD) ++ const unsigned char *end = hs + hs_len - ne_len; ++ ++ if (ne_len == 2) ++ { ++ uint32_t nw = ne[0] << 16 | ne[1], hw = hs[0] << 16 | hs[1]; ++ for (hs++; hs <= end && hw != nw; ) ++ hw = hw << 16 | *++hs; ++ return hw == nw ? (void *)hs - 1 : NULL; ++ } ++ ++ /* Use Two-Way algorithm for very long needles. */ ++ if (__builtin_expect (ne_len > 256, 0)) ++ return two_way_long_needle (hs, hs_len, ne, ne_len); ++ ++ uint8_t shift[256]; ++ size_t tmp, shift1; ++ size_t m1 = ne_len - 1; ++ size_t offset = 0; ++ ++ memset (shift, 0, sizeof (shift)); ++ for (int i = 1; i < m1; i++) ++ shift[hash2 (ne + i)] = i; ++ /* Shift1 is the amount we can skip after matching the hash of the ++ needle end but not the full needle. */ ++ shift1 = m1 - shift[hash2 (ne + m1)]; ++ shift[hash2 (ne + m1)] = m1; ++ ++ for ( ; hs <= end; ) + { +- haystack = memchr (haystack, *needle, haystack_len); +- if (!haystack || __builtin_expect (needle_len == 1, 0)) +- return (void *) haystack; +- haystack_len -= haystack - (const unsigned char *) haystack_start; +- if (haystack_len < needle_len) +- return NULL; +- return two_way_short_needle (haystack, haystack_len, needle, needle_len); ++ /* Skip past character pairs not in the needle. */ ++ do ++ { ++ hs += m1; ++ tmp = shift[hash2 (hs)]; ++ } ++ while (tmp == 0 && hs <= end); ++ ++ /* If the match is not at the end of the needle, shift to the end ++ and continue until we match the hash of the needle end. */ ++ hs -= tmp; ++ if (tmp < m1) ++ continue; ++ ++ /* Hash of the last 2 characters matches. If the needle is long, ++ try to quickly filter out mismatches. */ ++ if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0) ++ { ++ if (memcmp (hs, ne, m1) == 0) ++ return (void *) hs; ++ ++ /* Adjust filter offset when it doesn't find the mismatch. */ ++ offset = (offset >= 8 ? offset : m1) - 8; ++ } ++ ++ /* Skip based on matching the hash of the needle end. */ ++ hs += shift1; + } +- else +- return two_way_long_needle (haystack, haystack_len, needle, needle_len); ++ return NULL; + } + libc_hidden_def (__memmem) + weak_alias (__memmem, memmem) + libc_hidden_weak (memmem) +- +-#undef LONG_NEEDLE_THRESHOLD +diff --git a/string/str-two-way.h b/string/str-two-way.h +index cd2605857d..358959bef0 100644 +--- a/string/str-two-way.h ++++ b/string/str-two-way.h +@@ -221,7 +221,7 @@ critical_factorization (const unsigned char *needle, size_t needle_len, + most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. + If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * + HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching. */ +-static RETURN_TYPE ++static inline RETURN_TYPE + two_way_short_needle (const unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) + { +@@ -281,50 +281,50 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len, + } + else + { +- const unsigned char *phaystack = &haystack[suffix]; ++ const unsigned char *phaystack; + /* The comparison always starts from needle[suffix], so cache it + and use an optimized first-character loop. */ + unsigned char needle_suffix = CANON_ELEMENT (needle[suffix]); + +-#if CHECK_EOL +- /* We start matching from the SUFFIX'th element, so make sure we +- don't hit '\0' before that. */ +- if (haystack_len < suffix + 1 +- && !AVAILABLE (haystack, haystack_len, 0, suffix + 1)) +- return NULL; +-#endif +- + /* The two halves of needle are distinct; no extra memory is + required, and any mismatch results in a maximal shift. */ + period = MAX (suffix, needle_len - suffix) + 1; + j = 0; +- while (1 +-#if !CHECK_EOL +- && AVAILABLE (haystack, haystack_len, j, needle_len) +-#endif +- ) ++ while (AVAILABLE (haystack, haystack_len, j, needle_len)) + { + unsigned char haystack_char; + const unsigned char *pneedle; + +- /* TODO: The first-character loop can be sped up by adapting +- longword-at-a-time implementation of memchr/strchr. */ +- if (needle_suffix ++ phaystack = &haystack[suffix + j]; ++ ++#ifdef FASTSEARCH ++ if (*phaystack++ != needle_suffix) ++ { ++ phaystack = FASTSEARCH (phaystack, needle_suffix, ++ haystack_len - needle_len - j); ++ if (phaystack == NULL) ++ goto ret0; ++ j = phaystack - &haystack[suffix]; ++ phaystack++; ++ } ++#else ++ while (needle_suffix + != (haystack_char = CANON_ELEMENT (*phaystack++))) + { + RET0_IF_0 (haystack_char); +-#if !CHECK_EOL ++# if !CHECK_EOL + ++j; +-#endif +- continue; ++ if (!AVAILABLE (haystack, haystack_len, j, needle_len)) ++ goto ret0; ++# endif + } + +-#if CHECK_EOL ++# if CHECK_EOL + /* Calculate J if it wasn't kept up-to-date in the first-character + loop. */ + j = phaystack - &haystack[suffix] - 1; ++# endif + #endif +- + /* Scan for matches in right half. */ + i = suffix + 1; + pneedle = &needle[i]; +@@ -338,6 +338,11 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len, + } + ++i; + } ++#if CHECK_EOL ++ /* Update minimal length of haystack. */ ++ if (phaystack > haystack + haystack_len) ++ haystack_len = phaystack - haystack; ++#endif + if (needle_len <= i) + { + /* Scan for matches in left half. */ +@@ -360,13 +365,6 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len, + } + else + j += i - suffix + 1; +- +-#if CHECK_EOL +- if (!AVAILABLE (haystack, haystack_len, j, needle_len)) +- break; +-#endif +- +- phaystack = &haystack[suffix + j]; + } + } + ret0: __attribute__ ((unused)) +@@ -384,8 +382,11 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len, + and sublinear performance O(HAYSTACK_LEN / NEEDLE_LEN) is possible. + If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 * + HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and +- sublinear performance is not possible. */ +-static RETURN_TYPE ++ sublinear performance is not possible. ++ ++ Since this function is large and complex, block inlining to avoid ++ slowing down the common case of small needles. */ ++__attribute__((noinline)) static RETURN_TYPE + two_way_long_needle (const unsigned char *haystack, size_t haystack_len, + const unsigned char *needle, size_t needle_len) + { +diff --git a/string/strcasestr.c b/string/strcasestr.c +index 90ba189790..8aa76037dc 100644 +--- a/string/strcasestr.c ++++ b/string/strcasestr.c +@@ -37,8 +37,9 @@ + /* Two-Way algorithm. */ + #define RETURN_TYPE char * + #define AVAILABLE(h, h_l, j, n_l) \ +- (!memchr ((h) + (h_l), '\0', (j) + (n_l) - (h_l)) \ +- && ((h_l) = (j) + (n_l))) ++ (((j) + (n_l) <= (h_l)) \ ++ || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ ++ (j) + (n_l) <= (h_l))) + #define CHECK_EOL (1) + #define RET0_IF_0(a) if (!a) goto ret0 + #define CANON_ELEMENT(c) TOLOWER (c) +@@ -58,31 +59,22 @@ + case-insensitive comparison. This function gives unspecified + results in multibyte locales. */ + char * +-STRCASESTR (const char *haystack_start, const char *needle_start) ++STRCASESTR (const char *haystack, const char *needle) + { +- const char *haystack = haystack_start; +- const char *needle = needle_start; + size_t needle_len; /* Length of NEEDLE. */ + size_t haystack_len; /* Known minimum length of HAYSTACK. */ +- bool ok = true; /* True if NEEDLE is prefix of HAYSTACK. */ +- +- /* Determine length of NEEDLE, and in the process, make sure +- HAYSTACK is at least as long (no point processing all of a long +- NEEDLE if HAYSTACK is too short). */ +- while (*haystack && *needle) +- { +- ok &= (TOLOWER ((unsigned char) *haystack) +- == TOLOWER ((unsigned char) *needle)); +- haystack++; +- needle++; +- } +- if (*needle) ++ ++ /* Handle empty NEEDLE special case. */ ++ if (needle[0] == '\0') ++ return (char *) haystack; ++ ++ /* Ensure HAYSTACK length is at least as long as NEEDLE length. ++ Since a match may occur early on in a huge HAYSTACK, use strnlen ++ and read ahead a few cachelines for improved performance. */ ++ needle_len = strlen (needle); ++ haystack_len = __strnlen (haystack, needle_len + 256); ++ if (haystack_len < needle_len) + return NULL; +- if (ok) +- return (char *) haystack_start; +- needle_len = needle - needle_start; +- haystack = haystack_start + 1; +- haystack_len = needle_len - 1; + + /* Perform the search. Abstract memory is considered to be an array + of 'unsigned char' values, not an array of 'char' values. See +@@ -90,10 +82,10 @@ STRCASESTR (const char *haystack_start, const char *needle_start) + if (needle_len < LONG_NEEDLE_THRESHOLD) + return two_way_short_needle ((const unsigned char *) haystack, + haystack_len, +- (const unsigned char *) needle_start, ++ (const unsigned char *) needle, + needle_len); + return two_way_long_needle ((const unsigned char *) haystack, haystack_len, +- (const unsigned char *) needle_start, ++ (const unsigned char *) needle, + needle_len); + } + +diff --git a/string/strstr.c b/string/strstr.c +index b3b5deb673..7ffb18ab42 100644 +--- a/string/strstr.c ++++ b/string/strstr.c +@@ -16,27 +16,17 @@ + License along with the GNU C Library; if not, see + . */ + +-/* This particular implementation was written by Eric Blake, 2008. */ +- + #ifndef _LIBC + # include + #endif + +-/* Specification of strstr. */ + #include + +-#include +- +-#ifndef _LIBC +-# define __builtin_expect(expr, val) (expr) +-#endif +- + #define RETURN_TYPE char * + #define AVAILABLE(h, h_l, j, n_l) \ +- (!memchr ((h) + (h_l), '\0', (j) + (n_l) - (h_l)) \ +- && ((h_l) = (j) + (n_l))) +-#define CHECK_EOL (1) +-#define RET0_IF_0(a) if (!a) goto ret0 ++ (((j) + (n_l) <= (h_l)) \ ++ || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \ ++ (j) + (n_l) <= (h_l))) + #include "str-two-way.h" + + #undef strstr +@@ -45,48 +35,128 @@ + #define STRSTR strstr + #endif + +-/* Return the first occurrence of NEEDLE in HAYSTACK. Return HAYSTACK +- if NEEDLE is empty, otherwise NULL if NEEDLE is not found in +- HAYSTACK. */ ++static inline char * ++strstr2 (const unsigned char *hs, const unsigned char *ne) ++{ ++ uint32_t h1 = (ne[0] << 16) | ne[1]; ++ uint32_t h2 = 0; ++ for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs) ++ h2 = (h2 << 16) | c; ++ return h1 == h2 ? (char *)hs - 2 : NULL; ++} ++ ++static inline char * ++strstr3 (const unsigned char *hs, const unsigned char *ne) ++{ ++ uint32_t h1 = ((uint32_t)ne[0] << 24) | (ne[1] << 16) | (ne[2] << 8); ++ uint32_t h2 = 0; ++ for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs) ++ h2 = (h2 | c) << 8; ++ return h1 == h2 ? (char *)hs - 3 : NULL; ++} ++ ++/* Hash character pairs so a small shift table can be used. All bits of ++ p[0] are included, but not all bits from p[-1]. So if two equal hashes ++ match on p[-1], p[0] matches too. Hash collisions are harmless and result ++ in smaller shifts. */ ++#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift)) ++ ++/* Fast strstr algorithm with guaranteed linear-time performance. ++ Small needles up to size 3 use a dedicated linear search. Longer needles ++ up to size 256 use a novel modified Horspool algorithm. It hashes pairs ++ of characters to quickly skip past mismatches. The main search loop only ++ exits if the last 2 characters match, avoiding unnecessary calls to memcmp ++ and allowing for a larger skip if there is no match. A self-adapting ++ filtering check is used to quickly detect mismatches in long needles. ++ By limiting the needle length to 256, the shift table can be reduced to 8 ++ bits per entry, lowering preprocessing overhead and minimizing cache effects. ++ The limit also implies worst-case performance is linear. ++ Needles larger than 256 characters use the linear-time Two-Way algorithm. */ + char * +-STRSTR (const char *haystack_start, const char *needle_start) ++STRSTR (const char *haystack, const char *needle) + { +- const char *haystack = haystack_start; +- const char *needle = needle_start; +- size_t needle_len; /* Length of NEEDLE. */ +- size_t haystack_len; /* Known minimum length of HAYSTACK. */ +- bool ok = true; /* True if NEEDLE is prefix of HAYSTACK. */ +- +- /* Determine length of NEEDLE, and in the process, make sure +- HAYSTACK is at least as long (no point processing all of a long +- NEEDLE if HAYSTACK is too short). */ +- while (*haystack && *needle) +- ok &= *haystack++ == *needle++; +- if (*needle) ++ const unsigned char *hs = (const unsigned char *) haystack; ++ const unsigned char *ne = (const unsigned char *) needle; ++ ++ /* Handle short needle special cases first. */ ++ if (ne[0] == '\0') ++ return (char *)hs; ++ hs = (const unsigned char *)strchr ((const char*)hs, ne[0]); ++ if (hs == NULL || ne[1] == '\0') ++ return (char*)hs; ++ if (ne[2] == '\0') ++ return strstr2 (hs, ne); ++ if (ne[3] == '\0') ++ return strstr3 (hs, ne); ++ ++ /* Ensure haystack length is at least as long as needle length. ++ Since a match may occur early on in a huge haystack, use strnlen ++ and read ahead a few cachelines for improved performance. */ ++ size_t ne_len = strlen ((const char*)ne); ++ size_t hs_len = __strnlen ((const char*)hs, ne_len | 512); ++ if (hs_len < ne_len) + return NULL; +- if (ok) +- return (char *) haystack_start; +- +- /* Reduce the size of haystack using strchr, since it has a smaller +- linear coefficient than the Two-Way algorithm. */ +- needle_len = needle - needle_start; +- haystack = strchr (haystack_start + 1, *needle_start); +- if (!haystack || __builtin_expect (needle_len == 1, 0)) +- return (char *) haystack; +- needle -= needle_len; +- haystack_len = (haystack > haystack_start + needle_len ? 1 +- : needle_len + haystack_start - haystack); +- +- /* Perform the search. Abstract memory is considered to be an array +- of 'unsigned char' values, not an array of 'char' values. See +- ISO C 99 section 6.2.6.1. */ +- if (needle_len < LONG_NEEDLE_THRESHOLD) +- return two_way_short_needle ((const unsigned char *) haystack, +- haystack_len, +- (const unsigned char *) needle, needle_len); +- return two_way_long_needle ((const unsigned char *) haystack, haystack_len, +- (const unsigned char *) needle, needle_len); ++ ++ /* Check whether we have a match. This improves performance since we ++ avoid initialization overheads. */ ++ if (memcmp (hs, ne, ne_len) == 0) ++ return (char *) hs; ++ ++ /* Use Two-Way algorithm for very long needles. */ ++ if (__glibc_unlikely (ne_len > 256)) ++ return two_way_long_needle (hs, hs_len, ne, ne_len); ++ ++ const unsigned char *end = hs + hs_len - ne_len; ++ uint8_t shift[256]; ++ size_t tmp, shift1; ++ size_t m1 = ne_len - 1; ++ size_t offset = 0; ++ ++ /* Initialize bad character shift hash table. */ ++ memset (shift, 0, sizeof (shift)); ++ for (int i = 1; i < m1; i++) ++ shift[hash2 (ne + i)] = i; ++ /* Shift1 is the amount we can skip after matching the hash of the ++ needle end but not the full needle. */ ++ shift1 = m1 - shift[hash2 (ne + m1)]; ++ shift[hash2 (ne + m1)] = m1; ++ ++ while (1) ++ { ++ if (__glibc_unlikely (hs > end)) ++ { ++ end += __strnlen ((const char*)end + m1 + 1, 2048); ++ if (hs > end) ++ return NULL; ++ } ++ ++ /* Skip past character pairs not in the needle. */ ++ do ++ { ++ hs += m1; ++ tmp = shift[hash2 (hs)]; ++ } ++ while (tmp == 0 && hs <= end); ++ ++ /* If the match is not at the end of the needle, shift to the end ++ and continue until we match the hash of the needle end. */ ++ hs -= tmp; ++ if (tmp < m1) ++ continue; ++ ++ /* Hash of the last 2 characters matches. If the needle is long, ++ try to quickly filter out mismatches. */ ++ if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0) ++ { ++ if (memcmp (hs, ne, m1) == 0) ++ return (void *) hs; ++ ++ /* Adjust filter offset when it doesn't find the mismatch. */ ++ offset = (offset >= 8 ? offset : m1) - 8; ++ } ++ ++ /* Skip based on matching the hash of the needle end. */ ++ hs += shift1; ++ } + } + libc_hidden_builtin_def (strstr) +- +-#undef LONG_NEEDLE_THRESHOLD +diff --git a/string/test-memcpy.c b/string/test-memcpy.c +index 45f20a6d80..3c8066da52 100644 +--- a/string/test-memcpy.c ++++ b/string/test-memcpy.c +@@ -212,6 +212,50 @@ do_random_tests (void) + } + } + ++static void ++do_test1 (void) ++{ ++ size_t size = 0x100000; ++ void *large_buf; ++ ++ large_buf = mmap (NULL, size * 2 + page_size, PROT_READ | PROT_WRITE, ++ MAP_PRIVATE | MAP_ANON, -1, 0); ++ if (large_buf == MAP_FAILED) ++ { ++ puts ("Failed to allocat large_buf, skipping do_test1"); ++ return; ++ } ++ ++ if (mprotect (large_buf + size, page_size, PROT_NONE)) ++ error (EXIT_FAILURE, errno, "mprotect failed"); ++ ++ size_t arrary_size = size / sizeof (uint32_t); ++ uint32_t *dest = large_buf; ++ uint32_t *src = large_buf + size + page_size; ++ size_t i; ++ ++ for (i = 0; i < arrary_size; i++) ++ src[i] = (uint32_t) i; ++ ++ FOR_EACH_IMPL (impl, 0) ++ { ++ memset (dest, -1, size); ++ CALL (impl, (char *) dest, (char *) src, size); ++ for (i = 0; i < arrary_size; i++) ++ if (dest[i] != src[i]) ++ { ++ error (0, 0, ++ "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"", ++ impl->name, dest, src, i); ++ ret = 1; ++ break; ++ } ++ } ++ ++ munmap ((void *) dest, size); ++ munmap ((void *) src, size); ++} ++ + int + test_main (void) + { +@@ -253,6 +297,9 @@ test_main (void) + do_test (0, 0, getpagesize ()); + + do_random_tests (); ++ ++ do_test1 (); ++ + return ret; + } + +diff --git a/string/test-mempcpy.c b/string/test-mempcpy.c +index c08fba895e..d98ecdd2d9 100644 +--- a/string/test-mempcpy.c ++++ b/string/test-mempcpy.c +@@ -18,6 +18,7 @@ + . */ + + #define MEMCPY_RESULT(dst, len) (dst) + (len) ++#define MIN_PAGE_SIZE 131072 + #define TEST_MAIN + #define TEST_NAME "mempcpy" + #include "test-string.h" +diff --git a/string/test-strcasestr.c b/string/test-strcasestr.c +index 2b0a38ea73..9b1088df54 100644 +--- a/string/test-strcasestr.c ++++ b/string/test-strcasestr.c +@@ -25,6 +25,7 @@ + #define STRCASESTR simple_strcasestr + #define NO_ALIAS + #define __strncasecmp strncasecmp ++#define __strnlen strnlen + #include "strcasestr.c" + + +diff --git a/string/test-strstr.c b/string/test-strstr.c +index acf6ff8224..5861b01b73 100644 +--- a/string/test-strstr.c ++++ b/string/test-strstr.c +@@ -24,6 +24,7 @@ + + #define STRSTR simple_strstr + #define libc_hidden_builtin_def(arg) /* nothing */ ++#define __strnlen strnlen + #include "strstr.c" + + +@@ -150,6 +151,32 @@ check2 (void) + } + } + ++#define N 1024 ++ ++static void ++pr23637 (void) ++{ ++ char *h = (char*) buf1; ++ char *n = (char*) buf2; ++ ++ for (int i = 0; i < N; i++) ++ { ++ n[i] = 'x'; ++ h[i] = ' '; ++ h[i + N] = 'x'; ++ } ++ ++ n[N] = '\0'; ++ h[N * 2] = '\0'; ++ ++ /* Ensure we don't match at the first 'x'. */ ++ h[0] = 'x'; ++ ++ char *exp_result = stupid_strstr (h, n); ++ FOR_EACH_IMPL (impl, 0) ++ check_result (impl, h, n, exp_result); ++} ++ + static int + test_main (void) + { +@@ -157,6 +184,7 @@ test_main (void) + + check1 (); + check2 (); ++ pr23637 (); + + printf ("%23s", ""); + FOR_EACH_IMPL (impl, 0) +@@ -201,6 +229,9 @@ test_main (void) + do_test (15, 9, hlen, klen, 1); + do_test (15, 15, hlen, klen, 0); + do_test (15, 15, hlen, klen, 1); ++ ++ do_test (15, 15, hlen + klen * 4, klen * 4, 0); ++ do_test (15, 15, hlen + klen * 4, klen * 4, 1); + } + + do_test (0, 0, page_size - 1, 16, 0); +diff --git a/sunrpc/rpc_common.c b/sunrpc/rpc_common.c +index 710191163c..2d42827a87 100644 +--- a/sunrpc/rpc_common.c ++++ b/sunrpc/rpc_common.c +@@ -46,7 +46,14 @@ + the variable is declared. So we use the section attribute. */ + struct opaque_auth _null_auth __attribute__ ((nocommon)); + libc_hidden_nolink_sunrpc (_null_auth, GLIBC_2_0) +-fd_set svc_fdset; +-struct rpc_createerr rpc_createerr; +-struct pollfd *svc_pollfd; +-int svc_max_pollfd; ++ ++/* The variables need the nocommon attribute, so that it is possible ++ to create aliases and specify symbol versions. */ ++fd_set svc_fdset __attribute__ ((nocommon)); ++libc_hidden_nolink_sunrpc (svc_fdset, GLIBC_2_0) ++struct rpc_createerr rpc_createerr __attribute__ ((nocommon)); ++libc_hidden_nolink_sunrpc (rpc_createerr, GLIBC_2_0) ++struct pollfd *svc_pollfd __attribute__ ((nocommon)); ++libc_hidden_nolink_sunrpc (svc_pollfd, GLIBC_2_2) ++int svc_max_pollfd __attribute__ ((nocommon)); ++libc_hidden_nolink_sunrpc (svc_max_pollfd, GLIBC_2_2) +diff --git a/sunrpc/svcauth_des.c b/sunrpc/svcauth_des.c +index f99a5a324f..9ce4804239 100644 +--- a/sunrpc/svcauth_des.c ++++ b/sunrpc/svcauth_des.c +@@ -87,16 +87,21 @@ static void cache_ref (uint32_t sid); /* note that sid was ref'd */ + + static void invalidate (char *cred); /* invalidate entry in cache */ + +-/* +- * cache statistics +- */ ++/* Cache statistics. Accidental historic export without a matching ++ declaration in any header file. */ ++#ifndef SHARED ++static ++#endif + struct + { + u_long ncachehits; /* times cache hit, and is not replay */ + u_long ncachereplays; /* times cache hit, and is replay */ + u_long ncachemisses; /* times cache missed */ + } +-svcauthdes_stats; ++svcauthdes_stats __attribute__ ((nocommon)); ++#ifdef SHARED ++compat_symbol (libc, svcauthdes_stats, svcauthdes_stats, GLIBC_2_0); ++#endif + + /* + * Service side authenticator for AUTH_DES +diff --git a/support/Makefile b/support/Makefile +index 1bda81e55e..7ebc1a32f5 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -43,6 +43,7 @@ libsupport-routines = \ + support_capture_subprocess \ + support_capture_subprocess_check \ + support_chroot \ ++ support_descriptors \ + support_enter_mount_namespace \ + support_enter_network_namespace \ + support_format_address_family \ +@@ -52,9 +53,13 @@ libsupport-routines = \ + support_format_hostent \ + support_format_netent \ + support_isolate_in_subprocess \ ++ support_openpty \ ++ support_quote_blob \ ++ support_quote_string \ + support_record_failure \ + support_run_diff \ + support_shared_allocate \ ++ support_test_compare_blob \ + support_test_compare_failure \ + support_write_file_string \ + support_test_main \ +@@ -95,6 +100,9 @@ libsupport-routines = \ + xpthread_barrier_destroy \ + xpthread_barrier_init \ + xpthread_barrier_wait \ ++ xpthread_barrierattr_destroy \ ++ xpthread_barrierattr_init \ ++ xpthread_barrierattr_setpshared \ + xpthread_cancel \ + xpthread_check_return \ + xpthread_cond_wait \ +@@ -149,9 +157,13 @@ tests = \ + README-testing \ + tst-support-namespace \ + tst-support_capture_subprocess \ ++ tst-support_descriptors \ + tst-support_format_dns_packet \ ++ tst-support_quote_blob \ ++ tst-support_quote_string \ + tst-support_record_failure \ + tst-test_compare \ ++ tst-test_compare_blob \ + tst-xreadlink \ + + ifeq ($(run-built-tests),yes) +diff --git a/support/check.h b/support/check.h +index 2192f38941..10468b74d8 100644 +--- a/support/check.h ++++ b/support/check.h +@@ -64,6 +64,8 @@ __BEGIN_DECLS + (1, __FILE__, __LINE__, #expr); \ + }) + ++ ++ + int support_print_failure_impl (const char *file, int line, + const char *format, ...) + __attribute__ ((nonnull (1), format (printf, 3, 4))); +@@ -141,6 +143,26 @@ void support_test_compare_failure (const char *file, int line, + int right_size); + + ++/* Compare [LEFT, LEFT + LEFT_LENGTH) with [RIGHT, RIGHT + ++ RIGHT_LENGTH) and report a test failure if the arrays are ++ different. LEFT_LENGTH and RIGHT_LENGTH are measured in bytes. If ++ the length is null, the corresponding pointer is ignored (i.e., it ++ can be NULL). The blobs should be reasonably short because on ++ mismatch, both are printed. */ ++#define TEST_COMPARE_BLOB(left, left_length, right, right_length) \ ++ (support_test_compare_blob (left, left_length, right, right_length, \ ++ __FILE__, __LINE__, \ ++ #left, #left_length, #right, #right_length)) ++ ++void support_test_compare_blob (const void *left, ++ unsigned long int left_length, ++ const void *right, ++ unsigned long int right_length, ++ const char *file, int line, ++ const char *left_exp, const char *left_len_exp, ++ const char *right_exp, ++ const char *right_len_exp); ++ + /* Internal function called by the test driver. */ + int support_report_failure (int status) + __attribute__ ((weak, warn_unused_result)); +@@ -148,6 +170,10 @@ int support_report_failure (int status) + /* Internal function used to test the failure recording framework. */ + void support_record_failure_reset (void); + ++/* Returns true or false depending on whether there have been test ++ failures or not. */ ++int support_record_failure_is_failed (void); ++ + __END_DECLS + + #endif /* SUPPORT_CHECK_H */ +diff --git a/support/descriptors.h b/support/descriptors.h +new file mode 100644 +index 0000000000..8ec4cbbdfb +--- /dev/null ++++ b/support/descriptors.h +@@ -0,0 +1,47 @@ ++/* Monitoring file descriptor usage. ++ Copyright (C) 2018 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 SUPPORT_DESCRIPTORS_H ++#define SUPPORT_DESCRIPTORS_H ++ ++#include ++ ++/* Opaque pointer, for capturing file descriptor lists. */ ++struct support_descriptors; ++ ++/* Record the currently open file descriptors and store them in the ++ returned list. Terminate the process if the listing operation ++ fails. */ ++struct support_descriptors *support_descriptors_list (void); ++ ++/* Deallocate the list of descriptors. */ ++void support_descriptors_free (struct support_descriptors *); ++ ++/* Write the list of descriptors to STREAM, adding PREFIX to each ++ line. */ ++void support_descriptors_dump (struct support_descriptors *, ++ const char *prefix, FILE *stream); ++ ++/* Check for file descriptor leaks and other file descriptor changes: ++ Compare the current list of descriptors with the passed list. ++ Record a test failure if there are additional open descriptors, ++ descriptors have been closed, or if a change in file descriptor can ++ be detected. */ ++void support_descriptors_check (struct support_descriptors *); ++ ++#endif /* SUPPORT_DESCRIPTORS_H */ +diff --git a/support/support.h b/support/support.h +index bc5827ed87..4ea92e1c21 100644 +--- a/support/support.h ++++ b/support/support.h +@@ -59,6 +59,17 @@ void support_shared_free (void *); + process on error. */ + void support_write_file_string (const char *path, const char *contents); + ++/* Quote the contents of the byte array starting at BLOB, of LENGTH ++ bytes, in such a way that the result string can be included in a C ++ literal (in single/double quotes, without putting the quotes into ++ the result). */ ++char *support_quote_blob (const void *blob, size_t length); ++ ++/* Quote the contents of the string, in such a way that the result ++ string can be included in a C literal (in single/double quotes, ++ without putting the quotes into the result). */ ++char *support_quote_string (const char *); ++ + /* Error-checking wrapper functions which terminate the process on + error. */ + +diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c +index 6d2029e13b..93f6ea3102 100644 +--- a/support/support_capture_subprocess.c ++++ b/support/support_capture_subprocess.c +@@ -59,8 +59,12 @@ support_capture_subprocess (void (*callback) (void *), void *closure) + + int stdout_pipe[2]; + xpipe (stdout_pipe); ++ TEST_VERIFY (stdout_pipe[0] > STDERR_FILENO); ++ TEST_VERIFY (stdout_pipe[1] > STDERR_FILENO); + int stderr_pipe[2]; + xpipe (stderr_pipe); ++ TEST_VERIFY (stderr_pipe[0] > STDERR_FILENO); ++ TEST_VERIFY (stderr_pipe[1] > STDERR_FILENO); + + TEST_VERIFY (fflush (stdout) == 0); + TEST_VERIFY (fflush (stderr) == 0); +@@ -72,6 +76,8 @@ support_capture_subprocess (void (*callback) (void *), void *closure) + xclose (stderr_pipe[0]); + xdup2 (stdout_pipe[1], STDOUT_FILENO); + xdup2 (stderr_pipe[1], STDERR_FILENO); ++ xclose (stdout_pipe[1]); ++ xclose (stderr_pipe[1]); + callback (closure); + _exit (0); + } +diff --git a/support/support_descriptors.c b/support/support_descriptors.c +new file mode 100644 +index 0000000000..d66cf55080 +--- /dev/null ++++ b/support/support_descriptors.c +@@ -0,0 +1,274 @@ ++/* Monitoring file descriptor usage. ++ Copyright (C) 2018 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 ++ ++struct procfs_descriptor ++{ ++ int fd; ++ char *link_target; ++ dev_t dev; ++ ino64_t ino; ++}; ++ ++/* Used with qsort. */ ++static int ++descriptor_compare (const void *l, const void *r) ++{ ++ const struct procfs_descriptor *left = l; ++ const struct procfs_descriptor *right = r; ++ /* Cannot overflow due to limited file descriptor range. */ ++ return left->fd - right->fd; ++} ++ ++#define DYNARRAY_STRUCT descriptor_list ++#define DYNARRAY_ELEMENT struct procfs_descriptor ++#define DYNARRAY_PREFIX descriptor_list_ ++#define DYNARRAY_ELEMENT_FREE(e) free ((e)->link_target) ++#define DYNARRAY_INITIAL_SIZE 0 ++#include ++ ++struct support_descriptors ++{ ++ struct descriptor_list list; ++}; ++ ++struct support_descriptors * ++support_descriptors_list (void) ++{ ++ struct support_descriptors *result = xmalloc (sizeof (*result)); ++ descriptor_list_init (&result->list); ++ ++ DIR *fds = opendir ("/proc/self/fd"); ++ if (fds == NULL) ++ FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m"); ++ ++ while (true) ++ { ++ errno = 0; ++ struct dirent64 *e = readdir64 (fds); ++ if (e == NULL) ++ { ++ if (errno != 0) ++ FAIL_EXIT1 ("readdir: %m"); ++ break; ++ } ++ ++ if (e->d_name[0] == '.') ++ continue; ++ ++ char *endptr; ++ long int fd = strtol (e->d_name, &endptr, 10); ++ if (*endptr != '\0' || fd < 0 || fd > INT_MAX) ++ FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s", ++ e->d_name); ++ ++ /* Skip the descriptor which is used to enumerate the ++ descriptors. */ ++ if (fd == dirfd (fds)) ++ continue; ++ ++ char *target; ++ { ++ char *path = xasprintf ("/proc/self/fd/%ld", fd); ++ target = xreadlink (path); ++ free (path); ++ } ++ struct stat64 st; ++ if (fstat64 (fd, &st) != 0) ++ FAIL_EXIT1 ("readdir: fstat64 (%ld) failed: %m", fd); ++ ++ struct procfs_descriptor *item = descriptor_list_emplace (&result->list); ++ if (item == NULL) ++ FAIL_EXIT1 ("descriptor_list_emplace: %m"); ++ item->fd = fd; ++ item->link_target = target; ++ item->dev = st.st_dev; ++ item->ino = st.st_ino; ++ } ++ ++ closedir (fds); ++ ++ /* Perform a merge join between descrs and current. This assumes ++ that the arrays are sorted by file descriptor. */ ++ ++ qsort (descriptor_list_begin (&result->list), ++ descriptor_list_size (&result->list), ++ sizeof (struct procfs_descriptor), descriptor_compare); ++ ++ return result; ++} ++ ++void ++support_descriptors_free (struct support_descriptors *descrs) ++{ ++ descriptor_list_free (&descrs->list); ++ free (descrs); ++} ++ ++void ++support_descriptors_dump (struct support_descriptors *descrs, ++ const char *prefix, FILE *fp) ++{ ++ struct procfs_descriptor *end = descriptor_list_end (&descrs->list); ++ for (struct procfs_descriptor *d = descriptor_list_begin (&descrs->list); ++ d != end; ++d) ++ { ++ char *quoted = support_quote_string (d->link_target); ++ fprintf (fp, "%s%d: target=\"%s\" major=%lld minor=%lld ino=%lld\n", ++ prefix, d->fd, quoted, ++ (long long int) major (d->dev), ++ (long long int) minor (d->dev), ++ (long long int) d->ino); ++ free (quoted); ++ } ++} ++ ++static void ++dump_mismatch (bool *first, ++ struct support_descriptors *descrs, ++ struct support_descriptors *current) ++{ ++ if (*first) ++ *first = false; ++ else ++ return; ++ ++ puts ("error: Differences found in descriptor set"); ++ puts ("Reference descriptor set:"); ++ support_descriptors_dump (descrs, " ", stdout); ++ puts ("Current descriptor set:"); ++ support_descriptors_dump (current, " ", stdout); ++ puts ("Differences:"); ++} ++ ++static void ++report_closed_descriptor (bool *first, ++ struct support_descriptors *descrs, ++ struct support_descriptors *current, ++ struct procfs_descriptor *left) ++{ ++ support_record_failure (); ++ dump_mismatch (first, descrs, current); ++ printf ("error: descriptor %d was closed\n", left->fd); ++} ++ ++static void ++report_opened_descriptor (bool *first, ++ struct support_descriptors *descrs, ++ struct support_descriptors *current, ++ struct procfs_descriptor *right) ++{ ++ support_record_failure (); ++ dump_mismatch (first, descrs, current); ++ char *quoted = support_quote_string (right->link_target); ++ printf ("error: descriptor %d was opened (\"%s\")\n", right->fd, quoted); ++ free (quoted); ++} ++ ++void ++support_descriptors_check (struct support_descriptors *descrs) ++{ ++ struct support_descriptors *current = support_descriptors_list (); ++ ++ /* Perform a merge join between descrs and current. This assumes ++ that the arrays are sorted by file descriptor. */ ++ ++ struct procfs_descriptor *left = descriptor_list_begin (&descrs->list); ++ struct procfs_descriptor *left_end = descriptor_list_end (&descrs->list); ++ struct procfs_descriptor *right = descriptor_list_begin (¤t->list); ++ struct procfs_descriptor *right_end = descriptor_list_end (¤t->list); ++ ++ bool first = true; ++ while (left != left_end && right != right_end) ++ { ++ if (left->fd == right->fd) ++ { ++ if (strcmp (left->link_target, right->link_target) != 0) ++ { ++ support_record_failure (); ++ char *left_quoted = support_quote_string (left->link_target); ++ char *right_quoted = support_quote_string (right->link_target); ++ dump_mismatch (&first, descrs, current); ++ printf ("error: descriptor %d changed from \"%s\" to \"%s\"\n", ++ left->fd, left_quoted, right_quoted); ++ free (left_quoted); ++ free (right_quoted); ++ } ++ if (left->dev != right->dev) ++ { ++ support_record_failure (); ++ dump_mismatch (&first, descrs, current); ++ printf ("error: descriptor %d changed device" ++ " from %lld:%lld to %lld:%lld\n", ++ left->fd, ++ (long long int) major (left->dev), ++ (long long int) minor (left->dev), ++ (long long int) major (right->dev), ++ (long long int) minor (right->dev)); ++ } ++ if (left->ino != right->ino) ++ { ++ support_record_failure (); ++ dump_mismatch (&first, descrs, current); ++ printf ("error: descriptor %d changed ino from %lld to %lld\n", ++ left->fd, ++ (long long int) left->ino, (long long int) right->ino); ++ } ++ ++left; ++ ++right; ++ } ++ else if (left->fd < right->fd) ++ { ++ /* Gap on the right. */ ++ report_closed_descriptor (&first, descrs, current, left); ++ ++left; ++ } ++ else ++ { ++ /* Gap on the left. */ ++ TEST_VERIFY_EXIT (left->fd > right->fd); ++ report_opened_descriptor (&first, descrs, current, right); ++ ++right; ++ } ++ } ++ ++ while (left != left_end) ++ { ++ /* Closed descriptors (more descriptors on the left). */ ++ report_closed_descriptor (&first, descrs, current, left); ++ ++left; ++ } ++ ++ while (right != right_end) ++ { ++ /* Opened descriptors (more descriptors on the right). */ ++ report_opened_descriptor (&first, descrs, current, right); ++ ++right; ++ } ++ ++ support_descriptors_free (current); ++} +diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c +index c5e00e516a..60d2cc40f6 100644 +--- a/support/support_format_addrinfo.c ++++ b/support/support_format_addrinfo.c +@@ -67,8 +67,6 @@ format_ai_flags (FILE *out, struct addrinfo *ai) + FLAG (AI_ADDRCONFIG); + FLAG (AI_IDN); + FLAG (AI_CANONIDN); +- FLAG (AI_IDN_ALLOW_UNASSIGNED); +- FLAG (AI_IDN_USE_STD3_ASCII_RULES); + FLAG (AI_NUMERICSERV); + #undef FLAG + int remaining = ai->ai_flags & ~flags_printed; +@@ -220,7 +218,11 @@ support_format_addrinfo (struct addrinfo *ai, int ret) + xopen_memstream (&mem); + if (ret != 0) + { +- fprintf (mem.out, "error: %s\n", gai_strerror (ret)); ++ const char *errmsg = gai_strerror (ret); ++ if (strcmp (errmsg, "Unknown error") == 0) ++ fprintf (mem.out, "error: Unknown error %d\n", ret); ++ else ++ fprintf (mem.out, "error: %s\n", errmsg); + if (ret == EAI_SYSTEM) + { + errno = errno_copy; +diff --git a/support/support_openpty.c b/support/support_openpty.c +new file mode 100644 +index 0000000000..ac779ab91e +--- /dev/null ++++ b/support/support_openpty.c +@@ -0,0 +1,109 @@ ++/* Open a pseudoterminal. ++ Copyright (C) 2018 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 ++ ++/* As ptsname, but allocates space for an appropriately-sized string ++ using malloc. */ ++static char * ++xptsname (int fd) ++{ ++ int rv; ++ size_t buf_len = 128; ++ char *buf = xmalloc (buf_len); ++ for (;;) ++ { ++ rv = ptsname_r (fd, buf, buf_len); ++ if (rv) ++ FAIL_EXIT1 ("ptsname_r: %s", strerror (errno)); ++ ++ if (memchr (buf, '\0', buf_len)) ++ return buf; /* ptsname succeeded and the buffer was not truncated */ ++ ++ buf_len *= 2; ++ buf = xrealloc (buf, buf_len); ++ } ++} ++ ++void ++support_openpty (int *a_outer, int *a_inner, char **a_name, ++ const struct termios *termp, ++ const struct winsize *winp) ++{ ++ int outer = -1, inner = -1; ++ char *namebuf = 0; ++ ++ outer = posix_openpt (O_RDWR | O_NOCTTY); ++ if (outer == -1) ++ FAIL_EXIT1 ("posix_openpt: %s", strerror (errno)); ++ ++ if (grantpt (outer)) ++ FAIL_EXIT1 ("grantpt: %s", strerror (errno)); ++ ++ if (unlockpt (outer)) ++ FAIL_EXIT1 ("unlockpt: %s", strerror (errno)); ++ ++ ++#ifdef TIOCGPTPEER ++ inner = ioctl (outer, TIOCGPTPEER, O_RDWR | O_NOCTTY); ++#endif ++ if (inner == -1) ++ { ++ /* The kernel might not support TIOCGPTPEER, fall back to open ++ by name. */ ++ namebuf = xptsname (outer); ++ inner = open (namebuf, O_RDWR | O_NOCTTY); ++ if (inner == -1) ++ FAIL_EXIT1 ("%s: %s", namebuf, strerror (errno)); ++ } ++ ++ if (termp) ++ { ++ if (tcsetattr (inner, TCSAFLUSH, termp)) ++ FAIL_EXIT1 ("tcsetattr: %s", strerror (errno)); ++ } ++#ifdef TIOCSWINSZ ++ if (winp) ++ { ++ if (ioctl (inner, TIOCSWINSZ, winp)) ++ FAIL_EXIT1 ("TIOCSWINSZ: %s", strerror (errno)); ++ } ++#endif ++ ++ if (a_name) ++ { ++ if (!namebuf) ++ namebuf = xptsname (outer); ++ *a_name = namebuf; ++ } ++ else ++ free (namebuf); ++ *a_outer = outer; ++ *a_inner = inner; ++} +diff --git a/support/support_quote_blob.c b/support/support_quote_blob.c +new file mode 100644 +index 0000000000..d6a678d8d6 +--- /dev/null ++++ b/support/support_quote_blob.c +@@ -0,0 +1,83 @@ ++/* Quote a blob so that it can be used in C literals. ++ Copyright (C) 2018 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 ++ ++char * ++support_quote_blob (const void *blob, size_t length) ++{ ++ struct xmemstream out; ++ xopen_memstream (&out); ++ ++ const unsigned char *p = blob; ++ for (size_t i = 0; i < length; ++i) ++ { ++ unsigned char ch = p[i]; ++ ++ /* Use C backslash escapes for those control characters for ++ which they are defined. */ ++ switch (ch) ++ { ++ case '\a': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('a', out.out); ++ break; ++ case '\b': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('b', out.out); ++ break; ++ case '\f': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('f', out.out); ++ break; ++ case '\n': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('n', out.out); ++ break; ++ case '\r': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('r', out.out); ++ break; ++ case '\t': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('t', out.out); ++ break; ++ case '\v': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked ('v', out.out); ++ break; ++ case '\\': ++ case '\'': ++ case '\"': ++ putc_unlocked ('\\', out.out); ++ putc_unlocked (ch, out.out); ++ break; ++ default: ++ if (ch < ' ' || ch > '~') ++ /* Use octal sequences because they are fixed width, ++ unlike hexadecimal sequences. */ ++ fprintf (out.out, "\\%03o", ch); ++ else ++ putc_unlocked (ch, out.out); ++ } ++ } ++ ++ xfclose_memstream (&out); ++ return out.buffer; ++} +diff --git a/support/support_quote_string.c b/support/support_quote_string.c +new file mode 100644 +index 0000000000..d324371b13 +--- /dev/null ++++ b/support/support_quote_string.c +@@ -0,0 +1,26 @@ ++/* Quote a string so that it can be used in C literals. ++ Copyright (C) 2018 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 ++ ++char * ++support_quote_string (const char *str) ++{ ++ return support_quote_blob (str, strlen (str)); ++} +diff --git a/support/support_record_failure.c b/support/support_record_failure.c +index 356798f556..17ab1d80ef 100644 +--- a/support/support_record_failure.c ++++ b/support/support_record_failure.c +@@ -104,3 +104,11 @@ support_record_failure_reset (void) + __atomic_store_n (&state->failed, 0, __ATOMIC_RELAXED); + __atomic_add_fetch (&state->counter, 0, __ATOMIC_RELAXED); + } ++ ++int ++support_record_failure_is_failed (void) ++{ ++ /* Relaxed MO is sufficient because we need (blocking) external ++ synchronization for reliable test error reporting anyway. */ ++ return __atomic_load_n (&state->failed, __ATOMIC_RELAXED); ++} +diff --git a/support/support_test_compare_blob.c b/support/support_test_compare_blob.c +new file mode 100644 +index 0000000000..c5e63d1b93 +--- /dev/null ++++ b/support/support_test_compare_blob.c +@@ -0,0 +1,76 @@ ++/* Check two binary blobs for equality. ++ Copyright (C) 2018 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 void ++report_length (const char *what, unsigned long int length, const char *expr) ++{ ++ printf (" %s %lu bytes (from %s)\n", what, length, expr); ++} ++ ++static void ++report_blob (const char *what, const unsigned char *blob, ++ unsigned long int length, const char *expr) ++{ ++ if (length > 0) ++ { ++ printf (" %s (evaluated from %s):\n", what, expr); ++ char *quoted = support_quote_blob (blob, length); ++ printf (" \"%s\"\n", quoted); ++ free (quoted); ++ ++ fputs (" ", stdout); ++ for (unsigned long i = 0; i < length; ++i) ++ printf (" %02X", blob[i]); ++ putc ('\n', stdout); ++ } ++} ++ ++void ++support_test_compare_blob (const void *left, unsigned long int left_length, ++ const void *right, unsigned long int right_length, ++ const char *file, int line, ++ const char *left_expr, const char *left_len_expr, ++ const char *right_expr, const char *right_len_expr) ++{ ++ /* No differences are possible if both lengths are null. */ ++ if (left_length == 0 && right_length == 0) ++ return; ++ ++ if (left_length != right_length || left == NULL || right == NULL ++ || memcmp (left, right, left_length) != 0) ++ { ++ support_record_failure (); ++ printf ("%s:%d: error: blob comparison failed\n", file, line); ++ if (left_length == right_length) ++ printf (" blob length: %lu bytes\n", left_length); ++ else ++ { ++ report_length ("left length: ", left_length, left_len_expr); ++ report_length ("right length:", right_length, right_len_expr); ++ } ++ report_blob ("left", left, left_length, left_expr); ++ report_blob ("right", right, right_length, right_expr); ++ } ++} +diff --git a/support/support_test_main.c b/support/support_test_main.c +index 396385729b..23429779ac 100644 +--- a/support/support_test_main.c ++++ b/support/support_test_main.c +@@ -270,7 +270,8 @@ support_test_main (int argc, char **argv, const struct test_config *config) + timeout = DEFAULT_TIMEOUT; + + /* Make sure we see all message, even those on stdout. */ +- setvbuf (stdout, NULL, _IONBF, 0); ++ if (!config->no_setvbuf) ++ setvbuf (stdout, NULL, _IONBF, 0); + + /* Make sure temporary files are deleted. */ + if (support_delete_temp_files != NULL) +diff --git a/support/test-driver.c b/support/test-driver.c +index 09c8783e4f..9798f16227 100644 +--- a/support/test-driver.c ++++ b/support/test-driver.c +@@ -140,6 +140,10 @@ main (int argc, char **argv) + test_config.no_mallopt = 1; + #endif + ++#ifdef TEST_NO_SETVBUF ++ test_config.no_setvbuf = 1; ++#endif ++ + #ifdef TIMEOUT + test_config.timeout = TIMEOUT; + #endif +diff --git a/support/test-driver.h b/support/test-driver.h +index 1708d68d60..549179b254 100644 +--- a/support/test-driver.h ++++ b/support/test-driver.h +@@ -35,6 +35,7 @@ struct test_config + int expected_status; /* Expected exit status. */ + int expected_signal; /* If non-zero, expect termination by signal. */ + char no_mallopt; /* Boolean flag to disable mallopt. */ ++ char no_setvbuf; /* Boolean flag to disable setvbuf. */ + const char *optstring; /* Short command line options. */ + }; + +diff --git a/support/tst-support_descriptors.c b/support/tst-support_descriptors.c +new file mode 100644 +index 0000000000..5e9e824bc3 +--- /dev/null ++++ b/support/tst-support_descriptors.c +@@ -0,0 +1,198 @@ ++/* Tests for monitoring file descriptor usage. ++ Copyright (C) 2018 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 ++ ++/* This is the next free descriptor that the subprocess will pick. */ ++static int free_descriptor; ++ ++static void ++subprocess_no_change (void *closure) ++{ ++ struct support_descriptors *descrs = support_descriptors_list (); ++ int fd = xopen ("/dev/null", O_WRONLY, 0); ++ TEST_COMPARE (fd, free_descriptor); ++ xclose (fd); ++ support_descriptors_free (descrs); ++} ++ ++static void ++subprocess_closed_descriptor (void *closure) ++{ ++ int fd = xopen ("/dev/null", O_WRONLY, 0); ++ TEST_COMPARE (fd, free_descriptor); ++ struct support_descriptors *descrs = support_descriptors_list (); ++ xclose (fd); ++ support_descriptors_check (descrs); /* Will report failure. */ ++ puts ("EOT"); ++ support_descriptors_free (descrs); ++} ++ ++static void ++subprocess_opened_descriptor (void *closure) ++{ ++ struct support_descriptors *descrs = support_descriptors_list (); ++ int fd = xopen ("/dev/null", O_WRONLY, 0); ++ TEST_COMPARE (fd, free_descriptor); ++ support_descriptors_check (descrs); /* Will report failure. */ ++ puts ("EOT"); ++ support_descriptors_free (descrs); ++} ++ ++static void ++subprocess_changed_descriptor (void *closure) ++{ ++ int fd = xopen ("/dev/null", O_WRONLY, 0); ++ TEST_COMPARE (fd, free_descriptor); ++ struct support_descriptors *descrs = support_descriptors_list (); ++ xclose (fd); ++ TEST_COMPARE (xopen ("/dev", O_DIRECTORY | O_RDONLY, 0), fd); ++ support_descriptors_check (descrs); /* Will report failure. */ ++ puts ("EOT"); ++ support_descriptors_free (descrs); ++} ++ ++static void ++report_subprocess_output (const char *name, ++ struct support_capture_subprocess *proc) ++{ ++ printf ("info: BEGIN %s output\n" ++ "%s" ++ "info: END %s output\n", ++ name, proc->out.buffer, name); ++} ++ ++/* Use an explicit flag to preserve failure status across ++ support_record_failure_reset calls. */ ++static bool good = true; ++ ++static void ++test_run (void) ++{ ++ struct support_capture_subprocess proc = support_capture_subprocess ++ (&subprocess_no_change, NULL); ++ support_capture_subprocess_check (&proc, "subprocess_no_change", ++ 0, sc_allow_none); ++ support_capture_subprocess_free (&proc); ++ ++ char *expected = xasprintf ("\nDifferences:\n" ++ "error: descriptor %d was closed\n" ++ "EOT\n", ++ free_descriptor); ++ good = good && !support_record_failure_is_failed (); ++ proc = support_capture_subprocess (&subprocess_closed_descriptor, NULL); ++ good = good && support_record_failure_is_failed (); ++ support_record_failure_reset (); /* Discard the reported error. */ ++ report_subprocess_output ("subprocess_closed_descriptor", &proc); ++ TEST_VERIFY (strstr (proc.out.buffer, expected) != NULL); ++ support_capture_subprocess_check (&proc, "subprocess_closed_descriptor", ++ 0, sc_allow_stdout); ++ support_capture_subprocess_free (&proc); ++ free (expected); ++ ++ expected = xasprintf ("\nDifferences:\n" ++ "error: descriptor %d was opened (\"/dev/null\")\n" ++ "EOT\n", ++ free_descriptor); ++ good = good && !support_record_failure_is_failed (); ++ proc = support_capture_subprocess (&subprocess_opened_descriptor, NULL); ++ good = good && support_record_failure_is_failed (); ++ support_record_failure_reset (); /* Discard the reported error. */ ++ report_subprocess_output ("subprocess_opened_descriptor", &proc); ++ TEST_VERIFY (strstr (proc.out.buffer, expected) != NULL); ++ support_capture_subprocess_check (&proc, "subprocess_opened_descriptor", ++ 0, sc_allow_stdout); ++ support_capture_subprocess_free (&proc); ++ free (expected); ++ ++ expected = xasprintf ("\nDifferences:\n" ++ "error: descriptor %d changed from \"/dev/null\"" ++ " to \"/dev\"\n" ++ "error: descriptor %d changed ino ", ++ free_descriptor, free_descriptor); ++ good = good && !support_record_failure_is_failed (); ++ proc = support_capture_subprocess (&subprocess_changed_descriptor, NULL); ++ good = good && support_record_failure_is_failed (); ++ support_record_failure_reset (); /* Discard the reported error. */ ++ report_subprocess_output ("subprocess_changed_descriptor", &proc); ++ TEST_VERIFY (strstr (proc.out.buffer, expected) != NULL); ++ support_capture_subprocess_check (&proc, "subprocess_changed_descriptor", ++ 0, sc_allow_stdout); ++ support_capture_subprocess_free (&proc); ++ free (expected); ++} ++ ++static int ++do_test (void) ++{ ++ puts ("info: initial descriptor set"); ++ { ++ struct support_descriptors *descrs = support_descriptors_list (); ++ support_descriptors_dump (descrs, "info: ", stdout); ++ support_descriptors_free (descrs); ++ } ++ ++ free_descriptor = xopen ("/dev/null", O_WRONLY, 0); ++ puts ("info: descriptor set with additional free descriptor"); ++ { ++ struct support_descriptors *descrs = support_descriptors_list (); ++ support_descriptors_dump (descrs, "info: ", stdout); ++ support_descriptors_free (descrs); ++ } ++ TEST_VERIFY (free_descriptor >= 3); ++ xclose (free_descriptor); ++ ++ /* Initial test run without a sentinel descriptor. The presence of ++ such a descriptor exercises different conditions in the list ++ comparison in support_descriptors_check. */ ++ test_run (); ++ ++ /* Allocate a sentinel descriptor at the end of the descriptor list, ++ after free_descriptor. */ ++ int sentinel_fd; ++ { ++ int fd = xopen ("/dev/full", O_WRONLY, 0); ++ TEST_COMPARE (fd, free_descriptor); ++ sentinel_fd = dup (fd); ++ TEST_VERIFY_EXIT (sentinel_fd > fd); ++ xclose (fd); ++ } ++ puts ("info: descriptor set with sentinel descriptor"); ++ { ++ struct support_descriptors *descrs = support_descriptors_list (); ++ support_descriptors_dump (descrs, "info: ", stdout); ++ support_descriptors_free (descrs); ++ } ++ ++ /* Second test run with sentinel descriptor. */ ++ test_run (); ++ ++ xclose (sentinel_fd); ++ ++ return !good; ++} ++ ++#include +diff --git a/support/tst-support_quote_blob.c b/support/tst-support_quote_blob.c +new file mode 100644 +index 0000000000..5467a190a6 +--- /dev/null ++++ b/support/tst-support_quote_blob.c +@@ -0,0 +1,61 @@ ++/* Test the support_quote_blob function. ++ Copyright (C) 2018 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 ++ ++static int ++do_test (void) ++{ ++ /* Check handling of the empty blob, both with and without trailing ++ NUL byte. */ ++ char *p = support_quote_blob ("", 0); ++ TEST_COMPARE (strlen (p), 0); ++ free (p); ++ p = support_quote_blob ("X", 0); ++ TEST_COMPARE (strlen (p), 0); ++ free (p); ++ ++ /* Check escaping of backslash-escaped characters, and lack of ++ escaping for other shell meta-characters. */ ++ p = support_quote_blob ("$()*?`@[]{}~\'\"X", 14); ++ TEST_COMPARE (strcmp (p, "$()*?`@[]{}~\\'\\\""), 0); ++ free (p); ++ ++ /* Check lack of escaping for letters and digits. */ ++#define LETTERS_AND_DIGTS \ ++ "abcdefghijklmnopqrstuvwxyz" \ ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ ++ "0123456789" ++ p = support_quote_blob (LETTERS_AND_DIGTS "@", 2 * 26 + 10); ++ TEST_COMPARE (strcmp (p, LETTERS_AND_DIGTS), 0); ++ free (p); ++ ++ /* Check escaping of control characters and other non-printable ++ characters. */ ++ p = support_quote_blob ("\r\n\t\a\b\f\v\1\177\200\377\0@", 14); ++ TEST_COMPARE (strcmp (p, "\\r\\n\\t\\a\\b\\f\\v\\001" ++ "\\177\\200\\377\\000@\\000"), 0); ++ free (p); ++ ++ return 0; ++} ++ ++#include +diff --git a/support/tst-support_quote_string.c b/support/tst-support_quote_string.c +new file mode 100644 +index 0000000000..3c004759b7 +--- /dev/null ++++ b/support/tst-support_quote_string.c +@@ -0,0 +1,60 @@ ++/* Test the support_quote_string function. ++ Copyright (C) 2018 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 ++ ++static int ++do_test (void) ++{ ++ char *p = support_quote_string (""); ++ TEST_COMPARE (strlen (p), 0); ++ free (p); ++ p = support_quote_string ("X"); ++ TEST_COMPARE (strlen (p), 1); ++ TEST_COMPARE (p[0], 'X'); ++ free (p); ++ ++ /* Check escaping of backslash-escaped characters, and lack of ++ escaping for other shell meta-characters. */ ++ p = support_quote_string ("$()*?`@[]{}~\'\"X"); ++ TEST_COMPARE (strcmp (p, "$()*?`@[]{}~\\'\\\"X"), 0); ++ free (p); ++ ++ /* Check lack of escaping for letters and digits. */ ++#define LETTERS_AND_DIGTS \ ++ "abcdefghijklmnopqrstuvwxyz" \ ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ ++ "0123456789" ++ p = support_quote_string (LETTERS_AND_DIGTS "@"); ++ TEST_COMPARE (strcmp (p, LETTERS_AND_DIGTS "@"), 0); ++ free (p); ++ ++ /* Check escaping of control characters and other non-printable ++ characters. */ ++ p = support_quote_string ("\r\n\t\a\b\f\v\1\177\200\377@"); ++ TEST_COMPARE (strcmp (p, "\\r\\n\\t\\a\\b\\f\\v\\001" ++ "\\177\\200\\377@"), 0); ++ free (p); ++ ++ return 0; ++} ++ ++#include +diff --git a/support/tst-test_compare_blob.c b/support/tst-test_compare_blob.c +new file mode 100644 +index 0000000000..aa8643e182 +--- /dev/null ++++ b/support/tst-test_compare_blob.c +@@ -0,0 +1,125 @@ ++/* Basic test for the TEST_COMPARE_BLOB macro. ++ Copyright (C) 2018 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++ ++static void ++subprocess (void *closure) ++{ ++ /* These tests should fail. They were chosen to cover differences ++ in length (with the same contents), single-bit mismatches, and ++ mismatching null pointers. */ ++ TEST_COMPARE_BLOB ("", 0, "", 1); /* Line 29. */ ++ TEST_COMPARE_BLOB ("X", 1, "", 1); /* Line 30. */ ++ TEST_COMPARE_BLOB ("abcd", 3, "abcd", 4); /* Line 31. */ ++ TEST_COMPARE_BLOB ("abcd", 4, "abcD", 4); /* Line 32. */ ++ TEST_COMPARE_BLOB ("abcd", 4, NULL, 0); /* Line 33. */ ++ TEST_COMPARE_BLOB (NULL, 0, "abcd", 4); /* Line 34. */ ++} ++ ++/* Same contents, different addresses. */ ++char buffer_abc_1[] = "abc"; ++char buffer_abc_2[] = "abc"; ++ ++static int ++do_test (void) ++{ ++ /* This should succeed. Even if the pointers and array contents are ++ different, zero-length inputs are not different. */ ++ TEST_COMPARE_BLOB ("", 0, "", 0); ++ TEST_COMPARE_BLOB ("", 0, buffer_abc_1, 0); ++ TEST_COMPARE_BLOB (buffer_abc_1, 0, "", 0); ++ TEST_COMPARE_BLOB (NULL, 0, "", 0); ++ TEST_COMPARE_BLOB ("", 0, NULL, 0); ++ TEST_COMPARE_BLOB (NULL, 0, NULL, 0); ++ ++ /* Check equality of blobs containing a single NUL byte. */ ++ TEST_COMPARE_BLOB ("", 1, "", 1); ++ TEST_COMPARE_BLOB ("", 1, &buffer_abc_1[3], 1); ++ ++ /* Check equality of blobs of varying lengths. */ ++ for (size_t i = 0; i <= sizeof (buffer_abc_1); ++i) ++ TEST_COMPARE_BLOB (buffer_abc_1, i, buffer_abc_2, i); ++ ++ struct support_capture_subprocess proc = support_capture_subprocess ++ (&subprocess, NULL); ++ ++ /* Discard the reported error. */ ++ support_record_failure_reset (); ++ ++ puts ("info: *** subprocess output starts ***"); ++ fputs (proc.out.buffer, stdout); ++ puts ("info: *** subprocess output ends ***"); ++ ++ TEST_VERIFY ++ (strcmp (proc.out.buffer, ++"tst-test_compare_blob.c:29: error: blob comparison failed\n" ++" left length: 0 bytes (from 0)\n" ++" right length: 1 bytes (from 1)\n" ++" right (evaluated from \"\"):\n" ++" \"\\000\"\n" ++" 00\n" ++"tst-test_compare_blob.c:30: error: blob comparison failed\n" ++" blob length: 1 bytes\n" ++" left (evaluated from \"X\"):\n" ++" \"X\"\n" ++" 58\n" ++" right (evaluated from \"\"):\n" ++" \"\\000\"\n" ++" 00\n" ++"tst-test_compare_blob.c:31: error: blob comparison failed\n" ++" left length: 3 bytes (from 3)\n" ++" right length: 4 bytes (from 4)\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abc\"\n" ++" 61 62 63\n" ++" right (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++"tst-test_compare_blob.c:32: error: blob comparison failed\n" ++" blob length: 4 bytes\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++" right (evaluated from \"abcD\"):\n" ++" \"abcD\"\n" ++" 61 62 63 44\n" ++"tst-test_compare_blob.c:33: error: blob comparison failed\n" ++" left length: 4 bytes (from 4)\n" ++" right length: 0 bytes (from 0)\n" ++" left (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++"tst-test_compare_blob.c:34: error: blob comparison failed\n" ++" left length: 0 bytes (from 0)\n" ++" right length: 4 bytes (from 4)\n" ++" right (evaluated from \"abcd\"):\n" ++" \"abcd\"\n" ++" 61 62 63 64\n" ++ ) == 0); ++ ++ /* Check that there is no output on standard error. */ ++ support_capture_subprocess_check (&proc, "TEST_COMPARE_BLOB", ++ 0, sc_allow_stdout); ++ ++ return 0; ++} ++ ++#include +diff --git a/support/tty.h b/support/tty.h +new file mode 100644 +index 0000000000..1d37c42279 +--- /dev/null ++++ b/support/tty.h +@@ -0,0 +1,45 @@ ++/* Support functions related to (pseudo)terminals. ++ Copyright (C) 2018 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 _SUPPORT_TTY_H ++#define _SUPPORT_TTY_H 1 ++ ++struct termios; ++struct winsize; ++ ++/** Open a pseudoterminal pair. The outer fd is written to the address ++ A_OUTER and the inner fd to A_INNER. ++ ++ If A_NAME is not NULL, it will be set to point to a string naming ++ the /dev/pts/NNN device corresponding to the inner fd; space for ++ this string is allocated with malloc and should be freed by the ++ caller when no longer needed. (This is different from the libutil ++ function 'openpty'.) ++ ++ If TERMP is not NULL, the terminal parameters will be initialized ++ according to the termios structure it points to. ++ ++ If WINP is not NULL, the terminal window size will be set ++ accordingly. ++ ++ Terminates the process on failure (like xmalloc). */ ++extern void support_openpty (int *a_outer, int *a_inner, char **a_name, ++ const struct termios *termp, ++ const struct winsize *winp); ++ ++#endif +diff --git a/support/xpthread_barrierattr_destroy.c b/support/xpthread_barrierattr_destroy.c +new file mode 100644 +index 0000000000..3e471f9a81 +--- /dev/null ++++ b/support/xpthread_barrierattr_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_barrierattr_destroy with error checking. ++ Copyright (C) 2018 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 ++ ++void ++xpthread_barrierattr_destroy (pthread_barrierattr_t *attr) ++{ ++ xpthread_check_return ("pthread_barrierattr_destroy", ++ pthread_barrierattr_destroy (attr)); ++} +diff --git a/support/xpthread_barrierattr_init.c b/support/xpthread_barrierattr_init.c +new file mode 100644 +index 0000000000..4ee14e78f3 +--- /dev/null ++++ b/support/xpthread_barrierattr_init.c +@@ -0,0 +1,26 @@ ++/* pthread_barrierattr_init with error checking. ++ Copyright (C) 2018 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 ++ ++void ++xpthread_barrierattr_init (pthread_barrierattr_t *attr) ++{ ++ xpthread_check_return ("pthread_barrierattr_init", ++ pthread_barrierattr_init (attr)); ++} +diff --git a/support/xpthread_barrierattr_setpshared.c b/support/xpthread_barrierattr_setpshared.c +new file mode 100644 +index 0000000000..90b2c5bec6 +--- /dev/null ++++ b/support/xpthread_barrierattr_setpshared.c +@@ -0,0 +1,26 @@ ++/* pthread_barrierattr_setpshared with error checking. ++ Copyright (C) 2018 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 ++ ++void ++xpthread_barrierattr_setpshared (pthread_barrierattr_t *attr, int pshared) ++{ ++ xpthread_check_return ("pthread_barrierattr_setpshared", ++ pthread_barrierattr_setpshared (attr, pshared)); ++} +diff --git a/support/xthread.h b/support/xthread.h +index 79358e7c99..623f5ad0ac 100644 +--- a/support/xthread.h ++++ b/support/xthread.h +@@ -41,6 +41,9 @@ void xpthread_check_return (const char *function, int value); + void xpthread_barrier_init (pthread_barrier_t *barrier, + pthread_barrierattr_t *attr, unsigned int count); + void xpthread_barrier_destroy (pthread_barrier_t *barrier); ++void xpthread_barrierattr_destroy (pthread_barrierattr_t *); ++void xpthread_barrierattr_init (pthread_barrierattr_t *); ++void xpthread_barrierattr_setpshared (pthread_barrierattr_t *, int pshared); + void xpthread_mutexattr_destroy (pthread_mutexattr_t *); + void xpthread_mutexattr_init (pthread_mutexattr_t *); + void xpthread_mutexattr_setprotocol (pthread_mutexattr_t *, int); +diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h +index 7ce3c8eb8b..0c1f8d66b3 100644 +--- a/sysdeps/aarch64/dl-machine.h ++++ b/sysdeps/aarch64/dl-machine.h +@@ -388,10 +388,37 @@ elf_machine_lazy_rel (struct link_map *map, + /* Check for unexpected PLT reloc type. */ + if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1)) + { +- if (__builtin_expect (map->l_mach.plt, 0) == 0) +- *reloc_addr += l_addr; +- else +- *reloc_addr = map->l_mach.plt; ++ if (map->l_mach.plt == 0) ++ { ++ /* Prelinking. */ ++ *reloc_addr += l_addr; ++ return; ++ } ++ ++ if (1) /* DT_AARCH64_VARIANT_PCS is not available, so always check. */ ++ { ++ /* Check the symbol table for variant PCS symbols. */ ++ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info); ++ const ElfW (Sym) *symtab = ++ (const void *)D_PTR (map, l_info[DT_SYMTAB]); ++ const ElfW (Sym) *sym = &symtab[symndx]; ++ if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS)) ++ { ++ /* Avoid lazy resolution of variant PCS symbols. */ ++ const struct r_found_version *version = NULL; ++ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL) ++ { ++ const ElfW (Half) *vernum = ++ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]); ++ version = &map->l_versions[vernum[symndx] & 0x7fff]; ++ } ++ elf_machine_rela (map, reloc, sym, version, reloc_addr, ++ skip_ifunc); ++ return; ++ } ++ } ++ ++ *reloc_addr = map->l_mach.plt; + } + else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1)) + { +diff --git a/sysdeps/aarch64/memcmp.S b/sysdeps/aarch64/memcmp.S +index ccc795adeb..743bc078bb 100644 +--- a/sysdeps/aarch64/memcmp.S ++++ b/sysdeps/aarch64/memcmp.S +@@ -34,9 +34,12 @@ + /* Internal variables. */ + #define data1 x3 + #define data1w w3 +-#define data2 x4 +-#define data2w w4 +-#define tmp1 x5 ++#define data1h x4 ++#define data2 x5 ++#define data2w w5 ++#define data2h x6 ++#define tmp1 x7 ++#define tmp2 x8 + + ENTRY_ALIGN (memcmp, 6) + DELOUSE (0) +@@ -44,73 +47,104 @@ ENTRY_ALIGN (memcmp, 6) + DELOUSE (2) + + subs limit, limit, 8 +- b.lo .Lless8 ++ b.lo L(less8) + +- /* Limit >= 8, so check first 8 bytes using unaligned loads. */ + ldr data1, [src1], 8 + ldr data2, [src2], 8 +- and tmp1, src1, 7 +- add limit, limit, tmp1 + cmp data1, data2 +- bne .Lreturn ++ b.ne L(return) ++ ++ subs limit, limit, 8 ++ b.gt L(more16) ++ ++ ldr data1, [src1, limit] ++ ldr data2, [src2, limit] ++ b L(return) ++ ++L(more16): ++ ldr data1, [src1], 8 ++ ldr data2, [src2], 8 ++ cmp data1, data2 ++ bne L(return) ++ ++ /* Jump directly to comparing the last 16 bytes for 32 byte (or less) ++ strings. */ ++ subs limit, limit, 16 ++ b.ls L(last_bytes) ++ ++ /* We overlap loads between 0-32 bytes at either side of SRC1 when we ++ try to align, so limit it only to strings larger than 128 bytes. */ ++ cmp limit, 96 ++ b.ls L(loop16) + + /* Align src1 and adjust src2 with bytes not yet done. */ ++ and tmp1, src1, 15 ++ add limit, limit, tmp1 + sub src1, src1, tmp1 + sub src2, src2, tmp1 + +- subs limit, limit, 8 +- b.ls .Llast_bytes +- +- /* Loop performing 8 bytes per iteration using aligned src1. +- Limit is pre-decremented by 8 and must be larger than zero. +- Exit if <= 8 bytes left to do or if the data is not equal. */ ++ /* Loop performing 16 bytes per iteration using aligned src1. ++ Limit is pre-decremented by 16 and must be larger than zero. ++ Exit if <= 16 bytes left to do or if the data is not equal. */ + .p2align 4 +-.Lloop8: +- ldr data1, [src1], 8 +- ldr data2, [src2], 8 +- subs limit, limit, 8 +- ccmp data1, data2, 0, hi /* NZCV = 0b0000. */ +- b.eq .Lloop8 ++L(loop16): ++ ldp data1, data1h, [src1], 16 ++ ldp data2, data2h, [src2], 16 ++ subs limit, limit, 16 ++ ccmp data1, data2, 0, hi ++ ccmp data1h, data2h, 0, eq ++ b.eq L(loop16) + + cmp data1, data2 +- bne .Lreturn +- +- /* Compare last 1-8 bytes using unaligned access. */ +-.Llast_bytes: +- ldr data1, [src1, limit] +- ldr data2, [src2, limit] ++ bne L(return) ++ mov data1, data1h ++ mov data2, data2h ++ cmp data1, data2 ++ bne L(return) ++ ++ /* Compare last 1-16 bytes using unaligned access. */ ++L(last_bytes): ++ add src1, src1, limit ++ add src2, src2, limit ++ ldp data1, data1h, [src1] ++ ldp data2, data2h, [src2] ++ cmp data1, data2 ++ bne L(return) ++ mov data1, data1h ++ mov data2, data2h ++ cmp data1, data2 + + /* Compare data bytes and set return value to 0, -1 or 1. */ +-.Lreturn: ++L(return): + #ifndef __AARCH64EB__ + rev data1, data1 + rev data2, data2 + #endif + cmp data1, data2 +-.Lret_eq: ++L(ret_eq): + cset result, ne + cneg result, result, lo + ret + + .p2align 4 + /* Compare up to 8 bytes. Limit is [-8..-1]. */ +-.Lless8: ++L(less8): + adds limit, limit, 4 +- b.lo .Lless4 ++ b.lo L(less4) + ldr data1w, [src1], 4 + ldr data2w, [src2], 4 + cmp data1w, data2w +- b.ne .Lreturn ++ b.ne L(return) + sub limit, limit, 4 +-.Lless4: ++L(less4): + adds limit, limit, 4 +- beq .Lret_eq +-.Lbyte_loop: ++ beq L(ret_eq) ++L(byte_loop): + ldrb data1w, [src1], 1 + ldrb data2w, [src2], 1 + subs limit, limit, 1 + ccmp data1w, data2w, 0, ne /* NZCV = 0b0000. */ +- b.eq .Lbyte_loop ++ b.eq L(byte_loop) + sub result, data1w, data2w + ret + +diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c +index 3efea2c644..abeca6cff4 100644 +--- a/sysdeps/aarch64/multiarch/memcpy.c ++++ b/sysdeps/aarch64/multiarch/memcpy.c +@@ -35,7 +35,7 @@ extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden; + libc_ifunc (__libc_memcpy, + (IS_THUNDERX (midr) + ? __memcpy_thunderx +- : (IS_FALKOR (midr) ++ : (IS_FALKOR (midr) || IS_ARES (midr) + ? __memcpy_falkor + : __memcpy_generic))); + +diff --git a/sysdeps/aarch64/multiarch/memcpy_falkor.S b/sysdeps/aarch64/multiarch/memcpy_falkor.S +index 8dd8c1e03a..cdc2de4750 100644 +--- a/sysdeps/aarch64/multiarch/memcpy_falkor.S ++++ b/sysdeps/aarch64/multiarch/memcpy_falkor.S +@@ -29,11 +29,19 @@ + #define dst x3 + #define srcend x4 + #define dstend x5 +-#define A_l x6 +-#define A_lw w6 +-#define A_h x7 +-#define A_hw w7 + #define tmp1 x14 ++#define A_x x6 ++#define B_x x7 ++#define A_w w6 ++#define B_w w7 ++ ++#define A_q q0 ++#define B_q q1 ++#define C_q q2 ++#define D_q q3 ++#define E_q q4 ++#define F_q q5 ++#define G_q q6 + + /* Copies are split into 3 main cases: + +@@ -53,9 +61,9 @@ + bumping up the small copies up to 32 bytes allows us to do that without + cost and also allows us to reduce the size of the prep code before loop64. + +- All copies are done only via two registers r6 and r7. This is to ensure +- that all loads hit a single hardware prefetcher which can get correctly +- trained to prefetch a single stream. ++ The copy loop uses only one register q0. This is to ensure that all loads ++ hit a single hardware prefetcher which can get correctly trained to prefetch ++ a single stream. + + The non-temporal stores help optimize cache utilization. */ + +@@ -66,29 +74,29 @@ ENTRY_ALIGN (__memcpy_falkor, 6) + add srcend, src, count + add dstend, dstin, count + b.ls L(copy32) +- ldp A_l, A_h, [src] ++ ldr A_q, [src] + cmp count, 128 +- stp A_l, A_h, [dstin] ++ str A_q, [dstin] + b.hi L(copy_long) + + /* Medium copies: 33..128 bytes. */ + sub tmp1, count, 1 +- ldp A_l, A_h, [src, 16] +- stp A_l, A_h, [dstin, 16] ++ ldr A_q, [src, 16] ++ ldr B_q, [srcend, -32] ++ ldr C_q, [srcend, -16] + tbz tmp1, 6, 1f +- ldp A_l, A_h, [src, 32] +- stp A_l, A_h, [dstin, 32] +- ldp A_l, A_h, [src, 48] +- stp A_l, A_h, [dstin, 48] +- ldp A_l, A_h, [srcend, -64] +- stp A_l, A_h, [dstend, -64] +- ldp A_l, A_h, [srcend, -48] +- stp A_l, A_h, [dstend, -48] ++ ldr D_q, [src, 32] ++ ldr E_q, [src, 48] ++ str D_q, [dstin, 32] ++ str E_q, [dstin, 48] ++ ldr F_q, [srcend, -64] ++ ldr G_q, [srcend, -48] ++ str F_q, [dstend, -64] ++ str G_q, [dstend, -48] + 1: +- ldp A_l, A_h, [srcend, -32] +- stp A_l, A_h, [dstend, -32] +- ldp A_l, A_h, [srcend, -16] +- stp A_l, A_h, [dstend, -16] ++ str A_q, [dstin, 16] ++ str B_q, [dstend, -32] ++ str C_q, [dstend, -16] + ret + + .p2align 4 +@@ -97,44 +105,44 @@ L(copy32): + /* 16-32 */ + cmp count, 16 + b.lo 1f +- ldp A_l, A_h, [src] +- stp A_l, A_h, [dstin] +- ldp A_l, A_h, [srcend, -16] +- stp A_l, A_h, [dstend, -16] ++ ldr A_q, [src] ++ ldr B_q, [srcend, -16] ++ str A_q, [dstin] ++ str B_q, [dstend, -16] + ret + .p2align 4 + 1: + /* 8-15 */ + tbz count, 3, 1f +- ldr A_l, [src] +- str A_l, [dstin] +- ldr A_l, [srcend, -8] +- str A_l, [dstend, -8] ++ ldr A_x, [src] ++ ldr B_x, [srcend, -8] ++ str A_x, [dstin] ++ str B_x, [dstend, -8] + ret + .p2align 4 + 1: + /* 4-7 */ + tbz count, 2, 1f +- ldr A_lw, [src] +- str A_lw, [dstin] +- ldr A_lw, [srcend, -4] +- str A_lw, [dstend, -4] ++ ldr A_w, [src] ++ ldr B_w, [srcend, -4] ++ str A_w, [dstin] ++ str B_w, [dstend, -4] + ret + .p2align 4 + 1: + /* 2-3 */ + tbz count, 1, 1f +- ldrh A_lw, [src] +- strh A_lw, [dstin] +- ldrh A_lw, [srcend, -2] +- strh A_lw, [dstend, -2] ++ ldrh A_w, [src] ++ ldrh B_w, [srcend, -2] ++ strh A_w, [dstin] ++ strh B_w, [dstend, -2] + ret + .p2align 4 + 1: + /* 0-1 */ + tbz count, 0, 1f +- ldrb A_lw, [src] +- strb A_lw, [dstin] ++ ldrb A_w, [src] ++ strb A_w, [dstin] + 1: + ret + +@@ -153,30 +161,29 @@ L(copy_long): + add count, count, tmp1 + + L(loop64): +- ldp A_l, A_h, [src, 16]! +- stnp A_l, A_h, [dst, 16] +- ldp A_l, A_h, [src, 16]! ++ ldr A_q, [src, 16]! ++ str A_q, [dst, 16] ++ ldr A_q, [src, 16]! + subs count, count, 64 +- stnp A_l, A_h, [dst, 32] +- ldp A_l, A_h, [src, 16]! +- stnp A_l, A_h, [dst, 48] +- ldp A_l, A_h, [src, 16]! +- stnp A_l, A_h, [dst, 64] +- add dst, dst, 64 ++ str A_q, [dst, 32] ++ ldr A_q, [src, 16]! ++ str A_q, [dst, 48] ++ ldr A_q, [src, 16]! ++ str A_q, [dst, 64]! + b.hi L(loop64) + + /* Write the last full set of 64 bytes. The remainder is at most 64 + bytes, so it is safe to always copy 64 bytes from the end even if + there is just 1 byte left. */ + L(last64): +- ldp A_l, A_h, [srcend, -64] +- stnp A_l, A_h, [dstend, -64] +- ldp A_l, A_h, [srcend, -48] +- stnp A_l, A_h, [dstend, -48] +- ldp A_l, A_h, [srcend, -32] +- stnp A_l, A_h, [dstend, -32] +- ldp A_l, A_h, [srcend, -16] +- stnp A_l, A_h, [dstend, -16] ++ ldr E_q, [srcend, -64] ++ str E_q, [dstend, -64] ++ ldr D_q, [srcend, -48] ++ str D_q, [dstend, -48] ++ ldr C_q, [srcend, -32] ++ str C_q, [dstend, -32] ++ ldr B_q, [srcend, -16] ++ str B_q, [dstend, -16] + ret + + END (__memcpy_falkor) +diff --git a/sysdeps/aarch64/strcmp.S b/sysdeps/aarch64/strcmp.S +index 0b22f168b5..267aa4b551 100644 +--- a/sysdeps/aarch64/strcmp.S ++++ b/sysdeps/aarch64/strcmp.S +@@ -158,7 +158,7 @@ L(do_misaligned): + ccmp data1w, data2w, #0, cs /* NZCV = 0b0000. */ + b.ne L(done) + tst src1, #7 +- b.ne L(misaligned8) ++ b.ne L(do_misaligned) + + L(loop_misaligned): + /* Test if we are within the last dword of the end of a 4K page. If +diff --git a/sysdeps/aarch64/strncmp.S b/sysdeps/aarch64/strncmp.S +index a08d2c0aa5..759c752fc2 100644 +--- a/sysdeps/aarch64/strncmp.S ++++ b/sysdeps/aarch64/strncmp.S +@@ -49,6 +49,7 @@ + #define limit_wd x13 + #define mask x14 + #define endloop x15 ++#define count mask + + ENTRY_ALIGN_AND_PAD (strncmp, 6, 7) + DELOUSE (0) +@@ -58,9 +59,9 @@ ENTRY_ALIGN_AND_PAD (strncmp, 6, 7) + eor tmp1, src1, src2 + mov zeroones, #REP8_01 + tst tmp1, #7 ++ and count, src1, #7 + b.ne L(misaligned8) +- ands tmp1, src1, #7 +- b.ne L(mutual_align) ++ cbnz count, L(mutual_align) + /* Calculate the number of full and partial words -1. */ + sub limit_wd, limit, #1 /* limit != 0, so no underflow. */ + lsr limit_wd, limit_wd, #3 /* Convert to Dwords. */ +@@ -165,43 +166,107 @@ L(mutual_align): + bic src1, src1, #7 + bic src2, src2, #7 + ldr data1, [src1], #8 +- neg tmp3, tmp1, lsl #3 /* 64 - bits(bytes beyond align). */ ++ neg tmp3, count, lsl #3 /* 64 - bits(bytes beyond align). */ + ldr data2, [src2], #8 + mov tmp2, #~0 + sub limit_wd, limit, #1 /* limit != 0, so no underflow. */ + #ifdef __AARCH64EB__ + /* Big-endian. Early bytes are at MSB. */ +- lsl tmp2, tmp2, tmp3 /* Shift (tmp1 & 63). */ ++ lsl tmp2, tmp2, tmp3 /* Shift (count & 63). */ + #else + /* Little-endian. Early bytes are at LSB. */ +- lsr tmp2, tmp2, tmp3 /* Shift (tmp1 & 63). */ ++ lsr tmp2, tmp2, tmp3 /* Shift (count & 63). */ + #endif + and tmp3, limit_wd, #7 + lsr limit_wd, limit_wd, #3 + /* Adjust the limit. Only low 3 bits used, so overflow irrelevant. */ +- add limit, limit, tmp1 +- add tmp3, tmp3, tmp1 ++ add limit, limit, count ++ add tmp3, tmp3, count + orr data1, data1, tmp2 + orr data2, data2, tmp2 + add limit_wd, limit_wd, tmp3, lsr #3 + b L(start_realigned) + +-L(ret0): +- mov result, #0 +- RET +- + .p2align 6 ++ /* Don't bother with dwords for up to 16 bytes. */ + L(misaligned8): +- sub limit, limit, #1 +-1: ++ cmp limit, #16 ++ b.hs L(try_misaligned_words) ++ ++L(byte_loop): + /* Perhaps we can do better than this. */ + ldrb data1w, [src1], #1 + ldrb data2w, [src2], #1 + subs limit, limit, #1 +- ccmp data1w, #1, #0, cs /* NZCV = 0b0000. */ ++ ccmp data1w, #1, #0, hi /* NZCV = 0b0000. */ + ccmp data1w, data2w, #0, cs /* NZCV = 0b0000. */ +- b.eq 1b ++ b.eq L(byte_loop) ++L(done): + sub result, data1, data2 + RET ++ ++ /* Align the SRC1 to a dword by doing a bytewise compare and then do ++ the dword loop. */ ++L(try_misaligned_words): ++ lsr limit_wd, limit, #3 ++ cbz count, L(do_misaligned) ++ ++ neg count, count ++ and count, count, #7 ++ sub limit, limit, count ++ lsr limit_wd, limit, #3 ++ ++L(page_end_loop): ++ ldrb data1w, [src1], #1 ++ ldrb data2w, [src2], #1 ++ cmp data1w, #1 ++ ccmp data1w, data2w, #0, cs /* NZCV = 0b0000. */ ++ b.ne L(done) ++ subs count, count, #1 ++ b.hi L(page_end_loop) ++ ++L(do_misaligned): ++ /* Prepare ourselves for the next page crossing. Unlike the aligned ++ loop, we fetch 1 less dword because we risk crossing bounds on ++ SRC2. */ ++ mov count, #8 ++ subs limit_wd, limit_wd, #1 ++ b.lo L(done_loop) ++L(loop_misaligned): ++ and tmp2, src2, #0xff8 ++ eor tmp2, tmp2, #0xff8 ++ cbz tmp2, L(page_end_loop) ++ ++ ldr data1, [src1], #8 ++ ldr data2, [src2], #8 ++ sub tmp1, data1, zeroones ++ orr tmp2, data1, #REP8_7f ++ eor diff, data1, data2 /* Non-zero if differences found. */ ++ bics has_nul, tmp1, tmp2 /* Non-zero if NUL terminator. */ ++ ccmp diff, #0, #0, eq ++ b.ne L(not_limit) ++ subs limit_wd, limit_wd, #1 ++ b.pl L(loop_misaligned) ++ ++L(done_loop): ++ /* We found a difference or a NULL before the limit was reached. */ ++ and limit, limit, #7 ++ cbz limit, L(not_limit) ++ /* Read the last word. */ ++ sub src1, src1, 8 ++ sub src2, src2, 8 ++ ldr data1, [src1, limit] ++ ldr data2, [src2, limit] ++ sub tmp1, data1, zeroones ++ orr tmp2, data1, #REP8_7f ++ eor diff, data1, data2 /* Non-zero if differences found. */ ++ bics has_nul, tmp1, tmp2 /* Non-zero if NUL terminator. */ ++ ccmp diff, #0, #0, eq ++ b.ne L(not_limit) ++ ++L(ret0): ++ mov result, #0 ++ RET ++ + END (strncmp) + libc_hidden_builtin_def (strncmp) +diff --git a/sysdeps/generic/math_private.h b/sysdeps/generic/math_private.h +index e4b9d8697f..cff76149d6 100644 +--- a/sysdeps/generic/math_private.h ++++ b/sysdeps/generic/math_private.h +@@ -514,33 +514,6 @@ default_libc_feupdateenv_test (fenv_t *e, int ex) + # define HAVE_RM_CTX 0 + #endif + +-#if HAVE_RM_CTX +-/* Set/Restore Rounding Modes only when necessary. If defined, these functions +- set/restore floating point state only if the state needed within the lexical +- block is different from the current state. This saves a lot of time when +- the floating point unit is much slower than the fixed point units. */ +- +-# ifndef libc_feholdsetround_noex_ctx +-# define libc_feholdsetround_noex_ctx libc_feholdsetround_ctx +-# endif +-# ifndef libc_feholdsetround_noexf_ctx +-# define libc_feholdsetround_noexf_ctx libc_feholdsetroundf_ctx +-# endif +-# ifndef libc_feholdsetround_noexl_ctx +-# define libc_feholdsetround_noexl_ctx libc_feholdsetroundl_ctx +-# endif +- +-# ifndef libc_feresetround_noex_ctx +-# define libc_feresetround_noex_ctx libc_fesetenv_ctx +-# endif +-# ifndef libc_feresetround_noexf_ctx +-# define libc_feresetround_noexf_ctx libc_fesetenvf_ctx +-# endif +-# ifndef libc_feresetround_noexl_ctx +-# define libc_feresetround_noexl_ctx libc_fesetenvl_ctx +-# endif +- +-#else + + /* Default implementation using standard fenv functions. + Avoid unnecessary rounding mode changes by first checking the +@@ -548,7 +521,7 @@ default_libc_feupdateenv_test (fenv_t *e, int ex) + important for performance. */ + + static __always_inline void +-libc_feholdsetround_ctx (struct rm_ctx *ctx, int round) ++default_libc_feholdsetround_ctx (struct rm_ctx *ctx, int round) + { + ctx->updated_status = false; + +@@ -562,7 +535,7 @@ libc_feholdsetround_ctx (struct rm_ctx *ctx, int round) + } + + static __always_inline void +-libc_feresetround_ctx (struct rm_ctx *ctx) ++default_libc_feresetround_ctx (struct rm_ctx *ctx) + { + /* Restore the rounding mode if updated. */ + if (__glibc_unlikely (ctx->updated_status)) +@@ -570,7 +543,7 @@ libc_feresetround_ctx (struct rm_ctx *ctx) + } + + static __always_inline void +-libc_feholdsetround_noex_ctx (struct rm_ctx *ctx, int round) ++default_libc_feholdsetround_noex_ctx (struct rm_ctx *ctx, int round) + { + /* Save exception flags and rounding mode, and disable exception + traps. */ +@@ -582,12 +555,45 @@ libc_feholdsetround_noex_ctx (struct rm_ctx *ctx, int round) + } + + static __always_inline void +-libc_feresetround_noex_ctx (struct rm_ctx *ctx) ++default_libc_feresetround_noex_ctx (struct rm_ctx *ctx) + { + /* Restore exception flags and rounding mode. */ + __fesetenv (&ctx->env); + } + ++#if HAVE_RM_CTX ++/* Set/Restore Rounding Modes only when necessary. If defined, these functions ++ set/restore floating point state only if the state needed within the lexical ++ block is different from the current state. This saves a lot of time when ++ the floating point unit is much slower than the fixed point units. */ ++ ++# ifndef libc_feholdsetround_noex_ctx ++# define libc_feholdsetround_noex_ctx libc_feholdsetround_ctx ++# endif ++# ifndef libc_feholdsetround_noexf_ctx ++# define libc_feholdsetround_noexf_ctx libc_feholdsetroundf_ctx ++# endif ++# ifndef libc_feholdsetround_noexl_ctx ++# define libc_feholdsetround_noexl_ctx libc_feholdsetroundl_ctx ++# endif ++ ++# ifndef libc_feresetround_noex_ctx ++# define libc_feresetround_noex_ctx libc_fesetenv_ctx ++# endif ++# ifndef libc_feresetround_noexf_ctx ++# define libc_feresetround_noexf_ctx libc_fesetenvf_ctx ++# endif ++# ifndef libc_feresetround_noexl_ctx ++# define libc_feresetround_noexl_ctx libc_fesetenvl_ctx ++# endif ++ ++#else ++ ++# define libc_feholdsetround_ctx default_libc_feholdsetround_ctx ++# define libc_feresetround_ctx default_libc_feresetround_ctx ++# define libc_feholdsetround_noex_ctx default_libc_feholdsetround_noex_ctx ++# define libc_feresetround_noex_ctx default_libc_feresetround_noex_ctx ++ + # define libc_feholdsetroundf_ctx libc_feholdsetround_ctx + # define libc_feholdsetroundl_ctx libc_feholdsetround_ctx + # define libc_feresetroundf_ctx libc_feresetround_ctx +diff --git a/sysdeps/generic/mmap_info.h b/sysdeps/generic/mmap_info.h +new file mode 100644 +index 0000000000..b3087df2d3 +--- /dev/null ++++ b/sysdeps/generic/mmap_info.h +@@ -0,0 +1,16 @@ ++/* As default architectures with sizeof (off_t) < sizeof (off64_t) the mmap is ++ implemented with __SYS_mmap2 syscall and the offset is represented in ++ multiples of page size. For offset larger than ++ '1 << (page_shift + 8 * sizeof (off_t))' (that is, 1<<44 on system with ++ page size of 4096 bytes) the system call silently truncates the offset. ++ For this case, glibc mmap implementation returns EINVAL. */ ++ ++/* Return the maximum value expected as offset argument in mmap64 call. */ ++static inline uint64_t ++mmap64_maximum_offset (long int page_shift) ++{ ++ if (sizeof (off_t) < sizeof (off64_t)) ++ return (UINT64_C(1) << (page_shift + (8 * sizeof (off_t)))) - 1; ++ else ++ return UINT64_MAX; ++} +diff --git a/sysdeps/i386/Makefile b/sysdeps/i386/Makefile +index a1500454e5..9c7078e33c 100644 +--- a/sysdeps/i386/Makefile ++++ b/sysdeps/i386/Makefile +@@ -5,6 +5,14 @@ asm-CPPFLAGS += -DGAS_SYNTAX + # The i386 `long double' is a distinct type we support. + long-double-fcts = yes + ++ifeq ($(subdir),math) ++# These functions change the rounding mode internally and need to ++# update both the SSE2 rounding mode and the 387 rounding mode. See ++# the handling of MATH_SET_BOTH_ROUNDING_MODES in ++# sysdeps/i386/fpu/fenv_private.h. ++CFLAGS-e_gamma_r.c += -DMATH_SET_BOTH_ROUNDING_MODES ++endif ++ + ifeq ($(subdir),string) + sysdep_routines += cacheinfo + endif +diff --git a/sysdeps/i386/fpu/fenv_private.h b/sysdeps/i386/fpu/fenv_private.h +index 38fd0b92b5..03177bb1ed 100644 +--- a/sysdeps/i386/fpu/fenv_private.h ++++ b/sysdeps/i386/fpu/fenv_private.h +@@ -491,11 +491,19 @@ libc_feupdateenv_387_ctx (struct rm_ctx *ctx) + #endif /* __SSE_MATH__ */ + + #ifdef __SSE2_MATH__ +-# define libc_feholdexcept_setround_ctx libc_feholdexcept_setround_sse_ctx +-# define libc_fesetenv_ctx libc_fesetenv_sse_ctx +-# define libc_feupdateenv_ctx libc_feupdateenv_sse_ctx +-# define libc_feholdsetround_ctx libc_feholdsetround_sse_ctx +-# define libc_feresetround_ctx libc_feresetround_sse_ctx ++# if defined (__x86_64__) || !defined (MATH_SET_BOTH_ROUNDING_MODES) ++# define libc_feholdexcept_setround_ctx libc_feholdexcept_setround_sse_ctx ++# define libc_fesetenv_ctx libc_fesetenv_sse_ctx ++# define libc_feupdateenv_ctx libc_feupdateenv_sse_ctx ++# define libc_feholdsetround_ctx libc_feholdsetround_sse_ctx ++# define libc_feresetround_ctx libc_feresetround_sse_ctx ++# else ++# define libc_feholdexcept_setround_ctx default_libc_feholdexcept_setround_ctx ++# define libc_fesetenv_ctx default_libc_fesetenv_ctx ++# define libc_feupdateenv_ctx default_libc_feupdateenv_ctx ++# define libc_feholdsetround_ctx default_libc_feholdsetround_ctx ++# define libc_feresetround_ctx default_libc_feresetround_ctx ++# endif + #else + # define libc_feholdexcept_setround_ctx libc_feholdexcept_setround_387_ctx + # define libc_feupdateenv_ctx libc_feupdateenv_387_ctx +diff --git a/sysdeps/i386/fpu/libm-test-ulps b/sysdeps/i386/fpu/libm-test-ulps +index 862a74e09d..9d1c35c605 100644 +--- a/sysdeps/i386/fpu/libm-test-ulps ++++ b/sysdeps/i386/fpu/libm-test-ulps +@@ -281,20 +281,20 @@ ldouble: 1 + + Function: Real part of "cacos": + double: 1 +-float: 1 ++float: 2 + float128: 2 + idouble: 1 +-ifloat: 1 ++ifloat: 2 + ifloat128: 2 + ildouble: 1 + ldouble: 1 + + Function: Imaginary part of "cacos": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 +@@ -360,21 +360,21 @@ ildouble: 7 + ldouble: 7 + + Function: Real part of "cacosh": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: Imaginary part of "cacosh": + double: 1 +-float: 1 ++float: 2 + float128: 2 + idouble: 1 +-ifloat: 1 ++ifloat: 2 + ifloat128: 2 + ildouble: 1 + ldouble: 1 +@@ -420,10 +420,10 @@ ildouble: 2 + ldouble: 2 + + Function: Real part of "cacosh_upward": +-double: 4 ++double: 5 + float: 4 + float128: 6 +-idouble: 4 ++idouble: 5 + ifloat: 4 + ifloat128: 6 + ildouble: 5 +@@ -488,11 +488,11 @@ ildouble: 1 + ldouble: 1 + + Function: Imaginary part of "casin": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 +@@ -558,11 +558,11 @@ ildouble: 7 + ldouble: 7 + + Function: Real part of "casinh": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 +@@ -774,11 +774,11 @@ ildouble: 1 + ldouble: 1 + + Function: Real part of "catanh_upward": +-double: 2 +-float: 2 ++double: 4 ++float: 4 + float128: 4 +-idouble: 2 +-ifloat: 2 ++idouble: 4 ++ifloat: 4 + ifloat128: 4 + ildouble: 4 + ldouble: 4 +@@ -875,10 +875,10 @@ ldouble: 3 + + Function: Real part of "ccos_towardzero": + double: 1 +-float: 1 ++float: 2 + float128: 2 + idouble: 1 +-ifloat: 1 ++ifloat: 2 + ifloat128: 2 + ildouble: 3 + ldouble: 3 +@@ -934,10 +934,10 @@ ildouble: 1 + ldouble: 1 + + Function: Real part of "ccosh_downward": +-double: 1 ++double: 2 + float: 2 + float128: 2 +-idouble: 1 ++idouble: 2 + ifloat: 2 + ifloat128: 2 + ildouble: 3 +@@ -954,11 +954,11 @@ ildouble: 3 + ldouble: 3 + + Function: Real part of "ccosh_towardzero": +-double: 1 +-float: 2 ++double: 2 ++float: 3 + float128: 2 +-idouble: 1 +-ifloat: 2 ++idouble: 2 ++ifloat: 3 + ifloat128: 2 + ildouble: 3 + ldouble: 3 +@@ -1075,10 +1075,10 @@ ldouble: 3 + + Function: Real part of "clog": + double: 2 +-float: 1 ++float: 3 + float128: 2 + idouble: 2 +-ifloat: 1 ++ifloat: 3 + ifloat128: 2 + ildouble: 3 + ldouble: 3 +@@ -1092,79 +1092,81 @@ ildouble: 1 + ldouble: 1 + + Function: Real part of "clog10": +-double: 2 +-float: 2 ++double: 3 ++float: 4 + float128: 2 +-idouble: 2 +-ifloat: 2 ++idouble: 3 ++ifloat: 4 + ifloat128: 2 + ildouble: 4 + ldouble: 4 + + Function: Imaginary part of "clog10": +-double: 1 ++double: 2 ++float: 1 + float128: 2 +-idouble: 1 ++idouble: 2 ++ifloat: 1 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: Real part of "clog10_downward": +-double: 3 +-float: 3 ++double: 4 ++float: 4 + float128: 3 +-idouble: 3 +-ifloat: 3 ++idouble: 4 ++ifloat: 4 + ifloat128: 3 + ildouble: 8 + ldouble: 8 + + Function: Imaginary part of "clog10_downward": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: Real part of "clog10_towardzero": +-double: 3 +-float: 3 ++double: 5 ++float: 5 + float128: 4 +-idouble: 3 +-ifloat: 3 ++idouble: 5 ++ifloat: 5 + ifloat128: 4 + ildouble: 8 + ldouble: 8 + + Function: Imaginary part of "clog10_towardzero": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: Real part of "clog10_upward": +-double: 3 +-float: 3 ++double: 4 ++float: 5 + float128: 4 +-idouble: 3 +-ifloat: 3 ++idouble: 4 ++ifloat: 5 + ifloat128: 4 + ildouble: 7 + ldouble: 7 + + Function: Imaginary part of "clog10_upward": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 3 + ldouble: 3 +@@ -1191,10 +1193,10 @@ ldouble: 1 + + Function: Real part of "clog_towardzero": + double: 3 +-float: 3 ++float: 4 + float128: 3 + idouble: 3 +-ifloat: 3 ++ifloat: 4 + ifloat128: 3 + ildouble: 5 + ldouble: 5 +@@ -1230,8 +1232,10 @@ ildouble: 1 + ldouble: 1 + + Function: "cos": ++double: 1 + float: 1 + float128: 1 ++idouble: 1 + ifloat: 1 + ifloat128: 1 + ildouble: 1 +@@ -1462,7 +1466,9 @@ ildouble: 2 + ldouble: 2 + + Function: Real part of "csinh": ++float: 1 + float128: 1 ++ifloat: 1 + ifloat128: 1 + ildouble: 1 + ldouble: 1 +@@ -1478,10 +1484,10 @@ ildouble: 1 + ldouble: 1 + + Function: Real part of "csinh_downward": +-double: 1 ++double: 2 + float: 1 + float128: 2 +-idouble: 1 ++idouble: 2 + ifloat: 1 + ifloat128: 2 + ildouble: 3 +@@ -1498,11 +1504,11 @@ ildouble: 3 + ldouble: 3 + + Function: Real part of "csinh_towardzero": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 3 + ldouble: 3 +@@ -1538,79 +1544,81 @@ ildouble: 2 + ldouble: 2 + + Function: Real part of "csqrt": +-double: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: Imaginary part of "csqrt": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: Real part of "csqrt_downward": +-double: 1 +-float: 1 ++double: 4 ++float: 4 + float128: 4 +-idouble: 1 +-ifloat: 1 ++idouble: 4 ++ifloat: 4 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: Imaginary part of "csqrt_downward": +-double: 1 +-float: 1 ++double: 3 ++float: 3 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 4 + ldouble: 4 + + Function: Real part of "csqrt_towardzero": +-double: 1 +-float: 1 ++double: 3 ++float: 3 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 4 + ldouble: 4 + + Function: Imaginary part of "csqrt_towardzero": +-double: 1 +-float: 1 ++double: 3 ++float: 3 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 4 + ldouble: 4 + + Function: Real part of "csqrt_upward": +-double: 1 +-float: 1 ++double: 4 ++float: 4 + float128: 4 +-idouble: 1 +-ifloat: 1 ++idouble: 4 ++ifloat: 4 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: Imaginary part of "csqrt_upward": +-double: 1 +-float: 2 ++double: 3 ++float: 3 + float128: 3 +-idouble: 1 +-ifloat: 2 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 4 + ldouble: 4 +@@ -1626,21 +1634,21 @@ ildouble: 2 + ldouble: 2 + + Function: Imaginary part of "ctan": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 1 + ldouble: 1 + + Function: Real part of "ctan_downward": +-double: 1 +-float: 2 ++double: 6 ++float: 5 + float128: 4 +-idouble: 1 +-ifloat: 2 ++idouble: 6 ++ifloat: 5 + ifloat128: 4 + ildouble: 5 + ldouble: 5 +@@ -1656,11 +1664,11 @@ ildouble: 4 + ldouble: 4 + + Function: Real part of "ctan_towardzero": +-double: 3 +-float: 2 ++double: 5 ++float: 3 + float128: 4 +-idouble: 3 +-ifloat: 2 ++idouble: 5 ++ifloat: 3 + ifloat128: 4 + ildouble: 5 + ldouble: 5 +@@ -1677,10 +1685,10 @@ ldouble: 4 + + Function: Real part of "ctan_upward": + double: 3 +-float: 2 ++float: 4 + float128: 5 + idouble: 3 +-ifloat: 2 ++ifloat: 4 + ifloat128: 5 + ildouble: 3 + ldouble: 3 +@@ -1696,21 +1704,21 @@ ildouble: 3 + ldouble: 3 + + Function: Real part of "ctanh": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 1 + ldouble: 1 + + Function: Imaginary part of "ctanh": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 2 + ldouble: 2 +@@ -1726,11 +1734,11 @@ ildouble: 4 + ldouble: 4 + + Function: Imaginary part of "ctanh_downward": +-double: 2 +-float: 1 ++double: 6 ++float: 5 + float128: 4 +-idouble: 2 +-ifloat: 1 ++idouble: 6 ++ifloat: 5 + ifloat128: 4 + ildouble: 4 + ldouble: 4 +@@ -1746,31 +1754,31 @@ ildouble: 4 + ldouble: 4 + + Function: Imaginary part of "ctanh_towardzero": +-double: 2 +-float: 2 ++double: 5 ++float: 3 + float128: 3 +-idouble: 2 +-ifloat: 2 ++idouble: 5 ++ifloat: 3 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: Real part of "ctanh_upward": + double: 2 +-float: 1 ++float: 2 + float128: 5 + idouble: 2 +-ifloat: 1 ++ifloat: 2 + ifloat128: 5 + ildouble: 3 + ldouble: 3 + + Function: Imaginary part of "ctanh_upward": + double: 3 +-float: 2 ++float: 3 + float128: 5 + idouble: 3 +-ifloat: 2 ++ifloat: 3 + ifloat128: 5 + ildouble: 3 + ldouble: 3 +@@ -1816,41 +1824,41 @@ ildouble: 1 + ldouble: 1 + + Function: "erfc": +-double: 1 +-float: 1 ++double: 3 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 2 + ifloat128: 2 + ildouble: 3 + ldouble: 3 + + Function: "erfc_downward": +-double: 2 +-float: 3 ++double: 5 ++float: 6 + float128: 5 +-idouble: 2 +-ifloat: 3 ++idouble: 5 ++ifloat: 6 + ifloat128: 5 + ildouble: 4 + ldouble: 4 + + Function: "erfc_towardzero": +-double: 2 +-float: 2 ++double: 3 ++float: 4 + float128: 4 +-idouble: 2 +-ifloat: 2 ++idouble: 3 ++ifloat: 4 + ifloat128: 4 + ildouble: 4 + ldouble: 4 + + Function: "erfc_upward": +-double: 2 +-float: 3 ++double: 5 ++float: 6 + float128: 5 +-idouble: 2 +-ifloat: 3 ++idouble: 5 ++ifloat: 6 + ifloat128: 5 + ildouble: 5 + ldouble: 5 +@@ -1994,34 +2002,34 @@ ildouble: 4 + ldouble: 4 + + Function: "gamma": +-double: 3 ++double: 4 + float: 3 +-idouble: 3 ++idouble: 4 + ifloat: 3 + ildouble: 4 + ldouble: 4 + + Function: "gamma_downward": +-double: 4 ++double: 5 + float: 5 +-idouble: 4 ++idouble: 5 + ifloat: 5 + ildouble: 7 + ldouble: 7 + + Function: "gamma_towardzero": +-double: 4 +-float: 3 +-idouble: 4 +-ifloat: 3 ++double: 5 ++float: 4 ++idouble: 5 ++ifloat: 4 + ildouble: 7 + ldouble: 7 + + Function: "gamma_upward": +-double: 3 +-float: 4 +-idouble: 3 +-ifloat: 4 ++double: 5 ++float: 5 ++idouble: 5 ++ifloat: 5 + ildouble: 5 + ldouble: 5 + +@@ -2059,39 +2067,39 @@ ldouble: 1 + + Function: "j0": + double: 2 +-float: 1 ++float: 2 + float128: 2 + idouble: 2 +-ifloat: 1 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: "j0_downward": +-double: 1 +-float: 3 ++double: 2 ++float: 4 + float128: 4 +-idouble: 1 +-ifloat: 3 ++idouble: 2 ++ifloat: 4 + ifloat128: 4 + ildouble: 4 + ldouble: 4 + + Function: "j0_towardzero": +-double: 2 +-float: 1 ++double: 3 ++float: 2 + float128: 2 +-idouble: 2 +-ifloat: 1 ++idouble: 3 ++ifloat: 2 + ifloat128: 2 + ildouble: 5 + ldouble: 5 + + Function: "j0_upward": +-double: 2 ++double: 3 + float: 3 + float128: 5 +-idouble: 2 ++idouble: 3 + ifloat: 3 + ifloat128: 5 + ildouble: 4 +@@ -2108,111 +2116,111 @@ ildouble: 1 + ldouble: 1 + + Function: "j1_downward": +-double: 2 +-float: 2 ++double: 3 ++float: 3 + float128: 4 +-idouble: 2 +-ifloat: 2 ++idouble: 3 ++ifloat: 3 + ifloat128: 4 + ildouble: 4 + ldouble: 4 + + Function: "j1_towardzero": +-double: 2 ++double: 3 + float: 2 + float128: 4 +-idouble: 2 ++idouble: 3 + ifloat: 2 + ifloat128: 4 + ildouble: 4 + ldouble: 4 + + Function: "j1_upward": +-double: 2 +-float: 3 ++double: 3 ++float: 5 + float128: 3 +-idouble: 2 +-ifloat: 3 ++idouble: 3 ++ifloat: 5 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: "jn": +-double: 2 +-float: 3 ++double: 4 ++float: 4 + float128: 7 +-idouble: 2 +-ifloat: 3 ++idouble: 4 ++ifloat: 4 + ifloat128: 7 + ildouble: 4 + ldouble: 4 + + Function: "jn_downward": +-double: 2 +-float: 3 ++double: 5 ++float: 5 + float128: 8 +-idouble: 2 +-ifloat: 3 ++idouble: 5 ++ifloat: 5 + ifloat128: 8 + ildouble: 4 + ldouble: 4 + + Function: "jn_towardzero": +-double: 2 +-float: 3 ++double: 5 ++float: 5 + float128: 8 +-idouble: 2 +-ifloat: 3 ++idouble: 5 ++ifloat: 5 + ifloat128: 8 + ildouble: 5 + ldouble: 5 + + Function: "jn_upward": +-double: 2 +-float: 3 ++double: 5 ++float: 5 + float128: 7 +-idouble: 2 +-ifloat: 3 ++idouble: 5 ++ifloat: 5 + ifloat128: 7 + ildouble: 5 + ldouble: 5 + + Function: "lgamma": +-double: 3 ++double: 4 + float: 3 + float128: 5 +-idouble: 3 ++idouble: 4 + ifloat: 3 + ifloat128: 5 + ildouble: 4 + ldouble: 4 + + Function: "lgamma_downward": +-double: 4 ++double: 5 + float: 5 + float128: 8 +-idouble: 4 ++idouble: 5 + ifloat: 5 + ifloat128: 8 + ildouble: 7 + ldouble: 7 + + Function: "lgamma_towardzero": +-double: 4 +-float: 3 ++double: 5 ++float: 4 + float128: 5 +-idouble: 4 +-ifloat: 3 ++idouble: 5 ++ifloat: 4 + ifloat128: 5 + ildouble: 7 + ldouble: 7 + + Function: "lgamma_upward": +-double: 3 +-float: 4 ++double: 5 ++float: 5 + float128: 8 +-idouble: 3 +-ifloat: 4 ++idouble: 5 ++ifloat: 5 + ifloat128: 8 + ildouble: 5 + ldouble: 5 +@@ -2402,8 +2410,10 @@ ildouble: 4 + ldouble: 4 + + Function: "sin": ++double: 1 + float: 1 + float128: 1 ++idouble: 1 + ifloat: 1 + ifloat128: 1 + ildouble: 1 +@@ -2440,8 +2450,10 @@ ildouble: 3 + ldouble: 3 + + Function: "sincos": ++double: 1 + float: 1 + float128: 1 ++idouble: 1 + ifloat: 1 + ifloat128: 1 + ildouble: 1 +@@ -2478,39 +2490,41 @@ ildouble: 3 + ldouble: 3 + + Function: "sinh": +-double: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: "sinh_downward": +-double: 2 +-float: 1 ++double: 3 ++float: 3 + float128: 3 +-idouble: 2 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 5 + ldouble: 5 + + Function: "sinh_towardzero": + double: 2 +-float: 1 ++float: 2 + float128: 3 + idouble: 2 +-ifloat: 1 ++ifloat: 2 + ifloat128: 3 + ildouble: 4 + ldouble: 4 + + Function: "sinh_upward": + double: 4 +-float: 2 ++float: 3 + float128: 4 + idouble: 4 +-ifloat: 2 ++ifloat: 3 + ifloat128: 4 + ildouble: 5 + ldouble: 5 +@@ -2554,199 +2568,201 @@ ildouble: 2 + ldouble: 2 + + Function: "tanh": +-double: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 3 + ldouble: 3 + + Function: "tanh_downward": +-double: 1 +-float: 1 ++double: 3 ++float: 3 + float128: 4 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 4 + ildouble: 7 + ldouble: 4 + + Function: "tanh_towardzero": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: "tanh_upward": +-double: 1 +-float: 1 ++double: 3 ++float: 3 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 5 + ldouble: 4 + + Function: "tgamma": +-double: 3 +-float: 3 ++double: 5 ++float: 4 + float128: 4 +-idouble: 3 +-ifloat: 3 ++idouble: 5 ++ifloat: 4 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: "tgamma_downward": +-double: 3 +-float: 3 ++double: 6 ++float: 5 + float128: 5 +-idouble: 3 +-ifloat: 3 ++idouble: 6 ++ifloat: 5 + ifloat128: 5 + ildouble: 5 + ldouble: 5 + + Function: "tgamma_towardzero": +-double: 3 +-float: 3 ++double: 6 ++float: 4 + float128: 5 +-idouble: 3 +-ifloat: 3 ++idouble: 6 ++ifloat: 4 + ifloat128: 5 + ildouble: 5 + ldouble: 5 + + Function: "tgamma_upward": +-double: 3 +-float: 3 ++double: 5 ++float: 4 + float128: 4 +-idouble: 3 +-ifloat: 3 ++idouble: 5 ++ifloat: 4 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: "y0": +-double: 1 ++double: 2 + float: 1 + float128: 3 +-idouble: 1 ++idouble: 2 + ifloat: 1 + ifloat128: 3 + ildouble: 1 + ldouble: 1 + + Function: "y0_downward": +-double: 2 +-float: 3 ++double: 3 ++float: 4 + float128: 4 +-idouble: 2 +-ifloat: 3 ++idouble: 3 ++ifloat: 4 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: "y0_towardzero": +-double: 2 ++double: 3 + float: 3 + float128: 3 +-idouble: 2 ++idouble: 3 + ifloat: 3 + ifloat128: 3 + ildouble: 5 + ldouble: 5 + + Function: "y0_upward": +-double: 1 +-float: 3 ++double: 3 ++float: 5 + float128: 3 +-idouble: 1 +-ifloat: 3 ++idouble: 3 ++ifloat: 5 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: "y1": +-double: 2 ++double: 3 + float: 2 + float128: 2 +-idouble: 2 ++idouble: 3 + ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: "y1_downward": +-double: 2 ++double: 3 + float: 3 + float128: 4 +-idouble: 2 ++idouble: 3 + ifloat: 3 + ifloat128: 4 + ildouble: 7 + ldouble: 7 + + Function: "y1_towardzero": +-double: 2 ++double: 3 + float: 3 + float128: 2 +-idouble: 2 ++idouble: 3 + ifloat: 3 + ifloat128: 2 + ildouble: 5 + ldouble: 5 + + Function: "y1_upward": +-double: 1 ++double: 7 + float: 3 + float128: 5 +-idouble: 1 ++idouble: 7 + ifloat: 3 + ifloat128: 5 + ildouble: 7 + ldouble: 7 + + Function: "yn": +-double: 2 ++double: 3 + float: 3 + float128: 5 +-idouble: 2 ++idouble: 3 + ifloat: 3 + ifloat128: 5 + ildouble: 4 + ldouble: 4 + + Function: "yn_downward": +-double: 2 +-float: 3 ++double: 3 ++float: 4 + float128: 5 +-idouble: 2 +-ifloat: 3 ++idouble: 3 ++ifloat: 4 + ifloat128: 5 + ildouble: 5 + ldouble: 5 + + Function: "yn_towardzero": + double: 3 +-float: 3 ++float: 4 + float128: 5 + idouble: 3 +-ifloat: 3 ++ifloat: 4 + ifloat128: 5 + ildouble: 5 + ldouble: 5 + + Function: "yn_upward": +-double: 3 +-float: 3 ++double: 4 ++float: 5 + float128: 5 +-idouble: 3 +-ifloat: 3 ++idouble: 4 ++ifloat: 5 + ifloat128: 5 + ildouble: 4 + ldouble: 4 +diff --git a/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps b/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps +index 8a862ef2eb..1bc39f47e8 100644 +--- a/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps ++++ b/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps +@@ -281,20 +281,20 @@ ldouble: 1 + + Function: Real part of "cacos": + double: 1 +-float: 1 ++float: 2 + float128: 2 + idouble: 1 +-ifloat: 1 ++ifloat: 2 + ifloat128: 2 + ildouble: 1 + ldouble: 1 + + Function: Imaginary part of "cacos": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 +@@ -360,21 +360,21 @@ ildouble: 7 + ldouble: 7 + + Function: Real part of "cacosh": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: Imaginary part of "cacosh": + double: 1 +-float: 1 ++float: 2 + float128: 2 + idouble: 1 +-ifloat: 1 ++ifloat: 2 + ifloat128: 2 + ildouble: 1 + ldouble: 1 +@@ -420,10 +420,10 @@ ildouble: 2 + ldouble: 2 + + Function: Real part of "cacosh_upward": +-double: 4 ++double: 5 + float: 4 + float128: 6 +-idouble: 4 ++idouble: 5 + ifloat: 4 + ifloat128: 6 + ildouble: 5 +@@ -488,11 +488,11 @@ ildouble: 1 + ldouble: 1 + + Function: Imaginary part of "casin": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 +@@ -558,11 +558,11 @@ ildouble: 7 + ldouble: 7 + + Function: Real part of "casinh": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 +@@ -774,11 +774,11 @@ ildouble: 1 + ldouble: 1 + + Function: Real part of "catanh_upward": +-double: 2 +-float: 2 ++double: 4 ++float: 4 + float128: 4 +-idouble: 2 +-ifloat: 2 ++idouble: 4 ++ifloat: 4 + ifloat128: 4 + ildouble: 4 + ldouble: 4 +@@ -875,10 +875,10 @@ ldouble: 3 + + Function: Real part of "ccos_towardzero": + double: 1 +-float: 1 ++float: 2 + float128: 2 + idouble: 1 +-ifloat: 1 ++ifloat: 2 + ifloat128: 2 + ildouble: 3 + ldouble: 3 +@@ -934,10 +934,10 @@ ildouble: 1 + ldouble: 1 + + Function: Real part of "ccosh_downward": +-double: 1 ++double: 2 + float: 2 + float128: 2 +-idouble: 1 ++idouble: 2 + ifloat: 2 + ifloat128: 2 + ildouble: 3 +@@ -954,11 +954,11 @@ ildouble: 3 + ldouble: 3 + + Function: Real part of "ccosh_towardzero": +-double: 1 +-float: 2 ++double: 2 ++float: 3 + float128: 2 +-idouble: 1 +-ifloat: 2 ++idouble: 2 ++ifloat: 3 + ifloat128: 2 + ildouble: 3 + ldouble: 3 +@@ -1075,10 +1075,10 @@ ldouble: 3 + + Function: Real part of "clog": + double: 2 +-float: 1 ++float: 3 + float128: 2 + idouble: 2 +-ifloat: 1 ++ifloat: 3 + ifloat128: 2 + ildouble: 3 + ldouble: 3 +@@ -1092,79 +1092,81 @@ ildouble: 1 + ldouble: 1 + + Function: Real part of "clog10": +-double: 2 +-float: 2 ++double: 3 ++float: 4 + float128: 2 +-idouble: 2 +-ifloat: 2 ++idouble: 3 ++ifloat: 4 + ifloat128: 2 + ildouble: 4 + ldouble: 4 + + Function: Imaginary part of "clog10": +-double: 1 ++double: 2 ++float: 1 + float128: 2 +-idouble: 1 ++idouble: 2 ++ifloat: 1 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: Real part of "clog10_downward": +-double: 3 +-float: 3 ++double: 4 ++float: 4 + float128: 3 +-idouble: 3 +-ifloat: 3 ++idouble: 4 ++ifloat: 4 + ifloat128: 3 + ildouble: 8 + ldouble: 8 + + Function: Imaginary part of "clog10_downward": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: Real part of "clog10_towardzero": +-double: 3 +-float: 3 ++double: 5 ++float: 5 + float128: 4 +-idouble: 3 +-ifloat: 3 ++idouble: 5 ++ifloat: 5 + ifloat128: 4 + ildouble: 8 + ldouble: 8 + + Function: Imaginary part of "clog10_towardzero": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: Real part of "clog10_upward": +-double: 3 +-float: 3 ++double: 4 ++float: 5 + float128: 4 +-idouble: 3 +-ifloat: 3 ++idouble: 4 ++ifloat: 5 + ifloat128: 4 + ildouble: 8 + ldouble: 8 + + Function: Imaginary part of "clog10_upward": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 3 + ldouble: 3 +@@ -1191,10 +1193,10 @@ ldouble: 1 + + Function: Real part of "clog_towardzero": + double: 3 +-float: 3 ++float: 4 + float128: 3 + idouble: 3 +-ifloat: 3 ++ifloat: 4 + ifloat128: 3 + ildouble: 5 + ldouble: 5 +@@ -1230,7 +1232,9 @@ ildouble: 1 + ldouble: 1 + + Function: "cos": ++double: 1 + float128: 1 ++idouble: 1 + ifloat128: 1 + ildouble: 1 + ldouble: 1 +@@ -1478,10 +1482,10 @@ ildouble: 1 + ldouble: 1 + + Function: Real part of "csinh_downward": +-double: 1 ++double: 2 + float: 2 + float128: 2 +-idouble: 1 ++idouble: 2 + ifloat: 2 + ifloat128: 2 + ildouble: 3 +@@ -1498,10 +1502,10 @@ ildouble: 3 + ldouble: 3 + + Function: Real part of "csinh_towardzero": +-double: 1 ++double: 2 + float: 2 + float128: 2 +-idouble: 1 ++idouble: 2 + ifloat: 2 + ifloat128: 2 + ildouble: 3 +@@ -1538,79 +1542,81 @@ ildouble: 3 + ldouble: 3 + + Function: Real part of "csqrt": +-double: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: Imaginary part of "csqrt": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: Real part of "csqrt_downward": +-double: 1 +-float: 1 ++double: 4 ++float: 4 + float128: 4 +-idouble: 1 +-ifloat: 1 ++idouble: 4 ++ifloat: 4 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: Imaginary part of "csqrt_downward": +-double: 1 +-float: 1 ++double: 3 ++float: 3 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 4 + ldouble: 4 + + Function: Real part of "csqrt_towardzero": +-double: 1 +-float: 1 ++double: 3 ++float: 3 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 4 + ldouble: 4 + + Function: Imaginary part of "csqrt_towardzero": +-double: 1 +-float: 1 ++double: 3 ++float: 3 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 4 + ldouble: 4 + + Function: Real part of "csqrt_upward": +-double: 1 +-float: 1 ++double: 4 ++float: 4 + float128: 4 +-idouble: 1 +-ifloat: 1 ++idouble: 4 ++ifloat: 4 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: Imaginary part of "csqrt_upward": +-double: 1 +-float: 2 ++double: 3 ++float: 3 + float128: 3 +-idouble: 1 +-ifloat: 2 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 4 + ldouble: 4 +@@ -1626,21 +1632,21 @@ ildouble: 2 + ldouble: 2 + + Function: Imaginary part of "ctan": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 1 + ldouble: 1 + + Function: Real part of "ctan_downward": +-double: 1 +-float: 2 ++double: 6 ++float: 5 + float128: 4 +-idouble: 1 +-ifloat: 2 ++idouble: 6 ++ifloat: 5 + ifloat128: 4 + ildouble: 5 + ldouble: 5 +@@ -1656,31 +1662,31 @@ ildouble: 4 + ldouble: 4 + + Function: Real part of "ctan_towardzero": +-double: 3 +-float: 1 ++double: 5 ++float: 3 + float128: 4 +-idouble: 3 +-ifloat: 1 ++idouble: 5 ++ifloat: 3 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: Imaginary part of "ctan_towardzero": + double: 2 +-float: 1 ++float: 2 + float128: 5 + idouble: 2 +-ifloat: 1 ++ifloat: 2 + ifloat128: 5 + ildouble: 4 + ldouble: 4 + + Function: Real part of "ctan_upward": + double: 3 +-float: 2 ++float: 4 + float128: 5 + idouble: 3 +-ifloat: 2 ++ifloat: 4 + ifloat128: 5 + ildouble: 3 + ldouble: 3 +@@ -1696,21 +1702,21 @@ ildouble: 3 + ldouble: 3 + + Function: Real part of "ctanh": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 1 + ldouble: 1 + + Function: Imaginary part of "ctanh": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 2 + ldouble: 2 +@@ -1726,51 +1732,51 @@ ildouble: 4 + ldouble: 4 + + Function: Imaginary part of "ctanh_downward": +-double: 2 +-float: 1 ++double: 6 ++float: 5 + float128: 4 +-idouble: 2 +-ifloat: 1 ++idouble: 6 ++ifloat: 5 + ifloat128: 4 + ildouble: 4 + ldouble: 4 + + Function: Real part of "ctanh_towardzero": + double: 2 +-float: 1 ++float: 2 + float128: 5 + idouble: 2 +-ifloat: 1 ++ifloat: 2 + ifloat128: 5 + ildouble: 4 + ldouble: 4 + + Function: Imaginary part of "ctanh_towardzero": +-double: 2 +-float: 1 ++double: 5 ++float: 3 + float128: 3 +-idouble: 2 +-ifloat: 1 ++idouble: 5 ++ifloat: 3 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: Real part of "ctanh_upward": + double: 2 +-float: 1 ++float: 2 + float128: 5 + idouble: 2 +-ifloat: 1 ++ifloat: 2 + ifloat128: 5 + ildouble: 3 + ldouble: 3 + + Function: Imaginary part of "ctanh_upward": + double: 3 +-float: 2 ++float: 3 + float128: 5 + idouble: 3 +-ifloat: 2 ++ifloat: 3 + ifloat128: 5 + ildouble: 3 + ldouble: 3 +@@ -1816,41 +1822,41 @@ ildouble: 1 + ldouble: 1 + + Function: "erfc": +-double: 1 +-float: 1 ++double: 3 ++float: 2 + float128: 2 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 2 + ifloat128: 2 + ildouble: 3 + ldouble: 3 + + Function: "erfc_downward": +-double: 2 +-float: 3 ++double: 5 ++float: 6 + float128: 5 +-idouble: 2 +-ifloat: 3 ++idouble: 5 ++ifloat: 6 + ifloat128: 5 + ildouble: 4 + ldouble: 4 + + Function: "erfc_towardzero": +-double: 2 +-float: 2 ++double: 3 ++float: 4 + float128: 4 +-idouble: 2 +-ifloat: 2 ++idouble: 3 ++ifloat: 4 + ifloat128: 4 + ildouble: 4 + ldouble: 4 + + Function: "erfc_upward": +-double: 2 +-float: 3 ++double: 5 ++float: 6 + float128: 5 +-idouble: 2 +-ifloat: 3 ++idouble: 5 ++ifloat: 6 + ifloat128: 5 + ildouble: 5 + ldouble: 5 +@@ -1994,34 +2000,34 @@ ildouble: 4 + ldouble: 4 + + Function: "gamma": +-double: 3 ++double: 4 + float: 3 +-idouble: 3 ++idouble: 4 + ifloat: 3 + ildouble: 4 + ldouble: 4 + + Function: "gamma_downward": +-double: 4 ++double: 5 + float: 5 +-idouble: 4 ++idouble: 5 + ifloat: 5 + ildouble: 7 + ldouble: 7 + + Function: "gamma_towardzero": +-double: 4 ++double: 5 + float: 4 +-idouble: 4 ++idouble: 5 + ifloat: 4 + ildouble: 7 + ldouble: 7 + + Function: "gamma_upward": +-double: 3 +-float: 4 +-idouble: 3 +-ifloat: 4 ++double: 5 ++float: 5 ++idouble: 5 ++ifloat: 5 + ildouble: 6 + ldouble: 6 + +@@ -2059,39 +2065,39 @@ ldouble: 1 + + Function: "j0": + double: 2 +-float: 1 ++float: 2 + float128: 2 + idouble: 2 +-ifloat: 1 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: "j0_downward": +-double: 1 +-float: 3 ++double: 2 ++float: 4 + float128: 4 +-idouble: 1 +-ifloat: 3 ++idouble: 2 ++ifloat: 4 + ifloat128: 4 + ildouble: 4 + ldouble: 4 + + Function: "j0_towardzero": +-double: 2 +-float: 1 ++double: 3 ++float: 2 + float128: 2 +-idouble: 2 +-ifloat: 1 ++idouble: 3 ++ifloat: 2 + ifloat128: 2 + ildouble: 5 + ldouble: 5 + + Function: "j0_upward": +-double: 2 ++double: 3 + float: 3 + float128: 5 +-idouble: 2 ++idouble: 3 + ifloat: 3 + ifloat128: 5 + ildouble: 4 +@@ -2099,120 +2105,120 @@ ldouble: 4 + + Function: "j1": + double: 2 +-float: 1 ++float: 2 + float128: 4 + idouble: 2 +-ifloat: 1 ++ifloat: 2 + ifloat128: 4 + ildouble: 1 + ldouble: 1 + + Function: "j1_downward": +-double: 2 +-float: 2 ++double: 3 ++float: 3 + float128: 4 +-idouble: 2 +-ifloat: 2 ++idouble: 3 ++ifloat: 3 + ifloat128: 4 + ildouble: 4 + ldouble: 4 + + Function: "j1_towardzero": +-double: 2 ++double: 3 + float: 2 + float128: 4 +-idouble: 2 ++idouble: 3 + ifloat: 2 + ifloat128: 4 + ildouble: 4 + ldouble: 4 + + Function: "j1_upward": +-double: 2 +-float: 3 ++double: 3 ++float: 5 + float128: 3 +-idouble: 2 +-ifloat: 3 ++idouble: 3 ++ifloat: 5 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: "jn": +-double: 2 +-float: 3 ++double: 4 ++float: 4 + float128: 7 +-idouble: 2 +-ifloat: 3 ++idouble: 4 ++ifloat: 4 + ifloat128: 7 + ildouble: 4 + ldouble: 4 + + Function: "jn_downward": +-double: 2 +-float: 3 ++double: 5 ++float: 5 + float128: 8 +-idouble: 2 +-ifloat: 3 ++idouble: 5 ++ifloat: 5 + ifloat128: 8 + ildouble: 4 + ldouble: 4 + + Function: "jn_towardzero": +-double: 2 +-float: 3 ++double: 5 ++float: 5 + float128: 8 +-idouble: 2 +-ifloat: 3 ++idouble: 5 ++ifloat: 5 + ifloat128: 8 + ildouble: 5 + ldouble: 5 + + Function: "jn_upward": +-double: 2 +-float: 3 ++double: 5 ++float: 5 + float128: 7 +-idouble: 2 +-ifloat: 3 ++idouble: 5 ++ifloat: 5 + ifloat128: 7 + ildouble: 5 + ldouble: 5 + + Function: "lgamma": +-double: 3 ++double: 4 + float: 3 + float128: 5 +-idouble: 3 ++idouble: 4 + ifloat: 3 + ifloat128: 5 + ildouble: 4 + ldouble: 4 + + Function: "lgamma_downward": +-double: 4 ++double: 5 + float: 5 + float128: 8 +-idouble: 4 ++idouble: 5 + ifloat: 5 + ifloat128: 8 + ildouble: 7 + ldouble: 7 + + Function: "lgamma_towardzero": +-double: 4 ++double: 5 + float: 4 + float128: 5 +-idouble: 4 ++idouble: 5 + ifloat: 4 + ifloat128: 5 + ildouble: 7 + ldouble: 7 + + Function: "lgamma_upward": +-double: 3 +-float: 4 ++double: 5 ++float: 5 + float128: 8 +-idouble: 3 +-ifloat: 4 ++idouble: 5 ++ifloat: 5 + ifloat128: 8 + ildouble: 6 + ldouble: 6 +@@ -2402,7 +2408,9 @@ ildouble: 4 + ldouble: 4 + + Function: "sin": ++double: 1 + float128: 1 ++idouble: 1 + ifloat128: 1 + ildouble: 1 + ldouble: 1 +@@ -2432,7 +2440,9 @@ ildouble: 3 + ldouble: 3 + + Function: "sincos": ++double: 1 + float128: 1 ++idouble: 1 + ifloat128: 1 + ildouble: 1 + ldouble: 1 +@@ -2462,39 +2472,41 @@ ildouble: 3 + ldouble: 3 + + Function: "sinh": +-double: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: "sinh_downward": +-double: 2 +-float: 1 ++double: 3 ++float: 3 + float128: 3 +-idouble: 2 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 5 + ldouble: 5 + + Function: "sinh_towardzero": + double: 2 +-float: 1 ++float: 2 + float128: 3 + idouble: 2 +-ifloat: 1 ++ifloat: 2 + ifloat128: 3 + ildouble: 4 + ldouble: 4 + + Function: "sinh_upward": + double: 4 +-float: 2 ++float: 3 + float128: 4 + idouble: 4 +-ifloat: 2 ++ifloat: 3 + ifloat128: 4 + ildouble: 5 + ldouble: 5 +@@ -2538,199 +2550,201 @@ ildouble: 2 + ldouble: 2 + + Function: "tanh": +-double: 1 ++double: 2 ++float: 2 + float128: 2 +-idouble: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 2 + ildouble: 3 + ldouble: 3 + + Function: "tanh_downward": +-double: 1 +-float: 1 ++double: 3 ++float: 3 + float128: 4 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 4 + ildouble: 7 + ldouble: 4 + + Function: "tanh_towardzero": +-double: 1 +-float: 1 ++double: 2 ++float: 2 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 2 ++ifloat: 2 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: "tanh_upward": +-double: 1 +-float: 1 ++double: 3 ++float: 3 + float128: 3 +-idouble: 1 +-ifloat: 1 ++idouble: 3 ++ifloat: 3 + ifloat128: 3 + ildouble: 5 + ldouble: 4 + + Function: "tgamma": +-double: 3 +-float: 3 ++double: 5 ++float: 4 + float128: 4 +-idouble: 3 +-ifloat: 3 ++idouble: 5 ++ifloat: 4 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: "tgamma_downward": +-double: 3 ++double: 6 + float: 5 + float128: 5 +-idouble: 3 ++idouble: 6 + ifloat: 5 + ifloat128: 5 + ildouble: 5 + ldouble: 5 + + Function: "tgamma_towardzero": +-double: 4 ++double: 6 + float: 5 + float128: 5 +-idouble: 4 ++idouble: 6 + ifloat: 5 + ifloat128: 5 + ildouble: 5 + ldouble: 5 + + Function: "tgamma_upward": +-double: 4 ++double: 5 + float: 6 + float128: 4 +-idouble: 4 ++idouble: 5 + ifloat: 6 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: "y0": +-double: 1 ++double: 2 + float: 1 + float128: 3 +-idouble: 1 ++idouble: 2 + ifloat: 1 + ifloat128: 3 + ildouble: 1 + ldouble: 1 + + Function: "y0_downward": +-double: 2 +-float: 2 ++double: 3 ++float: 4 + float128: 4 +-idouble: 2 +-ifloat: 2 ++idouble: 3 ++ifloat: 4 + ifloat128: 4 + ildouble: 5 + ldouble: 5 + + Function: "y0_towardzero": +-double: 2 ++double: 3 + float: 3 + float128: 3 +-idouble: 2 ++idouble: 3 + ifloat: 3 + ifloat128: 3 + ildouble: 5 + ldouble: 5 + + Function: "y0_upward": +-double: 1 +-float: 3 ++double: 3 ++float: 5 + float128: 3 +-idouble: 1 +-ifloat: 3 ++idouble: 3 ++ifloat: 5 + ifloat128: 3 + ildouble: 3 + ldouble: 3 + + Function: "y1": +-double: 2 ++double: 3 + float: 2 + float128: 2 +-idouble: 2 ++idouble: 3 + ifloat: 2 + ifloat128: 2 + ildouble: 2 + ldouble: 2 + + Function: "y1_downward": +-double: 2 +-float: 2 ++double: 3 ++float: 4 + float128: 4 +-idouble: 2 +-ifloat: 2 ++idouble: 3 ++ifloat: 4 + ifloat128: 4 + ildouble: 7 + ldouble: 7 + + Function: "y1_towardzero": +-double: 2 +-float: 2 ++double: 3 ++float: 3 + float128: 2 +-idouble: 2 +-ifloat: 2 ++idouble: 3 ++ifloat: 3 + ifloat128: 2 + ildouble: 5 + ldouble: 5 + + Function: "y1_upward": +-double: 1 ++double: 7 + float: 3 + float128: 5 +-idouble: 1 ++idouble: 7 + ifloat: 3 + ifloat128: 5 + ildouble: 7 + ldouble: 7 + + Function: "yn": +-double: 2 ++double: 3 + float: 3 + float128: 5 +-idouble: 2 ++idouble: 3 + ifloat: 3 + ifloat128: 5 + ildouble: 4 + ldouble: 4 + + Function: "yn_downward": +-double: 2 +-float: 2 ++double: 3 ++float: 4 + float128: 5 +-idouble: 2 +-ifloat: 2 ++idouble: 3 ++ifloat: 4 + ifloat128: 5 + ildouble: 5 + ldouble: 5 + + Function: "yn_towardzero": + double: 3 +-float: 3 ++float: 4 + float128: 5 + idouble: 3 +-ifloat: 3 ++ifloat: 4 + ifloat128: 5 + ildouble: 5 + ldouble: 5 + + Function: "yn_upward": +-double: 3 +-float: 3 ++double: 4 ++float: 5 + float128: 5 +-idouble: 3 +-ifloat: 3 ++idouble: 4 ++ifloat: 5 + ifloat128: 5 + ildouble: 4 + ldouble: 4 +diff --git a/sysdeps/i386/i686/multiarch/strncmp-c.c b/sysdeps/i386/i686/multiarch/strncmp-c.c +index cc059da494..2e3eca9b2b 100644 +--- a/sysdeps/i386/i686/multiarch/strncmp-c.c ++++ b/sysdeps/i386/i686/multiarch/strncmp-c.c +@@ -1,4 +1,4 @@ +-#ifdef SHARED ++#if defined (SHARED) && IS_IN (libc) + # define STRNCMP __strncmp_ia32 + # undef libc_hidden_builtin_def + # define libc_hidden_builtin_def(name) \ +diff --git a/sysdeps/ia64/fpu/e_exp2f.S b/sysdeps/ia64/fpu/e_exp2f.S +index 77bc6ea686..3010a95a2d 100644 +--- a/sysdeps/ia64/fpu/e_exp2f.S ++++ b/sysdeps/ia64/fpu/e_exp2f.S +@@ -221,7 +221,7 @@ LOCAL_OBJECT_END(T_table) + + + .section .text +-GLOBAL_LIBM_ENTRY(__exp2f) ++WEAK_LIBM_ENTRY(exp2f) + + + {.mfi +@@ -468,10 +468,10 @@ OUT_RANGE_exp2: + } + ;; + +-GLOBAL_LIBM_END(__exp2f) ++WEAK_LIBM_END(exp2f) + libm_alias_float_other (__exp2, exp2) + #ifdef SHARED +-.symver __exp2f,exp2f@@GLIBC_2.27 ++.symver exp2f,exp2f@@GLIBC_2.27 + .weak __exp2f_compat + .set __exp2f_compat,__exp2f + .symver __exp2f_compat,exp2f@GLIBC_2.2 +diff --git a/sysdeps/ia64/fpu/e_log2f.S b/sysdeps/ia64/fpu/e_log2f.S +index 5ca3bd61ea..e4ea094344 100644 +--- a/sysdeps/ia64/fpu/e_log2f.S ++++ b/sysdeps/ia64/fpu/e_log2f.S +@@ -252,7 +252,7 @@ LOCAL_OBJECT_END(T_table) + + + .section .text +-GLOBAL_LIBM_ENTRY(__log2f) ++WEAK_LIBM_ENTRY(log2f) + + { .mfi + alloc r32=ar.pfs,1,4,4,0 +@@ -491,10 +491,10 @@ SPECIAL_log2f: + br.ret.sptk b0;; + } + +-GLOBAL_LIBM_END(__log2f) ++WEAK_LIBM_END(log2f) + libm_alias_float_other (__log2, log2) + #ifdef SHARED +-.symver __log2f,log2f@@GLIBC_2.27 ++.symver log2f,log2f@@GLIBC_2.27 + .weak __log2f_compat + .set __log2f_compat,__log2f + .symver __log2f_compat,log2f@GLIBC_2.2 +diff --git a/sysdeps/ia64/fpu/e_powf.S b/sysdeps/ia64/fpu/e_powf.S +index 7449f8c7d5..945d5cdf28 100644 +--- a/sysdeps/ia64/fpu/e_powf.S ++++ b/sysdeps/ia64/fpu/e_powf.S +@@ -868,7 +868,7 @@ data8 0xEAC0C6E7DD24392F , 0x00003FFF + LOCAL_OBJECT_END(pow_tbl2) + + .section .text +-GLOBAL_LIBM_ENTRY(__powf) ++WEAK_LIBM_ENTRY(powf) + + // Get exponent of x. Will be used to calculate K. + { .mfi +@@ -2002,10 +2002,10 @@ POW_OVER_UNDER_ERROR: + } + ;; + +-GLOBAL_LIBM_END(__powf) ++WEAK_LIBM_END(powf) + libm_alias_float_other (__pow, pow) + #ifdef SHARED +-.symver __powf,powf@@GLIBC_2.27 ++.symver powf,powf@@GLIBC_2.27 + .weak __powf_compat + .set __powf_compat,__powf + .symver __powf_compat,powf@GLIBC_2.2 +diff --git a/sysdeps/nptl/bits/thread-shared-types.h b/sysdeps/nptl/bits/thread-shared-types.h +index 1e2092a05d..05c94e7a71 100644 +--- a/sysdeps/nptl/bits/thread-shared-types.h ++++ b/sysdeps/nptl/bits/thread-shared-types.h +@@ -124,7 +124,27 @@ struct __pthread_mutex_s + unsigned int __nusers; + #endif + /* KIND must stay at this position in the structure to maintain +- binary compatibility with static initializers. */ ++ binary compatibility with static initializers. ++ ++ Concurrency notes: ++ The __kind of a mutex is initialized either by the static ++ PTHREAD_MUTEX_INITIALIZER or by a call to pthread_mutex_init. ++ ++ After a mutex has been initialized, the __kind of a mutex is usually not ++ changed. BUT it can be set to -1 in pthread_mutex_destroy or elision can ++ be enabled. This is done concurrently in the pthread_mutex_*lock functions ++ by using the macro FORCE_ELISION. This macro is only defined for ++ architectures which supports lock elision. ++ ++ For elision, there are the flags PTHREAD_MUTEX_ELISION_NP and ++ PTHREAD_MUTEX_NO_ELISION_NP which can be set in addition to the already set ++ type of a mutex. ++ Before a mutex is initialized, only PTHREAD_MUTEX_NO_ELISION_NP can be set ++ with pthread_mutexattr_settype. ++ After a mutex has been initialized, the functions pthread_mutex_*lock can ++ enable elision - if the mutex-type and the machine supports it - by setting ++ the flag PTHREAD_MUTEX_ELISION_NP. This is done concurrently. Afterwards ++ the lock / unlock functions are using specific elision code-paths. */ + int __kind; + __PTHREAD_COMPAT_PADDING_MID + #if __PTHREAD_MUTEX_NUSERS_AFTER_KIND +diff --git a/sysdeps/nptl/lowlevellock.h b/sysdeps/nptl/lowlevellock.h +index 8326e2805c..bfbda99940 100644 +--- a/sysdeps/nptl/lowlevellock.h ++++ b/sysdeps/nptl/lowlevellock.h +@@ -181,11 +181,14 @@ extern int __lll_timedlock_wait (int *futex, const struct timespec *, + thread ID while the clone is running and is reset to zero by the kernel + afterwards. The kernel up to version 3.16.3 does not use the private futex + operations for futex wake-up when the clone terminates. */ +-#define lll_wait_tid(tid) \ +- do { \ +- __typeof (tid) __tid; \ +- while ((__tid = (tid)) != 0) \ +- lll_futex_wait (&(tid), __tid, LLL_SHARED);\ ++#define lll_wait_tid(tid) \ ++ do { \ ++ __typeof (tid) __tid; \ ++ /* We need acquire MO here so that we synchronize \ ++ with the kernel's store to 0 when the clone \ ++ terminates. (see above) */ \ ++ while ((__tid = atomic_load_acquire (&(tid))) != 0) \ ++ lll_futex_wait (&(tid), __tid, LLL_SHARED); \ + } while (0) + + extern int __lll_timedwait_tid (int *, const struct timespec *) +diff --git a/sysdeps/posix/preadv2.c b/sysdeps/posix/preadv2.c +index d29147608f..4f8557ac83 100644 +--- a/sysdeps/posix/preadv2.c ++++ b/sysdeps/posix/preadv2.c +@@ -33,7 +33,10 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset, + return -1; + } + +- return preadv (fd, vector, count, offset); ++ if (offset == -1) ++ return __readv (fd, vector, count); ++ else ++ return preadv (fd, vector, count, offset); + } + + #endif +diff --git a/sysdeps/posix/preadv64v2.c b/sysdeps/posix/preadv64v2.c +index a4844b145c..f89ad08c54 100644 +--- a/sysdeps/posix/preadv64v2.c ++++ b/sysdeps/posix/preadv64v2.c +@@ -30,7 +30,10 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset, + return -1; + } + +- return preadv64 (fd, vector, count, offset); ++ if (offset == -1) ++ return __readv (fd, vector, count); ++ else ++ return preadv64 (fd, vector, count, offset); + } + + #ifdef __OFF_T_MATCHES_OFF64_T +diff --git a/sysdeps/posix/pwritev2.c b/sysdeps/posix/pwritev2.c +index 3abf37a810..a39304d9d9 100644 +--- a/sysdeps/posix/pwritev2.c ++++ b/sysdeps/posix/pwritev2.c +@@ -33,7 +33,10 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset, + return -1; + } + +- return pwritev (fd, vector, count, offset); ++ if (offset == -1) ++ return __writev (fd, vector, count); ++ else ++ return pwritev (fd, vector, count, offset); + } + + #endif +diff --git a/sysdeps/posix/pwritev64v2.c b/sysdeps/posix/pwritev64v2.c +index 374d2ad8a9..7a3a3239d7 100644 +--- a/sysdeps/posix/pwritev64v2.c ++++ b/sysdeps/posix/pwritev64v2.c +@@ -31,7 +31,10 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset, + return -1; + } + +- return pwritev64 (fd, vector, count, offset); ++ if (offset == -1) ++ return __writev (fd, vector, count); ++ else ++ return pwritev64 (fd, vector, count, offset); + } + + #ifdef __OFF_T_MATCHES_OFF64_T +diff --git a/sysdeps/posix/spawni.c b/sysdeps/posix/spawni.c +index 36bb5b4f78..b138ab4393 100644 +--- a/sysdeps/posix/spawni.c ++++ b/sysdeps/posix/spawni.c +@@ -310,6 +310,8 @@ __spawni (pid_t * pid, const char *file, + const posix_spawnattr_t * attrp, char *const argv[], + char *const envp[], int xflags) + { ++ /* It uses __execvpex to avoid run ENOEXEC in non compatibility mode (it ++ will be handled by maybe_script_execute). */ + return __spawnix (pid, file, acts, attrp, argv, envp, xflags, +- xflags & SPAWN_XFLAGS_USE_PATH ? __execvpe : __execve); ++ xflags & SPAWN_XFLAGS_USE_PATH ? __execvpex : __execve); + } +diff --git a/sysdeps/powerpc/powerpc64/addmul_1.S b/sysdeps/powerpc/powerpc64/addmul_1.S +index 48e3b1b290..e450d6a52c 100644 +--- a/sysdeps/powerpc/powerpc64/addmul_1.S ++++ b/sysdeps/powerpc/powerpc64/addmul_1.S +@@ -34,16 +34,27 @@ + #define N r5 + #define VL r6 + ++#define R27SAVE (-40) ++#define R28SAVE (-32) ++#define R29SAVE (-24) ++#define R30SAVE (-16) ++#define R31SAVE (-8) ++ + ENTRY_TOCLESS (FUNC, 5) +- std r31, -8(r1) ++ std r31, R31SAVE(r1) + rldicl. r0, N, 0, 62 +- std r30, -16(r1) ++ std r30, R30SAVE(r1) + cmpdi VL, r0, 2 +- std r29, -24(r1) ++ std r29, R29SAVE(r1) + addi N, N, 3 +- std r28, -32(r1) ++ std r28, R28SAVE(r1) + srdi N, N, 2 +- std r27, -40(r1) ++ std r27, R27SAVE(r1) ++ cfi_offset(r31, R31SAVE) ++ cfi_offset(r30, R30SAVE) ++ cfi_offset(r29, R29SAVE) ++ cfi_offset(r28, R28SAVE) ++ cfi_offset(r27, R27SAVE) + mtctr N + beq cr0, L(b00) + blt cr6, L(b01) +@@ -199,10 +210,10 @@ L(end): mulld r0, r9, VL + addic r11, r11, 1 + #endif + addze RP, r8 +- ld r31, -8(r1) +- ld r30, -16(r1) +- ld r29, -24(r1) +- ld r28, -32(r1) +- ld r27, -40(r1) ++ ld r31, R31SAVE(r1) ++ ld r30, R30SAVE(r1) ++ ld r29, R29SAVE(r1) ++ ld r28, R28SAVE(r1) ++ ld r27, R27SAVE(r1) + blr + END(FUNC) +diff --git a/sysdeps/powerpc/powerpc64/lshift.S b/sysdeps/powerpc/powerpc64/lshift.S +index 8b6396ee6c..855d6f2993 100644 +--- a/sysdeps/powerpc/powerpc64/lshift.S ++++ b/sysdeps/powerpc/powerpc64/lshift.S +@@ -26,11 +26,15 @@ + #define TNC r0 + #define U0 r30 + #define U1 r31 ++#define U0SAVE (-16) ++#define U1SAVE (-8) + #define RETVAL r5 + + ENTRY_TOCLESS (__mpn_lshift, 5) +- std U1, -8(r1) +- std U0, -16(r1) ++ std U1, U1SAVE(r1) ++ std U0, U0SAVE(r1) ++ cfi_offset(U1, U1SAVE) ++ cfi_offset(U0, U0SAVE) + subfic TNC, CNT, 64 + sldi r7, N, RP + add UP, UP, r7 +@@ -170,8 +174,8 @@ L(cj3): or r10, r12, r7 + L(cj2): std r10, -32(RP) + std r8, -40(RP) + +-L(ret): ld U1, -8(r1) +- ld U0, -16(r1) ++L(ret): ld U1, U1SAVE(r1) ++ ld U0, U0SAVE(r1) + mr RP, RETVAL + blr + END(__mpn_lshift) +diff --git a/sysdeps/powerpc/powerpc64/mul_1.S b/sysdeps/powerpc/powerpc64/mul_1.S +index 953ded8028..cade365258 100644 +--- a/sysdeps/powerpc/powerpc64/mul_1.S ++++ b/sysdeps/powerpc/powerpc64/mul_1.S +@@ -24,9 +24,14 @@ + #define N r5 + #define VL r6 + ++#define R26SAVE (-48) ++#define R27SAVE (-40) ++ + ENTRY_TOCLESS (__mpn_mul_1, 5) +- std r27, -40(r1) +- std r26, -48(r1) ++ std r27, R27SAVE(r1) ++ std r26, R26SAVE(r1) ++ cfi_offset(r27, R27SAVE) ++ cfi_offset(r26, R26SAVE) + li r12, 0 + ld r26, 0(UP) + +@@ -129,7 +134,7 @@ L(end): mulld r0, r26, VL + std r0, 0(RP) + std r7, 8(RP) + L(ret): addze RP, r8 +- ld r27, -40(r1) +- ld r26, -48(r1) ++ ld r27, R27SAVE(r1) ++ ld r26, R26SAVE(r1) + blr + END(__mpn_mul_1) +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index b0383bfb4c..f71d64c3ab 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -57,7 +57,8 @@ enum + }; + + #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \ +- | HWCAP_S390_EIMM | HWCAP_S390_DFP) ++ | HWCAP_S390_EIMM | HWCAP_S390_DFP \ ++ | HWCAP_S390_VX | HWCAP_S390_VXE) + + /* We cannot provide a general printing function. */ + #define _dl_procinfo(type, word) -1 +diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +index 33b87a8c46..540e93be27 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c ++++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +@@ -35,6 +35,7 @@ static struct cpu_list cpu_list[] = { + {"thunderxt88", 0x430F0A10}, + {"thunderx2t99", 0x431F0AF0}, + {"thunderx2t99p1", 0x420F5160}, ++ {"ares", 0x411FD0C0}, + {"generic", 0x0} + }; + +@@ -52,9 +53,6 @@ get_midr_from_mcpu (const char *mcpu) + static inline void + init_cpu_features (struct cpu_features *cpu_features) + { +- uint64_t hwcap_mask = GET_HWCAP_MASK(); +- uint64_t hwcap = GLRO (dl_hwcap) & hwcap_mask; +- + register uint64_t midr = UINT64_MAX; + + #if HAVE_TUNABLES +@@ -68,7 +66,7 @@ init_cpu_features (struct cpu_features *cpu_features) + allows it. */ + if (midr == UINT64_MAX) + { +- if (hwcap & HWCAP_CPUID) ++ if (GLRO (dl_hwcap) & HWCAP_CPUID) + asm volatile ("mrs %0, midr_el1" : "=r"(midr)); + else + midr = 0; +diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h +index c646f9dad1..9e315751c2 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h ++++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h +@@ -44,6 +44,9 @@ + #define IS_FALKOR(midr) (MIDR_IMPLEMENTOR(midr) == 'Q' \ + && MIDR_PARTNUM(midr) == 0xc00) + ++#define IS_ARES(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \ ++ && MIDR_PARTNUM(midr) == 0xd0c) ++ + struct cpu_features + { + uint64_t midr_el1; +diff --git a/sysdeps/unix/sysv/linux/aarch64/dl-procinfo.h b/sysdeps/unix/sysv/linux/aarch64/dl-procinfo.h +index 6887713149..f746f52c8d 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/dl-procinfo.h ++++ b/sysdeps/unix/sysv/linux/aarch64/dl-procinfo.h +@@ -27,9 +27,8 @@ + /* We cannot provide a general printing function. */ + #define _dl_procinfo(type, word) -1 + +-/* HWCAP_CPUID should be available by default to influence IFUNC as well as +- library search. */ +-#define HWCAP_IMPORTANT HWCAP_CPUID ++/* No additional library search paths. */ ++#define HWCAP_IMPORTANT HWCAP_ATOMICS + + static inline const char * + __attribute__ ((unused)) +diff --git a/sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h b/sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h +index 444edbb702..93e373c3ad 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/aarch64/sys/ptrace.h +@@ -132,8 +132,12 @@ enum __ptrace_request + #define PTRACE_SETSIGMASK PTRACE_SETSIGMASK + + /* Get seccomp BPF filters. */ +- PTRACE_SECCOMP_GET_FILTER = 0x420c ++ PTRACE_SECCOMP_GET_FILTER = 0x420c, + #define PTRACE_SECCOMP_GET_FILTER PTRACE_SECCOMP_GET_FILTER ++ ++ /* Get seccomp BPF filter metadata. */ ++ PTRACE_SECCOMP_GET_METADATA = 0x420d ++#define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + }; + + +diff --git a/sysdeps/unix/sysv/linux/arm/sys/ptrace.h b/sysdeps/unix/sysv/linux/arm/sys/ptrace.h +index fbcb9384bd..bc54a1e5e2 100644 +--- a/sysdeps/unix/sysv/linux/arm/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/arm/sys/ptrace.h +@@ -192,8 +192,12 @@ enum __ptrace_request + #define PTRACE_SETSIGMASK PTRACE_SETSIGMASK + + /* Get seccomp BPF filters. */ +- PTRACE_SECCOMP_GET_FILTER = 0x420c ++ PTRACE_SECCOMP_GET_FILTER = 0x420c, + #define PTRACE_SECCOMP_GET_FILTER PTRACE_SECCOMP_GET_FILTER ++ ++ /* Get seccomp BPF filter metadata. */ ++ PTRACE_SECCOMP_GET_METADATA = 0x420d ++#define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + }; + + +diff --git a/sysdeps/unix/sysv/linux/bits/ptrace-shared.h b/sysdeps/unix/sysv/linux/bits/ptrace-shared.h +index 960b101f94..03a779140c 100644 +--- a/sysdeps/unix/sysv/linux/bits/ptrace-shared.h ++++ b/sysdeps/unix/sysv/linux/bits/ptrace-shared.h +@@ -66,6 +66,13 @@ enum __ptrace_peeksiginfo_flags + PTRACE_PEEKSIGINFO_SHARED = (1 << 0) + }; + ++/* Argument and results of PTRACE_SECCOMP_GET_METADATA. */ ++struct __ptrace_seccomp_metadata ++{ ++ __uint64_t filter_off; /* Input: which filter. */ ++ __uint64_t flags; /* Output: filter's flags. */ ++}; ++ + /* Perform process tracing functions. REQUEST is one of the values + above, and determines the action to be taken. + For all requests except PTRACE_TRACEME, PID specifies the process to be +diff --git a/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h b/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h +index 33766d1813..43c4e009a4 100644 +--- a/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h ++++ b/sysdeps/unix/sysv/linux/bits/types/siginfo_t.h +@@ -107,7 +107,7 @@ typedef struct + /* SIGPOLL. */ + struct + { +- long int si_band; /* Band event for SIGPOLL. */ ++ __SI_BAND_TYPE si_band; /* Band event for SIGPOLL. */ + int si_fd; + } _sigpoll; + +diff --git a/sysdeps/unix/sysv/linux/bits/uio-ext.h b/sysdeps/unix/sysv/linux/bits/uio-ext.h +index 53663ed1a2..8698bc1200 100644 +--- a/sysdeps/unix/sysv/linux/bits/uio-ext.h ++++ b/sysdeps/unix/sysv/linux/bits/uio-ext.h +@@ -46,6 +46,7 @@ extern ssize_t process_vm_writev (pid_t __pid, const struct iovec *__lvec, + #define RWF_DSYNC 0x00000002 /* per-IO O_DSYNC. */ + #define RWF_SYNC 0x00000004 /* per-IO O_SYNC. */ + #define RWF_NOWAIT 0x00000008 /* per-IO nonblocking mode. */ ++#define RWF_APPEND 0x00000010 /* per-IO O_APPEND. */ + + __END_DECLS + +diff --git a/sysdeps/unix/sysv/linux/copy_file_range.c b/sysdeps/unix/sysv/linux/copy_file_range.c +index 7b1a50f752..b88b7c9e2e 100644 +--- a/sysdeps/unix/sysv/linux/copy_file_range.c ++++ b/sysdeps/unix/sysv/linux/copy_file_range.c +@@ -20,27 +20,16 @@ + #include + #include + +-/* Include the fallback implementation. */ +-#ifndef __ASSUME_COPY_FILE_RANGE +-#define COPY_FILE_RANGE_DECL static +-#define COPY_FILE_RANGE copy_file_range_compat +-#include +-#endif +- + ssize_t + copy_file_range (int infd, __off64_t *pinoff, + int outfd, __off64_t *poutoff, + size_t length, unsigned int flags) + { + #ifdef __NR_copy_file_range +- ssize_t ret = SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff, +- length, flags); +-# ifndef __ASSUME_COPY_FILE_RANGE +- if (ret == -1 && errno == ENOSYS) +- ret = copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags); +-# endif +- return ret; +-#else /* !__NR_copy_file_range */ +- return copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags); ++ return SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff, ++ length, flags); ++#else ++ __set_errno (ENOSYS); ++ return -1; + #endif + } +diff --git a/sysdeps/unix/sysv/linux/getlogin_r.c b/sysdeps/unix/sysv/linux/getlogin_r.c +index 84c51d0ecd..7a814ea92f 100644 +--- a/sysdeps/unix/sysv/linux/getlogin_r.c ++++ b/sysdeps/unix/sysv/linux/getlogin_r.c +@@ -54,6 +54,15 @@ __getlogin_r_loginuid (char *name, size_t namesize) + endp == uidbuf || *endp != '\0')) + return -1; + ++ /* If there is no login uid, linux sets /proc/self/loginid to the sentinel ++ value of, (uid_t) -1, so check if that value is set and return early to ++ avoid making unneeded nss lookups. */ ++ if (uid == (uid_t) -1) ++ { ++ __set_errno (ENXIO); ++ return ENXIO; ++ } ++ + size_t buflen = 1024; + char *buf = alloca (buflen); + bool use_malloc = false; +diff --git a/sysdeps/unix/sysv/linux/ia64/sys/ptrace.h b/sysdeps/unix/sysv/linux/ia64/sys/ptrace.h +index 1c73b9dee6..e00b1212fc 100644 +--- a/sysdeps/unix/sysv/linux/ia64/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/ia64/sys/ptrace.h +@@ -145,8 +145,12 @@ enum __ptrace_request + #define PTRACE_SETSIGMASK PTRACE_SETSIGMASK + + /* Get seccomp BPF filters. */ +- PTRACE_SECCOMP_GET_FILTER = 0x420c ++ PTRACE_SECCOMP_GET_FILTER = 0x420c, + #define PTRACE_SECCOMP_GET_FILTER PTRACE_SECCOMP_GET_FILTER ++ ++ /* Get seccomp BPF filter metadata. */ ++ PTRACE_SECCOMP_GET_METADATA = 0x420d ++#define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + }; + + +diff --git a/sysdeps/unix/sysv/linux/if_index.c b/sysdeps/unix/sysv/linux/if_index.c +index e3d08982d9..782fc5e175 100644 +--- a/sysdeps/unix/sysv/linux/if_index.c ++++ b/sysdeps/unix/sysv/linux/if_index.c +@@ -38,11 +38,6 @@ __if_nametoindex (const char *ifname) + return 0; + #else + struct ifreq ifr; +- int fd = __opensock (); +- +- if (fd < 0) +- return 0; +- + if (strlen (ifname) >= IFNAMSIZ) + { + __set_errno (ENODEV); +@@ -50,6 +45,12 @@ __if_nametoindex (const char *ifname) + } + + strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); ++ ++ int fd = __opensock (); ++ ++ if (fd < 0) ++ return 0; ++ + if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0) + { + int saved_errno = errno; +diff --git a/sysdeps/unix/sysv/linux/ifaddrs.c b/sysdeps/unix/sysv/linux/ifaddrs.c +index 32381f54e4..ac0e1e5738 100644 +--- a/sysdeps/unix/sysv/linux/ifaddrs.c ++++ b/sysdeps/unix/sysv/linux/ifaddrs.c +@@ -370,6 +370,14 @@ getifaddrs_internal (struct ifaddrs **ifap) + if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq) + continue; + ++ /* If the dump got interrupted, we can't rely on the results ++ so try again. */ ++ if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) ++ { ++ result = -EAGAIN; ++ goto exit_free; ++ } ++ + if (nlh->nlmsg_type == NLMSG_DONE) + break; /* ok */ + +diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h +index 3aa2052c71..880af1a31f 100644 +--- a/sysdeps/unix/sysv/linux/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/kernel-features.h +@@ -111,7 +111,3 @@ + #if __LINUX_KERNEL_VERSION >= 0x040400 + # define __ASSUME_MLOCK2 1 + #endif +- +-#if __LINUX_KERNEL_VERSION >= 0x040500 +-# define __ASSUME_COPY_FILE_RANGE 1 +-#endif +diff --git a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h +index 745f899911..e0e6483c91 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h +@@ -52,8 +52,3 @@ + #if __LINUX_KERNEL_VERSION < 0x040000 + # undef __ASSUME_EXECVEAT + #endif +- +-/* Support for the copy_file_range syscall was added in 4.10. */ +-#if __LINUX_KERNEL_VERSION < 0x040A00 +-# undef __ASSUME_COPY_FILE_RANGE +-#endif +diff --git a/sysdeps/unix/sysv/linux/mips/Makefile b/sysdeps/unix/sysv/linux/mips/Makefile +index 8217f42e75..03044e7365 100644 +--- a/sysdeps/unix/sysv/linux/mips/Makefile ++++ b/sysdeps/unix/sysv/linux/mips/Makefile +@@ -63,14 +63,25 @@ sysdep-dl-routines += dl-static + + sysdep_routines += dl-vdso + endif +- +-# Supporting non-executable stacks on MIPS requires changes to both +-# the Linux kernel and glibc. See +-# and +-# . ++# If the compiler doesn't use GNU.stack note, ++# this test is expected to fail. ++ifneq ($(mips-has-gnustack),yes) + test-xfail-check-execstack = yes + endif ++endif + + ifeq ($(subdir),stdlib) + gen-as-const-headers += ucontext_i.sym + endif ++ ++ifeq ($(mips-force-execstack),yes) ++CFLAGS-.o += -Wa,-execstack ++CFLAGS-.os += -Wa,-execstack ++CFLAGS-.op += -Wa,-execstack ++CFLAGS-.oS += -Wa,-execstack ++ ++ASFLAGS-.o += -Wa,-execstack ++ASFLAGS-.os += -Wa,-execstack ++ASFLAGS-.op += -Wa,-execstack ++ASFLAGS-.oS += -Wa,-execstack ++endif +diff --git a/sysdeps/unix/sysv/linux/mips/configure b/sysdeps/unix/sysv/linux/mips/configure +index 1ee7f41a36..25f98e0c7b 100644 +--- a/sysdeps/unix/sysv/linux/mips/configure ++++ b/sysdeps/unix/sysv/linux/mips/configure +@@ -475,3 +475,44 @@ if test -z "$arch_minimum_kernel"; then + arch_minimum_kernel=4.5.0 + fi + fi ++ ++# Check if we are supposed to run on kernels older than 4.8.0. If so, ++# force executable stack to avoid potential runtime problems with fpu ++# emulation. ++# NOTE: The check below assumes that in absence of user-provided minumum_kernel ++# we will default to arch_minimum_kernel which is currently less than 4.8.0 for ++# all known configurations. If this changes, the check must be updated. ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler must use executable stack" >&5 ++$as_echo_n "checking whether the compiler must use executable stack... " >&6; } ++if ${libc_cv_mips_force_execstack+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ libc_cv_mips_force_execstack=no ++ if test $libc_mips_float = hard; then ++ if test -n "$minimum_kernel"; then ++ ++ min_version=$((`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \* 65536 + \2 \* 256 + \3/'`)) ++ ++ if test $min_version -lt 264192; then ++ libc_cv_mips_force_execstack=yes ++ fi ++ else ++ libc_cv_mips_force_execstack=yes ++ fi ++ fi ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_mips_force_execstack" >&5 ++$as_echo "$libc_cv_mips_force_execstack" >&6; } ++ ++libc_mips_has_gnustack=$libc_cv_as_noexecstack ++ ++if test $libc_cv_mips_force_execstack = yes; then ++ libc_mips_has_gnustack=no ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: forcing executable stack for pre-4.8.0 Linux kernels" >&5 ++$as_echo "$as_me: WARNING: forcing executable stack for pre-4.8.0 Linux kernels" >&2;} ++fi ++ ++config_vars="$config_vars ++mips-force-execstack = ${libc_cv_mips_force_execstack}" ++config_vars="$config_vars ++mips-has-gnustack = ${libc_mips_has_gnustack}" +diff --git a/sysdeps/unix/sysv/linux/mips/configure.ac b/sysdeps/unix/sysv/linux/mips/configure.ac +index 9147aa4582..3db1b32b08 100644 +--- a/sysdeps/unix/sysv/linux/mips/configure.ac ++++ b/sysdeps/unix/sysv/linux/mips/configure.ac +@@ -134,3 +134,35 @@ if test -z "$arch_minimum_kernel"; then + arch_minimum_kernel=4.5.0 + fi + fi ++ ++# Check if we are supposed to run on kernels older than 4.8.0. If so, ++# force executable stack to avoid potential runtime problems with fpu ++# emulation. ++# NOTE: The check below assumes that in absence of user-provided minumum_kernel ++# we will default to arch_minimum_kernel which is currently less than 4.8.0 for ++# all known configurations. If this changes, the check must be updated. ++AC_CACHE_CHECK([whether the compiler must use executable stack], ++ libc_cv_mips_force_execstack, [dnl ++libc_cv_mips_force_execstack=no ++ if test $libc_mips_float = hard; then ++ if test -n "$minimum_kernel"; then ++ changequote(,) ++ min_version=$((`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \* 65536 + \2 \* 256 + \3/'`)) ++ changequote([,]) ++ if test $min_version -lt 264192; then ++ libc_cv_mips_force_execstack=yes ++ fi ++ else ++ libc_cv_mips_force_execstack=yes ++ fi ++ fi]) ++ ++libc_mips_has_gnustack=$libc_cv_as_noexecstack ++ ++if test $libc_cv_mips_force_execstack = yes; then ++ libc_mips_has_gnustack=no ++ AC_MSG_WARN([forcing executable stack for pre-4.8.0 Linux kernels]) ++fi ++ ++LIBC_CONFIG_VAR([mips-force-execstack],[${libc_cv_mips_force_execstack}]) ++LIBC_CONFIG_VAR([mips-has-gnustack],[${libc_mips_has_gnustack}]) +diff --git a/sysdeps/unix/sysv/linux/mips/mmap_info.h b/sysdeps/unix/sysv/linux/mips/mmap_info.h +new file mode 100644 +index 0000000000..07c9e3a044 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/mips/mmap_info.h +@@ -0,0 +1,13 @@ ++/* mips64n32 uses __NR_mmap for mmap64 while still having sizeof (off_t) ++ smaller than sizeof (off64_t). So it allows mapping large offsets ++ using mmap64 than 32-bit archs which uses __NR_mmap2. */ ++ ++static inline uint64_t ++mmap64_maximum_offset (long int page_shift) ++{ ++#if _MIPS_SIM == _ABIN32 || _MIPS_SIM == _ABI64 ++ return UINT64_MAX; ++#else ++ return (UINT64_C(1) << (page_shift + (8 * sizeof (off_t)))) - 1; ++#endif ++} +diff --git a/sysdeps/unix/sysv/linux/mmap64.c b/sysdeps/unix/sysv/linux/mmap64.c +index 118624185e..5d7598b4ba 100644 +--- a/sysdeps/unix/sysv/linux/mmap64.c ++++ b/sysdeps/unix/sysv/linux/mmap64.c +@@ -23,11 +23,18 @@ + #include + #include + ++#ifdef __NR_mmap2 + /* To avoid silent truncation of offset when using mmap2, do not accept + offset larger than 1 << (page_shift + off_t bits). For archictures with + 32 bits off_t and page size of 4096 it would be 1^44. */ +-#define MMAP_OFF_HIGH_MASK \ ++# define MMAP_OFF_HIGH_MASK \ + ((-(MMAP2_PAGE_UNIT << 1) << (8 * sizeof (off_t) - 1))) ++#else ++/* Some ABIs might use __NR_mmap while having sizeof (off_t) smaller than ++ sizeof (off64_t) (currently only MIPS64n32). For this case just set ++ zero the higher bits so mmap with large offset does not fail. */ ++# define MMAP_OFF_HIGH_MASK 0x0 ++#endif + + #define MMAP_OFF_MASK (MMAP_OFF_HIGH_MASK | MMAP_OFF_LOW_MASK) + +diff --git a/sysdeps/unix/sysv/linux/powerpc/force-elision.h b/sysdeps/unix/sysv/linux/powerpc/force-elision.h +index fe5d6ceade..d8f5a4b1c7 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/force-elision.h ++++ b/sysdeps/unix/sysv/linux/powerpc/force-elision.h +@@ -18,9 +18,45 @@ + + /* Automatically enable elision for existing user lock kinds. */ + #define FORCE_ELISION(m, s) \ +- if (__pthread_force_elision \ +- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ if (__pthread_force_elision) \ + { \ +- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ +- s; \ ++ /* See concurrency notes regarding __kind in \ ++ struct __pthread_mutex_s in \ ++ sysdeps/nptl/bits/thread-shared-types.h. \ ++ \ ++ There are the following cases for the kind of a mutex \ ++ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ ++ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ ++ only one of both flags can be set): \ ++ - both flags are not set: \ ++ This is the first lock operation for this mutex. Enable \ ++ elision as it is not enabled so far. \ ++ Note: It can happen that multiple threads are calling e.g. \ ++ pthread_mutex_lock at the same time as the first lock \ ++ operation for this mutex. Then elision is enabled for this \ ++ mutex by multiple threads. Storing with relaxed MO is enough \ ++ as all threads will store the same new value for the kind of \ ++ the mutex. But we have to ensure that we always use the \ ++ elision path regardless if this thread has enabled elision or \ ++ another one. \ ++ \ ++ - PTHREAD_MUTEX_ELISION_NP flag is set: \ ++ Elision was already enabled for this mutex by a previous lock \ ++ operation. See case above. Just use the elision path. \ ++ \ ++ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ ++ Elision was explicitly disabled by pthread_mutexattr_settype. \ ++ Do not use the elision path. \ ++ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ ++ changed after mutex initialization. */ \ ++ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ { \ ++ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ ++ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ ++ } \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ ++ { \ ++ s; \ ++ } \ + } +diff --git a/sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h b/sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h +index 8317821ab5..9fde99c748 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/powerpc/sys/ptrace.h +@@ -49,6 +49,7 @@ __BEGIN_DECLS + # undef PTRACE_POKEDATA + # undef PTRACE_POKETEXT + # undef PTRACE_SECCOMP_GET_FILTER ++# undef PTRACE_SECCOMP_GET_METADATA + # undef PTRACE_SEIZE + # undef PTRACE_SET_DEBUGREG + # undef PTRACE_SETEVRREGS +@@ -236,8 +237,12 @@ enum __ptrace_request + #define PTRACE_SETSIGMASK PTRACE_SETSIGMASK + + /* Get seccomp BPF filters. */ +- PTRACE_SECCOMP_GET_FILTER = 0x420c ++ PTRACE_SECCOMP_GET_FILTER = 0x420c, + #define PTRACE_SECCOMP_GET_FILTER PTRACE_SECCOMP_GET_FILTER ++ ++ /* Get seccomp BPF filter metadata. */ ++ PTRACE_SECCOMP_GET_METADATA = 0x420d ++#define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + }; + + +diff --git a/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c +index 06d29b1322..bb08cbc5fd 100644 +--- a/sysdeps/unix/sysv/linux/preadv2.c ++++ b/sysdeps/unix/sysv/linux/preadv2.c +@@ -32,7 +32,7 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset, + # ifdef __NR_preadv2 + ssize_t result = SYSCALL_CANCEL (preadv2, fd, vector, count, + LO_HI_LONG (offset), flags); +- if (result >= 0) ++ if (result >= 0 || errno != ENOSYS) + return result; + # endif + /* Trying to emulate the preadv2 syscall flags is troublesome: +@@ -49,7 +49,10 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset, + __set_errno (ENOTSUP); + return -1; + } +- return preadv (fd, vector, count, offset); ++ if (offset == -1) ++ return __readv (fd, vector, count); ++ else ++ return preadv (fd, vector, count, offset); + } + + #endif +diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c +index 58f7848352..b72a047347 100644 +--- a/sysdeps/unix/sysv/linux/preadv64v2.c ++++ b/sysdeps/unix/sysv/linux/preadv64v2.c +@@ -30,7 +30,7 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset, + #ifdef __NR_preadv64v2 + ssize_t result = SYSCALL_CANCEL (preadv64v2, fd, vector, count, + LO_HI_LONG (offset), flags); +- if (result >= 0) ++ if (result >= 0 || errno != ENOSYS) + return result; + #endif + /* Trying to emulate the preadv2 syscall flags is troublesome: +@@ -47,7 +47,11 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset, + __set_errno (ENOTSUP); + return -1; + } +- return preadv64 (fd, vector, count, offset); ++ ++ if (offset == -1) ++ return __readv (fd, vector, count); ++ else ++ return preadv64 (fd, vector, count, offset); + } + + #ifdef __OFF_T_MATCHES_OFF64_T +diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c +index d50d9f51f9..26333ebd43 100644 +--- a/sysdeps/unix/sysv/linux/pwritev2.c ++++ b/sysdeps/unix/sysv/linux/pwritev2.c +@@ -28,7 +28,7 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset, + # ifdef __NR_pwritev2 + ssize_t result = SYSCALL_CANCEL (pwritev2, fd, vector, count, + LO_HI_LONG (offset), flags); +- if (result >= 0) ++ if (result >= 0 || errno != ENOSYS) + return result; + # endif + /* Trying to emulate the pwritev2 syscall flags is troublesome: +@@ -45,7 +45,10 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset, + __set_errno (ENOTSUP); + return -1; + } +- return pwritev (fd, vector, count, offset); ++ if (offset == -1) ++ return __writev (fd, vector, count); ++ else ++ return pwritev (fd, vector, count, offset); + } + + #endif +diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c +index 40c2387690..17ea905aa6 100644 +--- a/sysdeps/unix/sysv/linux/pwritev64v2.c ++++ b/sysdeps/unix/sysv/linux/pwritev64v2.c +@@ -30,7 +30,7 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset, + #ifdef __NR_pwritev64v2 + ssize_t result = SYSCALL_CANCEL (pwritev64v2, fd, vector, count, + LO_HI_LONG (offset), flags); +- if (result >= 0) ++ if (result >= 0 || errno != ENOSYS) + return result; + #endif + /* Trying to emulate the pwritev2 syscall flags is troublesome: +@@ -47,7 +47,10 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset, + __set_errno (ENOTSUP); + return -1; + } +- return pwritev64 (fd, vector, count, offset); ++ if (offset == -1) ++ return __writev (fd, vector, count); ++ else ++ return pwritev64 (fd, vector, count, offset); + } + + #ifdef __OFF_T_MATCHES_OFF64_T +diff --git a/sysdeps/unix/sysv/linux/riscv/kernel_sigaction.h b/sysdeps/unix/sysv/linux/riscv/kernel_sigaction.h +new file mode 100644 +index 0000000000..2a62bcc5bc +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/riscv/kernel_sigaction.h +@@ -0,0 +1,7 @@ ++/* This is the sigaction structure from the RISC-V Linux 4.15 kernel. */ ++ ++struct kernel_sigaction { ++ __sighandler_t k_sa_handler; ++ unsigned long sa_flags; ++ sigset_t sa_mask; ++}; +diff --git a/sysdeps/unix/sysv/linux/s390/force-elision.h b/sysdeps/unix/sysv/linux/s390/force-elision.h +index d8a1b9972f..71f32367dd 100644 +--- a/sysdeps/unix/sysv/linux/s390/force-elision.h ++++ b/sysdeps/unix/sysv/linux/s390/force-elision.h +@@ -18,9 +18,45 @@ + + /* Automatically enable elision for existing user lock kinds. */ + #define FORCE_ELISION(m, s) \ +- if (__pthread_force_elision \ +- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ if (__pthread_force_elision) \ + { \ +- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ +- s; \ ++ /* See concurrency notes regarding __kind in \ ++ struct __pthread_mutex_s in \ ++ sysdeps/nptl/bits/thread-shared-types.h. \ ++ \ ++ There are the following cases for the kind of a mutex \ ++ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ ++ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ ++ only one of both flags can be set): \ ++ - both flags are not set: \ ++ This is the first lock operation for this mutex. Enable \ ++ elision as it is not enabled so far. \ ++ Note: It can happen that multiple threads are calling e.g. \ ++ pthread_mutex_lock at the same time as the first lock \ ++ operation for this mutex. Then elision is enabled for this \ ++ mutex by multiple threads. Storing with relaxed MO is enough \ ++ as all threads will store the same new value for the kind of \ ++ the mutex. But we have to ensure that we always use the \ ++ elision path regardless if this thread has enabled elision or \ ++ another one. \ ++ \ ++ - PTHREAD_MUTEX_ELISION_NP flag is set: \ ++ Elision was already enabled for this mutex by a previous lock \ ++ operation. See case above. Just use the elision path. \ ++ \ ++ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ ++ Elision was explicitly disabled by pthread_mutexattr_settype. \ ++ Do not use the elision path. \ ++ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ ++ changed after mutex initialization. */ \ ++ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ { \ ++ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ ++ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ ++ } \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ ++ { \ ++ s; \ ++ } \ + } +diff --git a/sysdeps/unix/sysv/linux/s390/sys/ptrace.h b/sysdeps/unix/sysv/linux/s390/sys/ptrace.h +index cca02489d6..d60a034b11 100644 +--- a/sysdeps/unix/sysv/linux/s390/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/s390/sys/ptrace.h +@@ -52,6 +52,7 @@ __BEGIN_DECLS + # undef PTRACE_GETSIGMASK + # undef PTRACE_SETSIGMASK + # undef PTRACE_SECCOMP_GET_FILTER ++# undef PTRACE_SECCOMP_GET_METADATA + # undef PTRACE_PEEKUSR_AREA + # undef PTRACE_POKEUSR_AREA + # undef PTRACE_GET_LAST_BREAK +@@ -193,6 +194,10 @@ enum __ptrace_request + PTRACE_SECCOMP_GET_FILTER = 0x420c, + #define PTRACE_SECCOMP_GET_FILTER PTRACE_SECCOMP_GET_FILTER + ++ /* Get seccomp BPF filter metadata. */ ++ PTRACE_SECCOMP_GET_METADATA = 0x420d, ++#define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA ++ + PTRACE_PEEKUSR_AREA = 0x5000, + #define PTRACE_PEEKUSR_AREA PTRACE_PEEKUSR_AREA + +diff --git a/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h b/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h +index 9f79715ebe..4dd35237f6 100644 +--- a/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h ++++ b/sysdeps/unix/sysv/linux/sparc/bits/siginfo-arch.h +@@ -2,7 +2,12 @@ + #ifndef _BITS_SIGINFO_ARCH_H + #define _BITS_SIGINFO_ARCH_H 1 + +-#define __SI_BAND_TYPE int ++/* The kernel uses int instead of long int (as in POSIX). In 32-bit ++ mode, we can still use long int, but in 64-bit mode, we need to ++ deviate from POSIX. */ ++#if __WORDSIZE == 64 ++# define __SI_BAND_TYPE int ++#endif + + #define __SI_SIGFAULT_ADDL \ + int _si_trapno; +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile b/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile +index 715af3df7b..218c246f16 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/Makefile +@@ -7,3 +7,8 @@ LD += -melf64_sparc + ifeq ($(subdir),stdlib) + sysdep_routines += __start_context + endif ++ ++ifeq ($(subdir),conform) ++# For bug 23821 (incorrect type of si_band). ++conformtest-xfail-conds += sparc64-linux ++endif +diff --git a/sysdeps/unix/sysv/linux/sparc/sys/ptrace.h b/sysdeps/unix/sysv/linux/sparc/sys/ptrace.h +index 9193275fac..c037734666 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/sparc/sys/ptrace.h +@@ -213,8 +213,12 @@ enum __ptrace_request + #define PTRACE_SETSIGMASK PTRACE_SETSIGMASK + + /* Get seccomp BPF filters. */ +- PTRACE_SECCOMP_GET_FILTER = 0x420c ++ PTRACE_SECCOMP_GET_FILTER = 0x420c, + #define PTRACE_SECCOMP_GET_FILTER PTRACE_SECCOMP_GET_FILTER ++ ++ /* Get seccomp BPF filter metadata. */ ++ PTRACE_SECCOMP_GET_METADATA = 0x420d ++#define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + }; + + +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index 6b699a46dd..5fa49b229e 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -101,7 +101,7 @@ maybe_script_execute (struct posix_spawn_args *args) + ptrdiff_t argc = args->argc; + + /* Construct an argument list for the shell. */ +- char *new_argv[argc + 1]; ++ char *new_argv[argc + 2]; + new_argv[0] = (char *) _PATH_BSHELL; + new_argv[1] = (char *) args->file; + if (argc > 1) +@@ -404,6 +404,8 @@ __spawni (pid_t * pid, const char *file, + const posix_spawnattr_t * attrp, char *const argv[], + char *const envp[], int xflags) + { ++ /* It uses __execvpex to avoid run ENOEXEC in non compatibility mode (it ++ will be handled by maybe_script_execute). */ + return __spawnix (pid, file, acts, attrp, argv, envp, xflags, +- xflags & SPAWN_XFLAGS_USE_PATH ? __execvpe : __execve); ++ xflags & SPAWN_XFLAGS_USE_PATH ? __execvpex :__execve); + } +diff --git a/sysdeps/unix/sysv/linux/sys/ptrace.h b/sysdeps/unix/sysv/linux/sys/ptrace.h +index 85772f348a..3c71a0ebd6 100644 +--- a/sysdeps/unix/sysv/linux/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/sys/ptrace.h +@@ -162,8 +162,12 @@ enum __ptrace_request + #define PTRACE_SETSIGMASK PTRACE_SETSIGMASK + + /* Get seccomp BPF filters. */ +- PTRACE_SECCOMP_GET_FILTER = 0x420c ++ PTRACE_SECCOMP_GET_FILTER = 0x420c, + #define PTRACE_SECCOMP_GET_FILTER PTRACE_SECCOMP_GET_FILTER ++ ++ /* Get seccomp BPF filter metadata. */ ++ PTRACE_SECCOMP_GET_METADATA = 0x420d ++#define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + }; + + +diff --git a/sysdeps/unix/sysv/linux/tile/sys/ptrace.h b/sysdeps/unix/sysv/linux/tile/sys/ptrace.h +index a1db185073..d391037ca8 100644 +--- a/sysdeps/unix/sysv/linux/tile/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/tile/sys/ptrace.h +@@ -136,8 +136,12 @@ enum __ptrace_request + #define PTRACE_SETSIGMASK PTRACE_SETSIGMASK + + /* Get seccomp BPF filters. */ +- PTRACE_SECCOMP_GET_FILTER = 0x420c ++ PTRACE_SECCOMP_GET_FILTER = 0x420c, + #define PTRACE_SECCOMP_GET_FILTER PTRACE_SECCOMP_GET_FILTER ++ ++ /* Get seccomp BPF filter metadata. */ ++ PTRACE_SECCOMP_GET_METADATA = 0x420d ++#define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + }; + + +diff --git a/sysdeps/unix/sysv/linux/x86/force-elision.h b/sysdeps/unix/sysv/linux/x86/force-elision.h +index dd659c908f..61282d6678 100644 +--- a/sysdeps/unix/sysv/linux/x86/force-elision.h ++++ b/sysdeps/unix/sysv/linux/x86/force-elision.h +@@ -18,9 +18,45 @@ + + /* Automatically enable elision for existing user lock kinds. */ + #define FORCE_ELISION(m, s) \ +- if (__pthread_force_elision \ +- && (m->__data.__kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ if (__pthread_force_elision) \ + { \ +- mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP; \ +- s; \ ++ /* See concurrency notes regarding __kind in \ ++ struct __pthread_mutex_s in \ ++ sysdeps/nptl/bits/thread-shared-types.h. \ ++ \ ++ There are the following cases for the kind of a mutex \ ++ (The mask PTHREAD_MUTEX_ELISION_FLAGS_NP covers the flags \ ++ PTHREAD_MUTEX_ELISION_NP and PTHREAD_MUTEX_NO_ELISION_NP where \ ++ only one of both flags can be set): \ ++ - both flags are not set: \ ++ This is the first lock operation for this mutex. Enable \ ++ elision as it is not enabled so far. \ ++ Note: It can happen that multiple threads are calling e.g. \ ++ pthread_mutex_lock at the same time as the first lock \ ++ operation for this mutex. Then elision is enabled for this \ ++ mutex by multiple threads. Storing with relaxed MO is enough \ ++ as all threads will store the same new value for the kind of \ ++ the mutex. But we have to ensure that we always use the \ ++ elision path regardless if this thread has enabled elision or \ ++ another one. \ ++ \ ++ - PTHREAD_MUTEX_ELISION_NP flag is set: \ ++ Elision was already enabled for this mutex by a previous lock \ ++ operation. See case above. Just use the elision path. \ ++ \ ++ - PTHREAD_MUTEX_NO_ELISION_NP flag is set: \ ++ Elision was explicitly disabled by pthread_mutexattr_settype. \ ++ Do not use the elision path. \ ++ Note: The flag PTHREAD_MUTEX_NO_ELISION_NP will never be \ ++ changed after mutex initialization. */ \ ++ int mutex_kind = atomic_load_relaxed (&((m)->__data.__kind)); \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_FLAGS_NP) == 0) \ ++ { \ ++ mutex_kind |= PTHREAD_MUTEX_ELISION_NP; \ ++ atomic_store_relaxed (&((m)->__data.__kind), mutex_kind); \ ++ } \ ++ if ((mutex_kind & PTHREAD_MUTEX_ELISION_NP) != 0) \ ++ { \ ++ s; \ ++ } \ + } +diff --git a/sysdeps/unix/sysv/linux/x86/sys/ptrace.h b/sysdeps/unix/sysv/linux/x86/sys/ptrace.h +index 60003422b3..6d4605b6ed 100644 +--- a/sysdeps/unix/sysv/linux/x86/sys/ptrace.h ++++ b/sysdeps/unix/sysv/linux/x86/sys/ptrace.h +@@ -182,8 +182,12 @@ enum __ptrace_request + #define PTRACE_SETSIGMASK PTRACE_SETSIGMASK + + /* Get seccomp BPF filters. */ +- PTRACE_SECCOMP_GET_FILTER = 0x420c ++ PTRACE_SECCOMP_GET_FILTER = 0x420c, + #define PTRACE_SECCOMP_GET_FILTER PTRACE_SECCOMP_GET_FILTER ++ ++ /* Get seccomp BPF filter metadata. */ ++ PTRACE_SECCOMP_GET_METADATA = 0x420d ++#define PTRACE_SECCOMP_GET_METADATA PTRACE_SECCOMP_GET_METADATA + }; + + +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h +index 194369174d..ac694c032e 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/dl-librecon.h +@@ -31,7 +31,8 @@ + environment variable, LD_PREFER_MAP_32BIT_EXEC. */ + #define EXTRA_LD_ENVVARS \ + case 21: \ +- if (memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0) \ ++ if (!__libc_enable_secure \ ++ && memcmp (envline, "PREFER_MAP_32BIT_EXEC", 21) == 0) \ + GLRO(dl_x86_cpu_features).feature[index_arch_Prefer_MAP_32BIT_EXEC] \ + |= bit_arch_Prefer_MAP_32BIT_EXEC; \ + break; +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 0fc3674c4b..ecc82fc6af 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -30,6 +30,20 @@ extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *) + attribute_hidden; + #endif + ++static void ++get_extended_indices (struct cpu_features *cpu_features) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ __cpuid (0x80000000, eax, ebx, ecx, edx); ++ if (eax >= 0x80000001) ++ __cpuid (0x80000001, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].eax, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ebx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ecx, ++ cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].edx); ++ ++} ++ + static void + get_common_indeces (struct cpu_features *cpu_features, + unsigned int *family, unsigned int *model, +@@ -205,6 +219,8 @@ init_cpu_features (struct cpu_features *cpu_features) + get_common_indeces (cpu_features, &family, &model, &extended_model, + &stepping); + ++ get_extended_indices (cpu_features); ++ + if (family == 0x06) + { + model += extended_model; +@@ -281,7 +297,13 @@ init_cpu_features (struct cpu_features *cpu_features) + | bit_arch_Fast_Unaligned_Copy + | bit_arch_Prefer_PMINUB_for_stringop); + break; ++ } + ++ /* Disable TSX on some Haswell processors to avoid TSX on kernels that ++ weren't updated with the latest microcode package (which disables ++ broken feature by default). */ ++ switch (model) ++ { + case 0x3f: + /* Xeon E7 v3 with stepping >= 4 has working TSX. */ + if (stepping >= 4) +@@ -324,16 +346,9 @@ init_cpu_features (struct cpu_features *cpu_features) + get_common_indeces (cpu_features, &family, &model, &extended_model, + &stepping); + +- ecx = cpu_features->cpuid[COMMON_CPUID_INDEX_1].ecx; ++ get_extended_indices (cpu_features); + +- unsigned int eax; +- __cpuid (0x80000000, eax, ebx, ecx, edx); +- if (eax >= 0x80000001) +- __cpuid (0x80000001, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].eax, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ebx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ecx, +- cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].edx); ++ ecx = cpu_features->cpuid[COMMON_CPUID_INDEX_1].ecx; + + if (HAS_ARCH_FEATURE (AVX_Usable)) + { +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index c60c2e4eeb..4588c11095 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -106,7 +106,7 @@ enum + { + COMMON_CPUID_INDEX_1 = 0, + COMMON_CPUID_INDEX_7, +- COMMON_CPUID_INDEX_80000001, /* for AMD */ ++ COMMON_CPUID_INDEX_80000001, + /* Keep the following line at the end. */ + COMMON_CPUID_INDEX_MAX + }; +@@ -202,7 +202,7 @@ extern const struct cpu_features *__get_cpu_features (void) + # define index_cpu_HTT COMMON_CPUID_INDEX_1 + # define index_cpu_BMI1 COMMON_CPUID_INDEX_7 + # define index_cpu_BMI2 COMMON_CPUID_INDEX_7 +-# define index_cpu_LZCNT COMMON_CPUID_INDEX_1 ++# define index_cpu_LZCNT COMMON_CPUID_INDEX_80000001 + # define index_cpu_MOVBE COMMON_CPUID_INDEX_1 + # define index_cpu_POPCNT COMMON_CPUID_INDEX_1 + # define index_cpu_IBT COMMON_CPUID_INDEX_7 +diff --git a/sysdeps/x86_64/memchr.S b/sysdeps/x86_64/memchr.S +index feef5d4f24..cb320257a2 100644 +--- a/sysdeps/x86_64/memchr.S ++++ b/sysdeps/x86_64/memchr.S +@@ -34,12 +34,16 @@ ENTRY(MEMCHR) + mov %edi, %ecx + + #ifdef USE_AS_WMEMCHR +- test %rdx, %rdx ++ test %RDX_LP, %RDX_LP + jz L(return_null) +- shl $2, %rdx ++ shl $2, %RDX_LP + #else ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++# endif + punpcklbw %xmm1, %xmm1 +- test %rdx, %rdx ++ test %RDX_LP, %RDX_LP + jz L(return_null) + punpcklbw %xmm1, %xmm1 + #endif +diff --git a/sysdeps/x86_64/memcmp.S b/sysdeps/x86_64/memcmp.S +index bcb4a2e88d..45918d375a 100644 +--- a/sysdeps/x86_64/memcmp.S ++++ b/sysdeps/x86_64/memcmp.S +@@ -21,14 +21,18 @@ + + .text + ENTRY (memcmp) +- test %rdx, %rdx ++#ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++#endif ++ test %RDX_LP, %RDX_LP + jz L(finz) + cmpq $1, %rdx +- jle L(finr1b) ++ jbe L(finr1b) + subq %rdi, %rsi + movq %rdx, %r10 + cmpq $32, %r10 +- jge L(gt32) ++ jae L(gt32) + /* Handle small chunks and last block of less than 32 bytes. */ + L(small): + testq $1, %r10 +@@ -156,7 +160,7 @@ L(A32): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + /* Pre-unroll to be ready for unrolled 64B loop. */ + testq $32, %rdi + jz L(A64) +@@ -178,7 +182,7 @@ L(A64): + movq %r11, %r10 + andq $-64, %r10 + cmpq %r10, %rdi +- jge L(mt32) ++ jae L(mt32) + + L(A64main): + movdqu (%rdi,%rsi), %xmm0 +@@ -216,7 +220,7 @@ L(mt32): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + + L(A32main): + movdqu (%rdi,%rsi), %xmm0 +@@ -254,7 +258,7 @@ L(ATR): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + testq $16, %rdi + jz L(ATR32) + +@@ -325,7 +329,7 @@ L(ATR64main): + movq %r11, %r10 + andq $-32, %r10 + cmpq %r10, %rdi +- jge L(mt16) ++ jae L(mt16) + + L(ATR32res): + movdqa (%rdi,%rsi), %xmm0 +diff --git a/sysdeps/x86_64/memrchr.S b/sysdeps/x86_64/memrchr.S +index b8e3fa1d87..dc82f8f73d 100644 +--- a/sysdeps/x86_64/memrchr.S ++++ b/sysdeps/x86_64/memrchr.S +@@ -24,13 +24,13 @@ + ENTRY (__memrchr) + movd %esi, %xmm1 + +- sub $16, %rdx ++ sub $16, %RDX_LP + jbe L(length_less16) + + punpcklbw %xmm1, %xmm1 + punpcklbw %xmm1, %xmm1 + +- add %rdx, %rdi ++ add %RDX_LP, %RDI_LP + pshufd $0, %xmm1, %xmm1 + + movdqu (%rdi), %xmm0 +diff --git a/sysdeps/x86_64/multiarch/memchr-avx2.S b/sysdeps/x86_64/multiarch/memchr-avx2.S +index 5f5e772554..c81da19bf0 100644 +--- a/sysdeps/x86_64/multiarch/memchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/memchr-avx2.S +@@ -40,16 +40,20 @@ + ENTRY (MEMCHR) + # ifndef USE_AS_RAWMEMCHR + /* Check for zero length. */ +- testq %rdx, %rdx ++ test %RDX_LP, %RDX_LP + jz L(null) + # endif + movl %edi, %ecx + /* Broadcast CHAR to YMM0. */ + vmovd %esi, %xmm0 + # ifdef USE_AS_WMEMCHR +- shl $2, %rdx ++ shl $2, %RDX_LP + vpbroadcastd %xmm0, %ymm0 + # else ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++# endif + vpbroadcastb %xmm0, %ymm0 + # endif + /* Check if we may cross page boundary with one vector load. */ +diff --git a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +index 30f764c393..e3a35b899e 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S ++++ b/sysdeps/x86_64/multiarch/memcmp-avx2-movbe.S +@@ -58,9 +58,12 @@ + .section .text.avx,"ax",@progbits + ENTRY (MEMCMP) + # ifdef USE_AS_WMEMCMP +- shl $2, %rdx ++ shl $2, %RDX_LP ++# elif defined __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx + # endif +- cmpq $VEC_SIZE, %rdx ++ cmp $VEC_SIZE, %RDX_LP + jb L(less_vec) + + /* From VEC to 2 * VEC. No branch when size == VEC_SIZE. */ +diff --git a/sysdeps/x86_64/multiarch/memcmp-sse4.S b/sysdeps/x86_64/multiarch/memcmp-sse4.S +index 0d96d6b775..07465dd7b4 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-sse4.S ++++ b/sysdeps/x86_64/multiarch/memcmp-sse4.S +@@ -42,13 +42,16 @@ + .section .text.sse4.1,"ax",@progbits + ENTRY (MEMCMP) + # ifdef USE_AS_WMEMCMP +- shl $2, %rdx ++ shl $2, %RDX_LP ++# elif defined __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx + # endif + pxor %xmm0, %xmm0 +- cmp $79, %rdx ++ cmp $79, %RDX_LP + ja L(79bytesormore) + # ifndef USE_AS_WMEMCMP +- cmp $1, %rdx ++ cmp $1, %RDX_LP + je L(firstbyte) + # endif + add %rdx, %rsi +diff --git a/sysdeps/x86_64/multiarch/memcmp-ssse3.S b/sysdeps/x86_64/multiarch/memcmp-ssse3.S +index 6f76c64123..69d030fc00 100644 +--- a/sysdeps/x86_64/multiarch/memcmp-ssse3.S ++++ b/sysdeps/x86_64/multiarch/memcmp-ssse3.S +@@ -33,9 +33,12 @@ + atom_text_section + ENTRY (MEMCMP) + # ifdef USE_AS_WMEMCMP +- shl $2, %rdx +- test %rdx, %rdx ++ shl $2, %RDX_LP ++ test %RDX_LP, %RDX_LP + jz L(equal) ++# elif defined __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx + # endif + mov %rdx, %rcx + mov %rdi, %rdx +diff --git a/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S b/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S +index 7e37035487..d5af5868fa 100644 +--- a/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S ++++ b/sysdeps/x86_64/multiarch/memcpy-ssse3-back.S +@@ -45,28 +45,33 @@ + .section .text.ssse3,"ax",@progbits + #if !defined USE_AS_MEMPCPY && !defined USE_AS_MEMMOVE + ENTRY (MEMPCPY_CHK) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMPCPY_CHK) + + ENTRY (MEMPCPY) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start) + END (MEMPCPY) + #endif + + #if !defined USE_AS_BCOPY + ENTRY (MEMCPY_CHK) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMCPY_CHK) + #endif + + ENTRY (MEMCPY) +- mov %rdi, %rax ++ mov %RDI_LP, %RAX_LP + #ifdef USE_AS_MEMPCPY +- add %rdx, %rax ++ add %RDX_LP, %RAX_LP ++#endif ++ ++#ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx + #endif + + #ifdef USE_AS_MEMMOVE +diff --git a/sysdeps/x86_64/multiarch/memcpy-ssse3.S b/sysdeps/x86_64/multiarch/memcpy-ssse3.S +index 5dd209034b..366626f33a 100644 +--- a/sysdeps/x86_64/multiarch/memcpy-ssse3.S ++++ b/sysdeps/x86_64/multiarch/memcpy-ssse3.S +@@ -45,28 +45,33 @@ + .section .text.ssse3,"ax",@progbits + #if !defined USE_AS_MEMPCPY && !defined USE_AS_MEMMOVE + ENTRY (MEMPCPY_CHK) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMPCPY_CHK) + + ENTRY (MEMPCPY) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start) + END (MEMPCPY) + #endif + + #if !defined USE_AS_BCOPY + ENTRY (MEMCPY_CHK) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMCPY_CHK) + #endif + + ENTRY (MEMCPY) +- mov %rdi, %rax ++ mov %RDI_LP, %RAX_LP + #ifdef USE_AS_MEMPCPY +- add %rdx, %rax ++ add %RDX_LP, %RAX_LP ++#endif ++ ++#ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx + #endif + + #ifdef USE_AS_MEMMOVE +diff --git a/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S b/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S +index 23c0f7a9ed..6ca2bbc91a 100644 +--- a/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S ++++ b/sysdeps/x86_64/multiarch/memmove-avx512-no-vzeroupper.S +@@ -24,27 +24,31 @@ + + .section .text.avx512,"ax",@progbits + ENTRY (__mempcpy_chk_avx512_no_vzeroupper) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (__mempcpy_chk_avx512_no_vzeroupper) + + ENTRY (__mempcpy_avx512_no_vzeroupper) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start) + END (__mempcpy_avx512_no_vzeroupper) + + ENTRY (__memmove_chk_avx512_no_vzeroupper) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (__memmove_chk_avx512_no_vzeroupper) + + ENTRY (__memmove_avx512_no_vzeroupper) +- mov %rdi, %rax ++ mov %RDI_LP, %RAX_LP + # ifdef USE_AS_MEMPCPY +- add %rdx, %rax ++ add %RDX_LP, %RAX_LP + # endif + L(start): ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx ++# endif + lea (%rsi, %rdx), %rcx + lea (%rdi, %rdx), %r9 + cmp $512, %rdx +@@ -336,6 +340,7 @@ L(preloop_large): + vmovups (%rsi), %zmm4 + vmovups 0x40(%rsi), %zmm5 + ++ mov %rdi, %r11 + /* Align destination for access with non-temporal stores in the loop. */ + mov %rdi, %r8 + and $-0x80, %rdi +@@ -366,8 +371,8 @@ L(gobble_256bytes_nt_loop): + cmp $256, %rdx + ja L(gobble_256bytes_nt_loop) + sfence +- vmovups %zmm4, (%rax) +- vmovups %zmm5, 0x40(%rax) ++ vmovups %zmm4, (%r11) ++ vmovups %zmm5, 0x40(%r11) + jmp L(check) + + L(preloop_large_bkw): +diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +index cbd0d077cf..be2cd1526a 100644 +--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S +@@ -107,20 +107,20 @@ + .section SECTION(.text),"ax",@progbits + #if defined SHARED && IS_IN (libc) + ENTRY (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned)) + #endif + + ENTRY (MEMPCPY_SYMBOL (__mempcpy, unaligned)) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start) + END (MEMPCPY_SYMBOL (__mempcpy, unaligned)) + + #if defined SHARED && IS_IN (libc) + ENTRY (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned)) + #endif +@@ -128,9 +128,13 @@ END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned)) + ENTRY (MEMMOVE_SYMBOL (__memmove, unaligned)) + movq %rdi, %rax + L(start): +- cmpq $VEC_SIZE, %rdx ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++# endif ++ cmp $VEC_SIZE, %RDX_LP + jb L(less_vec) +- cmpq $(VEC_SIZE * 2), %rdx ++ cmp $(VEC_SIZE * 2), %RDX_LP + ja L(more_2x_vec) + #if !defined USE_MULTIARCH || !IS_IN (libc) + L(last_2x_vec): +@@ -150,32 +154,32 @@ END (MEMMOVE_SYMBOL (__memmove, unaligned)) + + # if VEC_SIZE == 16 + ENTRY (__mempcpy_chk_erms) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (__mempcpy_chk_erms) + + /* Only used to measure performance of REP MOVSB. */ + ENTRY (__mempcpy_erms) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start_movsb) + END (__mempcpy_erms) + + ENTRY (__memmove_chk_erms) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (__memmove_chk_erms) + + ENTRY (__memmove_erms) + movq %rdi, %rax + L(start_movsb): +- movq %rdx, %rcx +- cmpq %rsi, %rdi ++ mov %RDX_LP, %RCX_LP ++ cmp %RSI_LP, %RDI_LP + jb 1f + /* Source == destination is less common. */ + je 2f +- leaq (%rsi,%rcx), %rdx +- cmpq %rdx, %rdi ++ lea (%rsi,%rcx), %RDX_LP ++ cmp %RDX_LP, %RDI_LP + jb L(movsb_backward) + 1: + rep movsb +@@ -195,20 +199,20 @@ strong_alias (__memmove_chk_erms, __memcpy_chk_erms) + + # ifdef SHARED + ENTRY (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned_erms)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMMOVE_CHK_SYMBOL (__mempcpy_chk, unaligned_erms)) + # endif + + ENTRY (MEMMOVE_SYMBOL (__mempcpy, unaligned_erms)) +- movq %rdi, %rax +- addq %rdx, %rax ++ mov %RDI_LP, %RAX_LP ++ add %RDX_LP, %RAX_LP + jmp L(start_erms) + END (MEMMOVE_SYMBOL (__mempcpy, unaligned_erms)) + + # ifdef SHARED + ENTRY (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned_erms)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned_erms)) + # endif +@@ -216,9 +220,13 @@ END (MEMMOVE_CHK_SYMBOL (__memmove_chk, unaligned_erms)) + ENTRY (MEMMOVE_SYMBOL (__memmove, unaligned_erms)) + movq %rdi, %rax + L(start_erms): +- cmpq $VEC_SIZE, %rdx ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %edx, %edx ++# endif ++ cmp $VEC_SIZE, %RDX_LP + jb L(less_vec) +- cmpq $(VEC_SIZE * 2), %rdx ++ cmp $(VEC_SIZE * 2), %RDX_LP + ja L(movsb_more_2x_vec) + L(last_2x_vec): + /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ +@@ -245,7 +253,7 @@ L(movsb): + # endif + jb L(more_8x_vec_backward) + 1: +- movq %rdx, %rcx ++ mov %RDX_LP, %RCX_LP + rep movsb + L(nop): + ret +diff --git a/sysdeps/x86_64/multiarch/memrchr-avx2.S b/sysdeps/x86_64/multiarch/memrchr-avx2.S +index b41a58bcba..ce488dd9e8 100644 +--- a/sysdeps/x86_64/multiarch/memrchr-avx2.S ++++ b/sysdeps/x86_64/multiarch/memrchr-avx2.S +@@ -32,10 +32,10 @@ ENTRY (__memrchr_avx2) + vmovd %esi, %xmm0 + vpbroadcastb %xmm0, %ymm0 + +- subq $VEC_SIZE, %rdx ++ sub $VEC_SIZE, %RDX_LP + jbe L(last_vec_or_less) + +- addq %rdx, %rdi ++ add %RDX_LP, %RDI_LP + + /* Check the last VEC_SIZE bytes. */ + vpcmpeqb (%rdi), %ymm0, %ymm1 +diff --git a/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S b/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S +index 689cc1199c..99e255195a 100644 +--- a/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S ++++ b/sysdeps/x86_64/multiarch/memset-avx512-no-vzeroupper.S +@@ -29,12 +29,16 @@ + .section .text.avx512,"ax",@progbits + #if defined PIC + ENTRY (MEMSET_CHK) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (MEMSET_CHK) + #endif + + ENTRY (MEMSET) ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx ++# endif + vpxor %xmm0, %xmm0, %xmm0 + vmovd %esi, %xmm1 + lea (%rdi, %rdx), %rsi +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index 14d1aa5beb..535e86fb90 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -75,8 +75,8 @@ + .section SECTION(.text),"ax",@progbits + #if VEC_SIZE == 16 && IS_IN (libc) + ENTRY (__bzero) +- movq %rdi, %rax /* Set return value. */ +- movq %rsi, %rdx /* Set n. */ ++ mov %RDI_LP, %RAX_LP /* Set return value. */ ++ mov %RSI_LP, %RDX_LP /* Set n. */ + pxor %xmm0, %xmm0 + jmp L(entry_from_bzero) + END (__bzero) +@@ -86,13 +86,13 @@ weak_alias (__bzero, bzero) + #if IS_IN (libc) + # if defined SHARED + ENTRY_CHK (WMEMSET_CHK_SYMBOL (__wmemset_chk, unaligned)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END_CHK (WMEMSET_CHK_SYMBOL (__wmemset_chk, unaligned)) + # endif + + ENTRY (WMEMSET_SYMBOL (__wmemset, unaligned)) +- shlq $2, %rdx ++ shl $2, %RDX_LP + WMEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) + jmp L(entry_from_bzero) + END (WMEMSET_SYMBOL (__wmemset, unaligned)) +@@ -100,13 +100,17 @@ END (WMEMSET_SYMBOL (__wmemset, unaligned)) + + #if defined SHARED && IS_IN (libc) + ENTRY_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned)) + #endif + + ENTRY (MEMSET_SYMBOL (__memset, unaligned)) + MEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx ++# endif + L(entry_from_bzero): + cmpq $VEC_SIZE, %rdx + jb L(less_vec) +@@ -122,7 +126,7 @@ END (MEMSET_SYMBOL (__memset, unaligned)) + + # if VEC_SIZE == 16 + ENTRY (__memset_chk_erms) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END (__memset_chk_erms) + +@@ -135,11 +139,11 @@ ENTRY (MEMSET_SYMBOL (__memset, erms)) + L(stosb): + /* Issue vzeroupper before rep stosb. */ + VZEROUPPER +- movq %rdx, %rcx ++ mov %RDX_LP, %RCX_LP + movzbl %sil, %eax +- movq %rdi, %rdx ++ mov %RDI_LP, %RDX_LP + rep stosb +- movq %rdx, %rax ++ mov %RDX_LP, %RAX_LP + ret + # if VEC_SIZE == 16 + END (__memset_erms) +@@ -149,16 +153,20 @@ END (MEMSET_SYMBOL (__memset, erms)) + + # if defined SHARED && IS_IN (libc) + ENTRY_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned_erms)) +- cmpq %rdx, %rcx ++ cmp %RDX_LP, %RCX_LP + jb HIDDEN_JUMPTARGET (__chk_fail) + END_CHK (MEMSET_CHK_SYMBOL (__memset_chk, unaligned_erms)) + # endif + + ENTRY (MEMSET_SYMBOL (__memset, unaligned_erms)) + MEMSET_VDUP_TO_VEC0_AND_SET_RETURN (%esi, %rdi) +- cmpq $VEC_SIZE, %rdx ++# ifdef __ILP32__ ++ /* Clear the upper 32 bits. */ ++ mov %edx, %edx ++# endif ++ cmp $VEC_SIZE, %RDX_LP + jb L(less_vec) +- cmpq $(VEC_SIZE * 2), %rdx ++ cmp $(VEC_SIZE * 2), %RDX_LP + ja L(stosb_more_2x_vec) + /* From VEC and to 2 * VEC. No branch when size == VEC_SIZE. */ + VMOVU %VEC(0), -VEC_SIZE(%rdi,%rdx) +diff --git a/sysdeps/x86_64/multiarch/strcmp-sse42.S b/sysdeps/x86_64/multiarch/strcmp-sse42.S +index 6fa0c2c7d2..4e099b56cf 100644 +--- a/sysdeps/x86_64/multiarch/strcmp-sse42.S ++++ b/sysdeps/x86_64/multiarch/strcmp-sse42.S +@@ -155,11 +155,11 @@ STRCMP_SSE42: + #endif + + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L +- test %rdx, %rdx ++ test %RDX_LP, %RDX_LP + je LABEL(strcmp_exitz) +- cmp $1, %rdx ++ cmp $1, %RDX_LP + je LABEL(Byte0) +- mov %rdx, %r11 ++ mov %RDX_LP, %R11_LP + #endif + mov %esi, %ecx + mov %edi, %eax +diff --git a/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S b/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S +index 56b748eb2c..59c742d68b 100644 +--- a/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S ++++ b/sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S +@@ -40,8 +40,8 @@ + .text + ENTRY (STRCPY) + # ifdef USE_AS_STRNCPY +- mov %rdx, %r8 +- test %r8, %r8 ++ mov %RDX_LP, %R8_LP ++ test %R8_LP, %R8_LP + jz L(ExitZero) + # endif + mov %rsi, %rcx +diff --git a/sysdeps/x86_64/multiarch/strcpy-ssse3.S b/sysdeps/x86_64/multiarch/strcpy-ssse3.S +index 9858d0c4d5..0a62814a06 100644 +--- a/sysdeps/x86_64/multiarch/strcpy-ssse3.S ++++ b/sysdeps/x86_64/multiarch/strcpy-ssse3.S +@@ -31,13 +31,13 @@ ENTRY (STRCPY) + + mov %rsi, %rcx + # ifdef USE_AS_STRNCPY +- mov %rdx, %r8 ++ mov %RDX_LP, %R8_LP + # endif + mov %rdi, %rdx + # ifdef USE_AS_STRNCPY +- test %r8, %r8 ++ test %R8_LP, %R8_LP + jz L(Exit0) +- cmp $8, %r8 ++ cmp $8, %R8_LP + jbe L(StrncpyExit8Bytes) + # endif + cmpb $0, (%rcx) +diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S +index 85d7259746..0d0f9c8d5c 100644 +--- a/sysdeps/x86_64/multiarch/strlen-avx2.S ++++ b/sysdeps/x86_64/multiarch/strlen-avx2.S +@@ -42,12 +42,15 @@ + ENTRY (STRLEN) + # ifdef USE_AS_STRNLEN + /* Check for zero length. */ +- testq %rsi, %rsi ++ test %RSI_LP, %RSI_LP + jz L(zero) + # ifdef USE_AS_WCSLEN +- shl $2, %rsi ++ shl $2, %RSI_LP ++# elif defined __ILP32__ ++ /* Clear the upper 32 bits. */ ++ movl %esi, %esi + # endif +- movq %rsi, %r8 ++ mov %RSI_LP, %R8_LP + # endif + movl %edi, %ecx + movq %rdi, %rdx +diff --git a/sysdeps/x86_64/multiarch/strncmp-sse2.S b/sysdeps/x86_64/multiarch/strncmp-sse2.S +index cc5252d826..a5ecb82b13 100644 +--- a/sysdeps/x86_64/multiarch/strncmp-sse2.S ++++ b/sysdeps/x86_64/multiarch/strncmp-sse2.S +@@ -18,10 +18,13 @@ + + #include + +-#define STRCMP __strncmp_sse2 +- +-#undef libc_hidden_builtin_def +-#define libc_hidden_builtin_def(strcmp) ++#if IS_IN (libc) ++# define STRCMP __strncmp_sse2 ++# undef libc_hidden_builtin_def ++# define libc_hidden_builtin_def(strcmp) ++#else ++# define STRCMP strncmp ++#endif + + #define USE_AS_STRNCMP + #include +diff --git a/sysdeps/x86_64/strcmp.S b/sysdeps/x86_64/strcmp.S +index de54fce647..0b16977ce6 100644 +--- a/sysdeps/x86_64/strcmp.S ++++ b/sysdeps/x86_64/strcmp.S +@@ -135,11 +135,11 @@ ENTRY (STRCMP) + * This implementation uses SSE to compare up to 16 bytes at a time. + */ + #if defined USE_AS_STRNCMP || defined USE_AS_STRNCASECMP_L +- test %rdx, %rdx ++ test %RDX_LP, %RDX_LP + je LABEL(strcmp_exitz) +- cmp $1, %rdx ++ cmp $1, %RDX_LP + je LABEL(Byte0) +- mov %rdx, %r11 ++ mov %RDX_LP, %R11_LP + #endif + mov %esi, %ecx + mov %edi, %eax +diff --git a/sysdeps/x86_64/strlen.S b/sysdeps/x86_64/strlen.S +index 01cb5fa846..f845f3d46e 100644 +--- a/sysdeps/x86_64/strlen.S ++++ b/sysdeps/x86_64/strlen.S +@@ -59,21 +59,21 @@ ENTRY(strlen) + + #ifdef AS_STRNLEN + /* Do not read anything when n==0. */ +- test %rsi, %rsi ++ test %RSI_LP, %RSI_LP + jne L(n_nonzero) + xor %rax, %rax + ret + L(n_nonzero): + # ifdef AS_WCSLEN +- shlq $2, %rsi ++ shl $2, %RSI_LP + # endif + + /* Initialize long lived registers. */ + +- add %rdi, %rsi +- mov %rsi, %r10 +- and $-64, %r10 +- mov %rsi, %r11 ++ add %RDI_LP, %RSI_LP ++ mov %RSI_LP, %R10_LP ++ and $-64, %R10_LP ++ mov %RSI_LP, %R11_LP + #endif + + pxor %xmm0, %xmm0 +diff --git a/sysdeps/x86_64/x32/Makefile b/sysdeps/x86_64/x32/Makefile +index f2ebc24fb0..8748956563 100644 +--- a/sysdeps/x86_64/x32/Makefile ++++ b/sysdeps/x86_64/x32/Makefile +@@ -4,3 +4,15 @@ ifeq ($(subdir),math) + # 64-bit llround. Add -fno-builtin-lround to silence the compiler. + CFLAGS-s_llround.c += -fno-builtin-lround + endif ++ ++ifeq ($(subdir),string) ++tests += tst-size_t-memchr tst-size_t-memcmp tst-size_t-memcpy \ ++ tst-size_t-memrchr tst-size_t-memset tst-size_t-strncasecmp \ ++ tst-size_t-strncmp tst-size_t-strncpy tst-size_t-strnlen \ ++ tst-size_t-memcmp-2 ++endif ++ ++ifeq ($(subdir),wcsmbs) ++tests += tst-size_t-wmemchr tst-size_t-wmemcmp tst-size_t-wmemset \ ++ tst-size_t-wcsncmp tst-size_t-wcsnlen ++endif +diff --git a/sysdeps/x86_64/x32/test-size_t.h b/sysdeps/x86_64/x32/test-size_t.h +new file mode 100644 +index 0000000000..78a940863e +--- /dev/null ++++ b/sysdeps/x86_64/x32/test-size_t.h +@@ -0,0 +1,35 @@ ++/* Test string/memory functions with size_t in the lower 32 bits of ++ 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define TEST_MAIN ++#include ++ ++/* On x32, parameter_t may be passed in a 64-bit register with the LEN ++ field in the lower 32 bits. When the LEN field of 64-bit register ++ is passed to string/memory function as the size_t parameter, only ++ the lower 32 bits can be used. */ ++typedef struct ++{ ++ union ++ { ++ size_t len; ++ void (*fn) (void); ++ }; ++ void *p; ++} parameter_t; +diff --git a/sysdeps/x86_64/x32/tst-size_t-memchr.c b/sysdeps/x86_64/x32/tst-size_t-memchr.c +new file mode 100644 +index 0000000000..29a3daf102 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memchr.c +@@ -0,0 +1,72 @@ ++/* Test memchr with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 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 WIDE ++# define TEST_NAME "memchr" ++#else ++# define TEST_NAME "wmemchr" ++#endif /* WIDE */ ++#include "test-size_t.h" ++ ++#ifndef WIDE ++# define MEMCHR memchr ++# define CHAR char ++# define UCHAR unsigned char ++#else ++# include ++# define MEMCHR wmemchr ++# define CHAR wchar_t ++# define UCHAR wchar_t ++#endif /* WIDE */ ++ ++IMPL (MEMCHR, 1) ++ ++typedef CHAR * (*proto_t) (const CHAR*, int, size_t); ++ ++static CHAR * ++__attribute__ ((noinline, noclone)) ++do_memchr (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, (uintptr_t) b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t src = { { page_size / sizeof (CHAR) }, buf2 }; ++ parameter_t c = { { 0 }, (void *) (uintptr_t) 0x12 }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ c.fn = impl->fn; ++ CHAR *res = do_memchr (src, c); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %p != NULL", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c +new file mode 100644 +index 0000000000..d8ae1a0813 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memcmp-2.c +@@ -0,0 +1,79 @@ ++/* Test memcmp with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define TEST_MAIN ++#ifdef WIDE ++# define TEST_NAME "wmemcmp" ++#else ++# define TEST_NAME "memcmp" ++#endif ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include ++# include ++ ++# define MEMCMP wmemcmp ++# define CHAR wchar_t ++#else ++# define MEMCMP memcmp ++# define CHAR char ++#endif ++ ++IMPL (MEMCMP, 1) ++ ++typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); ++ ++static int ++__attribute__ ((noinline, noclone)) ++do_memcmp (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size / sizeof (CHAR) }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ memcpy (buf1, buf2, page_size); ++ ++ CHAR *p = (CHAR *) buf1; ++ p[page_size / sizeof (CHAR) - 1] = (CHAR) 1; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ int res = do_memcmp (dest, src); ++ if (res >= 0) ++ { ++ error (0, 0, "Wrong result in function %s: %i >= 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-memcmp.c b/sysdeps/x86_64/x32/tst-size_t-memcmp.c +new file mode 100644 +index 0000000000..9bd6fdb45a +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memcmp.c +@@ -0,0 +1,76 @@ ++/* Test memcmp with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define TEST_MAIN ++#ifdef WIDE ++# define TEST_NAME "wmemcmp" ++#else ++# define TEST_NAME "memcmp" ++#endif ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include ++# include ++ ++# define MEMCMP wmemcmp ++# define CHAR wchar_t ++#else ++# define MEMCMP memcmp ++# define CHAR char ++#endif ++ ++IMPL (MEMCMP, 1) ++ ++typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); ++ ++static int ++__attribute__ ((noinline, noclone)) ++do_memcmp (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size / sizeof (CHAR) }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ memcpy (buf1, buf2, page_size); ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ int res = do_memcmp (dest, src); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %i != 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-memcpy.c b/sysdeps/x86_64/x32/tst-size_t-memcpy.c +new file mode 100644 +index 0000000000..66b71e1749 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memcpy.c +@@ -0,0 +1,58 @@ ++/* Test memcpy with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define TEST_NAME "memcpy" ++#include "test-size_t.h" ++ ++IMPL (memcpy, 1) ++ ++typedef void *(*proto_t) (void *, const void *, size_t); ++ ++static void * ++__attribute__ ((noinline, noclone)) ++do_memcpy (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ do_memcpy (dest, src); ++ int res = memcmp (dest.p, src.p, dest.len); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %i != 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-memrchr.c b/sysdeps/x86_64/x32/tst-size_t-memrchr.c +new file mode 100644 +index 0000000000..c83699c097 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memrchr.c +@@ -0,0 +1,57 @@ ++/* Test memrchr with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define TEST_NAME "memrchr" ++#include "test-size_t.h" ++ ++IMPL (memchr, 1) ++ ++typedef void * (*proto_t) (const void *, int, size_t); ++ ++static void * ++__attribute__ ((noinline, noclone)) ++do_memrchr (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, (uintptr_t) b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t src = { { page_size }, buf2 }; ++ parameter_t c = { { 0 }, (void *) (uintptr_t) 0x12 }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ c.fn = impl->fn; ++ void * res = do_memrchr (src, c); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %p != NULL", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-memset.c b/sysdeps/x86_64/x32/tst-size_t-memset.c +new file mode 100644 +index 0000000000..2c367af6cd +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-memset.c +@@ -0,0 +1,73 @@ ++/* Test memset with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 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 ++ . */ ++ ++#ifdef WIDE ++# define TEST_NAME "wmemset" ++#else ++# define TEST_NAME "memset" ++#endif /* WIDE */ ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include ++# define MEMSET wmemset ++# define CHAR wchar_t ++#else ++# define MEMSET memset ++# define CHAR char ++#endif /* WIDE */ ++ ++IMPL (MEMSET, 1) ++ ++typedef CHAR *(*proto_t) (CHAR *, int, size_t); ++ ++static void * ++__attribute__ ((noinline, noclone)) ++do_memset (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, (uintptr_t) b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ CHAR ch = 0x23; ++ parameter_t src = { { page_size / sizeof (CHAR) }, buf2 }; ++ parameter_t c = { { 0 }, (void *) (uintptr_t) ch }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ c.fn = impl->fn; ++ CHAR *p = (CHAR *) do_memset (src, c); ++ size_t i; ++ for (i = 0; i < src.len; i++) ++ if (p[i] != ch) ++ { ++ error (0, 0, "Wrong result in function %s", impl->name); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-strncasecmp.c b/sysdeps/x86_64/x32/tst-size_t-strncasecmp.c +new file mode 100644 +index 0000000000..862335937b +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-strncasecmp.c +@@ -0,0 +1,59 @@ ++/* Test strncaecmp with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define TEST_NAME "strncasecmp" ++#include "test-size_t.h" ++ ++IMPL (strncasecmp, 1) ++ ++typedef int (*proto_t) (const char *, const char *, size_t); ++ ++static int ++__attribute__ ((noinline, noclone)) ++do_strncasecmp (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ strncpy ((char *) buf1, (const char *) buf2, page_size); ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ int res = do_strncasecmp (dest, src); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %i != 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-strncmp.c b/sysdeps/x86_64/x32/tst-size_t-strncmp.c +new file mode 100644 +index 0000000000..54e6bd83ef +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-strncmp.c +@@ -0,0 +1,78 @@ ++/* Test strncmp with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 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 ++ . */ ++ ++#ifdef WIDE ++# define TEST_NAME "wcsncmp" ++#else ++# define TEST_NAME "strncmp" ++#endif ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include ++ ++# define STRNCMP wcsncmp ++# define STRNCPY wcsncpy ++# define CHAR wchar_t ++#else ++# define STRNCMP strncmp ++# define STRNCPY strncpy ++# define CHAR char ++#endif ++ ++IMPL (STRNCMP, 1) ++ ++typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); ++ ++ ++static int ++__attribute__ ((noinline, noclone)) ++do_strncmp (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ size_t size = page_size / sizeof (CHAR); ++ parameter_t dest = { { size }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ STRNCPY ((CHAR *) buf1, (const CHAR *) buf2, size); ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ int res = do_strncmp (dest, src); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %i != 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-strncpy.c b/sysdeps/x86_64/x32/tst-size_t-strncpy.c +new file mode 100644 +index 0000000000..4dec71e6b3 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-strncpy.c +@@ -0,0 +1,58 @@ ++/* Test strncpy with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define TEST_NAME "strncpy" ++#include "test-size_t.h" ++ ++IMPL (strncpy, 1) ++ ++typedef char *(*proto_t) (char *, const char*, size_t); ++ ++static void * ++__attribute__ ((noinline, noclone)) ++do_strncpy (parameter_t a, parameter_t b) ++{ ++ return CALL (&b, a.p, b.p, a.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ parameter_t dest = { { page_size }, buf1 }; ++ parameter_t src = { { 0 }, buf2 }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ do_strncpy (dest, src); ++ int res = strncmp (dest.p, src.p, dest.len); ++ if (res) ++ { ++ error (0, 0, "Wrong result in function %s: %i != 0", ++ impl->name, res); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-strnlen.c b/sysdeps/x86_64/x32/tst-size_t-strnlen.c +new file mode 100644 +index 0000000000..690a4a8a31 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-strnlen.c +@@ -0,0 +1,72 @@ ++/* Test strnlen with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 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 ++ . */ ++ ++#ifdef WIDE ++# define TEST_NAME "wcsnlen" ++#else ++# define TEST_NAME "strnlen" ++#endif /* WIDE */ ++ ++#include "test-size_t.h" ++ ++#ifdef WIDE ++# include ++# define STRNLEN wcsnlen ++# define CHAR wchar_t ++#else ++# define STRNLEN strnlen ++# define CHAR char ++#endif /* WIDE */ ++ ++IMPL (STRNLEN, 1) ++ ++typedef size_t (*proto_t) (const CHAR *, size_t); ++ ++static size_t ++__attribute__ ((noinline, noclone)) ++do_strnlen (parameter_t a, parameter_t b) ++{ ++ return CALL (&a, a.p, b.len); ++} ++ ++static int ++test_main (void) ++{ ++ test_init (); ++ ++ size_t size = page_size / sizeof (CHAR); ++ parameter_t src = { { 0 }, buf2 }; ++ parameter_t c = { { size }, (void *) (uintptr_t) 'a' }; ++ ++ int ret = 0; ++ FOR_EACH_IMPL (impl, 0) ++ { ++ src.fn = impl->fn; ++ size_t res = do_strnlen (src, c); ++ if (res != size) ++ { ++ error (0, 0, "Wrong result in function %s: 0x%x != 0x%x", ++ impl->name, res, size); ++ ret = 1; ++ } ++ } ++ ++ return ret ? EXIT_FAILURE : EXIT_SUCCESS; ++} ++ ++#include +diff --git a/sysdeps/x86_64/x32/tst-size_t-wcsncmp.c b/sysdeps/x86_64/x32/tst-size_t-wcsncmp.c +new file mode 100644 +index 0000000000..4829647c19 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-wcsncmp.c +@@ -0,0 +1,20 @@ ++/* Test wcsncmp with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define WIDE 1 ++#include "tst-size_t-strncmp.c" +diff --git a/sysdeps/x86_64/x32/tst-size_t-wcsnlen.c b/sysdeps/x86_64/x32/tst-size_t-wcsnlen.c +new file mode 100644 +index 0000000000..093b4bbe1b +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-wcsnlen.c +@@ -0,0 +1,20 @@ ++/* Test wcsnlen with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define WIDE 1 ++#include "tst-size_t-strnlen.c" +diff --git a/sysdeps/x86_64/x32/tst-size_t-wmemchr.c b/sysdeps/x86_64/x32/tst-size_t-wmemchr.c +new file mode 100644 +index 0000000000..877801d646 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-wmemchr.c +@@ -0,0 +1,20 @@ ++/* Test wmemchr with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define WIDE 1 ++#include "tst-size_t-memchr.c" +diff --git a/sysdeps/x86_64/x32/tst-size_t-wmemcmp.c b/sysdeps/x86_64/x32/tst-size_t-wmemcmp.c +new file mode 100644 +index 0000000000..e8b5ffd0d5 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-wmemcmp.c +@@ -0,0 +1,20 @@ ++/* Test wmemcmp with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define WIDE 1 ++#include "tst-size_t-memcmp.c" +diff --git a/sysdeps/x86_64/x32/tst-size_t-wmemset.c b/sysdeps/x86_64/x32/tst-size_t-wmemset.c +new file mode 100644 +index 0000000000..955eb488c2 +--- /dev/null ++++ b/sysdeps/x86_64/x32/tst-size_t-wmemset.c +@@ -0,0 +1,20 @@ ++/* Test wmemset with size_t in the lower 32 bits of 64-bit register. ++ Copyright (C) 2019 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#define WIDE 1 ++#include "tst-size_t-memset.c" +diff --git a/time/bits/types/struct_timespec.h b/time/bits/types/struct_timespec.h +index 644db9fdb6..5b77c52b4f 100644 +--- a/time/bits/types/struct_timespec.h ++++ b/time/bits/types/struct_timespec.h +@@ -1,5 +1,6 @@ +-#ifndef __timespec_defined +-#define __timespec_defined 1 ++/* NB: Include guard matches what uses. */ ++#ifndef _STRUCT_TIMESPEC ++#define _STRUCT_TIMESPEC 1 + + #include + diff -Nru glibc-2.27/debian/patches/series glibc-2.27/debian/patches/series --- glibc-2.27/debian/patches/series 2020-06-04 17:25:26.000000000 +0000 +++ glibc-2.27/debian/patches/series 2022-01-24 12:53:44.000000000 +0000 @@ -1,4 +1,5 @@ git-updates.diff +git-updates-2.diff locale/check-unknown-symbols.diff locale/locale-print-LANGUAGE.diff @@ -147,6 +148,7 @@ sparc/submitted-sparc64-socketcall.diff +all/branch-pthread_rwlock_trywrlock-hang-23844.patch all/local-alias-et_EE.diff all/local-remove-manual.diff all/local-ru_RU.diff @@ -183,10 +185,6 @@ any/submitted-resolv-unaligned.diff any/submitted-intl-tstgettext.diff any/local-cudacc-float128.diff -any/CVE-2018-11236.patch -any/CVE-2018-11237-1.patch -any/CVE-2018-11237-2.patch -any/CVE-2018-19591.patch # Ubuntu patches live in their own little world, to maintain sanity ubuntu/local-altlocaledir.diff @@ -202,8 +200,23 @@ ubuntu/localedata/sd_PK.diff ubuntu/localedata/ug_CN@latin.diff any/CVE-2019-9169.patch -any/CVE-2019-19126.patch any/CVE-2020-1751.patch any/CVE-2020-1752.patch any/CVE-2020-10029-1.patch any/CVE-2020-10029-2.patch +ubuntu/test-make-preadwritev2-invalid-flag-unsupported.patch +any/CVE-2016-10228-pre1.patch +any/CVE-2016-10228-1.patch +any/CVE-2016-10228-2.patch +any/CVE-2019-25013.patch +any/CVE-2020-27618.patch +any/CVE-2020-6096-3.patch +any/CVE-2020-6096-4.patch +any/CVE-2021-3326.patch +any/CVE-2021-35942.patch +any/CVE-2021-3999.patch +any/CVE-2022-23218-pre1.patch +any/CVE-2022-23218.patch +any/CVE-2022-23219.patch +any/CVE-2020-29562.patch +any/fix_test-errno-linux.patch diff -Nru glibc-2.27/debian/patches/ubuntu/test-make-preadwritev2-invalid-flag-unsupported.patch glibc-2.27/debian/patches/ubuntu/test-make-preadwritev2-invalid-flag-unsupported.patch --- glibc-2.27/debian/patches/ubuntu/test-make-preadwritev2-invalid-flag-unsupported.patch 1970-01-01 00:00:00.000000000 +0000 +++ glibc-2.27/debian/patches/ubuntu/test-make-preadwritev2-invalid-flag-unsupported.patch 2020-12-07 16:38:09.000000000 +0000 @@ -0,0 +1,31 @@ +Author: Thadeu Lima de Souza Cascardo +Forwarded: no +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1770480 +Subject: make preadwritev2 invalid flags tests unsupported + New kernels allow new flags for preadv2 and pwritev2. Instead of failing + and exiting when those test succeeds or fail with an error different from + unsupported, fail with unsupported, which is equivalent to skipping the + test instead of failing it. +Index: glibc-2.27/misc/tst-preadvwritev2-common.c +=================================================================== +--- glibc-2.27.orig/misc/tst-preadvwritev2-common.c ++++ glibc-2.27/misc/tst-preadvwritev2-common.c +@@ -42,14 +42,14 @@ do_test_with_invalid_flags (void) + char buf[32]; + const struct iovec vec = { .iov_base = buf, .iov_len = sizeof (buf) }; + if (preadv2 (temp_fd, &vec, 1, 0, invalid_flag) != -1) +- FAIL_EXIT1 ("preadv2 did not fail with an invalid flag"); ++ FAIL_UNSUPPORTED ("preadv2 did not fail with an invalid flag"); + if (errno != ENOTSUP) +- FAIL_EXIT1 ("preadv2 failure did not set errno to ENOTSUP (%d)", errno); ++ FAIL_UNSUPPORTED ("preadv2 failure did not set errno to ENOTSUP (%d)", errno); + + /* This might fail for compat syscall (32 bits running on 64 bits kernel) + due a kernel issue. */ + if (pwritev2 (temp_fd, &vec, 1, 0, invalid_flag) != -1) +- FAIL_EXIT1 ("pwritev2 did not fail with an invalid flag"); ++ FAIL_UNSUPPORTED ("pwritev2 did not fail with an invalid flag"); + if (errno != ENOTSUP) +- FAIL_EXIT1 ("pwritev2 failure did not set errno to ENOTSUP (%d)", errno); ++ FAIL_UNSUPPORTED ("pwritev2 failure did not set errno to ENOTSUP (%d)", errno); + } diff -Nru glibc-2.27/debian/rules glibc-2.27/debian/rules --- glibc-2.27/debian/rules 2018-04-16 20:02:50.000000000 +0000 +++ glibc-2.27/debian/rules 2020-12-07 16:38:09.000000000 +0000 @@ -173,6 +173,7 @@ DEBUG_$(libc) = 1 DEBUG_libc6-xen = 1 DEBUG_libc6.1-alphaev67 = 1 +DEBUG_libc6-lse = 1 ifeq ($(filter stage1,$(DEB_BUILD_PROFILES)),) ifeq ($(threads),yes) @@ -195,7 +196,7 @@ # Required Debian targets build-arch: $(stamp)info \ $(patsubst %,$(stamp)build_%,$(GLIBC_PASSES)) \ - $(patsubst %,$(stamp)check_%,$(GLIBC_PASSES)) + $(patsubst %,$(stamp)check_%,$(filter-out $(GLIBC_PASSES_NOCHECK),$(GLIBC_PASSES))) ifeq ($(filter stage1,$(DEB_BUILD_PROFILES)),) build-arch: $(stamp)build_C.UTF-8 \ $(stamp)build_locales-all diff -Nru glibc-2.27/debian/sysdeps/arm64.mk glibc-2.27/debian/sysdeps/arm64.mk --- glibc-2.27/debian/sysdeps/arm64.mk 2016-03-10 10:14:20.000000000 +0000 +++ glibc-2.27/debian/sysdeps/arm64.mk 2020-12-07 16:38:09.000000000 +0000 @@ -1,2 +1,12 @@ # configuration options for all flavours extra_config_options = --enable-multi-arch + +ifeq (,$(filter stage1 stage2, $(DEB_BUILD_PROFILES))) +# build an LSE optimized library +GLIBC_PASSES += lse +GLIBC_PASSES_NOCHECK += $(shell [ $$(dpkg --print-architecture) != arm64 ] || grep -q '^Features.*atomics' /proc/cpuinfo || echo "lse") +DEB_ARCH_REGULAR_PACKAGES += libc6-lse +lse_CC = $(CC) -march=armv8-a+lse +lse_CXX = $(CXX) -march=armv8-a+lse +lse_slibdir = /lib/$(DEB_HOST_MULTIARCH)/atomics +endif diff -Nru glibc-2.27/debian/testsuite-xfail-debian.mk glibc-2.27/debian/testsuite-xfail-debian.mk --- glibc-2.27/debian/testsuite-xfail-debian.mk 2018-04-16 20:14:20.000000000 +0000 +++ glibc-2.27/debian/testsuite-xfail-debian.mk 2020-12-07 16:38:09.000000000 +0000 @@ -15,6 +15,9 @@ # control, we'll just let it fail test-xfail-tst-create-detached = yes +# LP: #1891403 needs good entropy source +test-xfail-tst-getrandom = yes + ###################################################################### # alpha (including optimized flavours) ###################################################################### @@ -194,6 +197,7 @@ # This test is currently known to fail under lxc, where we run our ARM # regression tests, so pretend it fails on ARM: test-xfail-tst-ttyname = yes +test-xfail-tst-support_descriptors = yes # There is not support for protection key on Alpha yet, and there is a # disagreement between kernel and glibc how to report that. @@ -216,6 +220,7 @@ # This test is currently known to fail under lxc, where we run our ARM # regression tests, so pretend it fails on ARM: test-xfail-tst-ttyname = yes +test-xfail-tst-support_descriptors = yes # There is not support for protection key on Alpha yet, and there is a # disagreement between kernel and glibc how to report that.