[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1007746: buster-pu: package glibc/2.28-10+deb10u1



Package: release.debian.org
Severity: normal
Tags: buster
User: release.debian.org@packages.debian.org
Usertags: pu

[ Reason ]
A big part of the changes have been in the buster git branch for many
months, but I failed to submit the package for a point release up to
now. What triggered me to look at it again is breakage in the preinst
script when running on kernel x.y.z with z > 255.

In other changes are just an (old) pull from the stable branch, fixing
a few important bugs.

[ Impact ]
The preinst script fixes are important in order for the security team to
provide kernels with minor version greater than 255. Given that the
current stable kernel from the 4.19 branch is 4.19.234, it is likely to
happen in a few months.

[ Tests ]
The preinst changes have been in testing for more than 6 months and have
been submitted to stable (see bug#1005949).

The other changes have been in stable and in testing/sid for more than 2
years. They come with additional tests, which actually represent a
significant part of the diff.

[ Risks ]
The risk can probably be considered low, as the changes have been tested
in testing/sid and upstream or on other distributions.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]

Let me comment the changelog:

  * debian/patches/git-updates.diff: update from upstream stable branch
    (Closes: #930697):

This is an (old) pull from the upstream stable branch, here are the
details:

    - Add more integrity check to malloc() function.

This adds a few more early checks to the malloc() function, to detect
memory corruption early to reduce the attack surface.

    - Fix crash in _IO_wfile_sync.

This fixes a stack smashing in fgetwc() with some locales. See
https://sourceware.org/bugzilla/show_bug.cgi?id=20568 for more details.

    - Fix bad free() in libdl if dlerror() is not used.  Closes: #953257.

This fixes a wrong call to free() that might causes a crash when running
under valgrind.

    - Fix overflow in glibc.malloc.tcache_count tunable.

This limit the user provided value of the glibc.malloc.tcache_count
tunable (from the GLIBC_TUNABLES environment variable) to avoid a later
assertion in malloc. See
https://sourceware.org/bugzilla/show_bug.cgi?id=24531 for more details.

    - Fix old x86 applications crash on exit() under valgrind.

See https://sourceware.org/bugzilla/show_bug.cgi?id=24228 for more
details.

    - Remove copy_file_range emulation. The kernel interface has at evolved
      and the glibc emulation doesn't match it anymore, so it's better for
      it to return -ENOSYS. This only impacts Linux kernels << 4.8.

Note that even old-old-stable runs kernel 4.9, so this is mostly useful
for users which run older kernels for various reasons, and which might
experience data corruption in the worst case.

See https://sourceware.org/bugzilla/show_bug.cgi?id=24744 for more
details.

    - Avoid lazy binding of symbols that may follow a variant PCS on arm64, to
      support binaries using AdvSIMD and SVE vector calls.

This is need to run binaries using ISA extension. ARM SVE is starting to
become a bit more common nowadays.

    - Fix large mmap64 offset for the N32 ABI on mips/mipsel/mips64el.

This change fixes a bug introduced in glibc 2.26 on the mips N32 ABI.
Note that it is not the ABI used by any of the official ports, but is
solely shipped as multilib. See
https://sourceware.org/bugzilla/show_bug.cgi?id=20568 for more details.

    - Improve string functions performances on arm64.

This is obviously not fully stable material, but upstream considered it
is important enough for stable. Note that the corresponding code is
unchanged since this optimization, in other words the code in glibc 2.35
is still the same. In addition it comes with a fix for a corner
case: https://sourceware.org/bugzilla/show_bug.cgi?id=23637

  * debian/patches/any/git-libio-stdout-putc.diff: refresh.

This is just a rebase as there were minor conflict with the above patch.

  * debian/debhelper.in/libc.preinst: simplify the version comparison by only
    comparing the two first parts, now that kernel 2.X are not supported
    anymore.  Closes: #1004861.
  * debian/debhelper.in/libc.preinst: drop the check for kernel release > 255
    now that glibc and preinstall script are fixed.  Closes: #987266.

These two changes just drop the comparison for the z part in kernel
version x.y.z, as z is not relevant anymore since kernel 3.0, and the
minimum supported kernel version since buster is 3.2. This fixes cases
where z > 255 as with recent upstream stable kernels.
diff --git a/debian/changelog b/debian/changelog
index 0cbb4f9a..cb7fa65c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,29 @@
+glibc (2.28-10+deb10u1) buster; urgency=medium
+
+  [ Aurelien Jarno ]
+  * debian/patches/git-updates.diff: update from upstream stable branch
+    (Closes: #930697):
+    - Add more integrity check to malloc() function.
+    - Fix crash in _IO_wfile_sync.
+    - Fix bad free() in libdl if dlerror() is not used.  Closes: #953257.
+    - Fix overflow in glibc.malloc.tcache_count tunable.
+    - Fix old x86 applications crash on exit() under valgrind.
+    - Remove copy_file_range emulation. The kernel interface has at evolved
+      and the glibc emulation doesn't match it anymore, so it's better for
+      it to return -ENOSYS. This only impacts Linux kernels << 4.8.
+    - Avoid lazy binding of symbols that may follow a variant PCS on arm64, to
+      support binaries using AdvSIMD and SVE vector calls.
+    - Fix large mmap64 offset for the N32 ABI on mips/mipsel/mips64el.
+    - Improve string functions performances on arm64.
+  * debian/patches/any/git-libio-stdout-putc.diff: refresh.
+  * debian/debhelper.in/libc.preinst: simplify the version comparison by only
+    comparing the two first parts, now that kernel 2.X are not supported
+    anymore.  Closes: #1004861.
+  * debian/debhelper.in/libc.preinst: drop the check for kernel release > 255
+    now that glibc and preinstall script are fixed.  Closes: #987266.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Tue, 15 Mar 2022 23:48:49 +0100
+
 glibc (2.28-10) unstable; urgency=medium
 
   [ Aurelien Jarno ]
diff --git a/debian/debhelper.in/libc.preinst b/debian/debhelper.in/libc.preinst
index f321e652..62531b4b 100644
--- a/debian/debhelper.in/libc.preinst
+++ b/debian/debhelper.in/libc.preinst
@@ -5,14 +5,7 @@ export LC_ALL=C
 type=$1
 preversion=$2
 
-linux_compare_versions () {
-    verA=$(($(echo "$1" | sed 's/^\([0-9]*\.[0-9]*\)\([^.0-9]\|$\)/\1.0\2/; s/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \* 10000 + \2 \* 100 + \3/')))
-    verB=$(($(echo "$3" | sed 's/^\([0-9]*\.[0-9]*\)\([^.0-9]\|$\)/\1.0\2/; s/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \* 10000 + \2 \* 100 + \3/')))
-
-    test $verA -$2 $verB
-}
-
-kfreebsd_compare_versions () {
+kernel_compare_versions () {
     verA=$(($(echo "$1" | sed 's/\([0-9]*\)\.\([0-9]*\).*/\1 \* 100 + \2/')))
     verB=$(($(echo "$3" | sed 's/\([0-9]*\)\.\([0-9]*\).*/\1 \* 100 + \2/')))
 
@@ -126,21 +119,6 @@ then
     system=`uname -s`
     if [ "$system" = "Linux" ]
     then
-        # Test to make sure z < 255, in x.y.z-n form of kernel version
-        # Also make sure we don't trip on x.y.zFOO-n form
-        kernel_rev=$(uname -r | sed 's/\([0-9]*\.\)\{1,2\}\([0-9]*\)\(.*\)/\2/')
-        if [ "$kernel_rev" -ge 255 ]
-        then
-            echo "ERROR: Your kernel version indicates a revision number"
-            echo "of 255 or greater.  Glibc has a number of built in"
-            echo "assumptions that this revision number is less than 255."
-            echo "If you\'ve built your own kernel, please make sure that any"
-            echo "custom version numbers are appended to the upstream"
-            echo "kernel number with a dash or some other delimiter."
-            echo
-            exit 1
-        fi
-
         # sanity checking for the appropriate kernel on each architecture.
         kernel_ver=`uname -r`
         case ${DPKG_MAINTSCRIPT_ARCH:-$(dpkg --print-architecture)} in
@@ -151,7 +129,7 @@ then
                 ;;
         esac
 
-        if linux_compare_versions "$kernel_ver" lt $kernel_ver_min
+        if kernel_compare_versions "$kernel_ver" lt $kernel_ver_min
         then
             if [ -f /usr/share/debconf/confmodule ]
             then
@@ -171,7 +149,7 @@ then
             exit 1
         fi
 
-        if linux_compare_versions "$kernel_ver" lt $kernel_ver_rec
+        if kernel_compare_versions "$kernel_ver" lt $kernel_ver_rec
         then
             if [ -f /usr/share/debconf/confmodule ]
             then
@@ -194,7 +172,7 @@ then
     then
         kernel_ver=`uname -r`
         kernel_ver_min=8.3
-        if kfreebsd_compare_versions "$kernel_ver" lt $kernel_ver_min
+        if kernel_compare_versions "$kernel_ver" lt $kernel_ver_min
         then
             if [ -f /usr/share/debconf/confmodule ]
             then
diff --git a/debian/patches/any/git-libio-stdout-putc.diff b/debian/patches/any/git-libio-stdout-putc.diff
index 819fed9d..8bc6b565 100644
--- a/debian/patches/any/git-libio-stdout-putc.diff
+++ b/debian/patches/any/git-libio-stdout-putc.diff
@@ -13,13 +13,12 @@
 
 --- a/libio/Makefile
 +++ b/libio/Makefile
-@@ -64,7 +64,8 @@
- 	bug-memstream1 bug-wmemstream1 \
+@@ -65,7 +65,7 @@
  	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-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
-+	tst-bz24051
+ 	tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
+-	tst-wfile-sync
++	tst-wfile-sync tst-bz24051
  
  tests-internal = tst-vtables tst-vtables-interposed tst-readline
  
diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff
index bc53ecf1..765a7f2c 100644
--- a/debian/patches/git-updates.diff
+++ b/debian/patches/git-updates.diff
@@ -1,10 +1,153 @@
 GIT update of https://sourceware.org/git/glibc.git/release/2.28/master from glibc-2.28
 
 diff --git a/ChangeLog b/ChangeLog
-index 08b42bd2f5..63917cc15d 100644
+index 08b42bd2f5..416c61a94c 100644
 --- a/ChangeLog
 +++ b/ChangeLog
-@@ -1,3 +1,822 @@
+@@ -1,3 +1,965 @@
++2019-09-13  Wilco Dijkstra  <wdijkstr@arm.com>
++
++	* string/memmem.c (__memmem): Rewrite to improve performance.
++
++2019-06-12  Wilco Dijkstra  <wdijkstr@arm.com>
++
++	* string/str-two-way.h (two_way_short_needle): Add inline to avoid
++	warning.
++	(two_way_long_needle): Block inlining.
++	* string/strstr.c (strstr2): Add new function.
++	(strstr3): Likewise.
++	(STRSTR): Completely rewrite strstr to improve performance.
++
++2019-09-13  Rajalakshmi Srinivasaraghavan  <raji@linux.vnet.ibm.com>
++
++	* string/memmem.c: Use memcmp for first match.
++
++2019-09-13  Wilco Dijkstra  <wdijkstr@arm.com>
++
++	* string/strcasestr.c (STRCASESTR): Simplify and speedup first match.
++	* string/strstr.c (AVAILABLE): Likewise.
++
++2019-09-06  Wilco Dijkstra  <wdijkstr@arm.com>
++
++	* manual/tunables.texi (glibc.cpu.name): Add ares tunable.
++	* sysdeps/aarch64/multiarch/memcpy.c (__libc_memcpy): Use
++	__memcpy_falkor for ares.
++	* sysdeps/unix/sysv/linux/aarch64/cpu-features.h (IS_ARES):
++	Add new define.
++	* sysdeps/unix/sysv/linux/aarch64/cpu-features.c (cpu_list):
++	Add ares cpu.
++
++2019-07-12  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
++
++	[BZ #24699]
++	* posix/tst-mmap-offset.c: Mention BZ #24699.
++	(do_test_bz21270): Rename to do_test_large_offset and use
++	mmap64_maximum_offset to check for maximum expected offset value.
++	* sysdeps/generic/mmap_info.h: New file.
++	* sysdeps/unix/sysv/linux/mips/mmap_info.h: Likewise.
++	* sysdeps/unix/sysv/linux/mmap64.c (MMAP_OFF_HIGH_MASK): Define iff
++	__NR_mmap2 is used.
++
++2019-07-12  Szabolcs Nagy  <szabolcs.nagy@arm.com>
++
++	* sysdeps/aarch64/dl-machine.h (elf_machine_lazy_rel): Check
++	STO_AARCH64_VARIANT_PCS and bind such symbols at load time.
++
++2019-06-13  Szabolcs Nagy  <szabolcs.nagy@arm.com>
++
++	* elf/elf.h (STO_AARCH64_VARIANT_PCS): Define.
++	(DT_AARCH64_VARIANT_PCS): Define.
++
++2019-06-28  Florian Weimer  <fweimer@redhat.com>
++
++	[BZ #24744]
++	io: Remove the copy_file_range emulation.
++	* sysdeps/unix/sysv/linux/copy_file_range.c (copy_file_range): Do
++	not define and call copy_file_range_compat.
++	* io/Makefile (tests-static, tests-internal): Do not add
++	tst-copy_file_range-compat.
++	* io/copy_file_range-compat.c: Remove file.
++	* io/copy_file_range.c (copy_file_range): Define as stub.
++	* io/tst-copy_file_range-compat.c: Remove file.
++	* io/tst-copy_file_range.c (xdevfile): Remove variable.
++	(typical_sizes): Update comment.  Remove 16K sizes.
++	(maximum_offset, maximum_offset_errno, maximum_offset_hard_limit):
++	Remove variables.
++	(find_maximum_offset, pipe_as_source, pipe_as_destination)
++	(delayed_write_failure_beginning, delayed_write_failure_end)
++	(cross_device_failure, enospc_failure_1, enospc_failure)
++	(oappend_failure): Remove functions.
++	(tests): Adjust test case list.
++	(do_test): Remove file system search code.  Check for ENOSYS from
++	copy_file_range.  Do not free xdevfile.
++	* manual/llio.texi (Copying File Data): Document ENOSYS error from
++	copy_file_range.  Do not document the EXDEV error, which future
++	kernels may not report.  Update the wording to reflect that
++	further errors are possible.
++	* sysdeps/unix/sysv/linux/alpha/kernel-features.h
++	[__LINUX_KERNEL_VERSION < 0x040D00] (__ASSUME_COPY_FILE_RANGE): Do
++	not undefine.
++	* sysdeps/unix/sysv/linux/kernel-features.h
++	[__LINUX_KERNEL_VERSION >= 0x040500] (__ASSUME_COPY_FILE_RANGE):
++	Remove definition.
++	* sysdeps/unix/sysv/linux/microblaze/kernel-features.h
++	[__LINUX_KERNEL_VERSION < 0x040A00] (__ASSUME_COPY_FILE_RANGE): Do
++	not undefine.
++
++2019-06-20  Dmitry V. Levin  <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-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.
++
++2018-12-21  Istvan Kurucsai <pistukem@gmail.com>
++
++	* malloc/malloc.c (munmap_chunk): Verify chunk alignment.
++
++2018-12-20  Istvan Kurucsai <pistukem@gmail.com>
++
++	* malloc/malloc.c (mremap_chunk): Additional checks.
++
++2018-08-17  Istvan Kurucsai  <pistukem@gmail.com>
++
++	* malloc/malloc.c (_int_malloc): Additional binning code checks.
++
 +2019-04-23  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
 +
 +	[BZ #18035]
@@ -845,10 +988,10 @@ index 608ffe648c..f5e81bdf5d 100644
  # We might want to compile with some stack-protection flag.
  ifneq ($(stack-protector),)
 diff --git a/NEWS b/NEWS
-index 154ab22d7c..9c2c37652f 100644
+index 154ab22d7c..f249ff690c 100644
 --- a/NEWS
 +++ b/NEWS
-@@ -5,6 +5,87 @@ See the end for copying conditions.
+@@ -5,6 +5,99 @@ See the end for copying conditions.
  Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
  using `glibc' in the "product" field.
  
@@ -869,12 +1012,21 @@ index 154ab22d7c..9c2c37652f 100644
 +  HTM state is saved and restore lazily (the state being saved even when the
 +  process actually does not use HTM).
 +
++* The copy_file_range function fails with ENOSYS if the kernel does not
++  support the system call of the same name.  Previously, user space
++  emulation was performed, but its behavior did not match the kernel
++  behavior, which was deemed too confusing.  Applications which use the
++  copy_file_range function will have to be run on kernels which implement
++  the copy_file_range system call.  Support for most architectures was added
++  in version 4.5 of the mainline Linux kernel.
++
 +The following bugs are resolved with this release:
 +
 +  [18035] Fix pldd hang
 +  [19444] build failures with -O1 due to -Wmaybe-uninitialized
 +  [20018] getaddrinfo should reject IP addresses with trailing characters
 +  [20209] localedata: Spelling mistake for Sunday in Greenlandic kl_GL
++  [20568] Fix crash in _IO_wfile_sync
 +  [22927] libanl: properly cleanup if first helper thread creation failed
 +  [23400] stdlib/test-bz22786.c creates temporary files in glibc source tree
 +  [23497] readdir64@GLIBC_2.1 cannot parse the kernel directory stream
@@ -904,6 +1056,9 @@ index 154ab22d7c..9c2c37652f 100644
 +  [24097] Can't use 64-bit register for size_t in assembly codes for x32 (CVE-2019-6488)
 +  [24155] x32 memcmp can treat positive length as 0 (if sign bit in RDX is set) (CVE-2019-7309)
 +  [24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
++  [24228] old x86 applications that use legacy libio crash on exit
++  [24476] dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once)
++  [24744] io: Remove the copy_file_range emulation.
 +
 +Security related changes:
 +
@@ -936,7 +1091,7 @@ index 154ab22d7c..9c2c37652f 100644
  Version 2.28
  
  Major new features:
-@@ -422,6 +503,8 @@ The following bugs are resolved with this release:
+@@ -422,6 +515,8 @@ The following bugs are resolved with this release:
    [23459] libc: COMMON_CPUID_INDEX_80000001 isn't populated for Intel
      processors
    [23467] dynamic-link: x86/CET: A property note parser bug
@@ -974,10 +1129,30 @@ index ed3869b34f..c0761424da 100644
  element siginfo_t {union sigval} si_value
  # endif
 diff --git a/dlfcn/dlerror.c b/dlfcn/dlerror.c
-index 33574faab6..96bf925333 100644
+index 33574faab6..06732460ea 100644
 --- a/dlfcn/dlerror.c
 +++ b/dlfcn/dlerror.c
-@@ -198,7 +198,10 @@ check_free (struct dl_action_result *rec)
+@@ -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)
+@@ -198,7 +205,10 @@ check_free (struct dl_action_result *rec)
        Dl_info info;
        if (_dl_addr (check_free, &info, &map, NULL) != 0 && map->l_ns == 0)
  #endif
@@ -989,6 +1164,31 @@ index 33574faab6..96bf925333 100644
      }
  }
  
+@@ -227,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 cd0771307f..6027926bd1 100644
 --- a/elf/Makefile
@@ -1087,6 +1287,24 @@ index 63bbc89776..3d2f4a7a76 100644
        ElfW(Sym) *defsym = ((ElfW(Sym) *) D_PTR (reloc_result->bound,
  						l_info[DT_SYMTAB])
  			   + reloc_result->boundndx);
+diff --git a/elf/elf.h b/elf/elf.h
+index 7e2b072a7f..74f7f479ce 100644
+--- a/elf/elf.h
++++ b/elf/elf.h
+@@ -2847,6 +2847,13 @@ enum
+ #define R_AARCH64_TLSDESC      1031	/* TLS Descriptor.  */
+ #define R_AARCH64_IRELATIVE	1032	/* STT_GNU_IFUNC relocation.  */
+ 
++/* AArch64 specific values for the Dyn d_tag field.  */
++#define DT_AARCH64_VARIANT_PCS	(DT_LOPROC + 5)
++#define DT_AARCH64_NUM		6
++
++/* AArch64 specific values for the st_other field.  */
++#define STO_AARCH64_VARIANT_PCS 0x80
++
+ /* ARM relocs.  */
+ 
+ #define R_ARM_NONE		0	/* No reloc */
 diff --git a/elf/pldd-xx.c b/elf/pldd-xx.c
 index 2823dea662..f818d98582 100644
 --- a/elf/pldd-xx.c
@@ -1701,6 +1919,1062 @@ index 2a50369948..25f47c5bd3 100644
  	  dirname = xdirname;
  	}
  #ifndef IN_LIBGLOCALE
+diff --git a/io/Makefile b/io/Makefile
+index ec5c6d7a2f..043f4b80ea 100644
+--- a/io/Makefile
++++ b/io/Makefile
+@@ -73,11 +73,6 @@ tests		:= test-utime test-stat test-stat2 test-lfs tst-getcwd \
+ 		   tst-fts tst-fts-lfs tst-open-tmpfile \
+ 		   tst-copy_file_range tst-getcwd-abspath \
+ 
+-# This test includes the compat implementation of copy_file_range,
+-# which uses internal, unexported libc functions.
+-tests-static += tst-copy_file_range-compat
+-tests-internal += tst-copy_file_range-compat
+-
+ # Likewise for statx, but we do not need static linking here.
+ tests-internal += tst-statx
+ 
+diff --git a/io/copy_file_range-compat.c b/io/copy_file_range-compat.c
+deleted file mode 100644
+index 4ab22cad19..0000000000
+--- a/io/copy_file_range-compat.c
++++ /dev/null
+@@ -1,160 +0,0 @@
+-/* Emulation of copy_file_range.
+-   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+-   This file is part of the GNU C Library.
+-
+-   The GNU C Library is free software; you can redistribute it and/or
+-   modify it under the terms of the GNU Lesser General Public
+-   License as published by the Free Software Foundation; either
+-   version 2.1 of the License, or (at your option) any later version.
+-
+-   The GNU C Library is distributed in the hope that it will be useful,
+-   but WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   Lesser General Public License for more details.
+-
+-   You should have received a copy of the GNU Lesser General Public
+-   License along with the GNU C Library; if not, see
+-   <http://www.gnu.org/licenses/>.  */
+-
+-/* The following macros should be defined before including this
+-   file:
+-
+-   COPY_FILE_RANGE_DECL   Declaration specifiers for the function below.
+-   COPY_FILE_RANGE        Name of the function to define.  */
+-
+-#include <errno.h>
+-#include <fcntl.h>
+-#include <inttypes.h>
+-#include <limits.h>
+-#include <sys/stat.h>
+-#include <sys/types.h>
+-#include <unistd.h>
+-
+-COPY_FILE_RANGE_DECL
+-ssize_t
+-COPY_FILE_RANGE (int infd, __off64_t *pinoff,
+-                 int outfd, __off64_t *poutoff,
+-                 size_t length, unsigned int flags)
+-{
+-  if (flags != 0)
+-    {
+-      __set_errno (EINVAL);
+-      return -1;
+-    }
+-
+-  {
+-    struct stat64 instat;
+-    struct stat64 outstat;
+-    if (fstat64 (infd, &instat) != 0 || fstat64 (outfd, &outstat) != 0)
+-      return -1;
+-    if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode))
+-      {
+-        __set_errno (EISDIR);
+-        return -1;
+-      }
+-    if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode))
+-      {
+-        /* We need a regular input file so that the we can seek
+-           backwards in case of a write failure.  */
+-        __set_errno (EINVAL);
+-        return -1;
+-      }
+-    if (instat.st_dev != outstat.st_dev)
+-      {
+-        /* Cross-device copies are not supported.  */
+-        __set_errno (EXDEV);
+-        return -1;
+-      }
+-  }
+-
+-  /* The output descriptor must not have O_APPEND set.  */
+-  {
+-    int flags = __fcntl (outfd, F_GETFL);
+-    if (flags & O_APPEND)
+-      {
+-        __set_errno (EBADF);
+-        return -1;
+-      }
+-  }
+-
+-  /* Avoid an overflow in the result.  */
+-  if (length > SSIZE_MAX)
+-    length = SSIZE_MAX;
+-
+-  /* Main copying loop.  The buffer size is arbitrary and is a
+-     trade-off between stack size consumption, cache usage, and
+-     amortization of system call overhead.  */
+-  size_t copied = 0;
+-  char buf[8192];
+-  while (length > 0)
+-    {
+-      size_t to_read = length;
+-      if (to_read > sizeof (buf))
+-        to_read = sizeof (buf);
+-
+-      /* Fill the buffer.  */
+-      ssize_t read_count;
+-      if (pinoff == NULL)
+-        read_count = read (infd, buf, to_read);
+-      else
+-        read_count = __libc_pread64 (infd, buf, to_read, *pinoff);
+-      if (read_count == 0)
+-        /* End of file reached prematurely.  */
+-        return copied;
+-      if (read_count < 0)
+-        {
+-          if (copied > 0)
+-            /* Report the number of bytes copied so far.  */
+-            return copied;
+-          return -1;
+-        }
+-      if (pinoff != NULL)
+-        *pinoff += read_count;
+-
+-      /* Write the buffer part which was read to the destination.  */
+-      char *end = buf + read_count;
+-      for (char *p = buf; p < end; )
+-        {
+-          ssize_t write_count;
+-          if (poutoff == NULL)
+-            write_count = write (outfd, p, end - p);
+-          else
+-            write_count = __libc_pwrite64 (outfd, p, end - p, *poutoff);
+-          if (write_count < 0)
+-            {
+-              /* Adjust the input read position to match what we have
+-                 written, so that the caller can pick up after the
+-                 error.  */
+-              size_t written = p - buf;
+-              /* NB: This needs to be signed so that we can form the
+-                 negative value below.  */
+-              ssize_t overread = read_count - written;
+-              if (pinoff == NULL)
+-                {
+-                  if (overread > 0)
+-                    {
+-                      /* We are on an error recovery path, so we
+-                         cannot deal with failure here.  */
+-                      int save_errno = errno;
+-                      (void) __libc_lseek64 (infd, -overread, SEEK_CUR);
+-                      __set_errno (save_errno);
+-                    }
+-                }
+-              else /* pinoff != NULL */
+-                *pinoff -= overread;
+-
+-              if (copied + written > 0)
+-                /* Report the number of bytes copied so far.  */
+-                return copied + written;
+-              return -1;
+-            }
+-          p += write_count;
+-          if (poutoff != NULL)
+-            *poutoff += write_count;
+-        } /* Write loop.  */
+-
+-      copied += read_count;
+-      length -= read_count;
+-    }
+-  return copied;
+-}
+diff --git a/io/copy_file_range.c b/io/copy_file_range.c
+index 98bff8bd26..59fb979773 100644
+--- a/io/copy_file_range.c
++++ b/io/copy_file_range.c
+@@ -1,5 +1,5 @@
+-/* Generic implementation of copy_file_range.
+-   Copyright (C) 2017-2018 Free Software Foundation, Inc.
++/* Stub implementation of copy_file_range.
++   Copyright (C) 2017-2019 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+ 
+    The GNU C Library is free software; you can redistribute it and/or
+@@ -16,7 +16,15 @@
+    License along with the GNU C Library; if not, see
+    <http://www.gnu.org/licenses/>.  */
+ 
+-#define COPY_FILE_RANGE_DECL
+-#define COPY_FILE_RANGE copy_file_range
++#include <errno.h>
++#include <unistd.h>
+ 
+-#include <io/copy_file_range-compat.c>
++ssize_t
++copy_file_range (int infd, __off64_t *pinoff,
++                 int outfd, __off64_t *poutoff,
++                 size_t length, unsigned int flags)
++{
++  __set_errno (ENOSYS);
++  return -1;
++}
++stub_warning (copy_file_range)
+diff --git a/io/tst-copy_file_range-compat.c b/io/tst-copy_file_range-compat.c
+deleted file mode 100644
+index 00c109a74d..0000000000
+--- a/io/tst-copy_file_range-compat.c
++++ /dev/null
+@@ -1,30 +0,0 @@
+-/* Test the fallback implementation of copy_file_range.
+-   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+-   This file is part of the GNU C Library.
+-
+-   The GNU C Library is free software; you can redistribute it and/or
+-   modify it under the terms of the GNU Lesser General Public
+-   License as published by the Free Software Foundation; either
+-   version 2.1 of the License, or (at your option) any later version.
+-
+-   The GNU C Library is distributed in the hope that it will be useful,
+-   but WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   Lesser General Public License for more details.
+-
+-   You should have received a copy of the GNU Lesser General Public
+-   License along with the GNU C Library; if not, see
+-   <http://www.gnu.org/licenses/>.  */
+-
+-/* Get the declaration of the official copy_of_range function.  */
+-#include <unistd.h>
+-
+-/* Compile a local version of copy_file_range.  */
+-#define COPY_FILE_RANGE_DECL static
+-#define COPY_FILE_RANGE copy_file_range_compat
+-#include <io/copy_file_range-compat.c>
+-
+-/* Re-use the test, but run it against copy_file_range_compat defined
+-   above.  */
+-#define copy_file_range copy_file_range_compat
+-#include "tst-copy_file_range.c"
+diff --git a/io/tst-copy_file_range.c b/io/tst-copy_file_range.c
+index 3d531a1937..a9237cb384 100644
+--- a/io/tst-copy_file_range.c
++++ b/io/tst-copy_file_range.c
+@@ -1,5 +1,5 @@
+ /* Tests for copy_file_range.
+-   Copyright (C) 2017-2018 Free Software Foundation, Inc.
++   Copyright (C) 2017-2019 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+ 
+    The GNU C Library is free software; you can redistribute it and/or
+@@ -20,22 +20,15 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <inttypes.h>
+-#include <libgen.h>
+-#include <poll.h>
+-#include <sched.h>
+ #include <stdbool.h>
+ #include <stdio.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/xunistd.h>
+-#ifdef CLONE_NEWNS
+-# include <sys/mount.h>
+-#endif
+ 
+ /* Boolean flags which indicate whether to use pointers with explicit
+    output flags.  */
+@@ -49,10 +42,6 @@ static int infd;
+ static char *outfile;
+ static int outfd;
+ 
+-/* Like the above, but on a different file system.  xdevfile can be
+-   NULL if no suitable file system has been found.  */
+-static char *xdevfile;
+-
+ /* Input and output offsets.  Set according to do_inoff and do_outoff
+    before the test.  The offsets themselves are always set to
+    zero.  */
+@@ -61,13 +50,10 @@ static off64_t *pinoff;
+ static off64_t outoff;
+ static off64_t *poutoff;
+ 
+-/* These are a collection of copy sizes used in tests.  The selection
+-   takes into account that the fallback implementation uses an
+-   internal buffer of 8192 bytes.  */
++/* These are a collection of copy sizes used in tests.    */
+ enum { maximum_size = 99999 };
+ static const int typical_sizes[] =
+-  { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, 16383, 16384, 16385,
+-    maximum_size };
++  { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, maximum_size };
+ 
+ /* The random contents of this array can be used as a pattern to check
+    for correct write operations.  */
+@@ -76,101 +62,6 @@ static unsigned char random_data[maximum_size];
+ /* The size chosen by the test harness.  */
+ static int current_size;
+ 
+-/* Maximum writable file offset.  Updated by find_maximum_offset
+-   below.  */
+-static off64_t maximum_offset;
+-
+-/* Error code when crossing the offset.  */
+-static int maximum_offset_errno;
+-
+-/* If true: Writes which cross the limit will fail.  If false: Writes
+-   which cross the limit will result in a partial write.  */
+-static bool maximum_offset_hard_limit;
+-
+-/* Fills maximum_offset etc. above.  Truncates outfd as a side
+-   effect.  */
+-static void
+-find_maximum_offset (void)
+-{
+-  xftruncate (outfd, 0);
+-  if (maximum_offset != 0)
+-    return;
+-
+-  uint64_t upper = -1;
+-  upper >>= 1;                  /* Maximum of off64_t.  */
+-  TEST_VERIFY ((off64_t) upper > 0);
+-  TEST_VERIFY ((off64_t) (upper + 1) < 0);
+-  if (lseek64 (outfd, upper, SEEK_SET) >= 0)
+-    {
+-      if (write (outfd, "", 1) == 1)
+-        FAIL_EXIT1 ("created a file larger than the off64_t range");
+-    }
+-
+-  uint64_t lower = 1024 * 1024; /* A reasonable minimum file size.  */
+-  /* Loop invariant: writing at lower succeeds, writing at upper fails.  */
+-  while (lower + 1 < upper)
+-    {
+-      uint64_t middle = (lower + upper) / 2;
+-      if (test_verbose > 0)
+-        printf ("info: %s: remaining test range %" PRIu64 " .. %" PRIu64
+-                ", probe at %" PRIu64 "\n", __func__, lower, upper, middle);
+-      xftruncate (outfd, 0);
+-      if (lseek64 (outfd, middle, SEEK_SET) >= 0
+-          && write (outfd, "", 1) == 1)
+-        lower = middle;
+-      else
+-        upper = middle;
+-    }
+-  TEST_VERIFY (lower + 1 == upper);
+-  maximum_offset = lower;
+-  printf ("info: maximum writable file offset: %" PRIu64 " (%" PRIx64 ")\n",
+-          lower, lower);
+-
+-  /* Check that writing at the valid offset actually works.  */
+-  xftruncate (outfd, 0);
+-  xlseek (outfd, lower, SEEK_SET);
+-  TEST_COMPARE (write (outfd, "", 1), 1);
+-
+-  /* Cross the boundary with a two-byte write.  This can either result
+-     in a short write, or a failure.  */
+-  xlseek (outfd, lower, SEEK_SET);
+-  ssize_t ret = write (outfd, " ", 2);
+-  if (ret < 0)
+-    {
+-      maximum_offset_errno = errno;
+-      maximum_offset_hard_limit = true;
+-    }
+-  else
+-    maximum_offset_hard_limit = false;
+-
+-  /* Check that writing at the next offset actually fails.  This also
+-     obtains the expected errno value.  */
+-  xftruncate (outfd, 0);
+-  const char *action;
+-  if (lseek64 (outfd, lower + 1, SEEK_SET) != 0)
+-    {
+-      if (write (outfd, "", 1) != -1)
+-        FAIL_EXIT1 ("write to impossible offset %" PRIu64 " succeeded",
+-                    lower + 1);
+-      action = "writing";
+-      int errno_copy = errno;
+-      if (maximum_offset_hard_limit)
+-        TEST_COMPARE (errno_copy, maximum_offset_errno);
+-      else
+-        maximum_offset_errno = errno_copy;
+-    }
+-  else
+-    {
+-      action = "seeking";
+-      maximum_offset_errno = errno;
+-    }
+-  printf ("info: %s out of range fails with %m (%d)\n",
+-          action, maximum_offset_errno);
+-
+-  xftruncate (outfd, 0);
+-  xlseek (outfd, 0, SEEK_SET);
+-}
+-
+ /* Perform a copy of a file.  */
+ static void
+ simple_file_copy (void)
+@@ -247,390 +138,6 @@ simple_file_copy (void)
+   free (bytes);
+ }
+ 
+-/* Test that reading from a pipe willfails.  */
+-static void
+-pipe_as_source (void)
+-{
+-  int pipefds[2];
+-  xpipe (pipefds);
+-
+-  for (int length = 0; length < 2; ++length)
+-    {
+-      if (test_verbose > 0)
+-        printf ("info: %s: length=%d\n", __func__, length);
+-
+-      /* Make sure that there is something to copy in the pipe.  */
+-      xwrite (pipefds[1], "@", 1);
+-
+-      TEST_COMPARE (copy_file_range (pipefds[0], pinoff, outfd, poutoff,
+-                                     length, 0), -1);
+-      /* Linux 4.10 and later return EINVAL.  Older kernels return
+-         EXDEV.  */
+-      TEST_VERIFY (errno == EINVAL || errno == EXDEV);
+-      TEST_COMPARE (inoff, 0);
+-      TEST_COMPARE (outoff, 0);
+-      TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 0);
+-
+-      /* Make sure that nothing was read.  */
+-      char buf = 'A';
+-      TEST_COMPARE (read (pipefds[0], &buf, 1), 1);
+-      TEST_COMPARE (buf, '@');
+-    }
+-
+-  xclose (pipefds[0]);
+-  xclose (pipefds[1]);
+-}
+-
+-/* Test that writing to a pipe fails.  */
+-static void
+-pipe_as_destination (void)
+-{
+-  /* Make sure that there is something to read in the input file.  */
+-  xwrite (infd, "abc", 3);
+-  xlseek (infd, 0, SEEK_SET);
+-
+-  int pipefds[2];
+-  xpipe (pipefds);
+-
+-  for (int length = 0; length < 2; ++length)
+-    {
+-      if (test_verbose > 0)
+-        printf ("info: %s: length=%d\n", __func__, length);
+-
+-      TEST_COMPARE (copy_file_range (infd, pinoff, pipefds[1], poutoff,
+-                                     length, 0), -1);
+-      /* Linux 4.10 and later return EINVAL.  Older kernels return
+-         EXDEV.  */
+-      TEST_VERIFY (errno == EINVAL || errno == EXDEV);
+-      TEST_COMPARE (inoff, 0);
+-      TEST_COMPARE (outoff, 0);
+-      TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
+-
+-      /* Make sure that nothing was written.  */
+-      struct pollfd pollfd = { .fd = pipefds[0], .events = POLLIN, };
+-      TEST_COMPARE (poll (&pollfd, 1, 0), 0);
+-    }
+-
+-  xclose (pipefds[0]);
+-  xclose (pipefds[1]);
+-}
+-
+-/* Test a write failure after (potentially) writing some bytes.
+-   Failure occurs near the start of the buffer.  */
+-static void
+-delayed_write_failure_beginning (void)
+-{
+-  /* We need to write something to provoke the error.  */
+-  if (current_size == 0)
+-    return;
+-  xwrite (infd, random_data, sizeof (random_data));
+-  xlseek (infd, 0, SEEK_SET);
+-
+-  /* Write failure near the start.  The actual error code varies among
+-     file systems.  */
+-  find_maximum_offset ();
+-  off64_t where = maximum_offset;
+-
+-  if (current_size == 1)
+-    ++where;
+-  outoff = where;
+-  if (do_outoff)
+-    xlseek (outfd, 1, SEEK_SET);
+-  else
+-    xlseek (outfd, where, SEEK_SET);
+-  if (maximum_offset_hard_limit || where > maximum_offset)
+-    {
+-      TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
+-                                     sizeof (random_data), 0), -1);
+-      TEST_COMPARE (errno, maximum_offset_errno);
+-      TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
+-      TEST_COMPARE (inoff, 0);
+-      if (do_outoff)
+-        TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1);
+-      else
+-        TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where);
+-      TEST_COMPARE (outoff, where);
+-      struct stat64 st;
+-      xfstat (outfd, &st);
+-      TEST_COMPARE (st.st_size, 0);
+-    }
+-  else
+-    {
+-      /* The offset is not a hard limit.  This means we write one
+-         byte.  */
+-      TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
+-                                     sizeof (random_data), 0), 1);
+-      if (do_inoff)
+-        {
+-          TEST_COMPARE (inoff, 1);
+-          TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
+-        }
+-      else
+-        {
+-          TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 1);
+-          TEST_COMPARE (inoff, 0);
+-        }
+-      if (do_outoff)
+-        {
+-          TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1);
+-          TEST_COMPARE (outoff, where + 1);
+-        }
+-      else
+-        {
+-          TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where + 1);
+-          TEST_COMPARE (outoff, where);
+-        }
+-      struct stat64 st;
+-      xfstat (outfd, &st);
+-      TEST_COMPARE (st.st_size, where + 1);
+-    }
+-}
+-
+-/* Test a write failure after (potentially) writing some bytes.
+-   Failure occurs near the end of the buffer.  */
+-static void
+-delayed_write_failure_end (void)
+-{
+-  if (current_size <= 1)
+-    /* This would be same as the first test because there is not
+-       enough data to write to make a difference.  */
+-    return;
+-  xwrite (infd, random_data, sizeof (random_data));
+-  xlseek (infd, 0, SEEK_SET);
+-
+-  find_maximum_offset ();
+-  off64_t where = maximum_offset - current_size + 1;
+-  if (current_size == sizeof (random_data))
+-    /* Otherwise we do not reach the non-writable byte.  */
+-    ++where;
+-  outoff = where;
+-  if (do_outoff)
+-    xlseek (outfd, 1, SEEK_SET);
+-  else
+-    xlseek (outfd, where, SEEK_SET);
+-  ssize_t ret = copy_file_range (infd, pinoff, outfd, poutoff,
+-                                 sizeof (random_data), 0);
+-  if (ret < 0)
+-    {
+-      TEST_COMPARE (ret, -1);
+-      TEST_COMPARE (errno, maximum_offset_errno);
+-      struct stat64 st;
+-      xfstat (outfd, &st);
+-      TEST_COMPARE (st.st_size, 0);
+-    }
+-  else
+-    {
+-      /* The first copy succeeded.  This happens in the emulation
+-         because the internal buffer of limited size does not
+-         necessarily cross the off64_t boundary on the first write
+-         operation.  */
+-      if (test_verbose > 0)
+-        printf ("info:   copy_file_range (%zu) returned %zd\n",
+-                sizeof (random_data), ret);
+-      TEST_VERIFY (ret > 0);
+-      TEST_VERIFY (ret < maximum_size);
+-      struct stat64 st;
+-      xfstat (outfd, &st);
+-      TEST_COMPARE (st.st_size, where + ret);
+-      if (do_inoff)
+-        {
+-          TEST_COMPARE (inoff, ret);
+-          TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
+-        }
+-      else
+-          TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), ret);
+-
+-      char *buffer = xmalloc (ret);
+-      TEST_COMPARE (pread64 (outfd, buffer, ret, where), ret);
+-      TEST_VERIFY (memcmp (buffer, random_data, ret) == 0);
+-      free (buffer);
+-
+-      /* The second copy fails.  */
+-      TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
+-                                     sizeof (random_data), 0), -1);
+-      TEST_COMPARE (errno, maximum_offset_errno);
+-    }
+-}
+-
+-/* Test a write failure across devices.  */
+-static void
+-cross_device_failure (void)
+-{
+-  if (xdevfile == NULL)
+-    /* Subtest not supported due to missing cross-device file.  */
+-    return;
+-
+-  /* We need something to write.  */
+-  xwrite (infd, random_data, sizeof (random_data));
+-  xlseek (infd, 0, SEEK_SET);
+-
+-  int xdevfd = xopen (xdevfile, O_RDWR | O_LARGEFILE, 0);
+-  TEST_COMPARE (copy_file_range (infd, pinoff, xdevfd, poutoff,
+-                                 current_size, 0), -1);
+-  TEST_COMPARE (errno, EXDEV);
+-  TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
+-  struct stat64 st;
+-  xfstat (xdevfd, &st);
+-  TEST_COMPARE (st.st_size, 0);
+-
+-  xclose (xdevfd);
+-}
+-
+-/* Try to exercise ENOSPC behavior with a tempfs file system (so that
+-   we do not have to fill up a regular file system to get the error).
+-   This function runs in a subprocess, so that we do not change the
+-   mount namespace of the actual test process.  */
+-static void
+-enospc_failure_1 (void *closure)
+-{
+-#ifdef CLONE_NEWNS
+-  support_become_root ();
+-
+-  /* Make sure that we do not alter the file system mounts of the
+-     parents.  */
+-  if (! support_enter_mount_namespace ())
+-    {
+-      printf ("warning: ENOSPC test skipped\n");
+-      return;
+-    }
+-
+-  char *mountpoint = closure;
+-  if (mount ("none", mountpoint, "tmpfs", MS_NODEV | MS_NOEXEC,
+-             "size=500k") != 0)
+-    {
+-      printf ("warning: could not mount tmpfs at %s: %m\n", mountpoint);
+-      return;
+-    }
+-
+-  /* The source file must reside on the same file system.  */
+-  char *intmpfsfile = xasprintf ("%s/%s", mountpoint, "in");
+-  int intmpfsfd = xopen (intmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600);
+-  xwrite (intmpfsfd, random_data, sizeof (random_data));
+-  xlseek (intmpfsfd, 1, SEEK_SET);
+-  inoff = 1;
+-
+-  char *outtmpfsfile = xasprintf ("%s/%s", mountpoint, "out");
+-  int outtmpfsfd = xopen (outtmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600);
+-
+-  /* Fill the file with data until ENOSPC is reached.  */
+-  while (true)
+-    {
+-      ssize_t ret = write (outtmpfsfd, random_data, sizeof (random_data));
+-      if (ret < 0 && errno != ENOSPC)
+-        FAIL_EXIT1 ("write to %s: %m", outtmpfsfile);
+-      if (ret < sizeof (random_data))
+-        break;
+-    }
+-  TEST_COMPARE (write (outtmpfsfd, "", 1), -1);
+-  TEST_COMPARE (errno, ENOSPC);
+-  off64_t maxsize = xlseek (outtmpfsfd, 0, SEEK_CUR);
+-  TEST_VERIFY_EXIT (maxsize > sizeof (random_data));
+-
+-  /* Constructed the expected file contents.  */
+-  char *expected = xmalloc (maxsize);
+-  TEST_COMPARE (pread64 (outtmpfsfd, expected, maxsize, 0), maxsize);
+-  /* Go back a little, so some bytes can be written.  */
+-  enum { offset = 20000 };
+-  TEST_VERIFY_EXIT (offset < maxsize);
+-  TEST_VERIFY_EXIT (offset < sizeof (random_data));
+-  memcpy (expected + maxsize - offset, random_data + 1, offset);
+-
+-  if (do_outoff)
+-    {
+-      outoff = maxsize - offset;
+-      xlseek (outtmpfsfd, 2, SEEK_SET);
+-    }
+-  else
+-    xlseek (outtmpfsfd, -offset, SEEK_CUR);
+-
+-  /* First call is expected to succeed because we made room for some
+-     bytes.  */
+-  TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff,
+-                                 maximum_size, 0), offset);
+-  if (do_inoff)
+-    {
+-      TEST_COMPARE (inoff, 1 + offset);
+-      TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1);
+-    }
+-  else
+-      TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset);
+-  if (do_outoff)
+-    {
+-      TEST_COMPARE (outoff, maxsize);
+-      TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2);
+-    }
+-  else
+-    TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize);
+-  struct stat64 st;
+-  xfstat (outtmpfsfd, &st);
+-  TEST_COMPARE (st.st_size, maxsize);
+-  char *actual = xmalloc (st.st_size);
+-  TEST_COMPARE (pread64 (outtmpfsfd, actual, st.st_size, 0), st.st_size);
+-  TEST_VERIFY (memcmp (expected, actual, maxsize) == 0);
+-
+-  /* Second call should fail with ENOSPC.  */
+-  TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff,
+-                                 maximum_size, 0), -1);
+-  TEST_COMPARE (errno, ENOSPC);
+-
+-  /* Offsets should be unchanged.  */
+-  if (do_inoff)
+-    {
+-      TEST_COMPARE (inoff, 1 + offset);
+-      TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1);
+-    }
+-  else
+-    TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset);
+-  if (do_outoff)
+-    {
+-      TEST_COMPARE (outoff, maxsize);
+-      TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2);
+-    }
+-  else
+-    TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize);
+-  TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_END), maxsize);
+-  TEST_COMPARE (pread64 (outtmpfsfd, actual, maxsize, 0), maxsize);
+-  TEST_VERIFY (memcmp (expected, actual, maxsize) == 0);
+-
+-  free (actual);
+-  free (expected);
+-
+-  xclose (intmpfsfd);
+-  xclose (outtmpfsfd);
+-  free (intmpfsfile);
+-  free (outtmpfsfile);
+-
+-#else /* !CLONE_NEWNS */
+-  puts ("warning: ENOSPC test skipped (no mount namespaces)");
+-#endif
+-}
+-
+-/* Call enospc_failure_1 in a subprocess.  */
+-static void
+-enospc_failure (void)
+-{
+-  char *mountpoint
+-    = support_create_temp_directory ("tst-copy_file_range-enospc-");
+-  support_isolate_in_subprocess (enospc_failure_1, mountpoint);
+-  free (mountpoint);
+-}
+-
+-/* The target file descriptor must have O_APPEND enabled.  */
+-static void
+-oappend_failure (void)
+-{
+-  /* Add data, to make sure we do not fail because there is
+-     insufficient input data.  */
+-  xwrite (infd, random_data, current_size);
+-  xlseek (infd, 0, SEEK_SET);
+-
+-  xclose (outfd);
+-  outfd = xopen (outfile, O_RDWR | O_APPEND, 0);
+-  TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
+-                                 current_size, 0), -1);
+-  TEST_COMPARE (errno, EBADF);
+-}
+-
+ /* Test that a short input file results in a shortened copy.  */
+ static void
+ short_copy (void)
+@@ -721,14 +228,6 @@ struct test_case
+ static struct test_case tests[] =
+   {
+     { "simple_file_copy", simple_file_copy, .sizes = true },
+-    { "pipe_as_source", pipe_as_source, },
+-    { "pipe_as_destination", pipe_as_destination, },
+-    { "delayed_write_failure_beginning", delayed_write_failure_beginning,
+-      .sizes = true },
+-    { "delayed_write_failure_end", delayed_write_failure_end, .sizes = true },
+-    { "cross_device_failure", cross_device_failure, .sizes = true },
+-    { "enospc_failure", enospc_failure, },
+-    { "oappend_failure", oappend_failure, .sizes = true },
+     { "short_copy", short_copy, .sizes = true },
+   };
+ 
+@@ -739,53 +238,18 @@ do_test (void)
+     *p = rand () >> 24;
+ 
+   infd = create_temp_file ("tst-copy_file_range-in-", &infile);
+-  xclose (create_temp_file ("tst-copy_file_range-out-", &outfile));
+-
+-  /* Try to find a different directory from the default input/output
+-     file.  */
++  outfd = create_temp_file ("tst-copy_file_range-out-", &outfile);
+   {
+-    struct stat64 instat;
+-    xfstat (infd, &instat);
+-    static const char *const candidates[] =
+-      { NULL, "/var/tmp", "/dev/shm" };
+-    for (const char *const *c = candidates; c < array_end (candidates); ++c)
+-      {
+-        const char *path = *c;
+-        char *to_free = NULL;
+-        if (path == NULL)
+-          {
+-            to_free = xreadlink ("/proc/self/exe");
+-            path = dirname (to_free);
+-          }
+-
+-        struct stat64 cstat;
+-        xstat (path, &cstat);
+-        if (cstat.st_dev == instat.st_dev)
+-          {
+-            free (to_free);
+-            continue;
+-          }
+-
+-        printf ("info: using alternate temporary files directory: %s\n", path);
+-        xdevfile = xasprintf ("%s/tst-copy_file_range-xdev-XXXXXX", path);
+-        free (to_free);
+-        break;
+-      }
+-    if (xdevfile != NULL)
++    ssize_t ret = copy_file_range (infd, NULL, outfd, NULL, 0, 0);
++    if (ret != 0)
+       {
+-        int xdevfd = mkstemp (xdevfile);
+-        if (xdevfd < 0)
+-          FAIL_EXIT1 ("mkstemp (\"%s\"): %m", xdevfile);
+-        struct stat64 xdevst;
+-        xfstat (xdevfd, &xdevst);
+-        TEST_VERIFY (xdevst.st_dev != instat.st_dev);
+-        add_temp_file (xdevfile);
+-        xclose (xdevfd);
++        if (errno == ENOSYS)
++          FAIL_UNSUPPORTED ("copy_file_range is not support on this system");
++        FAIL_EXIT1 ("copy_file_range probing call: %m");
+       }
+-    else
+-      puts ("warning: no alternate directory on different file system found");
+   }
+   xclose (infd);
++  xclose (outfd);
+ 
+   for (do_inoff = 0; do_inoff < 2; ++do_inoff)
+     for (do_outoff = 0; do_outoff < 2; ++do_outoff)
+@@ -827,7 +291,6 @@ do_test (void)
+ 
+   free (infile);
+   free (outfile);
+-  free (xdevfile);
+ 
+   return 0;
+ }
+diff --git a/libio/Makefile b/libio/Makefile
+index cab0eae946..314e03d5ce 100644
+--- a/libio/Makefile
++++ b/libio/Makefile
+@@ -64,7 +64,8 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
+ 	bug-memstream1 bug-wmemstream1 \
+ 	tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
+ 	tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
+-	tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof
++	tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
++	tst-wfile-sync
+ 
+ tests-internal = tst-vtables tst-vtables-interposed tst-readline
+ 
+@@ -72,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
+ 
+@@ -152,11 +156,14 @@ CFLAGS-oldtmpfile.c += -fexceptions
+ 
+ CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\"
+ 
++LDFLAGS-tst-bz24228 = -Wl,--version-script=tst-bz24228.map
++
+ tst_wprintf2-ARGS = "Some Text"
+ 
+ test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace
+ tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace
+ tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace
++tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace
+ 
+ generated += test-fmemopen.mtrace test-fmemopen.check
+ generated += tst-fopenloc.mtrace tst-fopenloc.check
+@@ -165,6 +172,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
+ 
+@@ -179,7 +187,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
+ 
+@@ -207,6 +216,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
+@@ -230,3 +240,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 2fec221b99..a8241dd266 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-readline.c b/libio/tst-readline.c
 index 9322ef68da..63f5227760 100644
 --- a/libio/tst-readline.c
@@ -1712,6 +2986,77 @@ index 9322ef68da..63f5227760 100644
 +#define TIMEOUT 100
  #define PREPARE prepare
  #include <support/test-driver.c>
+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 63cb687652..10e7343f8f 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..30190b6248 100644
 --- a/localedata/locales/ja_JP
@@ -1758,10 +3103,62 @@ index 7d54bad866..388cf7e9ee 100644
  tests-static := \
  	 tst-interpose-static-nothread \
 diff --git a/malloc/malloc.c b/malloc/malloc.c
-index e247c77b7d..27cf6137c2 100644
+index e247c77b7d..0e7970001a 100644
 --- a/malloc/malloc.c
 +++ b/malloc/malloc.c
-@@ -2888,6 +2888,8 @@ mremap_chunk (mchunkptr p, size_t new_size)
+@@ -2810,6 +2810,7 @@ systrim (size_t pad, mstate av)
+ static void
+ munmap_chunk (mchunkptr p)
+ {
++  size_t pagesize = GLRO (dl_pagesize);
+   INTERNAL_SIZE_T size = chunksize (p);
+ 
+   assert (chunk_is_mmapped (p));
+@@ -2819,6 +2820,7 @@ munmap_chunk (mchunkptr p)
+   if (DUMPED_MAIN_ARENA_CHUNK (p))
+     return;
+ 
++  uintptr_t mem = (uintptr_t) chunk2mem (p);
+   uintptr_t block = (uintptr_t) p - prev_size (p);
+   size_t total_size = prev_size (p) + size;
+   /* Unfortunately we have to do the compilers job by hand here.  Normally
+@@ -2826,7 +2828,8 @@ munmap_chunk (mchunkptr p)
+      page size.  But gcc does not recognize the optimization possibility
+      (in the moment at least) so we combine the two values into one before
+      the bit test.  */
+-  if (__builtin_expect (((block | total_size) & (GLRO (dl_pagesize) - 1)) != 0, 0))
++  if (__glibc_unlikely ((block | total_size) & (pagesize - 1)) != 0
++      || __glibc_unlikely (!powerof2 (mem & (pagesize - 1))))
+     malloc_printerr ("munmap_chunk(): invalid pointer");
+ 
+   atomic_decrement (&mp_.n_mmaps);
+@@ -2849,16 +2852,22 @@ mremap_chunk (mchunkptr p, size_t new_size)
+   char *cp;
+ 
+   assert (chunk_is_mmapped (p));
+-  assert (((size + offset) & (GLRO (dl_pagesize) - 1)) == 0);
++
++  uintptr_t block = (uintptr_t) p - offset;
++  uintptr_t mem = (uintptr_t) chunk2mem(p);
++  size_t total_size = offset + size;
++  if (__glibc_unlikely ((block | total_size) & (pagesize - 1)) != 0
++      || __glibc_unlikely (!powerof2 (mem & (pagesize - 1))))
++    malloc_printerr("mremap_chunk(): invalid pointer");
+ 
+   /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
+   new_size = ALIGN_UP (new_size + offset + SIZE_SZ, pagesize);
+ 
+   /* No need to remap if the number of pages does not change.  */
+-  if (size + offset == new_size)
++  if (total_size == new_size)
+     return p;
+ 
+-  cp = (char *) __mremap ((char *) p - offset, size + offset, new_size,
++  cp = (char *) __mremap ((char *) block, total_size, new_size,
+                           MREMAP_MAYMOVE);
+ 
+   if (cp == MAP_FAILED)
+@@ -2888,6 +2897,8 @@ mremap_chunk (mchunkptr p, size_t new_size)
  typedef struct tcache_entry
  {
    struct tcache_entry *next;
@@ -1770,7 +3167,16 @@ index e247c77b7d..27cf6137c2 100644
  } tcache_entry;
  
  /* There is one of these for each thread, which contains the
-@@ -2911,6 +2913,11 @@ tcache_put (mchunkptr chunk, size_t tc_idx)
+@@ -2901,6 +2912,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;
+ 
+@@ -2911,6 +2924,11 @@ tcache_put (mchunkptr chunk, size_t tc_idx)
  {
    tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
    assert (tc_idx < TCACHE_MAX_BINS);
@@ -1782,7 +3188,7 @@ index e247c77b7d..27cf6137c2 100644
    e->next = tcache->entries[tc_idx];
    tcache->entries[tc_idx] = e;
    ++(tcache->counts[tc_idx]);
-@@ -2926,6 +2933,7 @@ tcache_get (size_t tc_idx)
+@@ -2926,6 +2944,7 @@ tcache_get (size_t tc_idx)
    assert (tcache->entries[tc_idx] > 0);
    tcache->entries[tc_idx] = e->next;
    --(tcache->counts[tc_idx]);
@@ -1790,7 +3196,7 @@ index e247c77b7d..27cf6137c2 100644
    return (void *) e;
  }
  
-@@ -3716,11 +3724,22 @@ _int_malloc (mstate av, size_t bytes)
+@@ -3716,11 +3735,22 @@ _int_malloc (mstate av, size_t bytes)
        while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
          {
            bck = victim->bk;
@@ -1812,12 +3218,27 @@ index e247c77b7d..27cf6137c2 100644
 +          if (__glibc_unlikely (bck->fd != victim)
 +              || __glibc_unlikely (victim->fd != unsorted_chunks (av)))
 +            malloc_printerr ("malloc(): unsorted double linked list corrupted");
-+          if (__glibc_unlikely (prev_inuse(next)))
++          if (__glibc_unlikely (prev_inuse (next)))
 +            malloc_printerr ("malloc(): invalid next->prev_inuse (unsorted)");
  
            /*
               If a small request, try to use last remainder if it is the
-@@ -4076,6 +4095,9 @@ _int_malloc (mstate av, size_t bytes)
+@@ -3841,10 +3871,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
+@@ -4076,6 +4110,9 @@ _int_malloc (mstate av, size_t bytes)
        victim = av->top;
        size = chunksize (victim);
  
@@ -1827,7 +3248,7 @@ index e247c77b7d..27cf6137c2 100644
        if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
          {
            remainder_size = size - nb;
-@@ -4151,13 +4173,33 @@ _int_free (mstate av, mchunkptr p, int have_lock)
+@@ -4151,13 +4188,33 @@ _int_free (mstate av, mchunkptr p, int have_lock)
  #if USE_TCACHE
    {
      size_t tc_idx = csize2tidx (size);
@@ -1867,7 +3288,7 @@ index e247c77b7d..27cf6137c2 100644
        }
    }
  #endif
-@@ -4278,6 +4320,8 @@ _int_free (mstate av, mchunkptr p, int have_lock)
+@@ -4278,6 +4335,8 @@ _int_free (mstate av, mchunkptr p, int have_lock)
        prevsize = prev_size (p);
        size += prevsize;
        p = chunk_at_offset(p, -((long) prevsize));
@@ -1876,7 +3297,7 @@ index e247c77b7d..27cf6137c2 100644
        unlink(av, p, bck, fwd);
      }
  
-@@ -4439,6 +4483,8 @@ static void malloc_consolidate(mstate av)
+@@ -4439,6 +4498,8 @@ static void malloc_consolidate(mstate av)
  	  prevsize = prev_size (p);
  	  size += prevsize;
  	  p = chunk_at_offset(p, -((long) prevsize));
@@ -1885,7 +3306,7 @@ index e247c77b7d..27cf6137c2 100644
  	  unlink(av, p, bck, fwd);
  	}
  
-@@ -4498,11 +4544,6 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
+@@ -4498,11 +4559,6 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
    mchunkptr        bck;             /* misc temp for linking */
    mchunkptr        fwd;             /* misc temp for linking */
  
@@ -1897,7 +3318,7 @@ index e247c77b7d..27cf6137c2 100644
    /* oldmem size */
    if (__builtin_expect (chunksize_nomask (oldp) <= 2 * SIZE_SZ, 0)
        || __builtin_expect (oldsize >= av->system_mem, 0))
-@@ -4570,43 +4611,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
+@@ -4570,43 +4626,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
              }
            else
              {
@@ -1942,6 +3363,20 @@ index e247c77b7d..27cf6137c2 100644
                _int_free (av, oldp, 1);
                check_inuse_chunk (av, newp);
                return chunk2mem (newp);
+@@ -5104,8 +5124,11 @@ static inline int
+ __always_inline
+ do_set_tcache_count (size_t value)
+ {
+-  LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
+-  mp_.tcache_count = value;
++  if (value <= MAX_TCACHE_COUNT)
++    {
++      LIBC_PROBE (memory_tunable_tcache_count, 2, value, mp_.tcache_count);
++      mp_.tcache_count = value;
++    }
+   return 1;
+ }
+ 
 diff --git a/malloc/tst-tcfree1.c b/malloc/tst-tcfree1.c
 new file mode 100644
 index 0000000000..bc29375ce7
@@ -4761,6 +6196,51 @@ index 73644c2341..06b8487c3e 100644
  		    return -1;
  		}
  	    }
+diff --git a/posix/tst-mmap-offset.c b/posix/tst-mmap-offset.c
+index 92ea794c5a..cf17ba077c 100644
+--- a/posix/tst-mmap-offset.c
++++ b/posix/tst-mmap-offset.c
+@@ -1,4 +1,4 @@
+-/* BZ #18877 and #21270 mmap offset test.
++/* BZ #18877, BZ #21270, and BZ #24699 mmap offset test.
+ 
+    Copyright (C) 2015-2018 Free Software Foundation, Inc.
+    This file is part of the GNU C Library.
+@@ -24,6 +24,7 @@
+ #include <unistd.h>
+ #include <errno.h>
+ #include <sys/mman.h>
++#include <mmap_info.h>
+ 
+ #include <support/check.h>
+ 
+@@ -76,7 +77,7 @@ do_test_bz18877 (void)
+ 
+ /* Check if invalid offset are handled correctly by mmap.  */
+ static int
+-do_test_bz21270 (void)
++do_test_large_offset (void)
+ {
+   /* For architectures with sizeof (off_t) < sizeof (off64_t) mmap is
+      implemented with __SYS_mmap2 syscall and the offset is represented in
+@@ -90,7 +91,7 @@ do_test_bz21270 (void)
+   const size_t length = 4096;
+ 
+   void *addr = mmap64 (NULL, length, prot, flags, fd, offset);
+-  if (sizeof (off_t) < sizeof (off64_t))
++  if (mmap64_maximum_offset (page_shift) < UINT64_MAX)
+     {
+       if ((addr != MAP_FAILED) && (errno != EINVAL))
+ 	FAIL_RET ("mmap succeed");
+@@ -110,7 +111,7 @@ do_test (void)
+   int ret = 0;
+ 
+   ret += do_test_bz18877 ();
+-  ret += do_test_bz21270 ();
++  ret += do_test_large_offset ();
+ 
+   return ret;
+ }
 diff --git a/posix/tst-regcomp-truncated.c b/posix/tst-regcomp-truncated.c
 new file mode 100644
 index 0000000000..a4a1581bbc
@@ -6053,8 +7533,190 @@ index 680431f921..aa2da9ca72 100644
  ifeq ($(run-built-tests),yes)
  tests-special += $(objpfx)tst-svc-cmp.out
  endif
+diff --git a/string/memmem.c b/string/memmem.c
+index 43efaa3fb7..7fbe1cb5d6 100644
+--- a/string/memmem.c
++++ b/string/memmem.c
+@@ -15,17 +15,13 @@
+    License along with the GNU C Library; if not, see
+    <http://www.gnu.org/licenses/>.  */
+ 
+-/* This particular implementation was written by Eric Blake, 2008.  */
+-
+ #ifndef _LIBC
+ # include <config.h>
+ #endif
+ 
+-/* Specification of memmem.  */
+ #include <string.h>
+ 
+ #ifndef _LIBC
+-# define __builtin_expect(expr, val)   (expr)
+ # define __memmem	memmem
+ #endif
+ 
+@@ -36,47 +32,98 @@
+ 
+ #undef memmem
+ 
+-/* Return the first occurrence of NEEDLE in HAYSTACK.  Return HAYSTACK
+-   if NEEDLE_LEN is 0, otherwise NULL if NEEDLE is not found in
+-   HAYSTACK.  */
++/* Hash character pairs so a small shift table can be used.  All bits of
++   p[0] are included, but not all bits from p[-1].  So if two equal hashes
++   match on p[-1], p[0] matches too.  Hash collisions are harmless and result
++   in smaller shifts.  */
++#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift))
++
++/* Fast memmem algorithm with guaranteed linear-time performance.
++   Small needles up to size 2 use a dedicated linear search.  Longer needles
++   up to size 256 use a novel modified Horspool algorithm.  It hashes pairs
++   of characters to quickly skip past mismatches.  The main search loop only
++   exits if the last 2 characters match, avoiding unnecessary calls to memcmp
++   and allowing for a larger skip if there is no match.  A self-adapting
++   filtering check is used to quickly detect mismatches in long needles.
++   By limiting the needle length to 256, the shift table can be reduced to 8
++   bits per entry, lowering preprocessing overhead and minimizing cache effects.
++   The limit also implies worst-case performance is linear.
++   Needles larger than 256 characters use the linear-time Two-Way algorithm.  */
+ void *
+-__memmem (const void *haystack_start, size_t haystack_len,
+-	  const void *needle_start, size_t needle_len)
++__memmem (const void *haystack, size_t hs_len,
++	  const void *needle, size_t ne_len)
+ {
+-  /* Abstract memory is considered to be an array of 'unsigned char' values,
+-     not an array of 'char' values.  See ISO C 99 section 6.2.6.1.  */
+-  const unsigned char *haystack = (const unsigned char *) haystack_start;
+-  const unsigned char *needle = (const unsigned char *) needle_start;
+-
+-  if (needle_len == 0)
+-    /* The first occurrence of the empty string is deemed to occur at
+-       the beginning of the string.  */
+-    return (void *) haystack;
+-
+-  /* Sanity check, otherwise the loop might search through the whole
+-     memory.  */
+-  if (__glibc_unlikely (haystack_len < needle_len))
++  const unsigned char *hs = (const unsigned char *) haystack;
++  const unsigned char *ne = (const unsigned char *) needle;
++
++  if (ne_len == 0)
++    return (void *) hs;
++  if (ne_len == 1)
++    return (void *) memchr (hs, ne[0], hs_len);
++
++  /* Ensure haystack length is >= needle length.  */
++  if (hs_len < ne_len)
+     return NULL;
+ 
+-  /* Use optimizations in memchr when possible, to reduce the search
+-     size of haystack using a linear algorithm with a smaller
+-     coefficient.  However, avoid memchr for long needles, since we
+-     can often achieve sublinear performance.  */
+-  if (needle_len < LONG_NEEDLE_THRESHOLD)
++  const unsigned char *end = hs + hs_len - ne_len;
++
++  if (ne_len == 2)
++    {
++      uint32_t nw = ne[0] << 16 | ne[1], hw = hs[0] << 16 | hs[1];
++      for (hs++; hs <= end && hw != nw; )
++	hw = hw << 16 | *++hs;
++      return hw == nw ? (void *)hs - 1 : NULL;
++    }
++
++  /* Use Two-Way algorithm for very long needles.  */
++  if (__builtin_expect (ne_len > 256, 0))
++    return two_way_long_needle (hs, hs_len, ne, ne_len);
++
++  uint8_t shift[256];
++  size_t tmp, shift1;
++  size_t m1 = ne_len - 1;
++  size_t offset = 0;
++
++  memset (shift, 0, sizeof (shift));
++  for (int i = 1; i < m1; i++)
++    shift[hash2 (ne + i)] = i;
++  /* Shift1 is the amount we can skip after matching the hash of the
++     needle end but not the full needle.  */
++  shift1 = m1 - shift[hash2 (ne + m1)];
++  shift[hash2 (ne + m1)] = m1;
++
++  for ( ; hs <= end; )
+     {
+-      haystack = memchr (haystack, *needle, haystack_len);
+-      if (!haystack || __builtin_expect (needle_len == 1, 0))
+-	return (void *) haystack;
+-      haystack_len -= haystack - (const unsigned char *) haystack_start;
+-      if (haystack_len < needle_len)
+-	return NULL;
+-      return two_way_short_needle (haystack, haystack_len, needle, needle_len);
++      /* Skip past character pairs not in the needle.  */
++      do
++	{
++	  hs += m1;
++	  tmp = shift[hash2 (hs)];
++	}
++      while (tmp == 0 && hs <= end);
++
++      /* If the match is not at the end of the needle, shift to the end
++	 and continue until we match the hash of the needle end.  */
++      hs -= tmp;
++      if (tmp < m1)
++	continue;
++
++      /* Hash of the last 2 characters matches.  If the needle is long,
++	 try to quickly filter out mismatches.  */
++      if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0)
++	{
++	  if (memcmp (hs, ne, m1) == 0)
++	    return (void *) hs;
++
++	  /* Adjust filter offset when it doesn't find the mismatch.  */
++	  offset = (offset >= 8 ? offset : m1) - 8;
++	}
++
++      /* Skip based on matching the hash of the needle end.  */
++      hs += shift1;
+     }
+-  else
+-    return two_way_long_needle (haystack, haystack_len, needle, needle_len);
++  return NULL;
+ }
+ libc_hidden_def (__memmem)
+ weak_alias (__memmem, memmem)
+ libc_hidden_weak (memmem)
+-
+-#undef LONG_NEEDLE_THRESHOLD
+diff --git a/string/str-two-way.h b/string/str-two-way.h
+index 523d946c59..358959bef0 100644
+--- a/string/str-two-way.h
++++ b/string/str-two-way.h
+@@ -221,7 +221,7 @@ critical_factorization (const unsigned char *needle, size_t needle_len,
+    most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching.
+    If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 *
+    HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching.  */
+-static RETURN_TYPE
++static inline RETURN_TYPE
+ two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
+ 		      const unsigned char *needle, size_t needle_len)
+ {
+@@ -382,8 +382,11 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
+    and sublinear performance O(HAYSTACK_LEN / NEEDLE_LEN) is possible.
+    If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 *
+    HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and
+-   sublinear performance is not possible.  */
+-static RETURN_TYPE
++   sublinear performance is not possible.
++
++   Since this function is large and complex, block inlining to avoid
++   slowing down the common case of small needles.  */
++__attribute__((noinline)) static RETURN_TYPE
+ two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
+ 		     const unsigned char *needle, size_t needle_len)
+ {
 diff --git a/string/strcasestr.c b/string/strcasestr.c
-index 5909fe3cdb..421764bd1b 100644
+index 5909fe3cdb..8aa76037dc 100644
 --- a/string/strcasestr.c
 +++ b/string/strcasestr.c
 @@ -37,8 +37,9 @@
@@ -6069,22 +7731,268 @@ index 5909fe3cdb..421764bd1b 100644
  #define CHECK_EOL (1)
  #define RET0_IF_0(a) if (!a) goto ret0
  #define CANON_ELEMENT(c) TOLOWER (c)
+@@ -58,31 +59,22 @@
+    case-insensitive comparison.  This function gives unspecified
+    results in multibyte locales.  */
+ char *
+-STRCASESTR (const char *haystack_start, const char *needle_start)
++STRCASESTR (const char *haystack, const char *needle)
+ {
+-  const char *haystack = haystack_start;
+-  const char *needle = needle_start;
+   size_t needle_len; /* Length of NEEDLE.  */
+   size_t haystack_len; /* Known minimum length of HAYSTACK.  */
+-  bool ok = true; /* True if NEEDLE is prefix of HAYSTACK.  */
+-
+-  /* Determine length of NEEDLE, and in the process, make sure
+-     HAYSTACK is at least as long (no point processing all of a long
+-     NEEDLE if HAYSTACK is too short).  */
+-  while (*haystack && *needle)
+-    {
+-      ok &= (TOLOWER ((unsigned char) *haystack)
+-	     == TOLOWER ((unsigned char) *needle));
+-      haystack++;
+-      needle++;
+-    }
+-  if (*needle)
++
++  /* Handle empty NEEDLE special case.  */
++  if (needle[0] == '\0')
++    return (char *) haystack;
++
++  /* Ensure HAYSTACK length is at least as long as NEEDLE length.
++     Since a match may occur early on in a huge HAYSTACK, use strnlen
++     and read ahead a few cachelines for improved performance.  */
++  needle_len = strlen (needle);
++  haystack_len = __strnlen (haystack, needle_len + 256);
++  if (haystack_len < needle_len)
+     return NULL;
+-  if (ok)
+-    return (char *) haystack_start;
+-  needle_len = needle - needle_start;
+-  haystack = haystack_start + 1;
+-  haystack_len = needle_len - 1;
+ 
+   /* Perform the search.  Abstract memory is considered to be an array
+      of 'unsigned char' values, not an array of 'char' values.  See
+@@ -90,10 +82,10 @@ STRCASESTR (const char *haystack_start, const char *needle_start)
+   if (needle_len < LONG_NEEDLE_THRESHOLD)
+     return two_way_short_needle ((const unsigned char *) haystack,
+ 				 haystack_len,
+-				 (const unsigned char *) needle_start,
++				 (const unsigned char *) needle,
+ 				 needle_len);
+   return two_way_long_needle ((const unsigned char *) haystack, haystack_len,
+-			      (const unsigned char *) needle_start,
++			      (const unsigned char *) needle,
+ 			      needle_len);
+ }
+ 
 diff --git a/string/strstr.c b/string/strstr.c
-index 265e9f310c..79ebcc7532 100644
+index 265e9f310c..7ffb18ab42 100644
 --- a/string/strstr.c
 +++ b/string/strstr.c
-@@ -33,8 +33,9 @@
+@@ -16,28 +16,17 @@
+    License along with the GNU C Library; if not, see
+    <http://www.gnu.org/licenses/>.  */
+ 
+-/* This particular implementation was written by Eric Blake, 2008.  */
+-
+ #ifndef _LIBC
+ # include <config.h>
+ #endif
+ 
+-/* Specification of strstr.  */
+ #include <string.h>
  
+-#include <stdbool.h>
+-
+-#ifndef _LIBC
+-# define __builtin_expect(expr, val)   (expr)
+-#endif
+-
  #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)))
+-#define CHECK_EOL (1)
+-#define RET0_IF_0(a) if (!a) goto ret0
+-#define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C))
 +  (((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))
+ #include "str-two-way.h"
+ 
+ #undef strstr
+@@ -46,48 +35,128 @@
+ #define STRSTR strstr
+ #endif
+ 
+-/* Return the first occurrence of NEEDLE in HAYSTACK.  Return HAYSTACK
+-   if NEEDLE is empty, otherwise NULL if NEEDLE is not found in
+-   HAYSTACK.  */
++static inline char *
++strstr2 (const unsigned char *hs, const unsigned char *ne)
++{
++  uint32_t h1 = (ne[0] << 16) | ne[1];
++  uint32_t h2 = 0;
++  for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs)
++      h2 = (h2 << 16) | c;
++  return h1 == h2 ? (char *)hs - 2 : NULL;
++}
++
++static inline char *
++strstr3 (const unsigned char *hs, const unsigned char *ne)
++{
++  uint32_t h1 = ((uint32_t)ne[0] << 24) | (ne[1] << 16) | (ne[2] << 8);
++  uint32_t h2 = 0;
++  for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs)
++      h2 = (h2 | c) << 8;
++  return h1 == h2 ? (char *)hs - 3 : NULL;
++}
++
++/* Hash character pairs so a small shift table can be used.  All bits of
++   p[0] are included, but not all bits from p[-1].  So if two equal hashes
++   match on p[-1], p[0] matches too.  Hash collisions are harmless and result
++   in smaller shifts.  */
++#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift))
++
++/* Fast strstr algorithm with guaranteed linear-time performance.
++   Small needles up to size 3 use a dedicated linear search.  Longer needles
++   up to size 256 use a novel modified Horspool algorithm.  It hashes pairs
++   of characters to quickly skip past mismatches.  The main search loop only
++   exits if the last 2 characters match, avoiding unnecessary calls to memcmp
++   and allowing for a larger skip if there is no match.  A self-adapting
++   filtering check is used to quickly detect mismatches in long needles.
++   By limiting the needle length to 256, the shift table can be reduced to 8
++   bits per entry, lowering preprocessing overhead and minimizing cache effects.
++   The limit also implies worst-case performance is linear.
++   Needles larger than 256 characters use the linear-time Two-Way algorithm.  */
+ char *
+-STRSTR (const char *haystack_start, const char *needle_start)
++STRSTR (const char *haystack, const char *needle)
+ {
+-  const char *haystack = haystack_start;
+-  const char *needle = needle_start;
+-  size_t needle_len; /* Length of NEEDLE.  */
+-  size_t haystack_len; /* Known minimum length of HAYSTACK.  */
+-  bool ok = true; /* True if NEEDLE is prefix of HAYSTACK.  */
+-
+-  /* Determine length of NEEDLE, and in the process, make sure
+-     HAYSTACK is at least as long (no point processing all of a long
+-     NEEDLE if HAYSTACK is too short).  */
+-  while (*haystack && *needle)
+-    ok &= *haystack++ == *needle++;
+-  if (*needle)
++  const unsigned char *hs = (const unsigned char *) haystack;
++  const unsigned char *ne = (const unsigned char *) needle;
++
++  /* Handle short needle special cases first.  */
++  if (ne[0] == '\0')
++    return (char *)hs;
++  hs = (const unsigned char *)strchr ((const char*)hs, ne[0]);
++  if (hs == NULL || ne[1] == '\0')
++    return (char*)hs;
++  if (ne[2] == '\0')
++    return strstr2 (hs, ne);
++  if (ne[3] == '\0')
++    return strstr3 (hs, ne);
++
++  /* Ensure haystack length is at least as long as needle length.
++     Since a match may occur early on in a huge haystack, use strnlen
++     and read ahead a few cachelines for improved performance.  */
++  size_t ne_len = strlen ((const char*)ne);
++  size_t hs_len = __strnlen ((const char*)hs, ne_len | 512);
++  if (hs_len < ne_len)
+     return NULL;
+-  if (ok)
+-    return (char *) haystack_start;
+-
+-  /* Reduce the size of haystack using strchr, since it has a smaller
+-     linear coefficient than the Two-Way algorithm.  */
+-  needle_len = needle - needle_start;
+-  haystack = strchr (haystack_start + 1, *needle_start);
+-  if (!haystack || __builtin_expect (needle_len == 1, 0))
+-    return (char *) haystack;
+-  needle -= needle_len;
+-  haystack_len = (haystack > haystack_start + needle_len ? 1
+-		  : needle_len + haystack_start - haystack);
+-
+-  /* Perform the search.  Abstract memory is considered to be an array
+-     of 'unsigned char' values, not an array of 'char' values.  See
+-     ISO C 99 section 6.2.6.1.  */
+-  if (needle_len < LONG_NEEDLE_THRESHOLD)
+-    return two_way_short_needle ((const unsigned char *) haystack,
+-				 haystack_len,
+-				 (const unsigned char *) needle, needle_len);
+-  return two_way_long_needle ((const unsigned char *) haystack, haystack_len,
+-			      (const unsigned char *) needle, needle_len);
++
++  /* Check whether we have a match.  This improves performance since we
++     avoid initialization overheads.  */
++  if (memcmp (hs, ne, ne_len) == 0)
++    return (char *) hs;
++
++  /* Use Two-Way algorithm for very long needles.  */
++  if (__glibc_unlikely (ne_len > 256))
++    return two_way_long_needle (hs, hs_len, ne, ne_len);
++
++  const unsigned char *end = hs + hs_len - ne_len;
++  uint8_t shift[256];
++  size_t tmp, shift1;
++  size_t m1 = ne_len - 1;
++  size_t offset = 0;
++
++  /* Initialize bad character shift hash table.  */
++  memset (shift, 0, sizeof (shift));
++  for (int i = 1; i < m1; i++)
++    shift[hash2 (ne + i)] = i;
++  /* Shift1 is the amount we can skip after matching the hash of the
++     needle end but not the full needle.  */
++  shift1 = m1 - shift[hash2 (ne + m1)];
++  shift[hash2 (ne + m1)] = m1;
++
++  while (1)
++    {
++      if (__glibc_unlikely (hs > end))
++	{
++	  end += __strnlen ((const char*)end + m1 + 1, 2048);
++	  if (hs > end)
++	    return NULL;
++	}
++
++      /* Skip past character pairs not in the needle.  */
++      do
++	{
++	  hs += m1;
++	  tmp = shift[hash2 (hs)];
++	}
++      while (tmp == 0 && hs <= end);
++
++      /* If the match is not at the end of the needle, shift to the end
++	 and continue until we match the hash of the needle end.  */
++      hs -= tmp;
++      if (tmp < m1)
++	continue;
++
++      /* Hash of the last 2 characters matches.  If the needle is long,
++	 try to quickly filter out mismatches.  */
++      if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0)
++	{
++	  if (memcmp (hs, ne, m1) == 0)
++	    return (void *) hs;
++
++	  /* Adjust filter offset when it doesn't find the mismatch.  */
++	  offset = (offset >= 8 ? offset : m1) - 8;
++	}
++
++      /* Skip based on matching the hash of the needle end.  */
++      hs += shift1;
++    }
+ }
+ libc_hidden_builtin_def (strstr)
+-
+-#undef LONG_NEEDLE_THRESHOLD
 diff --git a/string/test-strerror-errno.c b/string/test-strerror-errno.c
 new file mode 100644
 index 0000000000..8e744e7ed9
@@ -7530,6 +9438,65 @@ index 5889ee187b..bef71ed0f3 100644
  }
  
  #endif
+diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
+index 4935aa7c54..9617cb754f 100644
+--- a/sysdeps/aarch64/dl-machine.h
++++ b/sysdeps/aarch64/dl-machine.h
+@@ -388,10 +388,37 @@ elf_machine_lazy_rel (struct link_map *map,
+   /* Check for unexpected PLT reloc type.  */
+   if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
+     {
+-      if (__builtin_expect (map->l_mach.plt, 0) == 0)
+-	*reloc_addr += l_addr;
+-      else
+-	*reloc_addr = map->l_mach.plt;
++      if (map->l_mach.plt == 0)
++	{
++	  /* Prelinking.  */
++	  *reloc_addr += l_addr;
++	  return;
++	}
++
++      if (1) /* DT_AARCH64_VARIANT_PCS is not available, so always check.  */
++	{
++	  /* Check the symbol table for variant PCS symbols.  */
++	  const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
++	  const ElfW (Sym) *symtab =
++	    (const void *)D_PTR (map, l_info[DT_SYMTAB]);
++	  const ElfW (Sym) *sym = &symtab[symndx];
++	  if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS))
++	    {
++	      /* Avoid lazy resolution of variant PCS symbols.  */
++	      const struct r_found_version *version = NULL;
++	      if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
++		{
++		  const ElfW (Half) *vernum =
++		    (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
++		  version = &map->l_versions[vernum[symndx] & 0x7fff];
++		}
++	      elf_machine_rela (map, reloc, sym, version, reloc_addr,
++				skip_ifunc);
++	      return;
++	    }
++	}
++
++      *reloc_addr = map->l_mach.plt;
+     }
+   else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
+     {
+diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c
+index 4a04a63b0f..8f5d4e7df5 100644
+--- a/sysdeps/aarch64/multiarch/memcpy.c
++++ b/sysdeps/aarch64/multiarch/memcpy.c
+@@ -36,7 +36,7 @@ extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden;
+ libc_ifunc (__libc_memcpy,
+             (IS_THUNDERX (midr)
+ 	     ? __memcpy_thunderx
+-	     : (IS_FALKOR (midr) || IS_PHECDA (midr)
++	     : (IS_FALKOR (midr) || IS_PHECDA (midr) || IS_ARES (midr)
+ 		? __memcpy_falkor
+ 		: (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)
+ 		  ? __memcpy_thunderx2
 diff --git a/sysdeps/alpha/fpu/libm-test-ulps b/sysdeps/alpha/fpu/libm-test-ulps
 index 12a6127ddf..3fc18d57d7 100644
 --- a/sysdeps/alpha/fpu/libm-test-ulps
@@ -7587,6 +9554,28 @@ index a7b6456075..be6eb7743e 100644
  }
  
  #endif /* dl-irel.h */
+diff --git a/sysdeps/generic/mmap_info.h b/sysdeps/generic/mmap_info.h
+new file mode 100644
+index 0000000000..b3087df2d3
+--- /dev/null
++++ b/sysdeps/generic/mmap_info.h
+@@ -0,0 +1,16 @@
++/* As default architectures with sizeof (off_t) < sizeof (off64_t) the mmap is
++   implemented with __SYS_mmap2 syscall and the offset is represented in
++   multiples of page size.  For offset larger than
++   '1 << (page_shift + 8 * sizeof (off_t))' (that is, 1<<44 on system with
++   page size of 4096 bytes) the system call silently truncates the offset.
++   For this case, glibc mmap implementation returns EINVAL.  */
++
++/* Return the maximum value expected as offset argument in mmap64 call.  */
++static inline uint64_t
++mmap64_maximum_offset (long int page_shift)
++{
++  if (sizeof (off_t) < sizeof (off64_t))
++    return (UINT64_C(1) << (page_shift + (8 * sizeof (off_t)))) - 1;
++  else
++    return UINT64_MAX;
++}
 diff --git a/sysdeps/generic/unwind-dw2.c b/sysdeps/generic/unwind-dw2.c
 index 082609b34a..724c16a7f0 100644
 --- a/sysdeps/generic/unwind-dw2.c
@@ -8454,6 +10443,43 @@ index f71cc39c7e..773aaea0e9 100644
  endif
  
  ifeq ($(subdir),nis)
+diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+index 39eba0186f..56076849ca 100644
+--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
++++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+@@ -36,6 +36,7 @@ static struct cpu_list cpu_list[] = {
+       {"thunderx2t99",   0x431F0AF0},
+       {"thunderx2t99p1", 0x420F5160},
+       {"phecda",	 0x680F0000},
++      {"ares",		 0x411FD0C0},
+       {"generic", 	 0x0}
+ };
+ 
+diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
+index eb35adfbe9..153d258afe 100644
+--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
++++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
+@@ -51,6 +51,8 @@
+ 
+ #define IS_PHECDA(midr) (MIDR_IMPLEMENTOR(midr) == 'h'			      \
+                         && MIDR_PARTNUM(midr) == 0x000)
++#define IS_ARES(midr) (MIDR_IMPLEMENTOR(midr) == 'A'			      \
++			&& MIDR_PARTNUM(midr) == 0xd0c)
+ 
+ struct cpu_features
+ {
+diff --git a/sysdeps/unix/sysv/linux/alpha/kernel-features.h b/sysdeps/unix/sysv/linux/alpha/kernel-features.h
+index 402d2573d7..26344cd610 100644
+--- a/sysdeps/unix/sysv/linux/alpha/kernel-features.h
++++ b/sysdeps/unix/sysv/linux/alpha/kernel-features.h
+@@ -48,7 +48,6 @@
+ /* Support for copy_file_range, statx was added in kernel 4.13.  */
+ #if __LINUX_KERNEL_VERSION < 0x040D00
+ # undef __ASSUME_MLOCK2
+-# undef __ASSUME_COPY_FILE_RANGE
+ # undef __ASSUME_STATX
+ #endif
+ 
 diff --git a/sysdeps/unix/sysv/linux/arm/atomic-machine.h b/sysdeps/unix/sysv/linux/arm/atomic-machine.h
 index ad165274d8..a5d244e65e 100644
 --- a/sysdeps/unix/sysv/linux/arm/atomic-machine.h
@@ -8513,6 +10539,43 @@ index 33766d1813..43c4e009a4 100644
  	    int si_fd;
  	  } _sigpoll;
  
+diff --git a/sysdeps/unix/sysv/linux/copy_file_range.c b/sysdeps/unix/sysv/linux/copy_file_range.c
+index 7b1a50f752..b88b7c9e2e 100644
+--- a/sysdeps/unix/sysv/linux/copy_file_range.c
++++ b/sysdeps/unix/sysv/linux/copy_file_range.c
+@@ -20,27 +20,16 @@
+ #include <sysdep-cancel.h>
+ #include <unistd.h>
+ 
+-/* Include the fallback implementation.  */
+-#ifndef __ASSUME_COPY_FILE_RANGE
+-#define COPY_FILE_RANGE_DECL static
+-#define COPY_FILE_RANGE copy_file_range_compat
+-#include <io/copy_file_range-compat.c>
+-#endif
+-
+ ssize_t
+ copy_file_range (int infd, __off64_t *pinoff,
+                  int outfd, __off64_t *poutoff,
+                  size_t length, unsigned int flags)
+ {
+ #ifdef __NR_copy_file_range
+-  ssize_t ret = SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff,
+-                                length, flags);
+-# ifndef __ASSUME_COPY_FILE_RANGE
+-  if (ret == -1 && errno == ENOSYS)
+-    ret = copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags);
+-# endif
+-  return ret;
+-#else  /* !__NR_copy_file_range */
+-  return copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags);
++  return SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff,
++                         length, flags);
++#else
++  __set_errno (ENOSYS);
++  return -1;
+ #endif
+ }
 diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c
 index 3bde0cf4f0..46eb5f4419 100644
 --- a/sysdeps/unix/sysv/linux/getdents64.c
@@ -8680,6 +10743,21 @@ index e3d08982d9..782fc5e175 100644
    if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
      {
        int saved_errno = errno;
+diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h
+index 5543d92d7e..7a74835495 100644
+--- a/sysdeps/unix/sysv/linux/kernel-features.h
++++ b/sysdeps/unix/sysv/linux/kernel-features.h
+@@ -111,10 +111,6 @@
+ # define __ASSUME_MLOCK2 1
+ #endif
+ 
+-#if __LINUX_KERNEL_VERSION >= 0x040500
+-# define __ASSUME_COPY_FILE_RANGE 1
+-#endif
+-
+ /* Support for statx was added in kernel 4.11.  */
+ #if __LINUX_KERNEL_VERSION >= 0x040B00
+ # define __ASSUME_STATX 1
 diff --git a/sysdeps/unix/sysv/linux/kernel_sigaction.h b/sysdeps/unix/sysv/linux/kernel_sigaction.h
 index 2dbec08099..1c36146d46 100644
 --- a/sysdeps/unix/sysv/linux/kernel_sigaction.h
@@ -8745,6 +10823,63 @@ index 54972feb13..464b351d6d 100644
 +   on kernel sigaction struct.  */
 +#define HAS_SA_RESTORER 1
 +#include <sysdeps/unix/sysv/linux/kernel_sigaction.h>
+diff --git a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h
+index e8e2ac6a87..0dab05bedc 100644
+--- a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h
++++ b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h
+@@ -58,9 +58,6 @@
+ # undef __ASSUME_EXECVEAT
+ #endif
+ 
+-/* Support for the copy_file_range syscall was added in 4.10.  */
+-#if __LINUX_KERNEL_VERSION < 0x040A00
+-# undef __ASSUME_COPY_FILE_RANGE
+ #endif
+ 
+ /* Support for statx was added in kernel 4.12.  */
+diff --git a/sysdeps/unix/sysv/linux/mips/mmap_info.h b/sysdeps/unix/sysv/linux/mips/mmap_info.h
+new file mode 100644
+index 0000000000..07c9e3a044
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/mips/mmap_info.h
+@@ -0,0 +1,13 @@
++/* mips64n32 uses __NR_mmap for mmap64 while still having sizeof (off_t)
++   smaller than sizeof (off64_t).  So it allows mapping large offsets
++   using mmap64 than 32-bit archs which uses __NR_mmap2.  */
++
++static inline uint64_t
++mmap64_maximum_offset (long int page_shift)
++{
++#if _MIPS_SIM == _ABIN32 || _MIPS_SIM == _ABI64
++  return UINT64_MAX;
++#else
++  return (UINT64_C(1) << (page_shift + (8 * sizeof (off_t)))) - 1;
++#endif
++}
+diff --git a/sysdeps/unix/sysv/linux/mmap64.c b/sysdeps/unix/sysv/linux/mmap64.c
+index 118624185e..5d7598b4ba 100644
+--- a/sysdeps/unix/sysv/linux/mmap64.c
++++ b/sysdeps/unix/sysv/linux/mmap64.c
+@@ -23,11 +23,18 @@
+ #include <sysdep.h>
+ #include <mmap_internal.h>
+ 
++#ifdef __NR_mmap2
+ /* To avoid silent truncation of offset when using mmap2, do not accept
+    offset larger than 1 << (page_shift + off_t bits).  For archictures with
+    32 bits off_t and page size of 4096 it would be 1^44.  */
+-#define MMAP_OFF_HIGH_MASK \
++# define MMAP_OFF_HIGH_MASK \
+   ((-(MMAP2_PAGE_UNIT << 1) << (8 * sizeof (off_t) - 1)))
++#else
++/* Some ABIs might use __NR_mmap while having sizeof (off_t) smaller than
++   sizeof (off64_t) (currently only MIPS64n32).  For this case just set
++   zero the higher bits so mmap with large offset does not fail.  */
++# define MMAP_OFF_HIGH_MASK  0x0
++#endif
+ 
+ #define MMAP_OFF_MASK (MMAP_OFF_HIGH_MASK | MMAP_OFF_LOW_MASK)
+ 
 diff --git a/sysdeps/unix/sysv/linux/netlink_assert_response.c b/sysdeps/unix/sysv/linux/netlink_assert_response.c
 index f31ccb52ff..6afc3a17ce 100644
 --- a/sysdeps/unix/sysv/linux/netlink_assert_response.c

Reply to: