summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes2019-07-04 15:25:01 -0400
committerTavian Barnes2019-07-04 15:25:01 -0400
commit363e369b0d94b0b33328597f90a0a910056b7990 (patch)
treea3f72cff32e1581696b8928878e0cd0a13e18c19
parentcbacff4f8fa16e713686e844f163c492c1c35333 (diff)
downloadaur-363e369b0d94b0b33328597f90a0a910056b7990.tar.gz
Bump to 2.29-3
-rw-r--r--.SRCINFO26
-rw-r--r--0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch194
-rw-r--r--PKGBUILD28
-rw-r--r--bz20338.patch114
-rw-r--r--file-truncated-while-reading-soname-after-patchelf.patch85
-rw-r--r--glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch4059
-rw-r--r--glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch1798
7 files changed, 4488 insertions, 1816 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 78b5006d0ea..0e8e0161b56 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,10 +1,8 @@
-# Generated by mksrcinfo v8
-# Sun Feb 3 02:23:32 UTC 2019
pkgbase = arm-linux-gnueabihf-glibc-headers
pkgdesc = GNU C Library headers (arm-linux-gnueabihf)
- pkgver = 2.28
- pkgrel = 5
- url = http://www.gnu.org/software/libc/
+ pkgver = 2.29
+ pkgrel = 3
+ url = https://www.gnu.org/software/libc/
arch = any
license = GPL
license = LGPL
@@ -13,12 +11,20 @@ pkgbase = arm-linux-gnueabihf-glibc-headers
options = !buildflags
options = !strip
options = staticlibs
- source = https://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.xz
- source = https://ftp.gnu.org/gnu/glibc/glibc-2.28.tar.xz.sig
- source = glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch
- md5sums = c81d2388896379997bc359d4f2084239
+ source = https://ftp.gnu.org/gnu/glibc/glibc-2.29.tar.xz
+ source = https://ftp.gnu.org/gnu/glibc/glibc-2.29.tar.xz.sig
+ source = glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch
+ source = bz20338.patch
+ source = 0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch
+ source = file-truncated-while-reading-soname-after-patchelf.patch
+ validpgpkeys = 7273542B39962DF7B299931416792B4EA25340F8
+ validpgpkeys = BC7C7372637EC10C57D7AA6579C43DFBF1CF2187
+ md5sums = e6c279d5b2f0736f740216f152acf974
md5sums = SKIP
- md5sums = b64d9921601d1e25cca2c802f15d6dcf
+ md5sums = 35a4ca5cdf86d706e054e02bb31d1616
+ md5sums = dc0d3ad59aeaaf591b085a77de6e03e9
+ md5sums = af5d3c5227ac639effe39667a43879a1
+ md5sums = 0820504d2e83ee15f74a656771361872
pkgname = arm-linux-gnueabihf-glibc-headers
diff --git a/0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch b/0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch
new file mode 100644
index 00000000000..ba9b874f361
--- /dev/null
+++ b/0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch
@@ -0,0 +1,194 @@
+From 2cbf10ae2ea9e378ff91b8f5c4d8cb77ed05378e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Bart=C5=82omiej=20Piotrowski?= <bpiotrowski@archlinux.org>
+Date: Fri, 10 Aug 2018-2019 14:12:40 +0000
+Subject: [PATCH] Revert "elf: Correct absolute (SHN_ABS) symbol run-time
+ calculation [BZ #19818]"
+
+This reverts commit e7feec374c635b6a29d65c39ae5e1855528fed39.
+---
+ elf/Makefile | 14 ++-----------
+ elf/dl-addr.c | 2 --
+ elf/tst-absolute-sym-lib.c | 25 ------------------------
+ elf/tst-absolute-sym-lib.lds | 19 ------------------
+ elf/tst-absolute-sym.c | 38 ------------------------------------
+ sysdeps/generic/ldsodefs.h | 3 +--
+ 6 files changed, 3 insertions(+), 98 deletions(-)
+ delete mode 100644 elf/tst-absolute-sym-lib.c
+ delete mode 100644 elf/tst-absolute-sym-lib.lds
+ delete mode 100644 elf/tst-absolute-sym.c
+
+diff --git a/elf/Makefile b/elf/Makefile
+index cd0771307f..5084ba4f6f 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -186,7 +186,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-absolute-sym tst-absolute-zero tst-big-note \
++ tst-debug1 tst-main1 \
+ tst-unwind-ctor tst-unwind-main
+ # reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+@@ -272,8 +272,7 @@ 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-absolute-sym-lib \
+- tst-absolute-zero-lib tst-big-note-lib tst-unwind-ctor-lib
++ tst-main1mod tst-libc_dlvsym-dso tst-unwind-ctor-lib
+ # Most modules build with _ISOMAC defined, but those filtered out
+ # depend on internal headers.
+ modules-names-tests = $(filter-out ifuncmod% tst-libc_dlvsym-dso tst-tlsmod%,\
+@@ -1465,14 +1463,6 @@ tst-main1-no-pie = yes
+ LDLIBS-tst-main1 = $(libsupport)
+ tst-main1mod.so-no-z-defs = yes
+
+-LDLIBS-tst-absolute-sym-lib.so = tst-absolute-sym-lib.lds
+-$(objpfx)tst-absolute-sym-lib.so: $(LDLIBS-tst-absolute-sym-lib.so)
+-$(objpfx)tst-absolute-sym: $(objpfx)tst-absolute-sym-lib.so
+-
+-LDLIBS-tst-absolute-zero-lib.so = tst-absolute-zero-lib.lds
+-$(objpfx)tst-absolute-zero-lib.so: $(LDLIBS-tst-absolute-zero-lib.so)
+-$(objpfx)tst-absolute-zero: $(objpfx)tst-absolute-zero-lib.so
+-
+ # Both the main program and the DSO for tst-libc_dlvsym need to link
+ # against libdl.
+ $(objpfx)tst-libc_dlvsym: $(libdl)
+diff --git a/elf/dl-addr.c b/elf/dl-addr.c
+index e6c7d02094..2250617a73 100644
+--- a/elf/dl-addr.c
++++ b/elf/dl-addr.c
+@@ -59,7 +59,6 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
+ we can omit that test here. */
+ if ((symtab[symndx].st_shndx != SHN_UNDEF
+ || symtab[symndx].st_value != 0)
+- && symtab[symndx].st_shndx != SHN_ABS
+ && ELFW(ST_TYPE) (symtab[symndx].st_info) != STT_TLS
+ && DL_ADDR_SYM_MATCH (match, &symtab[symndx],
+ matchsym, addr)
+@@ -92,7 +91,6 @@ determine_info (const ElfW(Addr) addr, struct link_map *match, Dl_info *info,
+ && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS
+ && (symtab->st_shndx != SHN_UNDEF
+ || symtab->st_value != 0)
+- && symtab->st_shndx != SHN_ABS
+ && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr)
+ && symtab->st_name < strtabsize)
+ matchsym = (ElfW(Sym) *) symtab;
+diff --git a/elf/tst-absolute-sym-lib.c b/elf/tst-absolute-sym-lib.c
+deleted file mode 100644
+index 912cb0048a..0000000000
+--- a/elf/tst-absolute-sym-lib.c
++++ /dev/null
+@@ -1,25 +0,0 @@
+-/* BZ #19818 absolute symbol calculation shared module.
+- Copyright (C) 2018-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
+- <http://www.gnu.org/licenses/>. */
+-
+-extern char absolute;
+-
+-void *
+-get_absolute (void)
+-{
+- return &absolute;
+-}
+diff --git a/elf/tst-absolute-sym-lib.lds b/elf/tst-absolute-sym-lib.lds
+deleted file mode 100644
+index d4a4128514..0000000000
+--- a/elf/tst-absolute-sym-lib.lds
++++ /dev/null
+@@ -1,19 +0,0 @@
+-/* BZ #19818 absolute symbol calculation linker script.
+- Copyright (C) 2018-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
+- <http://www.gnu.org/licenses/>. */
+-
+-"absolute" = 0x55aa;
+diff --git a/elf/tst-absolute-sym.c b/elf/tst-absolute-sym.c
+deleted file mode 100644
+index 111491d159..0000000000
+--- a/elf/tst-absolute-sym.c
++++ /dev/null
+@@ -1,38 +0,0 @@
+-/* BZ #19818 absolute symbol calculation main executable.
+- Copyright (C) 2018-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
+- <http://www.gnu.org/licenses/>. */
+-
+-#include <support/check.h>
+-#include <support/support.h>
+-#include <support/test-driver.h>
+-
+-void *get_absolute (void);
+-
+-static int
+-do_test (void)
+-{
+- void *ref = (void *) 0x55aa;
+- void *ptr;
+-
+- ptr = get_absolute ();
+- if (ptr != ref)
+- FAIL_EXIT1 ("Got %p, expected %p\n", ptr, ref);
+-
+- return 0;
+-}
+-
+-#include <support/test-driver.c>
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 95dc87519b..3cac4fa362 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -72,8 +72,7 @@ typedef struct link_map *lookup_t;
+ if non-NULL. Don't check for NULL map if MAP_SET is TRUE. */
+ #define SYMBOL_ADDRESS(map, ref, map_set) \
+ ((ref) == NULL ? 0 \
+- : (__glibc_unlikely ((ref)->st_shndx == SHN_ABS) ? 0 \
+- : LOOKUP_VALUE_ADDRESS (map, map_set)) + (ref)->st_value)
++ : LOOKUP_VALUE_ADDRESS (map, map_set) + (ref)->st_value)
+
+ /* On some architectures a pointer to a function is not just a pointer
+ to the actual code of the function but rather an architecture
+--
+2.18.0
+
diff --git a/PKGBUILD b/PKGBUILD
index c8dd7be1477..b7d32f2f06b 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -7,23 +7,30 @@
_target="arm-linux-gnueabihf"
pkgname=${_target}-glibc-headers
-pkgver=2.28
-pkgrel=5
+pkgver=2.29
+pkgrel=3
pkgdesc="GNU C Library headers (${_target})"
arch=('any')
-url="http://www.gnu.org/software/libc/"
+url="https://www.gnu.org/software/libc/"
license=(GPL LGPL)
depends=("${_target}-linux-api-headers>=4.17.11-1")
makedepends=("${_target}-gcc-stage1>=8.2.1+20181127")
options=(!buildflags !strip staticlibs)
-_commit=5a74abda201907cafbdabd1debf98890313ff71e
+_commit=34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4
#source=(git+https://sourceware.org/git/glibc.git#commit=$_commit
source=(https://ftp.gnu.org/gnu/glibc/glibc-$pkgver.tar.xz{,.sig}
- glibc-${_commit}.patch)
-validpgpkeys=(7273542B39962DF7B299931416792B4EA25340F8) # Carlos O'Donell
-md5sums=('c81d2388896379997bc359d4f2084239'
+ glibc-${_commit}.patch
+ bz20338.patch
+ 0001-Revert-elf-Correct-absolute-SHN_ABS-symbol-run-time-.patch
+ file-truncated-while-reading-soname-after-patchelf.patch)
+validpgpkeys=(7273542B39962DF7B299931416792B4EA25340F8 # Carlos O'Donell
+ BC7C7372637EC10C57D7AA6579C43DFBF1CF2187) # Siddhesh Poyarekar
+md5sums=('e6c279d5b2f0736f740216f152acf974'
'SKIP'
- 'b64d9921601d1e25cca2c802f15d6dcf')
+ '35a4ca5cdf86d706e054e02bb31d1616'
+ 'dc0d3ad59aeaaf591b085a77de6e03e9'
+ 'af5d3c5227ac639effe39667a43879a1'
+ '0820504d2e83ee15f74a656771361872')
prepare() {
mkdir -p glibc-build
@@ -65,6 +72,11 @@ build() {
# remove fortify for building libraries
CPPFLAGS=${CPPFLAGS/-D_FORTIFY_SOURCE=2/}
+ #
+ CFLAGS=${CFLAGS/-fno-plt/}
+ CXXFLAGS=${CXXFLAGS/-fno-plt/}
+ LDFLAGS=${LDFLAGS/,-z,now/}
+
export BUILD_CC=gcc
export CC=${_target}-gcc
export CXX=${_target}-g++
diff --git a/bz20338.patch b/bz20338.patch
new file mode 100644
index 00000000000..d223e9f0888
--- /dev/null
+++ b/bz20338.patch
@@ -0,0 +1,114 @@
+From 74250a7cdf106d4ca7d9506e6d5dc7c448dc3434 Mon Sep 17 00:00:00 2001
+From: David Michael <david.michael@coreos.com>
+Date: Thu, 15 Dec 2016 15:22:57 -0800
+Subject: [PATCH] gshadow: Sync fgetsgent_r.c with grp/fgetgrent_r.c
+
+ [BZ #20338]
+ * gshadow/fgetsgent_r.c: Include <libio/iolibio.h>.
+ (flockfile): New macro.
+ (funlockfile): Likewise.
+ (__fgetsgent_r): Sync with __fgetgrent_r.
+ * nss/nss_files/files-sgrp.c: Fix "fgetsgent_r.c" typo.
+---
+ gshadow/fgetsgent_r.c | 35 ++++++++++++++++++++++++-----------
+ nss/nss_files/files-sgrp.c | 2 +-
+ 2 files changed, 25 insertions(+), 12 deletions(-)
+
+diff --git a/gshadow/fgetsgent_r.c b/gshadow/fgetsgent_r.c
+index b70f6fa..02cd33a 100644
+--- a/gshadow/fgetsgent_r.c
++++ b/gshadow/fgetsgent_r.c
+@@ -20,39 +20,44 @@
+ #include <gshadow.h>
+ #include <stdio.h>
+
++#include <libio/iolibio.h>
++#define flockfile(s) _IO_flockfile (s)
++#define funlockfile(s) _IO_funlockfile (s)
++
+ /* Define a line parsing function using the common code
+ used in the nss_files module. */
+
+ #define STRUCTURE sgrp
+ #define ENTNAME sgent
+-#define EXTERN_PARSER 1
++#define EXTERN_PARSER 1
+ struct sgent_data {};
+
+ #include <nss/nss_files/files-parse.c>
+
+
+-/* Read one shadow entry from the given stream. */
++/* Read one entry from the given stream. */
+ int
+ __fgetsgent_r (FILE *stream, struct sgrp *resbuf, char *buffer, size_t buflen,
+ struct sgrp **result)
+ {
+ char *p;
++ int parse_result;
+
+- _IO_flockfile (stream);
++ flockfile (stream);
+ do
+ {
+ buffer[buflen - 1] = '\xff';
+ p = fgets_unlocked (buffer, buflen, stream);
+- if (p == NULL && feof_unlocked (stream))
++ if (__builtin_expect (p == NULL, 0) && feof_unlocked (stream))
+ {
+- _IO_funlockfile (stream);
++ funlockfile (stream);
+ *result = NULL;
+ __set_errno (ENOENT);
+ return errno;
+ }
+- if (p == NULL || buffer[buflen - 1] != '\xff')
++ if (__builtin_expect (p == NULL, 0) || buffer[buflen - 1] != '\xff')
+ {
+- _IO_funlockfile (stream);
++ funlockfile (stream);
+ *result = NULL;
+ __set_errno (ERANGE);
+ return errno;
+@@ -61,13 +66,21 @@ __fgetsgent_r (FILE *stream, struct sgrp *resbuf, char *buffer, size_t buflen,
+ /* Skip leading blanks. */
+ while (isspace (*p))
+ ++p;
+- } while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */
++ } while (*p == '\0' || *p == '#' /* Ignore empty and comment lines. */
+ /* Parse the line. If it is invalid, loop to
+ get the next line of the file to parse. */
+- ! parse_line (buffer, (void *) resbuf, (void *) buffer, buflen,
+- &errno));
++ || ! (parse_result = parse_line (p, resbuf,
++ (void *) buffer, buflen,
++ &errno)));
++
++ funlockfile (stream);
+
+- _IO_funlockfile (stream);
++ if (__builtin_expect (parse_result, 0) == -1)
++ {
++ /* The parser ran out of space. */
++ *result = NULL;
++ return errno;
++ }
+
+ *result = resbuf;
+ return 0;
+diff --git a/nss/nss_files/files-sgrp.c b/nss/nss_files/files-sgrp.c
+index 15dc659..05c3805 100644
+--- a/nss/nss_files/files-sgrp.c
++++ b/nss/nss_files/files-sgrp.c
+@@ -23,7 +23,7 @@
+ #define DATABASE "gshadow"
+ struct sgent_data {};
+
+-/* Our parser function is already defined in sgetspent_r.c, so use that
++/* Our parser function is already defined in sgetsgent_r.c, so use that
+ to parse lines from the database file. */
+ #define EXTERN_PARSER
+ #include "files-parse.c"
+--
+2.7.4
+
diff --git a/file-truncated-while-reading-soname-after-patchelf.patch b/file-truncated-while-reading-soname-after-patchelf.patch
new file mode 100644
index 00000000000..4c21284bf0b
--- /dev/null
+++ b/file-truncated-while-reading-soname-after-patchelf.patch
@@ -0,0 +1,85 @@
+[PATCH] ldconfig: file truncated while reading soname after patchelf [BZ #23964]
+
+The way loadaddr is computed from the first LOAD segment in process_elf_file
+assumes .dynstr is also contained in that segment. That is not necessarily
+true, especially for libraries that have been touched by patchelf.
+
+With this patch, the address read from the dynamic segment is checked against
+all applicable segments instead of only the first one.
+
+ [BZ #23964]
+ * elf/readelflib.c: Fix resolving of loadaddr for .dynstr vaddr.
+---
+ elf/readelflib.c | 33 ++++++++++++++++-----------------
+ 1 file changed, 16 insertions(+), 17 deletions(-)
+
+diff --git a/elf/readelflib.c b/elf/readelflib.c
+index 5a1e2dc2df..bc1195c175 100644
+--- a/elf/readelflib.c
++++ b/elf/readelflib.c
+@@ -98,11 +98,6 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
+
+ switch (segment->p_type)
+ {
+- case PT_LOAD:
+- if (loadaddr == (ElfW(Addr)) -1)
+- loadaddr = segment->p_vaddr - segment->p_offset;
+- break;
+-
+ case PT_DYNAMIC:
+ if (dynamic_addr)
+ error (0, 0, _("more than one dynamic segment\n"));
+@@ -176,11 +171,6 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
+ }
+
+ }
+- if (loadaddr == (ElfW(Addr)) -1)
+- {
+- /* Very strange. */
+- loadaddr = 0;
+- }
+
+ /* Now we can read the dynamic sections. */
+ if (dynamic_size == 0)
+@@ -190,22 +180,31 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
+ check_ptr (dynamic_segment);
+
+ /* Find the string table. */
+- dynamic_strings = NULL;
+ for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
+ ++dyn_entry)
+ {
+ check_ptr (dyn_entry);
+ if (dyn_entry->d_tag == DT_STRTAB)
+- {
+- dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
+- check_ptr (dynamic_strings);
+- break;
+- }
++ break;
+ }
+
+- if (dynamic_strings == NULL)
++ for (i = 0, segment = elf_pheader;i < elf_header->e_phnum; i++, segment++)
++ {
++ ElfW(Addr) vaddr = dyn_entry->d_un.d_ptr;
++ if (segment->p_type == PT_LOAD &&
++ vaddr >= segment->p_vaddr &&
++ vaddr < segment->p_vaddr + segment->p_filesz)
++ {
++ loadaddr = segment->p_vaddr - segment->p_offset;
++ break;
++ }
++ }
++ if (loadaddr == (ElfW(Addr)) -1)
+ return 1;
+
++ dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val - loadaddr);
++ check_ptr (dynamic_strings);
++
+ /* Now read the DT_NEEDED and DT_SONAME entries. */
+ for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
+ ++dyn_entry)
+--
+2.19.2
+
diff --git a/glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch b/glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch
new file mode 100644
index 00000000000..fa7f94c4a79
--- /dev/null
+++ b/glibc-34fb5f61d3c3f4b8fc616ea259fa19168b58ecd4.patch
@@ -0,0 +1,4059 @@
+diff --git a/ChangeLog b/ChangeLog
+index 59dab18463..20b650e026 100644
+--- a/ChangeLog
++++ b/ChangeLog
+@@ -1,3 +1,219 @@
++2019-06-20 Dmitry V. Levin <ldv@altlinux.org>
++ Florian Weimer <fweimer@redhat.com>
++
++ [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-03-13 Zack Weinberg <zackw@panix.com>
++
++ * scripts/check-obsolete-constructs.py: New test script.
++ * scripts/check-installed-headers.sh: Remove tests for
++ obsolete typedefs, superseded by check-obsolete-constructs.py.
++ * Rules: Run scripts/check-obsolete-constructs.py over $(headers)
++ as a special test. Update commentary.
++ * posix/bits/types.h (__SQUAD_TYPE, __S64_TYPE): Define as __int64_t.
++ (__UQUAD_TYPE, __U64_TYPE): Define as __uint64_t.
++ Update commentary.
++ * posix/sys/types.h (__u_intN_t): Remove.
++ (u_int8_t): Typedef using __uint8_t.
++ (u_int16_t): Typedef using __uint16_t.
++ (u_int32_t): Typedef using __uint32_t.
++ (u_int64_t): Typedef using __uint64_t.
++
++2019-04-18 Adhemerval Zanella <adhemerval.zanella@linaro.org>
++
++ * malloc/tst-memalign.c (do_test): Disable
++ -Walloc-size-larger-than= around tests of malloc with negative
++ sizes.
++ * malloc/tst-malloc-too-large.c (do_test): Likewise.
++
++2019-05-22 Wilco Dijkstra <wdijkstr@arm.com>
++
++ [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 Mark Wielaard <mark@klomp.org>
++
++ [BZ#24476]
++ * dlfcn/dlerror.c (__dlerror_main_freeres): Guard using
++ __libc_once_get (once) and static_buf == NULL.
++ (__dlerror): Check we have a valid key, set result to static_buf
++ otherwise.
++
++2019-05-15 Andreas Schwab <schwab@suse.de>
++
++ [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 <adhemerval.zanella@linaro.org>
++
++ [BZ #18035]
++ * elf/Makefile (tests-container): Add tst-pldd.
++ * 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.
++ * elf/tst-pldd.c: New file.
++
++2019-04-17 Adhemerval Zanella <adhemerval.zanella@linaro.org>
++
++ * support/Makefile (libsupport-routines): Add support_subprocess,
++ xposix_spawn, xposix_spawn_file_actions_addclose, and
++ xposix_spawn_file_actions_adddup2.
++ (tst-support_capture_subprocess-ARGS): New rule.
++ * support/capture_subprocess.h (support_capture_subprogram): New
++ prototype.
++ * support/support_capture_subprocess.c (support_capture_subprocess):
++ Refactor to use support_subprocess and support_capture_poll.
++ (support_capture_subprogram): New function.
++ * support/tst-support_capture_subprocess.c (write_mode_to_str,
++ str_to_write_mode, test_common, parse_int, handle_restart,
++ do_subprocess, do_subprogram, do_multiple_tests): New functions.
++ (do_test): Add support_capture_subprogram tests.
++ * support/subprocess.h: New file.
++ * support/support_subprocess.c: Likewise.
++ * support/xposix_spawn.c: Likewise.
++ * support/xposix_spawn_file_actions_addclose.c: Likewise.
++ * support/xposix_spawn_file_actions_adddup2.c: Likewise.
++ * support/xspawn.h: Likewise.
++
++2019-04-09 Carlos O'Donell <carlos@redhat.com>
++ Kwok Cheung Yeung <kcy@codesourcery.com>
++
++ [BZ #16573]
++ * malloc/mtrace.c: Define prototypes for all hooks.
++ (set_default_hooks): New function.
++ (set_trace_hooks): Likewise.
++ (save_default_hooks): Likewise.
++ (tr_freehook): Use new s*_hooks functions.
++ (tr_mallochook): Likewise.
++ (tr_reallochook): Likewise.
++ (tr_memalignhook): Likewise.
++ (mtrace): Likewise.
++ (muntrace): Likewise.
++
++2019-04-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
++
++ [BZ #22964]
++ * localedata/locales/ja_JP (LC_TIME): Add entry for the new Japanese
++ era.
++
++2019-03-02 TAMUKI Shoichi <tamuki@linet.gr.jp>
++
++ [BZ #24162]
++ * localedata/locales/ja_JP (LC_TIME): Change the offset for Taisho
++ gan-nen from 2 to 1. Problem reported by Morimitsu, Junji.
++
++2019-03-21 Stefan Liebler <stli@linux.ibm.com>
++
++ * sysdeps/s390/dl-procinfo.h (HWCAP_IMPORTANT):
++ Add HWCAP_S390_VX and HWCAP_S390_VXE.
++
++2019-01-31 Paul Eggert <eggert@cs.ucla.edu>
++
++ CVE-2019-9169
++ regex: fix read overrun [BZ #24114]
++ Problem found by AddressSanitizer, reported by Hongxu Chen in:
++ https://debbugs.gnu.org/34140
++ * posix/regexec.c (proceed_next_node):
++ Do not read past end of input buffer.
++
++2019-03-13 Stefan Liebler <stli@linux.ibm.com>
++
++ * elf/dl-sysdep.c (_dl_show_auxv): Remove condition and always
++ call _dl_procinfo.
++ * sysdeps/unix/sysv/linux/s390/dl-procinfo.h (_dl_procinfo):
++ Ignore types other than AT_HWCAP.
++ * sysdeps/sparc/dl-procinfo.h (_dl_procinfo): Likewise.
++ * sysdeps/unix/sysv/linux/i386/dl-procinfo.h (_dl_procinfo):
++ Likewise.
++ * sysdeps/powerpc/dl-procinfo.h (_dl_procinfo): Adjust comment
++ in the case of falling back to generic output mechanism.
++ * sysdeps/unix/sysv/linux/arm/dl-procinfo.h (_dl_procinfo):
++ Likewise.
++
++2019-02-15 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #24211]
++ * nptl/pthread_join_common.c (__pthread_timedjoin_ex): Do not read
++ pd->result after the thread descriptor has been freed.
++
++2019-02-08 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #24161]
++ * sysdeps/nptl/fork.h (__run_fork_handlers): Add multiple_threads
++ argument.
++ * nptl/register-atfork.c (__run_fork_handlers): Only perform
++ locking if the new do_locking argument is true.
++ * sysdeps/nptl/fork.c (__libc_fork): Pass multiple_threads to
++ __run_fork_handlers.
++
++2019-02-07 Stefan Liebler <stli@linux.ibm.com>
++
++ [BZ #24180]
++ * nptl/pthread_mutex_trylock.c (__pthread_mutex_trylock):
++ Add compiler barriers and comments.
++
++2019-02-05 Florian Weimer <fweimer@redhat.com>
++
++ [BZ #24164]
++ arm: Use "nr" constraint for Systemtap probes, to avoid the
++ compiler using memory operands for constants, due to the "o"
++ alternative in the default "nor" constraint.
++ * include/stap-probe.h [USE_STAP_PROBE]: Include
++ <stap-probe-machine.h>
++ * sysdeps/generic/stap-probe-machine.h: New file.
++ * sysdeps/arm/stap-probe-machine.h: Likewise.
++
++2019-02-04 H.J. Lu <hongjiu.lu@intel.com>
++
++ [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-01-31 Carlos O'Donell <carlos@redhat.com>
++ Torvald Riegel <triegel@redhat.com>
++ Rik Prohaska <prohaska7@gmail.com>
++
++ [BZ# 23844]
++ * nptl/Makefile (tests): Add tst-rwlock-tryrdlock-stall, and
++ tst-rwlock-trywrlock-stall.
++ * nptl/pthread_rwlock_tryrdlock.c (__pthread_rwlock_tryrdlock):
++ Wake waiters if PTHREAD_RWLOCK_FUTEX_USED is set.
++ * nptl/pthread_rwlock_trywrlock.c (__pthread_rwlock_trywrlock):
++ Set __wrphase_fute to 1 only if we started the write phase.
++ * nptl/tst-rwlock-tryrdlock-stall.c: New file.
++ * nptl/tst-rwlock-trywrlock-stall.c: New file.
++ * support/Makefile (libsupport-routines): Add xpthread_rwlock_destroy.
++ * support/xpthread_rwlock_destroy.c: New file.
++ * support/xthread.h: Declare xpthread_rwlock_destroy.
++
+ 2019-01-31 Siddhesh Poyarekar <siddhesh@sourceware.org>
+
+ * version.h (RELEASE): Set to "stable".
+diff --git a/NEWS b/NEWS
+index 912a9bdc0f..68d88b1036 100644
+--- a/NEWS
++++ b/NEWS
+@@ -4,6 +4,39 @@ See the end for copying conditions.
+
+ Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
+ using `glibc' in the "product" field.
++
++Version 2.29.1
++
++Major new features:
++
++* The entry for the new Japanese era has been added for ja_JP locale.
++
++The following bugs are resolved with this release:
++
++ [16573] malloc: Set and reset all hooks for tracing
++ [18035] Fix pldd hang
++ [20568] Fix crash in _IO_wfile_sync
++ [24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
++ [24164] Systemtap probes need to use "nr" constraint on 32-bit Arm
++ [24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
++ [24211] Use-after-free in Systemtap probe in pthread_join
++ [24228] old x86 applications that use legacy libio crash on exit
++ [24476] dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once)
++
++Security related changes:
++
++ 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-9169: Attempted case-insensitive regular-expression match
++ via proceed_next_node in posix/regexec.c leads to heap-based buffer
++ over-read. Reported by Hongxu Chen.
++
+
+ Version 2.29
+
+diff --git a/Rules b/Rules
+index 1562f2ce6d..16afa6acaa 100644
+--- a/Rules
++++ b/Rules
+@@ -82,7 +82,8 @@ $(common-objpfx)dummy.c:
+ common-generated += dummy.o dummy.c
+
+ ifneq "$(headers)" ""
+-# Special test of all the installed headers in this directory.
++# Test that all of the headers installed by this directory can be compiled
++# in isolation.
+ tests-special += $(objpfx)check-installed-headers-c.out
+ libof-check-installed-headers-c := testsuite
+ $(objpfx)check-installed-headers-c.out: \
+@@ -93,6 +94,8 @@ $(objpfx)check-installed-headers-c.out: \
+ $(evaluate-test)
+
+ ifneq "$(CXX)" ""
++# If a C++ compiler is available, also test that they can be compiled
++# in isolation as C++.
+ tests-special += $(objpfx)check-installed-headers-cxx.out
+ libof-check-installed-headers-cxx := testsuite
+ $(objpfx)check-installed-headers-cxx.out: \
+diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
+index 27376582d0..ca42c126c1 100644
+--- a/dlfcn/dlerror.c
++++ b/dlfcn/dlerror.c
+@@ -72,9 +72,16 @@ __dlerror (void)
+ __libc_once (once, init);
+
+ /* Get error string. */
+- result = (struct dl_action_result *) __libc_getspecific (key);
+- if (result == NULL)
+- result = &last_result;
++ if (static_buf != NULL)
++ result = static_buf;
++ else
++ {
++ /* init () has been run and we don't use the static buffer.
++ So we have a valid key. */
++ result = (struct dl_action_result *) __libc_getspecific (key);
++ if (result == NULL)
++ result = &last_result;
++ }
+
+ /* Test whether we already returned the string. */
+ if (result->returned != 0)
+@@ -230,13 +237,19 @@ free_key_mem (void *mem)
+ void
+ __dlerror_main_freeres (void)
+ {
+- void *mem;
+ /* Free the global memory if used. */
+ check_free (&last_result);
+- /* Free the TSD memory if used. */
+- mem = __libc_getspecific (key);
+- if (mem != NULL)
+- free_key_mem (mem);
++
++ if (__libc_once_get (once) && static_buf == NULL)
++ {
++ /* init () has been run and we don't use the static buffer.
++ So we have a valid key. */
++ void *mem;
++ /* Free the TSD memory if used. */
++ mem = __libc_getspecific (key);
++ if (mem != NULL)
++ free_key_mem (mem);
++ }
+ }
+
+ struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
+diff --git a/elf/Makefile b/elf/Makefile
+index 9cf5cd8dfd..e7457e809f 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -194,6 +194,7 @@ tests-internal += loadtest unload unload2 circleload1 \
+ tst-tls3 tst-tls6 tst-tls7 tst-tls8 tst-dlmopen2 \
+ tst-ptrguard1 tst-stackguard1 tst-libc_dlvsym \
+ tst-create_format1
++tests-container += tst-pldd
+ ifeq ($(build-hardcoded-path-in-tests),yes)
+ tests += tst-dlopen-aout
+ tst-dlopen-aout-no-pie = yes
+diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
+index 5f6c679a3f..5d19b100b2 100644
+--- a/elf/dl-sysdep.c
++++ b/elf/dl-sysdep.c
+@@ -328,14 +328,9 @@ _dl_show_auxv (void)
+ assert (AT_NULL == 0);
+ assert (AT_IGNORE == 1);
+
+- if (av->a_type == AT_HWCAP || av->a_type == AT_HWCAP2
+- || AT_L1I_CACHEGEOMETRY || AT_L1D_CACHEGEOMETRY
+- || AT_L2_CACHEGEOMETRY || AT_L3_CACHEGEOMETRY)
+- {
+- /* These are handled in a special way per platform. */
+- if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
+- continue;
+- }
++ /* Some entries are handled in a special way per platform. */
++ if (_dl_procinfo (av->a_type, av->a_un.a_val) == 0)
++ continue;
+
+ if (idx < sizeof (auxvars) / sizeof (auxvars[0])
+ && auxvars[idx].form != unknown)
+diff --git a/elf/pldd-xx.c b/elf/pldd-xx.c
+index 547f840ee1..756f6d7a1c 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 f3fac4e487..69629bd5d2 100644
+--- a/elf/pldd.c
++++ b/elf/pldd.c
+@@ -17,23 +17,17 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+-#include <alloca.h>
++#define _FILE_OFFSET_BITS 64
++
+ #include <argp.h>
+-#include <assert.h>
+ #include <dirent.h>
+-#include <elf.h>
+-#include <errno.h>
+ #include <error.h>
+ #include <fcntl.h>
+ #include <libintl.h>
+-#include <link.h>
+-#include <stddef.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+-#include <string.h>
+ #include <unistd.h>
+ #include <sys/ptrace.h>
+-#include <sys/stat.h>
+ #include <sys/wait.h>
+ #include <scratch_buffer.h>
+
+@@ -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 *) "<program name undetermined>";
++ /* Default stack allocation is at least 1024. */
++ snprintf (exe.data, exe.length, "<program name undetermined>");
+ 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/<pid>/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-pldd.c b/elf/tst-pldd.c
+new file mode 100644
+index 0000000000..ed19cedd05
+--- /dev/null
++++ b/elf/tst-pldd.c
+@@ -0,0 +1,118 @@
++/* Basic tests for pldd program.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <libgen.h>
++#include <stdbool.h>
++
++#include <array_length.h>
++#include <gnu/lib-names.h>
++
++#include <support/subprocess.h>
++#include <support/capture_subprocess.h>
++#include <support/check.h>
++
++static void
++target_process (void *arg)
++{
++ pause ();
++}
++
++/* The test runs in a container because pldd does not support tracing
++ a binary started by the loader iself (as with testrun.sh). */
++
++static int
++do_test (void)
++{
++ /* Create a copy of current test to check with pldd. */
++ struct support_subprocess target = support_subprocess (target_process, NULL);
++
++ /* Run 'pldd' on test subprocess. */
++ struct support_capture_subprocess pldd;
++ {
++ /* Three digits per byte plus null terminator. */
++ char pid[3 * sizeof (uint32_t) + 1];
++ snprintf (pid, array_length (pid), "%d", target.pid);
++
++ const char prog[] = "/usr/bin/pldd";
++
++ pldd = support_capture_subprogram (prog,
++ (char *const []) { (char *) prog, pid, NULL });
++
++ support_capture_subprocess_check (&pldd, "pldd", 0, sc_allow_stdout);
++ }
++
++ /* Check 'pldd' output. The test is expected to be linked against only
++ loader and libc. */
++ {
++ pid_t pid;
++ char buffer[512];
++#define STRINPUT(size) "%" # size "s"
++
++ FILE *out = fmemopen (pldd.out.buffer, pldd.out.length, "r");
++ TEST_VERIFY (out != NULL);
++
++ /* First line is in the form of <pid>: <full path of executable> */
++ TEST_COMPARE (fscanf (out, "%u: " STRINPUT (512), &pid, buffer), 2);
++
++ TEST_COMPARE (pid, target.pid);
++ TEST_COMPARE (strcmp (basename (buffer), "tst-pldd"), 0);
++
++ /* It expects only one loader and libc loaded by the program. */
++ bool interpreter_found = false, libc_found = false;
++ while (fgets (buffer, array_length (buffer), out) != NULL)
++ {
++ /* Ignore vDSO. */
++ if (buffer[0] != '/')
++ continue;
++
++ /* Remove newline so baseline (buffer) can compare against the
++ LD_SO and LIBC_SO macros unmodified. */
++ if (buffer[strlen(buffer)-1] == '\n')
++ buffer[strlen(buffer)-1] = '\0';
++
++ if (strcmp (basename (buffer), LD_SO) == 0)
++ {
++ TEST_COMPARE (interpreter_found, false);
++ interpreter_found = true;
++ continue;
++ }
++
++ if (strcmp (basename (buffer), LIBC_SO) == 0)
++ {
++ TEST_COMPARE (libc_found, false);
++ libc_found = true;
++ continue;
++ }
++ }
++ TEST_COMPARE (interpreter_found, true);
++ TEST_COMPARE (libc_found, true);
++
++ fclose (out);
++ }
++
++ support_capture_subprocess_free (&pldd);
++ support_process_terminate (&target);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/include/stap-probe.h b/include/stap-probe.h
+index c53dd86592..8c26292edd 100644
+--- a/include/stap-probe.h
++++ b/include/stap-probe.h
+@@ -21,6 +21,7 @@
+
+ #ifdef USE_STAP_PROBE
+
++# include <stap-probe-machine.h>
+ # include <sys/sdt.h>
+
+ /* Our code uses one macro LIBC_PROBE (name, n, arg1, ..., argn).
+diff --git a/libio/Makefile b/libio/Makefile
+index 5bee83e55c..9626a16b01 100644
+--- a/libio/Makefile
++++ b/libio/Makefile
+@@ -65,7 +65,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \
+ 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-fgetc-after-eof \
+- tst-sprintf-ub tst-sprintf-chk-ub
++ tst-sprintf-ub tst-sprintf-chk-ub tst-wfile-sync
+
+ tests-internal = tst-vtables tst-vtables-interposed tst-readline
+
+@@ -73,6 +73,9 @@ 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
+
+@@ -157,11 +160,14 @@ CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\"
+ CFLAGS-tst-sprintf-ub.c += -Wno-restrict
+ CFLAGS-tst-sprintf-chk-ub.c += -Wno-restrict
+
++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
+@@ -170,6 +176,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
+
+@@ -184,7 +191,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
+
+@@ -212,6 +220,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
+@@ -235,3 +244,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 2a0d9b81df..11a15549e8 100644
+--- a/libio/genops.c
++++ b/libio/genops.c
+@@ -789,9 +789,16 @@ _IO_unbuffer_all (void)
+
+ for (fp = (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;
+@@ -805,7 +812,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;
+
+@@ -816,7 +823,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
+@@ -827,7 +834,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/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
++ <https://www.gnu.org/licenses/>. */
++
++#include <mcheck.h>
++#include <support/test-driver.h>
++
++static int
++do_test (void)
++{
++ mtrace ();
++ return 0;
++}
++
++#include <support/test-driver.c>
+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-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
++ <http://www.gnu.org/licenses/>. */
++
++#include <locale.h>
++#include <stdio.h>
++#include <wchar.h>
++#include <support/check.h>
++#include <support/xunistd.h>
++
++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 <support/test-driver.c>
+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/wfileops.c b/libio/wfileops.c
+index 78f20486e5..bab2ba4892 100644
+--- a/libio/wfileops.c
++++ b/libio/wfileops.c
+@@ -508,11 +508,12 @@ _IO_wfile_sync (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/localedata/locales/ja_JP b/localedata/locales/ja_JP
+index 1fd2fee44b..c64aaaff55 100644
+--- a/localedata/locales/ja_JP
++++ b/localedata/locales/ja_JP
+@@ -14946,12 +14946,14 @@ am_pm "<U5348><U524D>";"<U5348><U5F8C>"
+
+ t_fmt_ampm "%p%I<U6642>%M<U5206>%S<U79D2>"
+
+-era "+:2:1990//01//01:+*:<U5E73><U6210>:%EC%Ey<U5E74>";/
++era "+:2:2020//01//01:+*:<U4EE4><U548C>:%EC%Ey<U5E74>";/
++ "+:1:2019//05//01:2019//12//31:<U4EE4><U548C>:%EC<U5143><U5E74>";/
++ "+:2:1990//01//01:2019//04//30:<U5E73><U6210>:%EC%Ey<U5E74>";/
+ "+:1:1989//01//08:1989//12//31:<U5E73><U6210>:%EC<U5143><U5E74>";/
+ "+:2:1927//01//01:1989//01//07:<U662D><U548C>:%EC%Ey<U5E74>";/
+ "+:1:1926//12//25:1926//12//31:<U662D><U548C>:%EC<U5143><U5E74>";/
+ "+:2:1913//01//01:1926//12//24:<U5927><U6B63>:%EC%Ey<U5E74>";/
+- "+:2:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/
++ "+:1:1912//07//30:1912//12//31:<U5927><U6B63>:%EC<U5143><U5E74>";/
+ "+:6:1873//01//01:1912//07//29:<U660E><U6CBB>:%EC%Ey<U5E74>";/
+ "+:1:0001//01//01:1872//12//31:<U897F><U66A6>:%EC%Ey<U5E74>";/
+ "+:1:-0001//12//31:-*:<U7D00><U5143><U524D>:%EC%Ey<U5E74>"
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index feaf7ee0bf..0abd653be2 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -2919,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;
+
+@@ -3876,10 +3878,14 @@ _int_malloc (mstate av, size_t bytes)
+ {
+ victim->fd_nextsize = fwd;
+ victim->bk_nextsize = fwd->bk_nextsize;
++ if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd))
++ malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)");
+ fwd->bk_nextsize = victim;
+ victim->bk_nextsize->fd_nextsize = victim;
+ }
+ bck = fwd->bk;
++ if (bck->fd != fwd)
++ malloc_printerr ("malloc(): largebin double linked list corrupted (bk)");
+ }
+ }
+ else
+@@ -5120,8 +5126,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/mtrace.c b/malloc/mtrace.c
+index a2facf65ea..2fda262508 100644
+--- a/malloc/mtrace.c
++++ b/malloc/mtrace.c
+@@ -121,6 +121,41 @@ lock_and_info (const void *caller, Dl_info *mem)
+ return res;
+ }
+
++static void tr_freehook (void *, const void *);
++static void * tr_mallochook (size_t, const void *);
++static void * tr_reallochook (void *, size_t, const void *);
++static void * tr_memalignhook (size_t, size_t, const void *);
++
++/* Set all the default non-trace hooks. */
++static __always_inline void
++set_default_hooks (void)
++{
++ __free_hook = tr_old_free_hook;
++ __malloc_hook = tr_old_malloc_hook;
++ __realloc_hook = tr_old_realloc_hook;
++ __memalign_hook = tr_old_memalign_hook;
++}
++
++/* Set all of the tracing hooks used for mtrace. */
++static __always_inline void
++set_trace_hooks (void)
++{
++ __free_hook = tr_freehook;
++ __malloc_hook = tr_mallochook;
++ __realloc_hook = tr_reallochook;
++ __memalign_hook = tr_memalignhook;
++}
++
++/* Save the current set of hooks as the default hooks. */
++static __always_inline void
++save_default_hooks (void)
++{
++ tr_old_free_hook = __free_hook;
++ tr_old_malloc_hook = __malloc_hook;
++ tr_old_realloc_hook = __realloc_hook;
++ tr_old_memalign_hook = __memalign_hook;
++}
++
+ static void
+ tr_freehook (void *ptr, const void *caller)
+ {
+@@ -138,12 +173,12 @@ tr_freehook (void *ptr, const void *caller)
+ tr_break ();
+ __libc_lock_lock (lock);
+ }
+- __free_hook = tr_old_free_hook;
++ set_default_hooks ();
+ if (tr_old_free_hook != NULL)
+ (*tr_old_free_hook)(ptr, caller);
+ else
+ free (ptr);
+- __free_hook = tr_freehook;
++ set_trace_hooks ();
+ __libc_lock_unlock (lock);
+ }
+
+@@ -155,12 +190,12 @@ tr_mallochook (size_t size, const void *caller)
+ Dl_info mem;
+ Dl_info *info = lock_and_info (caller, &mem);
+
+- __malloc_hook = tr_old_malloc_hook;
++ set_default_hooks ();
+ if (tr_old_malloc_hook != NULL)
+ hdr = (void *) (*tr_old_malloc_hook)(size, caller);
+ else
+ hdr = (void *) malloc (size);
+- __malloc_hook = tr_mallochook;
++ set_trace_hooks ();
+
+ tr_where (caller, info);
+ /* We could be printing a NULL here; that's OK. */
+@@ -185,16 +220,12 @@ tr_reallochook (void *ptr, size_t size, const void *caller)
+ Dl_info mem;
+ Dl_info *info = lock_and_info (caller, &mem);
+
+- __free_hook = tr_old_free_hook;
+- __malloc_hook = tr_old_malloc_hook;
+- __realloc_hook = tr_old_realloc_hook;
++ set_default_hooks ();
+ if (tr_old_realloc_hook != NULL)
+ hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
+ else
+ hdr = (void *) realloc (ptr, size);
+- __free_hook = tr_freehook;
+- __malloc_hook = tr_mallochook;
+- __realloc_hook = tr_reallochook;
++ set_trace_hooks ();
+
+ tr_where (caller, info);
+ if (hdr == NULL)
+@@ -230,14 +261,12 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller)
+ Dl_info mem;
+ Dl_info *info = lock_and_info (caller, &mem);
+
+- __memalign_hook = tr_old_memalign_hook;
+- __malloc_hook = tr_old_malloc_hook;
++ set_default_hooks ();
+ if (tr_old_memalign_hook != NULL)
+ hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
+ else
+ hdr = (void *) memalign (alignment, size);
+- __memalign_hook = tr_memalignhook;
+- __malloc_hook = tr_mallochook;
++ set_trace_hooks ();
+
+ tr_where (caller, info);
+ /* We could be printing a NULL here; that's OK. */
+@@ -305,14 +334,8 @@ mtrace (void)
+ malloc_trace_buffer = mtb;
+ setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
+ fprintf (mallstream, "= Start\n");
+- tr_old_free_hook = __free_hook;
+- __free_hook = tr_freehook;
+- tr_old_malloc_hook = __malloc_hook;
+- __malloc_hook = tr_mallochook;
+- tr_old_realloc_hook = __realloc_hook;
+- __realloc_hook = tr_reallochook;
+- tr_old_memalign_hook = __memalign_hook;
+- __memalign_hook = tr_memalignhook;
++ save_default_hooks ();
++ set_trace_hooks ();
+ #ifdef _LIBC
+ if (!added_atexit_handler)
+ {
+@@ -338,10 +361,7 @@ muntrace (void)
+ file. */
+ FILE *f = mallstream;
+ mallstream = NULL;
+- __free_hook = tr_old_free_hook;
+- __malloc_hook = tr_old_malloc_hook;
+- __realloc_hook = tr_old_realloc_hook;
+- __memalign_hook = tr_old_memalign_hook;
++ set_default_hooks ();
+
+ fprintf (f, "= End\n");
+ fclose (f);
+diff --git a/malloc/tst-malloc-too-large.c b/malloc/tst-malloc-too-large.c
+index 15e25f558e..51d42cee81 100644
+--- a/malloc/tst-malloc-too-large.c
++++ b/malloc/tst-malloc-too-large.c
+@@ -72,13 +72,28 @@ test_large_allocations (size_t size)
+ void * ptr_to_realloc;
+
+ test_setup ();
++ DIAG_PUSH_NEEDS_COMMENT;
++#if __GNUC_PREREQ (7, 0)
++ /* GCC 7 warns about too-large allocations; here we want to test
++ that they fail. */
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (malloc (size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+
+ ptr_to_realloc = malloc (16);
+ TEST_VERIFY_EXIT (ptr_to_realloc != NULL);
+ test_setup ();
++#if __GNUC_PREREQ (7, 0)
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (realloc (ptr_to_realloc, size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+ free (ptr_to_realloc);
+
+@@ -135,7 +150,13 @@ test_large_aligned_allocations (size_t size)
+ for (align = 1; align <= pagesize; align *= 2)
+ {
+ test_setup ();
++#if __GNUC_PREREQ (7, 0)
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (memalign (align, size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+
+ /* posix_memalign expects an alignment that is a power of 2 *and* a
+@@ -151,7 +172,13 @@ test_large_aligned_allocations (size_t size)
+ if ((size % align) == 0)
+ {
+ test_setup ();
++#if __GNUC_PREREQ (7, 0)
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (aligned_alloc (align, size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+ }
+ }
+@@ -159,11 +186,23 @@ test_large_aligned_allocations (size_t size)
+ /* Both valloc and pvalloc return page-aligned memory. */
+
+ test_setup ();
++#if __GNUC_PREREQ (7, 0)
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (valloc (size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+
+ test_setup ();
++#if __GNUC_PREREQ (7, 0)
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ TEST_VERIFY (pvalloc (size) == NULL);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+ TEST_VERIFY (errno == ENOMEM);
+ }
+
+diff --git a/malloc/tst-memalign.c b/malloc/tst-memalign.c
+index a6a9140a3d..e7997518cb 100644
+--- a/malloc/tst-memalign.c
++++ b/malloc/tst-memalign.c
+@@ -21,6 +21,7 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <unistd.h>
++#include <libc-diag.h>
+
+ static int errors = 0;
+
+@@ -41,9 +42,18 @@ do_test (void)
+
+ errno = 0;
+
++ DIAG_PUSH_NEEDS_COMMENT;
++#if __GNUC_PREREQ (7, 0)
++ /* GCC 7 warns about too-large allocations; here we want to test
++ that they fail. */
++ DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
++#endif
+ /* An attempt to allocate a huge value should return NULL and set
+ errno to ENOMEM. */
+ p = memalign (sizeof (void *), -1);
++#if __GNUC_PREREQ (7, 0)
++ DIAG_POP_NEEDS_COMMENT;
++#endif
+
+ save = errno;
+
+diff --git a/manual/tunables.texi b/manual/tunables.texi
+index af820820e0..8edfea4edd 100644
+--- a/manual/tunables.texi
++++ b/manual/tunables.texi
+@@ -189,8 +189,8 @@ per-thread cache. The default (and maximum) value is 1032 bytes on
+
+ @deftp Tunable glibc.malloc.tcache_count
+ The maximum number of chunks of each size to cache. The default is 7.
+-There is no upper limit, other than available system memory. If set
+-to zero, the per-thread cache is effectively disabled.
++The upper limit is 127. If set to zero, the per-thread cache is effectively
++disabled.
+
+ The approximate maximum overhead of the per-thread cache is thus equal
+ to the number of bins times the chunk count in each bin times the size
+diff --git a/nptl/Makefile b/nptl/Makefile
+index 340282c6cb..0e316edfac 100644
+--- a/nptl/Makefile
++++ b/nptl/Makefile
+@@ -319,7 +319,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
+ tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
+ tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \
+ tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \
+- 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 \
+diff --git a/nptl/pthread_join_common.c b/nptl/pthread_join_common.c
+index ecb78ffba5..366feb376b 100644
+--- a/nptl/pthread_join_common.c
++++ b/nptl/pthread_join_common.c
+@@ -86,6 +86,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
+ pthread_cleanup_pop (0);
+ }
+
++ void *pd_result = pd->result;
+ if (__glibc_likely (result == 0))
+ {
+ /* We mark the thread as terminated and as joined. */
+@@ -93,7 +94,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
+
+ /* Store the return value if the caller is interested. */
+ if (thread_return != NULL)
+- *thread_return = pd->result;
++ *thread_return = pd_result;
+
+ /* Free the TCB. */
+ __free_tcb (pd);
+@@ -101,7 +102,7 @@ __pthread_timedjoin_ex (pthread_t threadid, void **thread_return,
+ else
+ pd->joinid = NULL;
+
+- LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd->result);
++ LIBC_PROBE (pthread_join_ret, 3, threadid, result, pd_result);
+
+ return result;
+ }
+diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
+index 8fe43b8f0f..bf2869eca2 100644
+--- a/nptl/pthread_mutex_trylock.c
++++ b/nptl/pthread_mutex_trylock.c
+@@ -94,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
+@@ -119,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
+@@ -135,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;
+@@ -142,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);
+
+@@ -160,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;
+@@ -173,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;
+@@ -211,10 +233,15 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
+ }
+
+ 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;
+
+@@ -223,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. */
+@@ -250,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;
+@@ -270,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;
+@@ -287,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
+@@ -310,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);
+ }
+
+diff --git a/nptl/pthread_rwlock_tryrdlock.c b/nptl/pthread_rwlock_tryrdlock.c
+index 368862ff07..2f94f17f36 100644
+--- a/nptl/pthread_rwlock_tryrdlock.c
++++ b/nptl/pthread_rwlock_tryrdlock.c
+@@ -94,15 +94,22 @@ __pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
+ /* 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;
+diff --git a/nptl/pthread_rwlock_trywrlock.c b/nptl/pthread_rwlock_trywrlock.c
+index fd37a71ce4..fae475cc70 100644
+--- a/nptl/pthread_rwlock_trywrlock.c
++++ b/nptl/pthread_rwlock_trywrlock.c
+@@ -46,8 +46,15 @@ __pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
+ &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;
+diff --git a/nptl/register-atfork.c b/nptl/register-atfork.c
+index bc797b761a..80a1becb5f 100644
+--- a/nptl/register-atfork.c
++++ b/nptl/register-atfork.c
+@@ -107,13 +107,14 @@ __unregister_atfork (void *dso_handle)
+ }
+
+ void
+-__run_fork_handlers (enum __run_fork_handler_type who)
++__run_fork_handlers (enum __run_fork_handler_type who, _Bool do_locking)
+ {
+ struct fork_handler *runp;
+
+ if (who == atfork_run_prepare)
+ {
+- lll_lock (atfork_lock, LLL_PRIVATE);
++ if (do_locking)
++ lll_lock (atfork_lock, LLL_PRIVATE);
+ size_t sl = fork_handler_list_size (&fork_handlers);
+ for (size_t i = sl; i > 0; i--)
+ {
+@@ -133,7 +134,8 @@ __run_fork_handlers (enum __run_fork_handler_type who)
+ else if (who == atfork_run_parent && runp->parent_handler)
+ runp->parent_handler ();
+ }
+- lll_unlock (atfork_lock, LLL_PRIVATE);
++ if (do_locking)
++ lll_unlock (atfork_lock, LLL_PRIVATE);
+ }
+ }
+
+diff --git a/nptl/tst-rwlock-tryrdlock-stall.c b/nptl/tst-rwlock-tryrdlock-stall.c
+new file mode 100644
+index 0000000000..5e476da2b8
+--- /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
++ <http://www.gnu.org/licenses/>. */
++
++/* 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 <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <pthread.h>
++#include <support/xthread.h>
++#include <errno.h>
++
++/* 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 <support/test-driver.c>
+diff --git a/nptl/tst-rwlock-trywrlock-stall.c b/nptl/tst-rwlock-trywrlock-stall.c
+new file mode 100644
+index 0000000000..14d27cbcbc
+--- /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
++ <http://www.gnu.org/licenses/>. */
++
++/* 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 <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <pthread.h>
++#include <support/xthread.h>
++#include <errno.h>
++
++/* 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 <support/test-driver.c>
+diff --git a/posix/bits/types.h b/posix/bits/types.h
+index 27e065c3be..0de6c59bb4 100644
+--- a/posix/bits/types.h
++++ b/posix/bits/types.h
+@@ -87,7 +87,7 @@ __extension__ typedef unsigned long long int __uintmax_t;
+ 32 -- "natural" 32-bit type (always int)
+ 64 -- "natural" 64-bit type (long or long long)
+ LONG32 -- 32-bit type, traditionally long
+- QUAD -- 64-bit type, always long long
++ QUAD -- 64-bit type, traditionally long long
+ WORD -- natural type of __WORDSIZE bits (int or long)
+ LONGWORD -- type of __WORDSIZE bits, traditionally long
+
+@@ -113,14 +113,14 @@ __extension__ typedef unsigned long long int __uintmax_t;
+ #define __SLONGWORD_TYPE long int
+ #define __ULONGWORD_TYPE unsigned long int
+ #if __WORDSIZE == 32
+-# define __SQUAD_TYPE __quad_t
+-# define __UQUAD_TYPE __u_quad_t
++# define __SQUAD_TYPE __int64_t
++# define __UQUAD_TYPE __uint64_t
+ # define __SWORD_TYPE int
+ # define __UWORD_TYPE unsigned int
+ # define __SLONG32_TYPE long int
+ # define __ULONG32_TYPE unsigned long int
+-# define __S64_TYPE __quad_t
+-# define __U64_TYPE __u_quad_t
++# define __S64_TYPE __int64_t
++# define __U64_TYPE __uint64_t
+ /* We want __extension__ before typedef's that use nonstandard base types
+ such as `long long' in C89 mode. */
+ # define __STD_TYPE __extension__ typedef
+diff --git a/posix/regexec.c b/posix/regexec.c
+index 91d5a797b8..084b1222d9 100644
+--- a/posix/regexec.c
++++ b/posix/regexec.c
+@@ -1293,8 +1293,10 @@ proceed_next_node (const re_match_context_t *mctx, Idx nregs, regmatch_t *regs,
+ else if (naccepted)
+ {
+ char *buf = (char *) re_string_get_buffer (&mctx->input);
+- if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
+- naccepted) != 0)
++ if (mctx->input.valid_len - *pidx < naccepted
++ || (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx,
++ naccepted)
++ != 0))
+ return -1;
+ }
+ }
+diff --git a/posix/sys/types.h b/posix/sys/types.h
+index 27129c5c23..0e37b1ce6a 100644
+--- a/posix/sys/types.h
++++ b/posix/sys/types.h
+@@ -154,37 +154,20 @@ typedef unsigned int uint;
+
+ #include <bits/stdint-intn.h>
+
+-#if !__GNUC_PREREQ (2, 7)
+-
+ /* These were defined by ISO C without the first `_'. */
+-typedef unsigned char u_int8_t;
+-typedef unsigned short int u_int16_t;
+-typedef unsigned int u_int32_t;
+-# if __WORDSIZE == 64
+-typedef unsigned long int u_int64_t;
+-# else
+-__extension__ typedef unsigned long long int u_int64_t;
+-# endif
+-
+-typedef int register_t;
+-
+-#else
+-
+-/* For GCC 2.7 and later, we can use specific type-size attributes. */
+-# define __u_intN_t(N, MODE) \
+- typedef unsigned int u_int##N##_t __attribute__ ((__mode__ (MODE)))
+-
+-__u_intN_t (8, __QI__);
+-__u_intN_t (16, __HI__);
+-__u_intN_t (32, __SI__);
+-__u_intN_t (64, __DI__);
++typedef __uint8_t u_int8_t;
++typedef __uint16_t u_int16_t;
++typedef __uint32_t u_int32_t;
++typedef __uint64_t u_int64_t;
+
++#if __GNUC_PREREQ (2, 7)
+ typedef int register_t __attribute__ ((__mode__ (__word__)));
+-
++#else
++typedef int register_t;
++#endif
+
+ /* Some code from BIND tests this macro to see if the types above are
+ defined. */
+-#endif
+ #define __BIT_TYPES_DEFINED__ 1
+
+
+diff --git a/scripts/check-installed-headers.sh b/scripts/check-installed-headers.sh
+index 8e7beffd82..63bc8d4fa6 100644
+--- a/scripts/check-installed-headers.sh
++++ b/scripts/check-installed-headers.sh
+@@ -16,11 +16,9 @@
+ # License along with the GNU C Library; if not, see
+ # <http://www.gnu.org/licenses/>.
+
+-# Check installed headers for cleanliness. For each header, confirm
+-# that it's possible to compile a file that includes that header and
+-# does nothing else, in several different compilation modes. Also,
+-# scan the header for a set of obsolete typedefs that should no longer
+-# appear.
++# For each installed header, confirm that it's possible to compile a
++# file that includes that header and does nothing else, in several
++# different compilation modes.
+
+ # These compilation switches assume GCC or compatible, which is probably
+ # fine since we also assume that when _building_ glibc.
+@@ -31,13 +29,6 @@ cxx_modes="-std=c++98 -std=gnu++98 -std=c++11 -std=gnu++11"
+ # These are probably the most commonly used three.
+ lib_modes="-D_DEFAULT_SOURCE=1 -D_GNU_SOURCE=1 -D_XOPEN_SOURCE=700"
+
+-# sys/types.h+bits/types.h have to define the obsolete types.
+-# rpc(svc)/* have the obsolete types too deeply embedded in their API
+-# to remove.
+-skip_obsolete_type_check='*/sys/types.h|*/bits/types.h|*/rpc/*|*/rpcsvc/*'
+-obsolete_type_re=\
+-'\<((__)?(quad_t|u(short|int|long|_(char|short|int([0-9]+_t)?|long|quad_t))))\>'
+-
+ if [ $# -lt 3 ]; then
+ echo "usage: $0 c|c++ \"compile command\" header header header..." >&2
+ exit 2
+@@ -46,14 +37,10 @@ case "$1" in
+ (c)
+ lang_modes="$c_modes"
+ cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.c)
+- already="$skip_obsolete_type_check"
+ ;;
+ (c++)
+ lang_modes="$cxx_modes"
+ cih_test_c=$(mktemp ${TMPDIR-/tmp}/cih_test_XXXXXX.cc)
+- # The obsolete-type check can be skipped for C++; it is
+- # sufficient to do it for C.
+- already="*"
+ ;;
+ (*)
+ echo "usage: $0 c|c++ \"compile command\" header header header..." >&2
+@@ -151,22 +138,8 @@ $expanded_lib_mode
+ int avoid_empty_translation_unit;
+ EOF
+ if $cc_cmd -fsyntax-only $lang_mode "$cih_test_c" 2>&1
+- then
+- includes=$($cc_cmd -fsyntax-only -H $lang_mode \
+- "$cih_test_c" 2>&1 | sed -ne 's/^[.][.]* //p')
+- for h in $includes; do
+- # Don't repeat work.
+- eval 'case "$h" in ('"$already"') continue;; esac'
+-
+- if grep -qE "$obsolete_type_re" "$h"; then
+- echo "*** Obsolete types detected:"
+- grep -HE "$obsolete_type_re" "$h"
+- failed=1
+- fi
+- already="$already|$h"
+- done
+- else
+- failed=1
++ then :
++ else failed=1
+ fi
+ done
+ done
+diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py
+new file mode 100755
+index 0000000000..ce5c72251f
+--- /dev/null
++++ b/scripts/check-obsolete-constructs.py
+@@ -0,0 +1,466 @@
++#! /usr/bin/python3
++# 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
++# <http://www.gnu.org/licenses/>.
++
++"""Verifies that installed headers do not use any obsolete constructs:
++ * legacy BSD typedefs superseded by <stdint.h>:
++ ushort uint ulong u_char u_short u_int u_long u_intNN_t quad_t u_quad_t
++ (sys/types.h is allowed to _define_ these types, but not to use them
++ to define anything else).
++"""
++
++import argparse
++import collections
++import re
++import sys
++
++# Simplified lexical analyzer for C preprocessing tokens.
++# Does not implement trigraphs.
++# Does not implement backslash-newline in the middle of any lexical
++# item other than a string literal.
++# Does not implement universal-character-names in identifiers.
++# Treats prefixed strings (e.g. L"...") as two tokens (L and "...")
++# Accepts non-ASCII characters only within comments and strings.
++
++# Caution: The order of the outermost alternation matters.
++# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
++# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must
++# be last.
++# Caution: There should be no capturing groups other than the named
++# captures in the outermost alternation.
++
++# For reference, these are all of the C punctuators as of C11:
++# [ ] ( ) { } , ; ? ~
++# ! != * *= / /= ^ ^= = ==
++# # ##
++# % %= %> %: %:%:
++# & &= &&
++# | |= ||
++# + += ++
++# - -= -- ->
++# . ...
++# : :>
++# < <% <: << <<= <=
++# > >= >> >>=
++
++# The BAD_* tokens are not part of the official definition of pp-tokens;
++# they match unclosed strings, character constants, and block comments,
++# so that the regex engine doesn't have to backtrack all the way to the
++# beginning of a broken construct and then emit dozens of junk tokens.
++
++PP_TOKEN_RE_ = re.compile(r"""
++ (?P<STRING> \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\")
++ |(?P<BAD_STRING> \"(?:[^\"\\\r\n]|\\[ -~])*)
++ |(?P<CHARCONST> \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\')
++ |(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*)
++ |(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/)
++ |(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?)
++ |(?P<LINE_COMMENT> //[^\r\n]*)
++ |(?P<IDENT> [_a-zA-Z][_a-zA-Z0-9]*)
++ |(?P<PP_NUMBER> \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*)
++ |(?P<PUNCTUATOR>
++ [,;?~(){}\[\]]
++ | [!*/^=]=?
++ | \#\#?
++ | %(?:[=>]|:(?:%:)?)?
++ | &[=&]?
++ |\|[=|]?
++ |\+[=+]?
++ | -[=->]?
++ |\.(?:\.\.)?
++ | :>?
++ | <(?:[%:]|<(?:=|<=?)?)?
++ | >(?:=|>=?)?)
++ |(?P<ESCNL> \\(?:\r|\n|\r\n))
++ |(?P<WHITESPACE> [ \t\n\r\v\f]+)
++ |(?P<OTHER> .)
++""", re.DOTALL | re.VERBOSE)
++
++HEADER_NAME_RE_ = re.compile(r"""
++ < [^>\r\n]+ >
++ | " [^"\r\n]+ "
++""", re.DOTALL | re.VERBOSE)
++
++ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""")
++
++# based on the sample code in the Python re documentation
++Token_ = collections.namedtuple("Token", (
++ "kind", "text", "line", "column", "context"))
++Token_.__doc__ = """
++ One C preprocessing token, comment, or chunk of whitespace.
++ 'kind' identifies the token type, which will be one of:
++ STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT,
++ PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME,
++ or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are
++ handled within tokenize_c, below.
++
++ 'text' is the sequence of source characters making up the token;
++ no decoding whatsoever is performed.
++
++ 'line' and 'column' give the position of the first character of the
++ token within the source file. They are both 1-based.
++
++ 'context' indicates whether or not this token occurred within a
++ preprocessing directive; it will be None for running text,
++ '<null>' for the leading '#' of a directive line (because '#'
++ all by itself on a line is a "null directive"), or the name of
++ the directive for tokens within a directive line, starting with
++ the IDENT for the name itself.
++"""
++
++def tokenize_c(file_contents, reporter):
++ """Yield a series of Token objects, one for each preprocessing
++ token, comment, or chunk of whitespace within FILE_CONTENTS.
++ The REPORTER object is expected to have one method,
++ reporter.error(token, message), which will be called to
++ indicate a lexical error at the position of TOKEN.
++ If MESSAGE contains the four-character sequence '{!r}', that
++ is expected to be replaced by repr(token.text).
++ """
++
++ Token = Token_
++ PP_TOKEN_RE = PP_TOKEN_RE_
++ ENDLINE_RE = ENDLINE_RE_
++ HEADER_NAME_RE = HEADER_NAME_RE_
++
++ line_num = 1
++ line_start = 0
++ pos = 0
++ limit = len(file_contents)
++ directive = None
++ at_bol = True
++ while pos < limit:
++ if directive == "include":
++ mo = HEADER_NAME_RE.match(file_contents, pos)
++ if mo:
++ kind = "HEADER_NAME"
++ directive = "after_include"
++ else:
++ mo = PP_TOKEN_RE.match(file_contents, pos)
++ kind = mo.lastgroup
++ if kind != "WHITESPACE":
++ directive = "after_include"
++ else:
++ mo = PP_TOKEN_RE.match(file_contents, pos)
++ kind = mo.lastgroup
++
++ text = mo.group()
++ line = line_num
++ column = mo.start() - line_start
++ adj_line_start = 0
++ # only these kinds can contain a newline
++ if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT",
++ "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"):
++ for tmo in ENDLINE_RE.finditer(text):
++ line_num += 1
++ adj_line_start = tmo.end()
++ if adj_line_start:
++ line_start = mo.start() + adj_line_start
++
++ # Track whether or not we are scanning a preprocessing directive.
++ if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start):
++ at_bol = True
++ directive = None
++ else:
++ if kind == "PUNCTUATOR" and text == "#" and at_bol:
++ directive = "<null>"
++ elif kind == "IDENT" and directive == "<null>":
++ directive = text
++ at_bol = False
++
++ # Report ill-formed tokens and rewrite them as their well-formed
++ # equivalents, so downstream processing doesn't have to know about them.
++ # (Rewriting instead of discarding provides better error recovery.)
++ if kind == "BAD_BLOCK_COM":
++ reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""),
++ "unclosed block comment")
++ text += "*/"
++ kind = "BLOCK_COMMENT"
++ elif kind == "BAD_STRING":
++ reporter.error(Token("BAD_STRING", "", line, column+1, ""),
++ "unclosed string")
++ text += "\""
++ kind = "STRING"
++ elif kind == "BAD_CHARCONST":
++ reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""),
++ "unclosed char constant")
++ text += "'"
++ kind = "CHARCONST"
++
++ tok = Token(kind, text, line, column+1,
++ "include" if directive == "after_include" else directive)
++ # Do not complain about OTHER tokens inside macro definitions.
++ # $ and @ appear in macros defined by headers intended to be
++ # included from assembly language, e.g. sysdeps/mips/sys/asm.h.
++ if kind == "OTHER" and directive != "define":
++ self.error(tok, "stray {!r} in program")
++
++ yield tok
++ pos = mo.end()
++
++#
++# Base and generic classes for individual checks.
++#
++
++class ConstructChecker:
++ """Scan a stream of C preprocessing tokens and possibly report
++ problems with them. The REPORTER object passed to __init__ has
++ one method, reporter.error(token, message), which should be
++ called to indicate a problem detected at the position of TOKEN.
++ If MESSAGE contains the four-character sequence '{!r}' then that
++ will be replaced with a textual representation of TOKEN.
++ """
++ def __init__(self, reporter):
++ self.reporter = reporter
++
++ def examine(self, tok):
++ """Called once for each token in a header file.
++ Call self.reporter.error if a problem is detected.
++ """
++ raise NotImplementedError
++
++ def eof(self):
++ """Called once at the end of the stream. Subclasses need only
++ override this if it might have something to do."""
++ pass
++
++class NoCheck(ConstructChecker):
++ """Generic checker class which doesn't do anything. Substitute this
++ class for a real checker when a particular check should be skipped
++ for some file."""
++
++ def examine(self, tok):
++ pass
++
++#
++# Check for obsolete type names.
++#
++
++# The obsolete type names we're looking for:
++OBSOLETE_TYPE_RE_ = re.compile(r"""\A
++ (__)?
++ ( quad_t
++ | u(?: short | int | long
++ | _(?: char | short | int(?:[0-9]+_t)? | long | quad_t )))
++\Z""", re.VERBOSE)
++
++class ObsoleteNotAllowed(ConstructChecker):
++ """Don't allow any use of the obsolete typedefs."""
++ def examine(self, tok):
++ if OBSOLETE_TYPE_RE_.match(tok.text):
++ self.reporter.error(tok, "use of {!r}")
++
++class ObsoletePrivateDefinitionsAllowed(ConstructChecker):
++ """Allow definitions of the private versions of the
++ obsolete typedefs; that is, 'typedef [anything] __obsolete;'
++ """
++ def __init__(self, reporter):
++ super().__init__(reporter)
++ self.in_typedef = False
++ self.prev_token = None
++
++ def examine(self, tok):
++ # bits/types.h hides 'typedef' in a macro sometimes.
++ if (tok.kind == "IDENT"
++ and tok.text in ("typedef", "__STD_TYPE")
++ and tok.context is None):
++ self.in_typedef = True
++ elif tok.kind == "PUNCTUATOR" and tok.text == ";" and self.in_typedef:
++ self.in_typedef = False
++ if self.prev_token.kind == "IDENT":
++ m = OBSOLETE_TYPE_RE_.match(self.prev_token.text)
++ if m and m.group(1) != "__":
++ self.reporter.error(self.prev_token, "use of {!r}")
++ self.prev_token = None
++ else:
++ self._check_prev()
++
++ self.prev_token = tok
++
++ def eof(self):
++ self._check_prev()
++
++ def _check_prev(self):
++ if (self.prev_token is not None
++ and self.prev_token.kind == "IDENT"
++ and OBSOLETE_TYPE_RE_.match(self.prev_token.text)):
++ self.reporter.error(self.prev_token, "use of {!r}")
++
++class ObsoletePublicDefinitionsAllowed(ConstructChecker):
++ """Allow definitions of the public versions of the obsolete
++ typedefs. Only specific forms of definition are allowed:
++
++ typedef __obsolete obsolete; // identifiers must agree
++ typedef __uintN_t u_intN_t; // N must agree
++ typedef unsigned long int ulong;
++ typedef unsigned short int ushort;
++ typedef unsigned int uint;
++ """
++ def __init__(self, reporter):
++ super().__init__(reporter)
++ self.typedef_tokens = []
++
++ def examine(self, tok):
++ if tok.kind in ("WHITESPACE", "BLOCK_COMMENT",
++ "LINE_COMMENT", "NL", "ESCNL"):
++ pass
++
++ elif (tok.kind == "IDENT" and tok.text == "typedef"
++ and tok.context is None):
++ if self.typedef_tokens:
++ self.reporter.error(tok, "typedef inside typedef")
++ self._reset()
++ self.typedef_tokens.append(tok)
++
++ elif tok.kind == "PUNCTUATOR" and tok.text == ";":
++ self._finish()
++
++ elif self.typedef_tokens:
++ self.typedef_tokens.append(tok)
++
++ def eof(self):
++ self._reset()
++
++ def _reset(self):
++ while self.typedef_tokens:
++ tok = self.typedef_tokens.pop(0)
++ if tok.kind == "IDENT" and OBSOLETE_TYPE_RE_.match(tok.text):
++ self.reporter.error(tok, "use of {!r}")
++
++ def _finish(self):
++ if not self.typedef_tokens: return
++ if self.typedef_tokens[-1].kind == "IDENT":
++ m = OBSOLETE_TYPE_RE_.match(self.typedef_tokens[-1].text)
++ if m:
++ if self._permissible_public_definition(m):
++ self.typedef_tokens.clear()
++ self._reset()
++
++ def _permissible_public_definition(self, m):
++ if m.group(1) == "__": return False
++ name = m.group(2)
++ toks = self.typedef_tokens
++ ntok = len(toks)
++ if ntok == 3 and toks[1].kind == "IDENT":
++ defn = toks[1].text
++ n = OBSOLETE_TYPE_RE_.match(defn)
++ if n and n.group(1) == "__" and n.group(2) == name:
++ return True
++
++ if (name[:5] == "u_int" and name[-2:] == "_t"
++ and defn[:6] == "__uint" and defn[-2:] == "_t"
++ and name[5:-2] == defn[6:-2]):
++ return True
++
++ return False
++
++ if (name == "ulong" and ntok == 5
++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
++ and toks[2].kind == "IDENT" and toks[2].text == "long"
++ and toks[3].kind == "IDENT" and toks[3].text == "int"):
++ return True
++
++ if (name == "ushort" and ntok == 5
++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
++ and toks[2].kind == "IDENT" and toks[2].text == "short"
++ and toks[3].kind == "IDENT" and toks[3].text == "int"):
++ return True
++
++ if (name == "uint" and ntok == 4
++ and toks[1].kind == "IDENT" and toks[1].text == "unsigned"
++ and toks[2].kind == "IDENT" and toks[2].text == "int"):
++ return True
++
++ return False
++
++def ObsoleteTypedefChecker(reporter, fname):
++ """Factory: produce an instance of the appropriate
++ obsolete-typedef checker for FNAME."""
++
++ # The obsolete rpc/ and rpcsvc/ headers are allowed to use the
++ # obsolete types, because it would be more trouble than it's
++ # worth to remove them from headers that we intend to stop
++ # installing eventually anyway.
++ if (fname.startswith("rpc/")
++ or fname.startswith("rpcsvc/")
++ or "/rpc/" in fname
++ or "/rpcsvc/" in fname):
++ return NoCheck(reporter)
++
++ # bits/types.h is allowed to define the __-versions of the
++ # obsolete types.
++ if (fname == "bits/types.h"
++ or fname.endswith("/bits/types.h")):
++ return ObsoletePrivateDefinitionsAllowed(reporter)
++
++ # sys/types.h is allowed to use the __-versions of the
++ # obsolete types, but only to define the unprefixed versions.
++ if (fname == "sys/types.h"
++ or fname.endswith("/sys/types.h")):
++ return ObsoletePublicDefinitionsAllowed(reporter)
++
++ return ObsoleteNotAllowed(reporter)
++
++#
++# Master control
++#
++
++class HeaderChecker:
++ """Perform all of the checks on each header. This is also the
++ "reporter" object expected by tokenize_c and ConstructChecker.
++ """
++ def __init__(self):
++ self.fname = None
++ self.status = 0
++
++ def error(self, tok, message):
++ self.status = 1
++ if '{!r}' in message:
++ message = message.format(tok.text)
++ sys.stderr.write("{}:{}:{}: error: {}\n".format(
++ self.fname, tok.line, tok.column, message))
++
++ def check(self, fname):
++ self.fname = fname
++ try:
++ with open(fname, "rt") as fp:
++ contents = fp.read()
++ except OSError as e:
++ sys.stderr.write("{}: {}\n".format(fname, e.strerror))
++ self.status = 1
++ return
++
++ typedef_checker = ObsoleteTypedefChecker(self, self.fname)
++
++ for tok in tokenize_c(contents, self):
++ typedef_checker.examine(tok)
++
++def main():
++ ap = argparse.ArgumentParser(description=__doc__)
++ ap.add_argument("headers", metavar="header", nargs="+",
++ help="one or more headers to scan for obsolete constructs")
++ args = ap.parse_args()
++
++ checker = HeaderChecker()
++ for fname in args.headers:
++ # Headers whose installed name begins with "finclude/" contain
++ # Fortran, not C, and this program should completely ignore them.
++ if not (fname.startswith("finclude/") or "/finclude/" in fname):
++ checker.check(fname)
++ sys.exit(checker.status)
++
++main()
+diff --git a/support/Makefile b/support/Makefile
+index 432cf2fe6c..8d61de6c57 100644
+--- a/support/Makefile
++++ b/support/Makefile
+@@ -63,6 +63,7 @@ libsupport-routines = \
+ support_record_failure \
+ support_run_diff \
+ support_shared_allocate \
++ support_subprocess \
+ support_test_compare_blob \
+ support_test_compare_failure \
+ support_test_compare_string \
+@@ -129,6 +130,7 @@ libsupport-routines = \
+ xpthread_mutexattr_settype \
+ xpthread_once \
+ xpthread_rwlock_init \
++ xpthread_rwlock_destroy \
+ xpthread_rwlock_rdlock \
+ xpthread_rwlock_unlock \
+ xpthread_rwlock_wrlock \
+@@ -147,6 +149,9 @@ libsupport-routines = \
+ xsignal \
+ xsigstack \
+ xsocket \
++ xposix_spawn \
++ xposix_spawn_file_actions_addclose \
++ xposix_spawn_file_actions_adddup2 \
+ xstrdup \
+ xstrndup \
+ xsymlink \
+@@ -222,4 +227,6 @@ endif
+
+ $(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
+
++tst-support_capture_subprocess-ARGS = -- $(host-test-program-cmd)
++
+ include ../Rules
+diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
+index 2dce42e3a3..2832cfc635 100644
+--- a/support/capture_subprocess.h
++++ b/support/capture_subprocess.h
+@@ -35,6 +35,12 @@ struct support_capture_subprocess
+ struct support_capture_subprocess support_capture_subprocess
+ (void (*callback) (void *), void *closure);
+
++/* Issue FILE with ARGV arguments by using posix_spawn and capture standard
++ output, standard error, and the exit status. The out.buffer and err.buffer
++ are handle as support_capture_subprocess. */
++struct support_capture_subprocess support_capture_subprogram
++ (const char *file, char *const argv[]);
++
+ /* Deallocate the subprocess data captured by
+ support_capture_subprocess. */
+ void support_capture_subprocess_free (struct support_capture_subprocess *);
+diff --git a/support/subprocess.h b/support/subprocess.h
+new file mode 100644
+index 0000000000..c031878d94
+--- /dev/null
++++ b/support/subprocess.h
+@@ -0,0 +1,49 @@
++/* Create a subprocess.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++#ifndef SUPPORT_SUBPROCESS_H
++#define SUPPORT_SUBPROCESS_H
++
++#include <sys/types.h>
++
++struct support_subprocess
++{
++ int stdout_pipe[2];
++ int stderr_pipe[2];
++ pid_t pid;
++};
++
++/* Invoke CALLBACK (CLOSURE) in a subprocess created with fork and return
++ its PID, a pipe redirected to STDOUT, and a pipe redirected to STDERR. */
++struct support_subprocess support_subprocess
++ (void (*callback) (void *), void *closure);
++
++/* Issue FILE with ARGV arguments by using posix_spawn and return is PID, a
++ pipe redirected to STDOUT, and a pipe redirected to STDERR. */
++struct support_subprocess support_subprogram
++ (const char *file, char *const argv[]);
++
++/* Wait for the subprocess indicated by PROC::PID. Return the status
++ indicate by waitpid call. */
++int support_process_wait (struct support_subprocess *proc);
++
++/* Terminate the subprocess indicated by PROC::PID, first with a SIGTERM and
++ then with a SIGKILL. Return the status as for waitpid call. */
++int support_process_terminate (struct support_subprocess *proc);
++
++#endif
+diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
+index 167514faf1..948ce5a0c6 100644
+--- a/support/support_capture_subprocess.c
++++ b/support/support_capture_subprocess.c
+@@ -16,6 +16,7 @@
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
++#include <support/subprocess.h>
+ #include <support/capture_subprocess.h>
+
+ #include <errno.h>
+@@ -23,6 +24,7 @@
+ #include <support/check.h>
+ #include <support/xunistd.h>
+ #include <support/xsocket.h>
++#include <support/xspawn.h>
+
+ static void
+ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
+@@ -50,59 +52,53 @@ transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
+ }
+ }
+
+-struct support_capture_subprocess
+-support_capture_subprocess (void (*callback) (void *), void *closure)
++static void
++support_capture_poll (struct support_capture_subprocess *result,
++ struct support_subprocess *proc)
+ {
+- struct support_capture_subprocess result;
+- xopen_memstream (&result.out);
+- xopen_memstream (&result.err);
+-
+- 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);
+-
+- pid_t pid = xfork ();
+- if (pid == 0)
+- {
+- xclose (stdout_pipe[0]);
+- 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);
+- }
+- xclose (stdout_pipe[1]);
+- xclose (stderr_pipe[1]);
+-
+ struct pollfd fds[2] =
+ {
+- { .fd = stdout_pipe[0], .events = POLLIN },
+- { .fd = stderr_pipe[0], .events = POLLIN },
++ { .fd = proc->stdout_pipe[0], .events = POLLIN },
++ { .fd = proc->stderr_pipe[0], .events = POLLIN },
+ };
+
+ do
+ {
+ xpoll (fds, 2, -1);
+- transfer ("stdout", &fds[0], &result.out);
+- transfer ("stderr", &fds[1], &result.err);
++ transfer ("stdout", &fds[0], &result->out);
++ transfer ("stderr", &fds[1], &result->err);
+ }
+ while (fds[0].events != 0 || fds[1].events != 0);
+- xclose (stdout_pipe[0]);
+- xclose (stderr_pipe[0]);
+
+- xfclose_memstream (&result.out);
+- xfclose_memstream (&result.err);
+- xwaitpid (pid, &result.status, 0);
++ xfclose_memstream (&result->out);
++ xfclose_memstream (&result->err);
++
++ result->status = support_process_wait (proc);
++}
++
++struct support_capture_subprocess
++support_capture_subprocess (void (*callback) (void *), void *closure)
++{
++ struct support_capture_subprocess result;
++ xopen_memstream (&result.out);
++ xopen_memstream (&result.err);
++
++ struct support_subprocess proc = support_subprocess (callback, closure);
++
++ support_capture_poll (&result, &proc);
++ return result;
++}
++
++struct support_capture_subprocess
++support_capture_subprogram (const char *file, char *const argv[])
++{
++ struct support_capture_subprocess result;
++ xopen_memstream (&result.out);
++ xopen_memstream (&result.err);
++
++ struct support_subprocess proc = support_subprogram (file, argv);
++
++ support_capture_poll (&result, &proc);
+ return result;
+ }
+
+diff --git a/support/support_subprocess.c b/support/support_subprocess.c
+new file mode 100644
+index 0000000000..0c8cc6af30
+--- /dev/null
++++ b/support/support_subprocess.c
+@@ -0,0 +1,152 @@
++/* Create subprocess.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++#include <stdio.h>
++#include <signal.h>
++#include <time.h>
++#include <sys/wait.h>
++#include <stdbool.h>
++#include <support/xspawn.h>
++#include <support/check.h>
++#include <support/xunistd.h>
++#include <support/subprocess.h>
++
++static struct support_subprocess
++support_suprocess_init (void)
++{
++ struct support_subprocess result;
++
++ xpipe (result.stdout_pipe);
++ TEST_VERIFY (result.stdout_pipe[0] > STDERR_FILENO);
++ TEST_VERIFY (result.stdout_pipe[1] > STDERR_FILENO);
++
++ xpipe (result.stderr_pipe);
++ TEST_VERIFY (result.stderr_pipe[0] > STDERR_FILENO);
++ TEST_VERIFY (result.stderr_pipe[1] > STDERR_FILENO);
++
++ TEST_VERIFY (fflush (stdout) == 0);
++ TEST_VERIFY (fflush (stderr) == 0);
++
++ return result;
++}
++
++struct support_subprocess
++support_subprocess (void (*callback) (void *), void *closure)
++{
++ struct support_subprocess result = support_suprocess_init ();
++
++ result.pid = xfork ();
++ if (result.pid == 0)
++ {
++ xclose (result.stdout_pipe[0]);
++ xclose (result.stderr_pipe[0]);
++ xdup2 (result.stdout_pipe[1], STDOUT_FILENO);
++ xdup2 (result.stderr_pipe[1], STDERR_FILENO);
++ xclose (result.stdout_pipe[1]);
++ xclose (result.stderr_pipe[1]);
++ callback (closure);
++ _exit (0);
++ }
++ xclose (result.stdout_pipe[1]);
++ xclose (result.stderr_pipe[1]);
++
++ return result;
++}
++
++struct support_subprocess
++support_subprogram (const char *file, char *const argv[])
++{
++ struct support_subprocess result = support_suprocess_init ();
++
++ posix_spawn_file_actions_t fa;
++ /* posix_spawn_file_actions_init does not fail. */
++ posix_spawn_file_actions_init (&fa);
++
++ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[0]);
++ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[0]);
++ xposix_spawn_file_actions_adddup2 (&fa, result.stdout_pipe[1], STDOUT_FILENO);
++ xposix_spawn_file_actions_adddup2 (&fa, result.stderr_pipe[1], STDERR_FILENO);
++ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
++ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
++
++ result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
++
++ xclose (result.stdout_pipe[1]);
++ xclose (result.stderr_pipe[1]);
++
++ return result;
++}
++
++int
++support_process_wait (struct support_subprocess *proc)
++{
++ xclose (proc->stdout_pipe[0]);
++ xclose (proc->stderr_pipe[0]);
++
++ int status;
++ xwaitpid (proc->pid, &status, 0);
++ return status;
++}
++
++
++static bool
++support_process_kill (int pid, int signo, int *status)
++{
++ /* Kill the whole process group. */
++ kill (-pid, signo);
++ /* In case setpgid failed in the child, kill it individually too. */
++ kill (pid, signo);
++
++ /* Wait for it to terminate. */
++ pid_t killed;
++ for (int i = 0; i < 5; ++i)
++ {
++ int status;
++ killed = xwaitpid (pid, &status, WNOHANG|WUNTRACED);
++ if (killed != 0)
++ break;
++
++ /* Delay, give the system time to process the kill. If the
++ nanosleep() call return prematurely, all the better. We
++ won't restart it since this probably means the child process
++ finally died. */
++ nanosleep (&((struct timespec) { 0, 100000000 }), NULL);
++ }
++ if (killed != 0 && killed != pid)
++ return false;
++
++ return true;
++}
++
++int
++support_process_terminate (struct support_subprocess *proc)
++{
++ xclose (proc->stdout_pipe[0]);
++ xclose (proc->stderr_pipe[0]);
++
++ int status;
++ pid_t killed = xwaitpid (proc->pid, &status, WNOHANG|WUNTRACED);
++ if (killed != 0 && killed == proc->pid)
++ return status;
++
++ /* Subprocess is still running, terminate it. */
++ if (!support_process_kill (proc->pid, SIGTERM, &status) )
++ support_process_kill (proc->pid, SIGKILL, &status);
++
++ return status;
++}
+diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
+index d8ba42ea8b..ab363e41ac 100644
+--- a/support/tst-support_capture_subprocess.c
++++ b/support/tst-support_capture_subprocess.c
+@@ -23,8 +23,20 @@
+ #include <support/capture_subprocess.h>
+ #include <support/check.h>
+ #include <support/support.h>
++#include <support/temp_file.h>
+ #include <sys/wait.h>
+ #include <unistd.h>
++#include <paths.h>
++#include <getopt.h>
++#include <limits.h>
++#include <errno.h>
++#include <array_length.h>
++
++/* Nonzero if the program gets called via 'exec'. */
++static int restart;
++
++/* Hold the four initial argument used to respawn the process. */
++static char *initial_argv[5];
+
+ /* Write one byte at *P to FD and advance *P. Do nothing if *P is
+ '\0'. */
+@@ -42,6 +54,30 @@ transfer (const unsigned char **p, int fd)
+ enum write_mode { out_first, err_first, interleave,
+ write_mode_last = interleave };
+
++static const char *
++write_mode_to_str (enum write_mode mode)
++{
++ switch (mode)
++ {
++ case out_first: return "out_first";
++ case err_first: return "err_first";
++ case interleave: return "interleave";
++ default: return "write_mode_last";
++ }
++}
++
++static enum write_mode
++str_to_write_mode (const char *mode)
++{
++ if (strcmp (mode, "out_first") == 0)
++ return out_first;
++ else if (strcmp (mode, "err_first") == 0)
++ return err_first;
++ else if (strcmp (mode, "interleave") == 0)
++ return interleave;
++ return write_mode_last;
++}
++
+ /* Describe what to write in the subprocess. */
+ struct test
+ {
+@@ -52,11 +88,9 @@ struct test
+ int status;
+ };
+
+-/* For use with support_capture_subprocess. */
+-static void
+-callback (void *closure)
++_Noreturn static void
++test_common (const struct test *test)
+ {
+- const struct test *test = closure;
+ bool mode_ok = false;
+ switch (test->write_mode)
+ {
+@@ -95,6 +129,40 @@ callback (void *closure)
+ exit (test->status);
+ }
+
++static int
++parse_int (const char *str)
++{
++ char *endptr;
++ long int ret = strtol (str, &endptr, 10);
++ TEST_COMPARE (errno, 0);
++ TEST_VERIFY (ret >= 0 && ret <= INT_MAX);
++ return ret;
++}
++
++/* For use with support_capture_subprogram. */
++_Noreturn static void
++handle_restart (char *out, char *err, const char *write_mode,
++ const char *signal, const char *status)
++{
++ struct test test =
++ {
++ out,
++ err,
++ str_to_write_mode (write_mode),
++ parse_int (signal),
++ parse_int (status)
++ };
++ test_common (&test);
++}
++
++/* For use with support_capture_subprocess. */
++_Noreturn static void
++callback (void *closure)
++{
++ const struct test *test = closure;
++ test_common (test);
++}
++
+ /* Create a heap-allocated random string of letters. */
+ static char *
+ random_string (size_t length)
+@@ -130,12 +198,59 @@ check_stream (const char *what, const struct xmemstream *stream,
+ }
+ }
+
++static struct support_capture_subprocess
++do_subprocess (struct test *test)
++{
++ return support_capture_subprocess (callback, test);
++}
++
++static struct support_capture_subprocess
++do_subprogram (const struct test *test)
++{
++ /* Three digits per byte plus null terminator. */
++ char signalstr[3 * sizeof(int) + 1];
++ snprintf (signalstr, sizeof (signalstr), "%d", test->signal);
++ char statusstr[3 * sizeof(int) + 1];
++ snprintf (statusstr, sizeof (statusstr), "%d", test->status);
++
++ int argc = 0;
++ enum {
++ /* 4 elements from initial_argv (path to ld.so, '--library-path', the
++ path', and application name'), 2 for restart argument ('--direct',
++ '--restart'), 5 arguments plus NULL. */
++ argv_size = 12
++ };
++ char *args[argv_size];
++
++ for (char **arg = initial_argv; *arg != NULL; arg++)
++ args[argc++] = *arg;
++
++ args[argc++] = (char*) "--direct";
++ args[argc++] = (char*) "--restart";
++
++ args[argc++] = test->out;
++ args[argc++] = test->err;
++ args[argc++] = (char*) write_mode_to_str (test->write_mode);
++ args[argc++] = signalstr;
++ args[argc++] = statusstr;
++ args[argc] = NULL;
++ TEST_VERIFY (argc < argv_size);
++
++ return support_capture_subprogram (args[0], args);
++}
++
++enum test_type
++{
++ subprocess,
++ subprogram,
++};
++
+ static int
+-do_test (void)
++do_multiple_tests (enum test_type type)
+ {
+ const int lengths[] = {0, 1, 17, 512, 20000, -1};
+
+- /* Test multiple combinations of support_capture_subprocess.
++ /* Test multiple combinations of support_capture_sub{process,program}.
+
+ length_idx_stdout: Index into the lengths array above,
+ controls how many bytes are written by the subprocess to
+@@ -164,8 +279,10 @@ do_test (void)
+ TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]);
+ TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]);
+
+- struct support_capture_subprocess result
+- = support_capture_subprocess (callback, &test);
++ struct support_capture_subprocess result
++ = type == subprocess ? do_subprocess (&test)
++ : do_subprogram (&test);
++
+ check_stream ("stdout", &result.out, test.out);
+ check_stream ("stderr", &result.err, test.err);
+
+@@ -199,4 +316,54 @@ do_test (void)
+ return 0;
+ }
+
++static int
++do_test (int argc, char *argv[])
++{
++ /* We must have either:
++
++ - one or four parameters if called initially:
++ + argv[1]: path for ld.so optional
++ + argv[2]: "--library-path" optional
++ + argv[3]: the library path optional
++ + argv[4]: the application name
++
++ - six parameters left if called through re-execution:
++ + argv[1]: the application name
++ + argv[2]: the stdout to print
++ + argv[3]: the stderr to print
++ + argv[4]: the write mode to use
++ + argv[5]: the signal to issue
++ + argv[6]: the exit status code to use
++
++ * When built with --enable-hardcoded-path-in-tests or issued without
++ using the loader directly.
++ */
++
++ if (argc != (restart ? 6 : 5) && argc != (restart ? 6 : 2))
++ FAIL_EXIT1 ("wrong number of arguments (%d)", argc);
++
++ if (restart)
++ {
++ handle_restart (argv[1], /* stdout */
++ argv[2], /* stderr */
++ argv[3], /* write_mode */
++ argv[4], /* signal */
++ argv[5]); /* status */
++ }
++
++ initial_argv[0] = argv[1]; /* path for ld.so */
++ initial_argv[1] = argv[2]; /* "--library-path" */
++ initial_argv[2] = argv[3]; /* the library path */
++ initial_argv[3] = argv[4]; /* the application name */
++ initial_argv[4] = NULL;
++
++ do_multiple_tests (subprocess);
++ do_multiple_tests (subprogram);
++
++ return 0;
++}
++
++#define CMDLINE_OPTIONS \
++ { "restart", no_argument, &restart, 1 },
++#define TEST_FUNCTION_ARGV do_test
+ #include <support/test-driver.c>
+diff --git a/support/xposix_spawn.c b/support/xposix_spawn.c
+new file mode 100644
+index 0000000000..e846017632
+--- /dev/null
++++ b/support/xposix_spawn.c
+@@ -0,0 +1,32 @@
++/* xposix_spawn implementation.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++#include <support/xspawn.h>
++#include <support/check.h>
++
++pid_t
++xposix_spawn (const char *file, const posix_spawn_file_actions_t *fa,
++ const posix_spawnattr_t *attr, char *const args[],
++ char *const envp[])
++{
++ pid_t pid;
++ int status = posix_spawn (&pid, file, fa, attr, args, envp);
++ if (status != 0)
++ FAIL_EXIT1 ("posix_spawn to %s file failed: %m", file);
++ return pid;
++}
+diff --git a/support/xposix_spawn_file_actions_addclose.c b/support/xposix_spawn_file_actions_addclose.c
+new file mode 100644
+index 0000000000..eed54a6514
+--- /dev/null
++++ b/support/xposix_spawn_file_actions_addclose.c
+@@ -0,0 +1,29 @@
++/* xposix_spawn_file_actions_addclose implementation.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++#include <support/xspawn.h>
++#include <support/check.h>
++
++int
++xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *fa, int fd)
++{
++ int status = posix_spawn_file_actions_addclose (fa, fd);
++ if (status == -1)
++ FAIL_EXIT1 ("posix_spawn_file_actions_addclose failed: %m\n");
++ return status;
++}
+diff --git a/support/xposix_spawn_file_actions_adddup2.c b/support/xposix_spawn_file_actions_adddup2.c
+new file mode 100644
+index 0000000000..a43b6490be
+--- /dev/null
++++ b/support/xposix_spawn_file_actions_adddup2.c
+@@ -0,0 +1,30 @@
++/* xposix_spawn_file_actions_adddup2 implementation.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++#include <support/xspawn.h>
++#include <support/check.h>
++
++int
++xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *fa, int fd,
++ int newfd)
++{
++ int status = posix_spawn_file_actions_adddup2 (fa, fd, newfd);
++ if (status == -1)
++ FAIL_EXIT1 ("posix_spawn_file_actions_adddup2 failed: %m\n");
++ return status;
++}
+diff --git a/support/xpthread_rwlock_destroy.c b/support/xpthread_rwlock_destroy.c
+new file mode 100644
+index 0000000000..6d6e953569
+--- /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
++ <http://www.gnu.org/licenses/>. */
++
++#include <support/xthread.h>
++
++void
++xpthread_rwlock_destroy (pthread_rwlock_t *rwlock)
++{
++ xpthread_check_return ("pthread_rwlock_destroy",
++ pthread_rwlock_destroy (rwlock));
++}
+diff --git a/support/xspawn.h b/support/xspawn.h
+new file mode 100644
+index 0000000000..bbf89132e4
+--- /dev/null
++++ b/support/xspawn.h
+@@ -0,0 +1,34 @@
++/* posix_spawn with support checks.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++#ifndef SUPPORT_XSPAWN_H
++#define SUPPORT_XSPAWN_H
++
++#include <spawn.h>
++
++__BEGIN_DECLS
++
++int xposix_spawn_file_actions_addclose (posix_spawn_file_actions_t *, int);
++int xposix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *, int, int);
++
++pid_t xposix_spawn (const char *, const posix_spawn_file_actions_t *,
++ const posix_spawnattr_t *, char *const [], char *const []);
++
++__END_DECLS
++
++#endif
+diff --git a/support/xthread.h b/support/xthread.h
+index 47c23235f3..9fe1f68b3b 100644
+--- a/support/xthread.h
++++ b/support/xthread.h
+@@ -84,6 +84,7 @@ void xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref);
+ 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 --git a/sysdeps/arm/stap-probe-machine.h b/sysdeps/arm/stap-probe-machine.h
+new file mode 100644
+index 0000000000..d27ca22040
+--- /dev/null
++++ b/sysdeps/arm/stap-probe-machine.h
+@@ -0,0 +1,22 @@
++/* Macros for customizing Systemtap <sys/sdt.h>. Arm version.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++/* The default "nor" constraint produces unparseable memory references
++ for constants. Omit the problematic "o" constraint. See bug 24164
++ and GCC PR 89146. */
++#define STAP_SDT_ARG_CONSTRAINT nr
+diff --git a/sysdeps/generic/stap-probe-machine.h b/sysdeps/generic/stap-probe-machine.h
+new file mode 100644
+index 0000000000..2e5790c3b2
+--- /dev/null
++++ b/sysdeps/generic/stap-probe-machine.h
+@@ -0,0 +1,19 @@
++/* Macros for customizing Systemtap <sys/sdt.h>. Generic version.
++ 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
++ <http://www.gnu.org/licenses/>. */
++
++/* By default, there are no customizations. */
+diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
+index bd68f18b45..14b69a6f89 100644
+--- a/sysdeps/nptl/fork.c
++++ b/sysdeps/nptl/fork.c
+@@ -55,7 +55,7 @@ __libc_fork (void)
+ but our current fork implementation is not. */
+ bool multiple_threads = THREAD_GETMEM (THREAD_SELF, header.multiple_threads);
+
+- __run_fork_handlers (atfork_run_prepare);
++ __run_fork_handlers (atfork_run_prepare, multiple_threads);
+
+ /* If we are not running multiple threads, we do not have to
+ preserve lock state. If fork runs from a signal handler, only
+@@ -134,7 +134,7 @@ __libc_fork (void)
+ __rtld_lock_initialize (GL(dl_load_lock));
+
+ /* Run the handlers registered for the child. */
+- __run_fork_handlers (atfork_run_child);
++ __run_fork_handlers (atfork_run_child, multiple_threads);
+ }
+ else
+ {
+@@ -149,7 +149,7 @@ __libc_fork (void)
+ }
+
+ /* Run the handlers registered for the parent. */
+- __run_fork_handlers (atfork_run_parent);
++ __run_fork_handlers (atfork_run_parent, multiple_threads);
+ }
+
+ return pid;
+diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h
+index a1c3b26b68..99ed76034b 100644
+--- a/sysdeps/nptl/fork.h
++++ b/sysdeps/nptl/fork.h
+@@ -52,9 +52,11 @@ enum __run_fork_handler_type
+ - atfork_run_child: run all the CHILD_HANDLER and unlocks the internal
+ lock.
+ - atfork_run_parent: run all the PARENT_HANDLER and unlocks the internal
+- lock. */
+-extern void __run_fork_handlers (enum __run_fork_handler_type who)
+- attribute_hidden;
++ lock.
++
++ Perform locking only if DO_LOCKING. */
++extern void __run_fork_handlers (enum __run_fork_handler_type who,
++ _Bool do_locking) attribute_hidden;
+
+ /* C library side function to register new fork handlers. */
+ extern int __register_atfork (void (*__prepare) (void),
+diff --git a/sysdeps/powerpc/dl-procinfo.h b/sysdeps/powerpc/dl-procinfo.h
+index f542f7318f..dfc3b33a72 100644
+--- a/sysdeps/powerpc/dl-procinfo.h
++++ b/sysdeps/powerpc/dl-procinfo.h
+@@ -225,7 +225,7 @@ _dl_procinfo (unsigned int type, unsigned long int word)
+ break;
+ }
+ default:
+- /* This should not happen. */
++ /* Fallback to generic output mechanism. */
+ return -1;
+ }
+ _dl_printf ("\n");
+diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h
+index b4b81fc70a..99697ae649 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/sparc/dl-procinfo.h b/sysdeps/sparc/dl-procinfo.h
+index 282b8c5117..64ee267fc7 100644
+--- a/sysdeps/sparc/dl-procinfo.h
++++ b/sysdeps/sparc/dl-procinfo.h
+@@ -31,8 +31,8 @@ _dl_procinfo (unsigned int type, unsigned long int word)
+ {
+ int i;
+
+- /* Fallback to unknown output mechanism. */
+- if (type == AT_HWCAP2)
++ /* Fallback to generic output mechanism. */
++ if (type != AT_HWCAP)
+ return -1;
+
+ _dl_printf ("AT_HWCAP: ");
+diff --git a/sysdeps/unix/sysv/linux/arm/dl-procinfo.h b/sysdeps/unix/sysv/linux/arm/dl-procinfo.h
+index 66c00297b7..05c62c8687 100644
+--- a/sysdeps/unix/sysv/linux/arm/dl-procinfo.h
++++ b/sysdeps/unix/sysv/linux/arm/dl-procinfo.h
+@@ -67,7 +67,7 @@ _dl_procinfo (unsigned int type, unsigned long int word)
+ break;
+ }
+ default:
+- /* This should not happen. */
++ /* Fallback to generic output mechanism. */
+ return -1;
+ }
+ _dl_printf ("\n");
+diff --git a/sysdeps/unix/sysv/linux/i386/dl-procinfo.h b/sysdeps/unix/sysv/linux/i386/dl-procinfo.h
+index 22b43431bc..0585cdaa9c 100644
+--- a/sysdeps/unix/sysv/linux/i386/dl-procinfo.h
++++ b/sysdeps/unix/sysv/linux/i386/dl-procinfo.h
+@@ -30,8 +30,8 @@ _dl_procinfo (unsigned int type, unsigned long int word)
+ in the kernel sources. */
+ int i;
+
+- /* Fallback to unknown output mechanism. */
+- if (type == AT_HWCAP2)
++ /* Fallback to generic output mechanism. */
++ if (type != AT_HWCAP)
+ return -1;
+
+ _dl_printf ("AT_HWCAP: ");
+diff --git a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h
+index 19329a335b..d67fde368f 100644
+--- a/sysdeps/unix/sysv/linux/s390/dl-procinfo.h
++++ b/sysdeps/unix/sysv/linux/s390/dl-procinfo.h
+@@ -32,8 +32,8 @@ _dl_procinfo (unsigned int type, unsigned long int word)
+ in the kernel sources. */
+ int i;
+
+- /* Fallback to unknown output mechanism. */
+- if (type == AT_HWCAP2)
++ /* Fallback to generic output mechanism. */
++ if (type != AT_HWCAP)
+ return -1;
+
+ _dl_printf ("AT_HWCAP: ");
+diff --git a/sysdeps/x86_64/memcmp.S b/sysdeps/x86_64/memcmp.S
+index 1fc487caa5..1322bb3b92 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/x32/Makefile b/sysdeps/x86_64/x32/Makefile
+index 1557724b0c..8748956563 100644
+--- a/sysdeps/x86_64/x32/Makefile
++++ b/sysdeps/x86_64/x32/Makefile
+@@ -8,7 +8,8 @@ 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-strncmp tst-size_t-strncpy tst-size_t-strnlen \
++ tst-size_t-memcmp-2
+ endif
+
+ ifeq ($(subdir),wcsmbs)
+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
++ <http://www.gnu.org/licenses/>. */
++
++#define TEST_MAIN
++#ifdef WIDE
++# define TEST_NAME "wmemcmp"
++#else
++# define TEST_NAME "memcmp"
++#endif
++
++#include "test-size_t.h"
++
++#ifdef WIDE
++# include <inttypes.h>
++# include <wchar.h>
++
++# 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 <support/test-driver.c>
diff --git a/glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch b/glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch
deleted file mode 100644
index a80eacfd2c7..00000000000
--- a/glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch
+++ /dev/null
@@ -1,1798 +0,0 @@
-diff --git a/ChangeLog b/ChangeLog
-index 08b42bd2f5..7f4c6a48bc 100644
---- a/ChangeLog
-+++ b/ChangeLog
-@@ -1,3 +1,159 @@
-+2018-10-09 H.J. Lu <hongjiu.lu@intel.com>
-+
-+ [BZ #23716]
-+ * sysdeps/i386/dl-cet.c: Removed.
-+ * sysdeps/i386/dl-machine.h (_dl_runtime_resolve_shstk): New
-+ prototype.
-+ (_dl_runtime_profile_shstk): Likewise.
-+ (elf_machine_runtime_setup): Use _dl_runtime_profile_shstk or
-+ _dl_runtime_resolve_shstk if SHSTK is enabled by kernel.
-+
-+2018-10-09 Rafal Luzynski <digitalfreak@lingonborough.com>
-+
-+ [BZ #20209]
-+ * localedata/locales/kl_GL: (abday): Fix spelling of Sun (Sunday),
-+ should be "sap" rather than "sab".
-+ (day): Fix spelling of Sunday, should be "sapaat" rather than
-+ "sabaat".
-+
-+2018-09-28 Adhemerval Zanella <adhemerval.zanella@linaro.org>
-+
-+ [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-27 Andreas Schwab <schwab@suse.de>
-+
-+ [BZ #23717]
-+ * stdlib/tst-setcontext9.c (f1a): Make st2 static.
-+ (do_test): Make st1 static.
-+
-+2018-09-21 H.J. Lu <hongjiu.lu@intel.com>
-+ Xuepeng Guo <xuepeng.guo@intel.com>
-+
-+ [BZ #23606]
-+ * sysdeps/i386/start.S: Include <sysdep.h>
-+ (_start): Use ENTRY/END to insert ENDBR32 at entry when CET is
-+ enabled. Add cfi_undefined (eip).
-+
-+2018-09-19 Wilco Dijkstra <wdijkstr@arm.com>
-+
-+ [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.
-+
-+2018-09-19 Carlos O'Donell <carlos@redhat.com>
-+
-+ * stdlib/tst-setcontext9.c (f1): Rename to...
-+ (f1a): ... this.
-+ (f1b): New function implementing lower half of f1 in alternate stack.
-+
-+2018-09-20 Florian Weimer <fweimer@redhat.com>
-+
-+ * misc/tst-gethostid.c: New file.
-+ * misc/Makefile [$(build-shared)] (tests): Add tst-gethostid.
-+ (tst-gethostid): Link with -ldl.
-+
-+2018-09-20 Mingli Yu <Mingli.Yu@windriver.com>
-+
-+ * sysdeps/unix/sysv/linux/gethostid.c (gethostid): Check for NULL
-+ value from gethostbyname_r.
-+
-+2018-09-06 Stefan Liebler <stli@linux.ibm.com>
-+
-+ * sysdeps/unix/sysv/linux/spawni.c (maybe_script_execute):
-+ Increment size of new_argv by one.
-+
-+2018-08-28 Florian Weimer <fweimer@redhat.com>
-+
-+ [BZ #23578]
-+ * posix/tst-regcomp-truncated.c: New file.
-+ * posix/Makefile (tests): Add it.
-+ (tst-regcomp-truncated.out): Depend on generated locales.
-+
-+2018-08-25 Paul Eggert <eggert@cs.ucla.edu>
-+
-+ [BZ #23578]
-+ regex: fix uninitialized memory access
-+ I introduced this bug into gnulib in commit
-+ 8335a4d6c7b4448cd0bcb6d0bebf1d456bcfdb17 dated 2006-04-10;
-+ eventually it was merged into glibc. The bug was found by
-+ project-repo <bugs@feusi.co> and reported here:
-+ https://lists.gnu.org/r/sed-devel/2018-08/msg00017.html
-+ Diagnosis and draft fix reported by Assaf Gordon here:
-+ https://lists.gnu.org/r/bug-gnulib/2018-08/msg00071.html
-+ https://lists.gnu.org/r/bug-gnulib/2018-08/msg00142.html
-+ * posix/regex_internal.c (build_wcs_upper_buffer):
-+ Fix bug when mbrtowc returns 0.
-+
-+2018-08-27 Martin Kuchta <martin.kuchta@netapp.com>
-+ Torvald Riegel <triegel@redhat.com>
-+
-+ [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-08-03 DJ Delorie <dj@redhat.com>
-+
-+ * sysdeps/riscv/rvf/math_private.h (libc_feholdexcept_setround_riscv):
-+ Move libc_fesetround_riscv after libc_feholdexcept_riscv.
-+
-+ * sysdeps/riscv/rv64/rvd/libm-test-ulps: Update.
-+
-+2018-08-14 Florian Weimer <fweimer@redhat.com>
-+
-+ [BZ #23521]
-+ [BZ #23522]
-+ * nss/nss_files/files-alias.c (get_next_alias): During :include:
-+ processing, bail out if no room, and close the stream before
-+ returning ERANGE.
-+ * nss/Makefile (tests): Add tst-nss-files-alias-leak.
-+ (tst-nss-files-alias-leak): Link with libdl.
-+ (tst-nss-files-alias-leak.out): Depend on nss_files.
-+
-+ * nss/tst-nss-files-alias-leak.c: New file.
-+
-+2018-08-14 Florian Weimer <fweimer@redhat.com>
-+
-+ * nscd/nscd_conf.c (nscd_parse_file): Deallocate old storage for
-+ server_user, stat_user.
-+
-+2018-08-13 Florian Weimer <fweimer@redhat.com>
-+
-+ * misc/error.c (error): Add missing va_end call.
-+ (error_at_line): Likewise.
-+
-+2018-08-10 Florian Weimer <fweimer@redhat.com>
-+
-+ [BZ #23497]
-+ * sysdeps/unix/sysv/linux/getdents64.c (handle_overflow): New
-+ function.
-+ (__old_getdents64): Use getdents64. Convert entries without
-+ moving them.
-+ * sysdeps/unix/sysv/linux/tst-readdir64-compat.c: New file.
-+ * sysdeps/unix/sysv/linux/Makefile (tests-internal): Add
-+ tst-readdir64-compat.
-+
-+2018-08-08 Samuel Thibault <samuel.thibault@ens-lyon.org>
-+
-+ * htl/Versions (__pthread_getspecific, __pthread_setspecific): Add
-+ symbols.
-+ * sysdeps/htl/pthreadP.h [IS_IN (libpthread)] (__pthread_getspecific,
-+ __pthread_setspecific): Add hidden proto.
-+ * sysdeps/htl/pt-getspecific.c (__pthread_getspecific): Add hidden def.
-+ * sysdeps/htl/pt-setspecific.c (__pthread_setspecific): Add hidden def.
-+
- 2018-08-01 Carlos O'Donel <carlos@redhat.com>
-
- * version.h (RELEASE): Set to "stable".
-diff --git a/NEWS b/NEWS
-index 154ab22d7c..594cecfc75 100644
---- a/NEWS
-+++ b/NEWS
-@@ -5,6 +5,21 @@ See the end for copying conditions.
- Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
- using `glibc' in the "product" field.
-
-+Version 2.28.1
-+
-+The following bugs are resolved with this release:
-+
-+ [20209] localedata: Spelling mistake for Sunday in Greenlandic kl_GL
-+ [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream
-+ [23521] nss_files aliases database file stream leak
-+ [23538] pthread_cond_broadcast: Fix waiters-after-spinning case
-+ [23578] regex: Fix memory overread in re_compile_pattern
-+ [23579] libc: Errors misreported in preadv2
-+ [23606] Missing ENDBR32 in sysdeps/i386/start.S
-+ [23679] gethostid: Missing NULL check for gethostbyname_r result
-+ [23717] Fix stack overflow in stdlib/tst-setcontext9
-+
-+
- Version 2.28
-
- Major new features:
-diff --git a/htl/Versions b/htl/Versions
-index 6a63a1b8a1..c5a616da10 100644
---- a/htl/Versions
-+++ b/htl/Versions
-@@ -150,6 +150,8 @@ libpthread {
- __cthread_keycreate;
- __cthread_getspecific;
- __cthread_setspecific;
-+ __pthread_getspecific;
-+ __pthread_setspecific;
- __pthread_getattr_np;
- __pthread_attr_getstack;
- }
-diff --git a/localedata/locales/kl_GL b/localedata/locales/kl_GL
-index 5ab14a31aa..5723ce7dcf 100644
---- a/localedata/locales/kl_GL
-+++ b/localedata/locales/kl_GL
-@@ -70,11 +70,11 @@ copy "da_DK"
- END LC_NUMERIC
-
- LC_TIME
--abday "sab";"ata";/
-+abday "sap";"ata";/
- "mar";"pin";/
- "sis";"tal";/
- "arf"
--day "sabaat";/
-+day "sapaat";/
- "ataasinngorneq";/
- "marlunngorneq";/
- "pingasunngorneq";/
-diff --git a/misc/Makefile b/misc/Makefile
-index b7be2bc19a..c9f81515ac 100644
---- a/misc/Makefile
-+++ b/misc/Makefile
-@@ -86,6 +86,11 @@ tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \
- tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \
- tst-preadvwritev2 tst-preadvwritev64v2
-
-+# Tests which need libdl.
-+ifeq (yes,$(build-shared))
-+tests += tst-gethostid
-+endif
-+
- tests-internal := tst-atomic tst-atomic-long tst-allocate_once
- tests-static := tst-empty
-
-@@ -145,3 +150,5 @@ tst-allocate_once-ENV = MALLOC_TRACE=$(objpfx)tst-allocate_once.mtrace
- $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out
- $(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \
- $(evaluate-test)
-+
-+$(objpfx)tst-gethostid: $(libdl)
-diff --git a/misc/error.c b/misc/error.c
-index b4e8b6c938..03378e2f2a 100644
---- a/misc/error.c
-+++ b/misc/error.c
-@@ -319,6 +319,7 @@ error (int status, int errnum, const char *message, ...)
-
- va_start (args, message);
- error_tail (status, errnum, message, args);
-+ va_end (args);
-
- #ifdef _LIBC
- _IO_funlockfile (stderr);
-@@ -390,6 +391,7 @@ error_at_line (int status, int errnum, const char *file_name,
-
- va_start (args, message);
- error_tail (status, errnum, message, args);
-+ va_end (args);
-
- #ifdef _LIBC
- _IO_funlockfile (stderr);
-diff --git a/misc/tst-gethostid.c b/misc/tst-gethostid.c
-new file mode 100644
-index 0000000000..1490aaf3f5
---- /dev/null
-+++ b/misc/tst-gethostid.c
-@@ -0,0 +1,108 @@
-+/* Basic test for gethostid.
-+ 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
-+ <http://www.gnu.org/licenses/>. */
-+
-+#include <gnu/lib-names.h>
-+#include <nss.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <support/namespace.h>
-+#include <support/support.h>
-+#include <support/temp_file.h>
-+#include <support/xdlfcn.h>
-+#include <support/xstdio.h>
-+#include <support/xunistd.h>
-+#include <unistd.h>
-+
-+/* Initial test is run outside a chroot, to increase the likelihood of
-+ success. */
-+static void
-+outside_chroot (void *closure)
-+{
-+ long id = gethostid ();
-+ printf ("info: host ID outside chroot: 0x%lx\n", id);
-+}
-+
-+/* The same, but this time perform a chroot operation. */
-+static void
-+in_chroot (void *closure)
-+{
-+ const char *chroot_path = closure;
-+ xchroot (chroot_path);
-+ long id = gethostid ();
-+ printf ("info: host ID in chroot: 0x%lx\n", id);
-+}
-+
-+static int
-+do_test (void)
-+{
-+ support_isolate_in_subprocess (outside_chroot, NULL);
-+
-+ /* Now run the test inside a chroot. */
-+ support_become_root ();
-+ if (!support_can_chroot ())
-+ /* Cannot perform further tests. */
-+ return 0;
-+
-+ /* Only use nss_files. */
-+ __nss_configure_lookup ("hosts", "files");
-+
-+ /* Load the DSO outside of the chroot. */
-+ xdlopen (LIBNSS_FILES_SO, RTLD_LAZY);
-+
-+ char *chroot_dir = support_create_temp_directory ("tst-gethostid-");
-+ support_isolate_in_subprocess (in_chroot, chroot_dir);
-+
-+ /* Tests with /etc/hosts in the chroot. */
-+ {
-+ char *path = xasprintf ("%s/etc", chroot_dir);
-+ add_temp_file (path);
-+ xmkdir (path, 0777);
-+ free (path);
-+ path = xasprintf ("%s/etc/hosts", chroot_dir);
-+ add_temp_file (path);
-+
-+ FILE *fp = xfopen (path, "w");
-+ xfclose (fp);
-+ printf ("info: chroot test with an empty /etc/hosts file\n");
-+ support_isolate_in_subprocess (in_chroot, chroot_dir);
-+
-+ char hostname[1024];
-+ int ret = gethostname (hostname, sizeof (hostname));
-+ if (ret < 0)
-+ printf ("warning: invalid result from gethostname: %d\n", ret);
-+ else if (strlen (hostname) == 0)
-+ puts ("warning: gethostname returned empty string");
-+ else
-+ {
-+ printf ("info: chroot test with IPv6 address in /etc/hosts for: %s\n",
-+ hostname);
-+ fp = xfopen (path, "w");
-+ /* Use an IPv6 address to induce another lookup failure. */
-+ fprintf (fp, "2001:db8::1 %s\n", hostname);
-+ xfclose (fp);
-+ support_isolate_in_subprocess (in_chroot, chroot_dir);
-+ }
-+ free (path);
-+ }
-+ free (chroot_dir);
-+
-+ return 0;
-+}
-+
-+#include <support/test-driver.c>
-diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c
-index f889a21544..50b9da3fea 100644
---- a/misc/tst-preadvwritev2-common.c
-+++ b/misc/tst-preadvwritev2-common.c
-@@ -19,9 +19,6 @@
- #include <limits.h>
- #include <support/check.h>
-
--static void
--do_test_with_invalid_flags (void)
--{
- #ifndef RWF_HIPRI
- # define RWF_HIPRI 0
- #endif
-@@ -39,6 +36,68 @@ do_test_with_invalid_flags (void)
- #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 be22802dbe..cb58cbe41e 100644
---- a/misc/tst-preadvwritev2.c
-+++ b/misc/tst-preadvwritev2.c
-@@ -30,6 +30,8 @@ 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 8d3cc32b28..6a9de54c78 100644
---- a/misc/tst-preadvwritev64v2.c
-+++ b/misc/tst-preadvwritev64v2.c
-@@ -32,6 +32,8 @@ 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/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/nscd/nscd_conf.c b/nscd/nscd_conf.c
-index 265a02434d..7293b795b6 100644
---- a/nscd/nscd_conf.c
-+++ b/nscd/nscd_conf.c
-@@ -190,7 +190,10 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
- if (!arg1)
- error (0, 0, _("Must specify user name for server-user option"));
- else
-- server_user = xstrdup (arg1);
-+ {
-+ free ((char *) server_user);
-+ server_user = xstrdup (arg1);
-+ }
- }
- else if (strcmp (entry, "stat-user") == 0)
- {
-@@ -198,6 +201,7 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
- error (0, 0, _("Must specify user name for stat-user option"));
- else
- {
-+ free ((char *) stat_user);
- stat_user = xstrdup (arg1);
-
- struct passwd *pw = getpwnam (stat_user);
-diff --git a/nss/Makefile b/nss/Makefile
-index 66fac7f5b8..5209fc0456 100644
---- a/nss/Makefile
-+++ b/nss/Makefile
-@@ -65,6 +65,7 @@ ifeq (yes,$(build-shared))
- tests += tst-nss-files-hosts-erange
- tests += tst-nss-files-hosts-multi
- tests += tst-nss-files-hosts-getent
-+tests += tst-nss-files-alias-leak
- endif
-
- # If we have a thread library then we can test cancellation against
-@@ -171,3 +172,5 @@ endif
- $(objpfx)tst-nss-files-hosts-erange: $(libdl)
- $(objpfx)tst-nss-files-hosts-multi: $(libdl)
- $(objpfx)tst-nss-files-hosts-getent: $(libdl)
-+$(objpfx)tst-nss-files-alias-leak: $(libdl)
-+$(objpfx)tst-nss-files-alias-leak.out: $(objpfx)/libnss_files.so
-diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c
-index cfd34b66b9..35b0bfc5d2 100644
---- a/nss/nss_files/files-alias.c
-+++ b/nss/nss_files/files-alias.c
-@@ -221,6 +221,13 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result,
- {
- while (! feof_unlocked (listfile))
- {
-+ if (room_left < 2)
-+ {
-+ free (old_line);
-+ fclose (listfile);
-+ goto no_more_room;
-+ }
-+
- first_unused[room_left - 1] = '\xff';
- line = fgets_unlocked (first_unused, room_left,
- listfile);
-@@ -229,6 +236,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result,
- if (first_unused[room_left - 1] != '\xff')
- {
- free (old_line);
-+ fclose (listfile);
- goto no_more_room;
- }
-
-@@ -256,6 +264,7 @@ get_next_alias (FILE *stream, const char *match, struct aliasent *result,
- + __alignof__ (char *)))
- {
- free (old_line);
-+ fclose (listfile);
- goto no_more_room;
- }
- room_left -= ((first_unused - cp)
-diff --git a/nss/tst-nss-files-alias-leak.c b/nss/tst-nss-files-alias-leak.c
-new file mode 100644
-index 0000000000..26d38e2dba
---- /dev/null
-+++ b/nss/tst-nss-files-alias-leak.c
-@@ -0,0 +1,237 @@
-+/* Check for file descriptor leak in alias :include: processing (bug 23521).
-+ 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
-+ <http://www.gnu.org/licenses/>. */
-+
-+#include <aliases.h>
-+#include <array_length.h>
-+#include <dlfcn.h>
-+#include <errno.h>
-+#include <gnu/lib-names.h>
-+#include <nss.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <support/check.h>
-+#include <support/namespace.h>
-+#include <support/support.h>
-+#include <support/temp_file.h>
-+#include <support/test-driver.h>
-+#include <support/xstdio.h>
-+#include <support/xunistd.h>
-+
-+static struct support_chroot *chroot_env;
-+
-+/* Number of the aliases for the "many" user. This must be large
-+ enough to trigger reallocation for the pointer array, but result in
-+ answers below the maximum size tried in do_test. */
-+enum { many_aliases = 30 };
-+
-+static void
-+prepare (int argc, char **argv)
-+{
-+ chroot_env = support_chroot_create
-+ ((struct support_chroot_configuration) { } );
-+
-+ char *path = xasprintf ("%s/etc/aliases", chroot_env->path_chroot);
-+ add_temp_file (path);
-+ support_write_file_string
-+ (path,
-+ "user1: :include:/etc/aliases.user1\n"
-+ "user2: :include:/etc/aliases.user2\n"
-+ "comment: comment1, :include:/etc/aliases.comment\n"
-+ "many: :include:/etc/aliases.many\n");
-+ free (path);
-+
-+ path = xasprintf ("%s/etc/aliases.user1", chroot_env->path_chroot);
-+ add_temp_file (path);
-+ support_write_file_string (path, "alias1\n");
-+ free (path);
-+
-+ path = xasprintf ("%s/etc/aliases.user2", chroot_env->path_chroot);
-+ add_temp_file (path);
-+ support_write_file_string (path, "alias1a, alias2\n");
-+ free (path);
-+
-+ path = xasprintf ("%s/etc/aliases.comment", chroot_env->path_chroot);
-+ add_temp_file (path);
-+ support_write_file_string
-+ (path,
-+ /* The line must be longer than the line with the :include:
-+ directive in /etc/aliases. */
-+ "# Long line. ##############################################\n"
-+ "comment2\n");
-+ free (path);
-+
-+ path = xasprintf ("%s/etc/aliases.many", chroot_env->path_chroot);
-+ add_temp_file (path);
-+ FILE *fp = xfopen (path, "w");
-+ for (int i = 0; i < many_aliases; ++i)
-+ fprintf (fp, "a%d\n", i);
-+ TEST_VERIFY_EXIT (! ferror (fp));
-+ xfclose (fp);
-+ free (path);
-+}
-+
-+/* The names of the users to test. */
-+static const char *users[] = { "user1", "user2", "comment", "many" };
-+
-+static void
-+check_aliases (int id, const struct aliasent *e)
-+{
-+ TEST_VERIFY_EXIT (id >= 0 || id < array_length (users));
-+ const char *name = users[id];
-+ TEST_COMPARE_BLOB (e->alias_name, strlen (e->alias_name),
-+ name, strlen (name));
-+
-+ switch (id)
-+ {
-+ case 0:
-+ TEST_COMPARE (e->alias_members_len, 1);
-+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
-+ "alias1", strlen ("alias1"));
-+ break;
-+
-+ case 1:
-+ TEST_COMPARE (e->alias_members_len, 2);
-+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
-+ "alias1a", strlen ("alias1a"));
-+ TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]),
-+ "alias2", strlen ("alias2"));
-+ break;
-+
-+ case 2:
-+ TEST_COMPARE (e->alias_members_len, 2);
-+ TEST_COMPARE_BLOB (e->alias_members[0], strlen (e->alias_members[0]),
-+ "comment1", strlen ("comment1"));
-+ TEST_COMPARE_BLOB (e->alias_members[1], strlen (e->alias_members[1]),
-+ "comment2", strlen ("comment2"));
-+ break;
-+
-+ case 3:
-+ TEST_COMPARE (e->alias_members_len, many_aliases);
-+ for (int i = 0; i < e->alias_members_len; ++i)
-+ {
-+ char alias[30];
-+ int len = snprintf (alias, sizeof (alias), "a%d", i);
-+ TEST_VERIFY_EXIT (len > 0);
-+ TEST_COMPARE_BLOB (e->alias_members[i], strlen (e->alias_members[i]),
-+ alias, len);
-+ }
-+ break;
-+ }
-+}
-+
-+static int
-+do_test (void)
-+{
-+ /* Make sure we don't try to load the module in the chroot. */
-+ if (dlopen (LIBNSS_FILES_SO, RTLD_NOW) == NULL)
-+ FAIL_EXIT1 ("could not load " LIBNSS_FILES_SO ": %s", dlerror ());
-+
-+ /* Some of these descriptors will become unavailable if there is a
-+ file descriptor leak. 10 is chosen somewhat arbitrarily. The
-+ array must be longer than the number of files opened by nss_files
-+ at the same time (currently that number is 2). */
-+ int next_descriptors[10];
-+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
-+ {
-+ next_descriptors[i] = dup (0);
-+ TEST_VERIFY_EXIT (next_descriptors[i] > 0);
-+ }
-+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
-+ xclose (next_descriptors[i]);
-+
-+ support_become_root ();
-+ if (!support_can_chroot ())
-+ return EXIT_UNSUPPORTED;
-+
-+ __nss_configure_lookup ("aliases", "files");
-+
-+ xchroot (chroot_env->path_chroot);
-+
-+ /* Attempt various buffer sizes. If the operation succeeds, we
-+ expect correct data. */
-+ for (int id = 0; id < array_length (users); ++id)
-+ {
-+ bool found = false;
-+ for (size_t size = 1; size <= 1000; ++size)
-+ {
-+ void *buffer = malloc (size);
-+ struct aliasent result;
-+ struct aliasent *res;
-+ errno = EINVAL;
-+ int ret = getaliasbyname_r (users[id], &result, buffer, size, &res);
-+ if (ret == 0)
-+ {
-+ if (res != NULL)
-+ {
-+ found = true;
-+ check_aliases (id, res);
-+ }
-+ else
-+ {
-+ support_record_failure ();
-+ printf ("error: failed lookup for user \"%s\", size %zu\n",
-+ users[id], size);
-+ }
-+ }
-+ else if (ret != ERANGE)
-+ {
-+ support_record_failure ();
-+ printf ("error: invalid return code %d (user \%s\", size %zu)\n",
-+ ret, users[id], size);
-+ }
-+ free (buffer);
-+
-+ /* Make sure that we did not have a file descriptor leak. */
-+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
-+ {
-+ int new_fd = dup (0);
-+ if (new_fd != next_descriptors[i])
-+ {
-+ support_record_failure ();
-+ printf ("error: descriptor %d at index %zu leaked"
-+ " (user \"%s\", size %zu)\n",
-+ next_descriptors[i], i, users[id], size);
-+
-+ /* Close unexpected descriptor, the leak probing
-+ descriptors, and the leaked descriptor
-+ next_descriptors[i]. */
-+ xclose (new_fd);
-+ for (size_t j = 0; j <= i; ++j)
-+ xclose (next_descriptors[j]);
-+ goto next_size;
-+ }
-+ }
-+ for (size_t i = 0; i < array_length (next_descriptors); ++i)
-+ xclose (next_descriptors[i]);
-+
-+ next_size:
-+ ;
-+ }
-+ if (!found)
-+ {
-+ support_record_failure ();
-+ printf ("error: user %s not found\n", users[id]);
-+ }
-+ }
-+
-+ support_chroot_free (chroot_env);
-+ return 0;
-+}
-+
-+#define PREPARE prepare
-+#include <support/test-driver.c>
-diff --git a/posix/Makefile b/posix/Makefile
-index 00c62841a2..83162123f9 100644
---- a/posix/Makefile
-+++ b/posix/Makefile
-@@ -96,7 +96,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \
- tst-posix_fadvise tst-posix_fadvise64 \
- tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \
- tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
-- bug-regex38
-+ bug-regex38 tst-regcomp-truncated
- tests-internal := bug-regex5 bug-regex20 bug-regex33 \
- tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \
- tst-glob_lstat_compat tst-spawn4-compat
-@@ -194,6 +194,7 @@ $(objpfx)tst-regex2.out: $(gen-locales)
- $(objpfx)tst-regexloc.out: $(gen-locales)
- $(objpfx)tst-rxspencer.out: $(gen-locales)
- $(objpfx)tst-rxspencer-no-utf8.out: $(gen-locales)
-+$(objpfx)tst-regcomp-truncated.out: $(gen-locales)
- endif
-
- # If we will use the generic uname implementation, we must figure out what
-diff --git a/posix/regex_internal.c b/posix/regex_internal.c
-index 7f0083b918..b10588f1cc 100644
---- a/posix/regex_internal.c
-+++ b/posix/regex_internal.c
-@@ -317,7 +317,7 @@ build_wcs_upper_buffer (re_string_t *pstr)
- mbclen = __mbrtowc (&wc,
- ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx
- + byte_idx), remain_len, &pstr->cur_state);
-- if (BE (mbclen < (size_t) -2, 1))
-+ if (BE (0 < mbclen && mbclen < (size_t) -2, 1))
- {
- wchar_t wcu = __towupper (wc);
- if (wcu != wc)
-@@ -386,7 +386,7 @@ build_wcs_upper_buffer (re_string_t *pstr)
- else
- p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + src_idx;
- mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state);
-- if (BE (mbclen < (size_t) -2, 1))
-+ if (BE (0 < mbclen && mbclen < (size_t) -2, 1))
- {
- wchar_t wcu = __towupper (wc);
- if (wcu != wc)
-diff --git a/posix/tst-regcomp-truncated.c b/posix/tst-regcomp-truncated.c
-new file mode 100644
-index 0000000000..a4a1581bbc
---- /dev/null
-+++ b/posix/tst-regcomp-truncated.c
-@@ -0,0 +1,191 @@
-+/* Test compilation of truncated regular expressions.
-+ 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
-+ <http://www.gnu.org/licenses/>. */
-+
-+/* This test constructs various patterns in an attempt to trigger
-+ over-reading the regular expression compiler, such as bug
-+ 23578. */
-+
-+#include <array_length.h>
-+#include <errno.h>
-+#include <locale.h>
-+#include <regex.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <support/check.h>
-+#include <support/next_to_fault.h>
-+#include <support/support.h>
-+#include <support/test-driver.h>
-+#include <wchar.h>
-+
-+/* Locales to test. */
-+static const char locales[][17] =
-+ {
-+ "C",
-+ "en_US.UTF-8",
-+ "de_DE.ISO-8859-1",
-+ };
-+
-+/* Syntax options. Will be combined with other flags. */
-+static const reg_syntax_t syntaxes[] =
-+ {
-+ RE_SYNTAX_EMACS,
-+ RE_SYNTAX_AWK,
-+ RE_SYNTAX_GNU_AWK,
-+ RE_SYNTAX_POSIX_AWK,
-+ RE_SYNTAX_GREP,
-+ RE_SYNTAX_EGREP,
-+ RE_SYNTAX_POSIX_EGREP,
-+ RE_SYNTAX_POSIX_BASIC,
-+ RE_SYNTAX_POSIX_EXTENDED,
-+ RE_SYNTAX_POSIX_MINIMAL_EXTENDED,
-+ };
-+
-+/* Trailing characters placed after the initial character. */
-+static const char trailing_strings[][4] =
-+ {
-+ "",
-+ "[",
-+ "\\",
-+ "[\\",
-+ "(",
-+ "(\\",
-+ "\\(",
-+ };
-+
-+static int
-+do_test (void)
-+{
-+ /* Staging buffer for the constructed regular expression. */
-+ char buffer[16];
-+
-+ /* Allocation used to detect over-reading by the regular expression
-+ compiler. */
-+ struct support_next_to_fault ntf
-+ = support_next_to_fault_allocate (sizeof (buffer));
-+
-+ /* Arbitrary Unicode codepoint at which we stop generating
-+ characters. We do not probe the whole range because that would
-+ take too long due to combinatorical exploision as the result of
-+ combination with other flags. */
-+ static const wchar_t last_character = 0xfff;
-+
-+ for (size_t locale_idx = 0; locale_idx < array_length (locales);
-+ ++ locale_idx)
-+ {
-+ if (setlocale (LC_ALL, locales[locale_idx]) == NULL)
-+ {
-+ support_record_failure ();
-+ printf ("error: setlocale (\"%s\"): %m", locales[locale_idx]);
-+ continue;
-+ }
-+ if (test_verbose > 0)
-+ printf ("info: testing locale \"%s\"\n", locales[locale_idx]);
-+
-+ for (wchar_t wc = 0; wc <= last_character; ++wc)
-+ {
-+ char *after_wc;
-+ if (wc == 0)
-+ {
-+ /* wcrtomb treats L'\0' in a special way. */
-+ *buffer = '\0';
-+ after_wc = &buffer[1];
-+ }
-+ else
-+ {
-+ mbstate_t ps = { };
-+ size_t ret = wcrtomb (buffer, wc, &ps);
-+ if (ret == (size_t) -1)
-+ {
-+ /* EILSEQ means that the target character set
-+ cannot encode the character. */
-+ if (errno != EILSEQ)
-+ {
-+ support_record_failure ();
-+ printf ("error: wcrtomb (0x%x) failed: %m\n",
-+ (unsigned) wc);
-+ }
-+ continue;
-+ }
-+ TEST_VERIFY_EXIT (ret != 0);
-+ after_wc = &buffer[ret];
-+ }
-+
-+ for (size_t trailing_idx = 0;
-+ trailing_idx < array_length (trailing_strings);
-+ ++trailing_idx)
-+ {
-+ char *after_trailing
-+ = stpcpy (after_wc, trailing_strings[trailing_idx]);
-+
-+ for (int do_nul = 0; do_nul < 2; ++do_nul)
-+ {
-+ char *after_nul;
-+ if (do_nul)
-+ {
-+ *after_trailing = '\0';
-+ after_nul = &after_trailing[1];
-+ }
-+ else
-+ after_nul = after_trailing;
-+
-+ size_t length = after_nul - buffer;
-+
-+ /* Make sure that the faulting region starts
-+ after the used portion of the buffer. */
-+ char *ntf_start = ntf.buffer + sizeof (buffer) - length;
-+ memcpy (ntf_start, buffer, length);
-+
-+ for (const reg_syntax_t *psyntax = syntaxes;
-+ psyntax < array_end (syntaxes); ++psyntax)
-+ for (int do_icase = 0; do_icase < 2; ++do_icase)
-+ {
-+ re_syntax_options = *psyntax;
-+ if (do_icase)
-+ re_syntax_options |= RE_ICASE;
-+
-+ regex_t reg;
-+ memset (&reg, 0, sizeof (reg));
-+ const char *msg = re_compile_pattern
-+ (ntf_start, length, &reg);
-+ if (msg != NULL)
-+ {
-+ if (test_verbose > 0)
-+ {
-+ char *quoted = support_quote_blob
-+ (buffer, length);
-+ printf ("info: compilation failed for pattern"
-+ " \"%s\", syntax 0x%lx: %s\n",
-+ quoted, re_syntax_options, msg);
-+ free (quoted);
-+ }
-+ }
-+ else
-+ regfree (&reg);
-+ }
-+ }
-+ }
-+ }
-+ }
-+
-+ support_next_to_fault_free (&ntf);
-+
-+ return 0;
-+}
-+
-+#include <support/test-driver.c>
-diff --git a/stdlib/tst-setcontext9.c b/stdlib/tst-setcontext9.c
-index 4636ce9030..009928235d 100644
---- a/stdlib/tst-setcontext9.c
-+++ b/stdlib/tst-setcontext9.c
-@@ -41,30 +41,59 @@ f2 (void)
- }
-
- static void
--f1 (void)
-+f1b (void)
- {
-- puts ("start f1");
-- if (getcontext (&ctx[2]) != 0)
-- {
-- printf ("%s: getcontext: %m\n", __FUNCTION__);
-- exit (EXIT_FAILURE);
-- }
- if (done)
- {
-- puts ("set context in f1");
-+ puts ("set context in f1b");
- if (setcontext (&ctx[3]) != 0)
- {
- printf ("%s: setcontext: %m\n", __FUNCTION__);
- exit (EXIT_FAILURE);
- }
- }
-+ exit (EXIT_FAILURE);
-+}
-+
-+static void
-+f1a (void)
-+{
-+ static char st2[32768];
-+ puts ("start f1a");
-+ if (getcontext (&ctx[2]) != 0)
-+ {
-+ printf ("%s: getcontext: %m\n", __FUNCTION__);
-+ exit (EXIT_FAILURE);
-+ }
-+ ctx[2].uc_stack.ss_sp = st2;
-+ ctx[2].uc_stack.ss_size = sizeof st2;
-+ ctx[2].uc_link = &ctx[0];
-+ makecontext (&ctx[2], (void (*) (void)) f1b, 0);
- f2 ();
- }
-
-+/* The execution path through the test looks like this:
-+ do_test (call)
-+ -> "making contexts"
-+ -> "swap contexts"
-+ f1a (via swapcontext to ctx[1], with alternate stack)
-+ -> "start f1a"
-+ f2 (call)
-+ -> "swap contexts in f2"
-+ f1b (via swapcontext to ctx[2], with alternate stack)
-+ -> "set context in f1b"
-+ do_test (via setcontext to ctx[3], main stack)
-+ -> "setcontext"
-+ f2 (via setcontext to ctx[4], with alternate stack)
-+ -> "end f2"
-+
-+ We must use an alternate stack for f1b, because if we don't then the
-+ result of executing an earlier caller may overwrite registers
-+ spilled to the stack in f2. */
- static int
- do_test (void)
- {
-- char st1[32768];
-+ static char st1[32768];
- puts ("making contexts");
- if (getcontext (&ctx[0]) != 0)
- {
-@@ -79,7 +108,7 @@ do_test (void)
- ctx[1].uc_stack.ss_sp = st1;
- ctx[1].uc_stack.ss_size = sizeof st1;
- ctx[1].uc_link = &ctx[0];
-- makecontext (&ctx[1], (void (*) (void)) f1, 0);
-+ makecontext (&ctx[1], (void (*) (void)) f1a, 0);
- puts ("swap contexts");
- if (swapcontext (&ctx[3], &ctx[1]) != 0)
- {
-diff --git a/string/strcasestr.c b/string/strcasestr.c
-index 5909fe3cdb..421764bd1b 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) \
-- (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \
-- (j) + (n_l) <= (h_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)
-diff --git a/string/strstr.c b/string/strstr.c
-index 265e9f310c..79ebcc7532 100644
---- a/string/strstr.c
-+++ b/string/strstr.c
-@@ -33,8 +33,9 @@
-
- #define RETURN_TYPE char *
- #define AVAILABLE(h, h_l, j, n_l) \
-- (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \
-- (j) + (n_l) <= (h_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 FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C))
-diff --git a/string/test-strstr.c b/string/test-strstr.c
-index 8d99716ff3..5861b01b73 100644
---- a/string/test-strstr.c
-+++ b/string/test-strstr.c
-@@ -151,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)
- {
-@@ -158,6 +184,7 @@ test_main (void)
-
- check1 ();
- check2 ();
-+ pr23637 ();
-
- printf ("%23s", "");
- FOR_EACH_IMPL (impl, 0)
-@@ -202,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/sysdeps/htl/pt-getspecific.c b/sysdeps/htl/pt-getspecific.c
-index a0227a67f6..64ddf9551a 100644
---- a/sysdeps/htl/pt-getspecific.c
-+++ b/sysdeps/htl/pt-getspecific.c
-@@ -36,3 +36,4 @@ __pthread_getspecific (pthread_key_t key)
- return self->thread_specifics[key];
- }
- strong_alias (__pthread_getspecific, pthread_getspecific);
-+hidden_def (__pthread_getspecific)
-diff --git a/sysdeps/htl/pt-setspecific.c b/sysdeps/htl/pt-setspecific.c
-index a46a12f157..02aff417ef 100644
---- a/sysdeps/htl/pt-setspecific.c
-+++ b/sysdeps/htl/pt-setspecific.c
-@@ -48,3 +48,4 @@ __pthread_setspecific (pthread_key_t key, const void *value)
- return 0;
- }
- strong_alias (__pthread_setspecific, pthread_setspecific);
-+hidden_def (__pthread_setspecific)
-diff --git a/sysdeps/htl/pthreadP.h b/sysdeps/htl/pthreadP.h
-index 132ac1718e..71c2fcd9c6 100644
---- a/sysdeps/htl/pthreadP.h
-+++ b/sysdeps/htl/pthreadP.h
-@@ -68,6 +68,8 @@ struct __pthread_cancelation_handler **___pthread_get_cleanup_stack (void) attri
-
- #if IS_IN (libpthread)
- hidden_proto (__pthread_key_create)
-+hidden_proto (__pthread_getspecific)
-+hidden_proto (__pthread_setspecific)
- hidden_proto (_pthread_mutex_init)
- #endif
-
-diff --git a/sysdeps/i386/dl-cet.c b/sysdeps/i386/dl-cet.c
-deleted file mode 100644
-index 5d9a4e8d51..0000000000
---- a/sysdeps/i386/dl-cet.c
-+++ /dev/null
-@@ -1,67 +0,0 @@
--/* Linux/i386 CET initializers function.
-- Copyright (C) 2018 Free Software Foundation, Inc.
--
-- The GNU C Library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 2.1 of the License, or (at your option) any later version.
--
-- The GNU C Library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public
-- License along with the GNU C Library; if not, see
-- <http://www.gnu.org/licenses/>. */
--
--
--#define LINKAGE static inline
--#define _dl_cet_check cet_check
--#include <sysdeps/x86/dl-cet.c>
--#undef _dl_cet_check
--
--#ifdef SHARED
--void
--_dl_cet_check (struct link_map *main_map, const char *program)
--{
-- cet_check (main_map, program);
--
-- if ((GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
-- {
-- /* Replace _dl_runtime_resolve and _dl_runtime_profile with
-- _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk,
-- respectively if SHSTK is enabled. */
-- extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
-- extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden;
-- extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
-- extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden;
-- unsigned int i;
-- struct link_map *l;
-- Elf32_Addr *got;
--
-- if (main_map->l_info[DT_JMPREL])
-- {
-- got = (Elf32_Addr *) D_PTR (main_map, l_info[DT_PLTGOT]);
-- if (got[2] == (Elf32_Addr) &_dl_runtime_resolve)
-- got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk;
-- else if (got[2] == (Elf32_Addr) &_dl_runtime_profile)
-- got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk;
-- }
--
-- i = main_map->l_searchlist.r_nlist;
-- while (i-- > 0)
-- {
-- l = main_map->l_initfini[i];
-- if (l->l_info[DT_JMPREL])
-- {
-- got = (Elf32_Addr *) D_PTR (l, l_info[DT_PLTGOT]);
-- if (got[2] == (Elf32_Addr) &_dl_runtime_resolve)
-- got[2] = (Elf32_Addr) &_dl_runtime_resolve_shstk;
-- else if (got[2] == (Elf32_Addr) &_dl_runtime_profile)
-- got[2] = (Elf32_Addr) &_dl_runtime_profile_shstk;
-- }
-- }
-- }
--}
--#endif
-diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
-index 1afdcbd9ea..f6cfb90e21 100644
---- a/sysdeps/i386/dl-machine.h
-+++ b/sysdeps/i386/dl-machine.h
-@@ -67,6 +67,11 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
- Elf32_Addr *got;
- extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
- extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
-+ extern void _dl_runtime_resolve_shstk (Elf32_Word) attribute_hidden;
-+ extern void _dl_runtime_profile_shstk (Elf32_Word) attribute_hidden;
-+ /* Check if SHSTK is enabled by kernel. */
-+ bool shstk_enabled
-+ = (GL(dl_x86_feature_1)[0] & GNU_PROPERTY_X86_FEATURE_1_SHSTK) != 0;
-
- if (l->l_info[DT_JMPREL] && lazy)
- {
-@@ -93,7 +98,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
- end in this function. */
- if (__glibc_unlikely (profile))
- {
-- got[2] = (Elf32_Addr) &_dl_runtime_profile;
-+ got[2] = (shstk_enabled
-+ ? (Elf32_Addr) &_dl_runtime_profile_shstk
-+ : (Elf32_Addr) &_dl_runtime_profile);
-
- if (GLRO(dl_profile) != NULL
- && _dl_name_match_p (GLRO(dl_profile), l))
-@@ -104,7 +111,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
- else
- /* This function will get called to fix up the GOT entry indicated by
- the offset on the stack, and then jump to the resolved address. */
-- got[2] = (Elf32_Addr) &_dl_runtime_resolve;
-+ got[2] = (shstk_enabled
-+ ? (Elf32_Addr) &_dl_runtime_resolve_shstk
-+ : (Elf32_Addr) &_dl_runtime_resolve);
- }
-
- return lazy;
-diff --git a/sysdeps/i386/start.S b/sysdeps/i386/start.S
-index 91035fa83f..e35e9bd31b 100644
---- a/sysdeps/i386/start.S
-+++ b/sysdeps/i386/start.S
-@@ -52,10 +52,11 @@
- NULL
- */
-
-- .text
-- .globl _start
-- .type _start,@function
--_start:
-+#include <sysdep.h>
-+
-+ENTRY (_start)
-+ /* Clearing frame pointer is insufficient, use CFI. */
-+ cfi_undefined (eip)
- /* Clear the frame pointer. The ABI suggests this be done, to mark
- the outermost frame obviously. */
- xorl %ebp, %ebp
-@@ -131,6 +132,7 @@ _start:
- 1: movl (%esp), %ebx
- ret
- #endif
-+END (_start)
-
- /* To fulfill the System V/i386 ABI we need this symbol. Yuck, it's so
- meaningless since we don't support machines < 80386. */
-diff --git a/sysdeps/riscv/rv64/rvd/libm-test-ulps b/sysdeps/riscv/rv64/rvd/libm-test-ulps
-index f8feadcd0d..61be2df60d 100644
---- a/sysdeps/riscv/rv64/rvd/libm-test-ulps
-+++ b/sysdeps/riscv/rv64/rvd/libm-test-ulps
-@@ -1006,6 +1006,8 @@ ildouble: 2
- ldouble: 2
-
- Function: "cos":
-+double: 1
-+idouble: 1
- ildouble: 1
- ldouble: 1
-
-@@ -1348,9 +1350,9 @@ ildouble: 4
- ldouble: 4
-
- Function: Imaginary part of "ctan_towardzero":
--double: 1
-+double: 2
- float: 2
--idouble: 1
-+idouble: 2
- ifloat: 2
- ildouble: 5
- ldouble: 5
-@@ -1898,10 +1900,12 @@ ldouble: 2
- Function: "log_upward":
- double: 1
- idouble: 1
--ildouble: 1
--ldouble: 1
-+ildouble: 2
-+ldouble: 2
-
- Function: "pow":
-+double: 1
-+idouble: 1
- ildouble: 2
- ldouble: 2
-
-@@ -1930,6 +1934,8 @@ ildouble: 2
- ldouble: 2
-
- Function: "sin":
-+double: 1
-+idouble: 1
- ildouble: 1
- ldouble: 1
-
-@@ -1952,6 +1958,8 @@ ildouble: 3
- ldouble: 3
-
- Function: "sincos":
-+double: 1
-+idouble: 1
- ildouble: 1
- ldouble: 1
-
-diff --git a/sysdeps/riscv/rvf/math_private.h b/sysdeps/riscv/rvf/math_private.h
-index cdb7858fc8..ca587620cb 100644
---- a/sysdeps/riscv/rvf/math_private.h
-+++ b/sysdeps/riscv/rvf/math_private.h
-@@ -72,8 +72,8 @@ libc_fesetround_riscv (int round)
- static __always_inline void
- libc_feholdexcept_setround_riscv (fenv_t *envp, int round)
- {
-- libc_fesetround_riscv (round);
- libc_feholdexcept_riscv (envp);
-+ libc_fesetround_riscv (round);
- }
-
- #define libc_feholdexcept_setround libc_feholdexcept_setround_riscv
-diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
-index f71cc39c7e..773aaea0e9 100644
---- a/sysdeps/unix/sysv/linux/Makefile
-+++ b/sysdeps/unix/sysv/linux/Makefile
-@@ -161,6 +161,7 @@ inhibit-glue = yes
-
- ifeq ($(subdir),dirent)
- sysdep_routines += getdirentries getdirentries64
-+tests-internal += tst-readdir64-compat
- endif
-
- ifeq ($(subdir),nis)
-diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c
-index 3bde0cf4f0..bc140b5a7f 100644
---- a/sysdeps/unix/sysv/linux/getdents64.c
-+++ b/sysdeps/unix/sysv/linux/getdents64.c
-@@ -33,41 +33,80 @@ strong_alias (__getdents64, __getdents)
- # include <shlib-compat.h>
-
- # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
--# include <olddirent.h>
-+# include <olddirent.h>
-+# include <unistd.h>
-
--/* kernel definition of as of 3.2. */
--struct compat_linux_dirent
-+static ssize_t
-+handle_overflow (int fd, __off64_t offset, ssize_t count)
- {
-- /* Both d_ino and d_off are compat_ulong_t which are defined in all
-- architectures as 'u32'. */
-- uint32_t d_ino;
-- uint32_t d_off;
-- unsigned short d_reclen;
-- char d_name[1];
--};
-+ /* If this is the first entry in the buffer, we can report the
-+ error. */
-+ if (count == 0)
-+ {
-+ __set_errno (EOVERFLOW);
-+ return -1;
-+ }
-+
-+ /* Otherwise, seek to the overflowing entry, so that the next call
-+ will report the error, and return the data read so far.. */
-+ if (__lseek64 (fd, offset, SEEK_SET) != 0)
-+ return -1;
-+ return count;
-+}
-
- ssize_t
- __old_getdents64 (int fd, char *buf, size_t nbytes)
- {
-- ssize_t retval = INLINE_SYSCALL_CALL (getdents, fd, buf, nbytes);
-+ /* We do not move the individual directory entries. This is only
-+ possible if the target type (struct __old_dirent64) is smaller
-+ than the source type. */
-+ _Static_assert (offsetof (struct __old_dirent64, d_name)
-+ <= offsetof (struct dirent64, d_name),
-+ "__old_dirent64 is larger than dirent64");
-+ _Static_assert (__alignof__ (struct __old_dirent64)
-+ <= __alignof__ (struct dirent64),
-+ "alignment of __old_dirent64 is larger than dirent64");
-
-- /* The kernel added the d_type value after the name. Change this now. */
-- if (retval != -1)
-+ ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes);
-+ if (retval > 0)
- {
-- union
-- {
-- struct compat_linux_dirent k;
-- struct dirent u;
-- } *kbuf = (void *) buf;
--
-- while ((char *) kbuf < buf + retval)
-+ char *p = buf;
-+ char *end = buf + retval;
-+ while (p < end)
- {
-- char d_type = *((char *) kbuf + kbuf->k.d_reclen - 1);
-- memmove (kbuf->u.d_name, kbuf->k.d_name,
-- strlen (kbuf->k.d_name) + 1);
-- kbuf->u.d_type = d_type;
-+ struct dirent64 *source = (struct dirent64 *) p;
-+
-+ /* Copy out the fixed-size data. */
-+ __ino_t ino = source->d_ino;
-+ __off64_t offset = source->d_off;
-+ unsigned int reclen = source->d_reclen;
-+ unsigned char type = source->d_type;
-+
-+ /* Check for ino_t overflow. */
-+ if (__glibc_unlikely (ino != source->d_ino))
-+ return handle_overflow (fd, offset, p - buf);
-+
-+ /* Convert to the target layout. Use a separate struct and
-+ memcpy to side-step aliasing issues. */
-+ struct __old_dirent64 result;
-+ result.d_ino = ino;
-+ result.d_off = offset;
-+ result.d_reclen = reclen;
-+ result.d_type = type;
-+
-+ /* Write the fixed-sized part of the result to the
-+ buffer. */
-+ size_t result_name_offset = offsetof (struct __old_dirent64, d_name);
-+ memcpy (p, &result, result_name_offset);
-+
-+ /* Adjust the position of the name if necessary. Copy
-+ everything until the end of the record, including the
-+ terminating NUL byte. */
-+ if (result_name_offset != offsetof (struct dirent64, d_name))
-+ memmove (p + result_name_offset, source->d_name,
-+ reclen - offsetof (struct dirent64, d_name));
-
-- kbuf = (void *) ((char *) kbuf + kbuf->k.d_reclen);
-+ p += reclen;
- }
- }
- return retval;
-diff --git a/sysdeps/unix/sysv/linux/gethostid.c b/sysdeps/unix/sysv/linux/gethostid.c
-index 2e20f034dc..ee0190e7f9 100644
---- a/sysdeps/unix/sysv/linux/gethostid.c
-+++ b/sysdeps/unix/sysv/linux/gethostid.c
-@@ -102,12 +102,12 @@ gethostid (void)
- {
- int ret = __gethostbyname_r (hostname, &hostbuf,
- tmpbuf.data, tmpbuf.length, &hp, &herr);
-- if (ret == 0)
-+ if (ret == 0 && hp != NULL)
- break;
- else
- {
- /* Enlarge the buffer on ERANGE. */
-- if (herr == NETDB_INTERNAL && errno == ERANGE)
-+ if (ret != 0 && herr == NETDB_INTERNAL && errno == ERANGE)
- {
- if (!scratch_buffer_grow (&tmpbuf))
- return 0;
-diff --git a/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c
-index c8bf0764ef..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:
-diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c
-index d7400a0252..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:
-diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c
-index 29c2264c8f..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:
-diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c
-index 42da321149..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:
-diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
-index cf0213ece5..85239cedbf 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)
-diff --git a/sysdeps/unix/sysv/linux/tst-readdir64-compat.c b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c
-new file mode 100644
-index 0000000000..43c4a8477c
---- /dev/null
-+++ b/sysdeps/unix/sysv/linux/tst-readdir64-compat.c
-@@ -0,0 +1,111 @@
-+/* Test readdir64 compatibility symbol.
-+ 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
-+ <http://www.gnu.org/licenses/>. */
-+
-+#include <dirent.h>
-+#include <dlfcn.h>
-+#include <errno.h>
-+#include <shlib-compat.h>
-+#include <stdbool.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <support/check.h>
-+
-+/* Copied from <olddirent.h>. */
-+struct __old_dirent64
-+ {
-+ __ino_t d_ino;
-+ __off64_t d_off;
-+ unsigned short int d_reclen;
-+ unsigned char d_type;
-+ char d_name[256];
-+ };
-+
-+typedef struct __old_dirent64 *(*compat_readdir64_type) (DIR *);
-+
-+#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2)
-+struct __old_dirent64 *compat_readdir64 (DIR *);
-+compat_symbol_reference (libc, compat_readdir64, readdir64, GLIBC_2_1);
-+#endif
-+
-+static int
-+do_test (void)
-+{
-+#if TEST_COMPAT (libc, GLIBC_2_1, GLIBC_2_2)
-+
-+ /* Directory stream using the non-compat readdir64 symbol. The test
-+ checks against this. */
-+ DIR *dir_reference = opendir (".");
-+ TEST_VERIFY_EXIT (dir_reference != NULL);
-+ DIR *dir_test = opendir (".");
-+ TEST_VERIFY_EXIT (dir_test != NULL);
-+
-+ /* This loop assumes that the enumeration order is consistent for
-+ two different handles. Nothing should write to the current
-+ directory (in the source tree) while this test runs, so there
-+ should not be any difference due to races. */
-+ size_t count = 0;
-+ while (true)
-+ {
-+ errno = 0;
-+ struct dirent64 *entry_reference = readdir64 (dir_reference);
-+ if (entry_reference == NULL && errno != 0)
-+ FAIL_EXIT1 ("readdir64 entry %zu: %m\n", count);
-+ struct __old_dirent64 *entry_test = compat_readdir64 (dir_test);
-+ if (entry_reference == NULL)
-+ {
-+ if (errno == EOVERFLOW)
-+ {
-+ TEST_VERIFY (entry_reference->d_ino
-+ != (__ino_t) entry_reference->d_ino);
-+ printf ("info: inode number overflow at entry %zu\n", count);
-+ break;
-+ }
-+ if (errno != 0)
-+ FAIL_EXIT1 ("compat readdir64 entry %zu: %m\n", count);
-+ }
-+
-+ /* Check that both streams end at the same time. */
-+ if (entry_reference == NULL)
-+ {
-+ TEST_VERIFY (entry_test == NULL);
-+ break;
-+ }
-+ else
-+ TEST_VERIFY_EXIT (entry_test != NULL);
-+
-+ /* Check that the entries are the same. */
-+ TEST_COMPARE_BLOB (entry_reference->d_name,
-+ strlen (entry_reference->d_name),
-+ entry_test->d_name, strlen (entry_test->d_name));
-+ TEST_COMPARE (entry_reference->d_ino, entry_test->d_ino);
-+ TEST_COMPARE (entry_reference->d_off, entry_test->d_off);
-+ TEST_COMPARE (entry_reference->d_type, entry_test->d_type);
-+ TEST_COMPARE (entry_reference->d_reclen, entry_test->d_reclen);
-+
-+ ++count;
-+ }
-+ printf ("info: %zu directory entries found\n", count);
-+ TEST_VERIFY (count >= 3); /* ".", "..", and some source files. */
-+
-+ TEST_COMPARE (closedir (dir_test), 0);
-+ TEST_COMPARE (closedir (dir_reference), 0);
-+#endif
-+ return 0;
-+}
-+
-+#include <support/test-driver.c>