summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes2019-02-02 21:14:22 -0500
committerTavian Barnes2019-02-02 21:23:43 -0500
commitcbacff4f8fa16e713686e844f163c492c1c35333 (patch)
treede29f2c9638c4cc8d62aeed1ca8ac0afe3a40e2b
parenta33e2f690fa32ccf99083d3ec7eaa5e209fc262c (diff)
downloadaur-cbacff4f8fa16e713686e844f163c492c1c35333.tar.gz
Bump to 2.28-5
-rw-r--r--.SRCINFO18
-rw-r--r--PKGBUILD18
-rw-r--r--glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch1798
3 files changed, 1818 insertions, 16 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 72900eab402..78b5006d0ea 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,22 +1,24 @@
# Generated by mksrcinfo v8
-# Fri May 11 15:28:59 UTC 2018
+# Sun Feb 3 02:23:32 UTC 2019
pkgbase = arm-linux-gnueabihf-glibc-headers
pkgdesc = GNU C Library headers (arm-linux-gnueabihf)
- pkgver = 2.27
- pkgrel = 3
+ pkgver = 2.28
+ pkgrel = 5
url = http://www.gnu.org/software/libc/
arch = any
license = GPL
license = LGPL
- makedepends = arm-linux-gnueabihf-gcc-stage1>=8.1.0-1
- depends = arm-linux-gnueabihf-linux-api-headers>=4.16.1-1
+ makedepends = arm-linux-gnueabihf-gcc-stage1>=8.2.1+20181127
+ depends = arm-linux-gnueabihf-linux-api-headers>=4.17.11-1
options = !buildflags
options = !strip
options = staticlibs
- source = https://ftp.gnu.org/gnu/glibc/glibc-2.27.tar.xz
- source = https://ftp.gnu.org/gnu/glibc/glibc-2.27.tar.xz.sig
- md5sums = 898cd5656519ffbc3a03fe811dd89e82
+ 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
md5sums = SKIP
+ md5sums = b64d9921601d1e25cca2c802f15d6dcf
pkgname = arm-linux-gnueabihf-glibc-headers
diff --git a/PKGBUILD b/PKGBUILD
index 04966542f32..c8dd7be1477 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -7,21 +7,23 @@
_target="arm-linux-gnueabihf"
pkgname=${_target}-glibc-headers
-pkgver=2.27
-pkgrel=3
+pkgver=2.28
+pkgrel=5
pkgdesc="GNU C Library headers (${_target})"
arch=('any')
url="http://www.gnu.org/software/libc/"
license=(GPL LGPL)
-depends=("${_target}-linux-api-headers>=4.16.1-1")
-makedepends=("${_target}-gcc-stage1>=8.1.0-1")
+depends=("${_target}-linux-api-headers>=4.17.11-1")
+makedepends=("${_target}-gcc-stage1>=8.2.1+20181127")
options=(!buildflags !strip staticlibs)
-_commit=23158b08a0908f381459f273a984c6fd328363cb
+_commit=5a74abda201907cafbdabd1debf98890313ff71e
#source=(git+https://sourceware.org/git/glibc.git#commit=$_commit
-source=(https://ftp.gnu.org/gnu/glibc/glibc-$pkgver.tar.xz{,.sig})
+source=(https://ftp.gnu.org/gnu/glibc/glibc-$pkgver.tar.xz{,.sig}
+ glibc-${_commit}.patch)
validpgpkeys=(7273542B39962DF7B299931416792B4EA25340F8) # Carlos O'Donell
-md5sums=('898cd5656519ffbc3a03fe811dd89e82'
- 'SKIP')
+md5sums=('c81d2388896379997bc359d4f2084239'
+ 'SKIP'
+ 'b64d9921601d1e25cca2c802f15d6dcf')
prepare() {
mkdir -p glibc-build
diff --git a/glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch b/glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch
new file mode 100644
index 00000000000..a80eacfd2c7
--- /dev/null
+++ b/glibc-5a74abda201907cafbdabd1debf98890313ff71e.patch
@@ -0,0 +1,1798 @@
+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>