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

Bug#1034548: marked as done (bullseye-pu: package glibc/2.31-13+deb11u6)



Your message dated Sat, 29 Apr 2023 10:54:14 +0100
with message-id <502b8fb37ece620c9723446611a9287974ba5a0c.camel@adam-barratt.org.uk>
and subject line Closing p-u requests for fixes included in 11.7
has caused the Debian Bug report #1034548,
regarding bullseye-pu: package glibc/2.31-13+deb11u6
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
1034548: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1034548
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bullseye
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: glibc@packages.debian.org, debian-boot@lists.debian.org, debian-glibc@lists.debian.org
Control: affects -1 + src:glibc

[ Reason ]
There are multiple fixes in this upload, all coming from the upstream
stable branch:
- Multiple crashes or memory leak in printf-family functions
- Overflow fix in the AVX2 implementation of wcsnlen

[ Impact ]
In case the update isn't approved, systems will be left with issues
which combined with other vulnerabilities might lead to denial of
service.

[ Tests ]
The upstream fixes come with additional tests, which represent a
significant part of the diff.

[ Risks ]
The most risky parts are probably the printf-family functions changes,
however those changes are in testing/sid for ~1.5 years (since glibc
2.32), but have only been identified as problematic recently. The
wcsnlen fix is in testing/sid for ~4 months. All of those changes come
with additional tests.

[ 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:

 - Drop debian/patches/amd64/local-require-bmi-in-avx2-ifunc.diff
   (obsolete).

The upstream stable branch for glibc 2.31 now includes the fix
introduced in glibc 2.31-13+deb11u5 to fix some crash on some CPU.
Therefore this patch is not needed anymore.

 - Fix memory leak in printf-family functions with long multibyte strings.

   This fixes a memory leak that might lead to OOM when calling with
   long multibyte strings. The simplest reproducer is:
     printf("%.1371337ls", L"A\n");

 - Fix a crash in printf-family due to width/precision-dependent
   allocations.

   This fixes a crash due to a missing overflow check in the requested
   precision. The simplest reproducer is:
     fprintf (fp, "%2$.*1$a", 0x7fffffff, 1e200);

 - Fix a segfault in printf handling thousands separator.

   This segmentation fault has been fixed as a side effect of the
   previous fix, but comes with a specific test. The simplest reproducer
   is:
     setlocale(LC_ALL, "en_US.UTF-8");
     printf("%'1000d\n", 1000);

 - Fix an overflow in the AVX2 implementation of wcsnlen when crossing
   pages.

   The overflow happens when wcsnlen is called with a huge maxlen
   argument (e.g. (1UL << 63)), triggering an assertion in the wcsnlen
   code.
diff --git a/debian/changelog b/debian/changelog
index 50f6135b..3d95edf8 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,18 @@
+glibc (2.31-13+deb11u6) UNRELEASED; urgency=medium
+
+  [ Aurelien Jarno ]
+  * debian/patches/git-updates.diff: update from upstream stable branch:
+    - Drop debian/patches/amd64/local-require-bmi-in-avx2-ifunc.diff
+      (obsolete).
+    - Fix memory leak in printf-family functions with long multibyte strings.
+    - Fix a crash in printf-family due to width/precision-dependent
+      allocations.
+    - Fix a segfault in printf handling thousands separator.
+    - Fix an overflow in the AVX2 implementation of wcsnlen when crossing
+      pages.
+
+ -- Aurelien Jarno <aurel32@debian.org>  Sun, 16 Apr 2023 18:58:33 +0200
+
 glibc (2.31-13+deb11u5) bullseye; urgency=medium
 
   * debian/patches/local-require-bmi-in-avx2-ifunc.diff: new patch extracted
diff --git a/debian/patches/amd64/local-require-bmi-in-avx2-ifunc.diff b/debian/patches/amd64/local-require-bmi-in-avx2-ifunc.diff
deleted file mode 100644
index 936f89ae..00000000
--- a/debian/patches/amd64/local-require-bmi-in-avx2-ifunc.diff
+++ /dev/null
@@ -1,38 +0,0 @@
-This patch is extracted from upstream commit 83c5b368226c ("x86-64: Require
-BMI2 for strchr-avx2.S"). It changes the common ifunc AVX2 selector to require
-the BMI2 instructions, and the backported fixes for memchr and strlen rely on
-that change.
-
---- a/sysdeps/x86_64/multiarch/ifunc-avx2.h
-+++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h
-@@ -21,28 +21,28 @@ IFUNC_SELECTOR (void)
- 
- extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2) attribute_hidden;
- extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden;
- extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden;
- extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden;
- 
- static inline void *
- IFUNC_SELECTOR (void)
- {
-   const struct cpu_features* cpu_features = __get_cpu_features ();
- 
-   if (CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)
-+      && CPU_FEATURES_CPU_P (cpu_features, BMI2)
-       && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load))
-     {
-       if (CPU_FEATURES_ARCH_P (cpu_features, AVX512VL_Usable)
--	  && CPU_FEATURES_ARCH_P (cpu_features, AVX512BW_Usable)
--	  && CPU_FEATURES_CPU_P (cpu_features, BMI2))
-+	  && CPU_FEATURES_ARCH_P (cpu_features, AVX512BW_Usable))
- 	return OPTIMIZE (evex);
- 
-       if (CPU_FEATURES_CPU_P (cpu_features, RTM))
- 	return OPTIMIZE (avx2_rtm);
- 
-       if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER))
- 	return OPTIMIZE (avx2);
-     }
- 
-   return OPTIMIZE (sse2);
- }
diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff
index e4bcb9ee..63246ab1 100644
--- a/debian/patches/git-updates.diff
+++ b/debian/patches/git-updates.diff
@@ -23,16 +23,17 @@ index 242cb06f91..b487e18634 100644
  '--disable-werror'
       By default, the GNU C Library is built with '-Werror'.  If you wish
 diff --git a/NEWS b/NEWS
-index 292fbc595a..a3278be684 100644
+index 292fbc595a..8a20d3c4e3 100644
 --- a/NEWS
 +++ b/NEWS
-@@ -5,6 +5,90 @@ See the end for copying conditions.
+@@ -5,6 +5,94 @@ See the end for copying conditions.
  Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
  using `glibc' in the "product" field.
  
 +Version 2.31.1
 +
 +The following bugs are resolved with this release:
++  [14231] stdio-common tests memory requirements
 +  [19519] iconv(1) with -c option hangs on illegal multi-byte sequences
 +    (CVE-2016-10228)
 +  [20019] NULL pointer dereference in libc.so.6 IFUNC due to uninitialized GOT
@@ -48,6 +49,7 @@ index 292fbc595a..a3278be684 100644
 +  [25635] arm: Wrong sysdep order selection for soft-fp
 +  [25639] localedata: Some names of days and months wrongly spelt in
 +    Occitan
++  [25691] stdio: Remove memory leak from multibyte convertion
 +  [25715] system() returns wrong errors when posix_spawn fails
 +  [25810] x32: Incorrect syscall entries with pointer, off_t and size_t
 +  [25896] Incorrect prctl
@@ -55,6 +57,7 @@ index 292fbc595a..a3278be684 100644
 +  [25933] Off by one error in __strncmp_avx2
 +  [25966] Incorrect access of __x86_shared_non_temporal_threshold for x32
 +  [25976] nss_compat: internal_end*ent may clobber errno, hiding ERANGE
++  [26211] printf integer overflow calculating allocation size
 +  [26224] iconv hangs when converting some invalid inputs from several IBM
 +    character sets (CVE-2020-27618)
 +  [26248] Incorrect argument types for INLINE_SETXID_SYSCALL
@@ -72,6 +75,7 @@ index 292fbc595a..a3278be684 100644
 +  [28769] CVE-2021-3999: Off-by-one buffer overflow/underflow in getcwd()
 +  [28896] strncmp-avx2-rtm and wcsncmp-avx2-rtm fallback on non-rtm
 +    variants when avoiding overflow
++  [29530] segfault in printf handling thousands separator
 +
 +Security related changes:
 +
@@ -117,7 +121,7 @@ index 292fbc595a..a3278be684 100644
  Version 2.31
  
  Major new features:
-@@ -141,6 +225,18 @@ Changes to build and runtime requirements:
+@@ -141,6 +229,18 @@ Changes to build and runtime requirements:
    source tree.  ChangeLog files are located in the ChangeLog.old directory as
    ChangeLog.N where the highest N has the latest entries.
  
@@ -4022,6 +4026,941 @@ index 0000000000..29c2a81afd
 +}
 +
 +#include <support/test-driver.c>
+diff --git a/stdio-common/Makefile b/stdio-common/Makefile
+index 95af0c12d7..5e92d6b9ae 100644
+--- a/stdio-common/Makefile
++++ b/stdio-common/Makefile
+@@ -66,6 +66,10 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
+ 	 tst-scanf-round \
+ 	 tst-renameat2 tst-bz11319 tst-bz11319-fortify2 \
+ 	 scanf14a scanf16a \
++	 tst-printf-bz25691 \
++	 tst-vfprintf-width-prec-alloc \
++	 tst-grouping2 \
++  # tests
+ 
+ 
+ test-srcs = tst-unbputc tst-printf tst-printfsz-islongdouble
+@@ -75,10 +79,12 @@ tests-special += $(objpfx)tst-unbputc.out $(objpfx)tst-printf.out \
+ 		 $(objpfx)tst-printf-bz18872-mem.out \
+ 		 $(objpfx)tst-setvbuf1-cmp.out \
+ 		 $(objpfx)tst-vfprintf-width-prec-mem.out \
+-		 $(objpfx)tst-printfsz-islongdouble.out
++		 $(objpfx)tst-printfsz-islongdouble.out \
++		 $(objpfx)tst-printf-bz25691-mem.out
+ generated += tst-printf-bz18872.c tst-printf-bz18872.mtrace \
+ 	     tst-printf-bz18872-mem.out \
+-	     tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out
++	     tst-vfprintf-width-prec.mtrace tst-vfprintf-width-prec-mem.out \
++	     tst-printf-bz25691.mtrace tst-printf-bz25691-mem.out
+ endif
+ 
+ include ../Rules
+@@ -91,6 +97,7 @@ $(objpfx)bug14.out: $(gen-locales)
+ $(objpfx)scanf13.out: $(gen-locales)
+ $(objpfx)test-vfprintf.out: $(gen-locales)
+ $(objpfx)tst-grouping.out: $(gen-locales)
++$(objpfx)tst-grouping2.out: $(gen-locales)
+ $(objpfx)tst-sprintf.out: $(gen-locales)
+ $(objpfx)tst-sscanf.out: $(gen-locales)
+ $(objpfx)tst-swprintf.out: $(gen-locales)
+@@ -100,6 +107,8 @@ endif
+ tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace
+ tst-vfprintf-width-prec-ENV = \
+   MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace
++tst-printf-bz25691-ENV = \
++  MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace
+ 
+ $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
+ 	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' > $@; \
+diff --git a/stdio-common/bug22.c b/stdio-common/bug22.c
+index b3d48eb8e1..029b549941 100644
+--- a/stdio-common/bug22.c
++++ b/stdio-common/bug22.c
+@@ -57,7 +57,7 @@ do_test (void)
+ 
+   ret = fprintf (fp, "%." SN3 "d", 1);
+   printf ("ret = %d\n", ret);
+-  if (ret != -1 || errno != EOVERFLOW)
++  if (ret != N3)
+ 	  return 1;
+ 
+   /* GCC 9 warns about output of more than INT_MAX characters; this is
+diff --git a/stdio-common/tst-grouping2.c b/stdio-common/tst-grouping2.c
+new file mode 100644
+index 0000000000..3024c942a6
+--- /dev/null
++++ b/stdio-common/tst-grouping2.c
+@@ -0,0 +1,39 @@
++/* Test printf with grouping and large width (bug 29530)
++   Copyright (C) 2022 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#include <locale.h>
++#include <stdio.h>
++#include <support/check.h>
++#include <support/support.h>
++
++static int
++do_test (void)
++{
++  const int field_width = 1000;
++  char buf[field_width + 1];
++
++  xsetlocale (LC_NUMERIC, "de_DE.UTF-8");
++
++  /* This used to crash in group_number.  */
++  TEST_COMPARE (sprintf (buf, "%'*d", field_width, 1000), field_width);
++  TEST_COMPARE_STRING (buf + field_width - 6, " 1.000");
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/stdio-common/tst-printf-bz25691.c b/stdio-common/tst-printf-bz25691.c
+new file mode 100644
+index 0000000000..37b30a3a8a
+--- /dev/null
++++ b/stdio-common/tst-printf-bz25691.c
+@@ -0,0 +1,108 @@
++/* Test for memory leak with large width (BZ#25691).
++   Copyright (C) 2020 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <wchar.h>
++#include <stdint.h>
++#include <locale.h>
++
++#include <mcheck.h>
++#include <support/check.h>
++#include <support/support.h>
++
++static int
++do_test (void)
++{
++  mtrace ();
++
++  /* For 's' conversion specifier with 'l' modifier the array must be
++     converted to multibyte characters up to the precision specific
++     value.  */
++  {
++    /* The input size value is to force a heap allocation on temporary
++       buffer (in the old implementation).  */
++    const size_t winputsize = 64 * 1024 + 1;
++    wchar_t *winput = xmalloc (winputsize * sizeof (wchar_t));
++    wmemset (winput, L'a', winputsize - 1);
++    winput[winputsize - 1] = L'\0';
++
++    char result[9];
++    const char expected[] = "aaaaaaaa";
++    int ret;
++
++    ret = snprintf (result, sizeof (result), "%.65537ls", winput);
++    TEST_COMPARE (ret, winputsize - 1);
++    TEST_COMPARE_BLOB (result, sizeof (result), expected, sizeof (expected));
++
++    ret = snprintf (result, sizeof (result), "%ls", winput);
++    TEST_COMPARE (ret, winputsize - 1);
++    TEST_COMPARE_BLOB (result, sizeof (result), expected, sizeof (expected));
++
++    free (winput);
++  }
++
++  /* For 's' converstion specifier the array is interpreted as a multibyte
++     character sequence and converted to wide characters up to the precision
++     specific value.  */
++  {
++    /* The input size value is to force a heap allocation on temporary
++       buffer (in the old implementation).  */
++    const size_t mbssize = 32 * 1024;
++    char *mbs = xmalloc (mbssize);
++    memset (mbs, 'a', mbssize - 1);
++    mbs[mbssize - 1] = '\0';
++
++    const size_t expectedsize = 32 * 1024;
++    wchar_t *expected = xmalloc (expectedsize * sizeof (wchar_t));
++    wmemset (expected, L'a', expectedsize - 1);
++    expected[expectedsize-1] = L'\0';
++
++    const size_t resultsize = mbssize * sizeof (wchar_t);
++    wchar_t *result = xmalloc (resultsize);
++    int ret;
++
++    ret = swprintf (result, resultsize, L"%.65537s", mbs);
++    TEST_COMPARE (ret, mbssize - 1);
++    TEST_COMPARE_BLOB (result, (ret + 1) * sizeof (wchar_t),
++		       expected, expectedsize * sizeof (wchar_t));
++
++    ret = swprintf (result, resultsize, L"%1$.65537s", mbs);
++    TEST_COMPARE (ret, mbssize - 1);
++    TEST_COMPARE_BLOB (result, (ret + 1) * sizeof (wchar_t),
++		       expected, expectedsize * sizeof (wchar_t));
++
++    /* Same test, but with an invalid multibyte sequence.  */
++    mbs[mbssize - 2] = 0xff;
++
++    ret = swprintf (result, resultsize, L"%.65537s", mbs);
++    TEST_COMPARE (ret, -1);
++
++    ret = swprintf (result, resultsize, L"%1$.65537s", mbs);
++    TEST_COMPARE (ret, -1);
++
++    free (mbs);
++    free (result);
++    free (expected);
++  }
++
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/stdio-common/tst-vfprintf-width-prec-alloc.c b/stdio-common/tst-vfprintf-width-prec-alloc.c
+new file mode 100644
+index 0000000000..0a74b53a33
+--- /dev/null
++++ b/stdio-common/tst-vfprintf-width-prec-alloc.c
+@@ -0,0 +1,41 @@
++/* Test large width or precision does not involve large allocation.
++   Copyright (C) 2020 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <https://www.gnu.org/licenses/>.  */
++
++#include <stdio.h>
++#include <sys/resource.h>
++#include <support/check.h>
++
++char test_string[] = "test";
++
++static int
++do_test (void)
++{
++  struct rlimit limit;
++  TEST_VERIFY_EXIT (getrlimit (RLIMIT_AS, &limit) == 0);
++  limit.rlim_cur = 200 * 1024 * 1024;
++  TEST_VERIFY_EXIT (setrlimit (RLIMIT_AS, &limit) == 0);
++  FILE *fp = fopen ("/dev/null", "w");
++  TEST_VERIFY_EXIT (fp != NULL);
++  TEST_COMPARE (fprintf (fp, "%1000000000d", 1), 1000000000);
++  TEST_COMPARE (fprintf (fp, "%.1000000000s", test_string), 4);
++  TEST_COMPARE (fprintf (fp, "%1000000000d %1000000000d", 1, 2), 2000000001);
++  TEST_COMPARE (fprintf (fp, "%2$.*1$s", 0x7fffffff, test_string), 4);
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
+index 3be92d4b6e..b1c8f5c43e 100644
+--- a/stdio-common/vfprintf-internal.c
++++ b/stdio-common/vfprintf-internal.c
+@@ -31,6 +31,7 @@
+ #include <locale/localeinfo.h>
+ #include <stdio.h>
+ #include <scratch_buffer.h>
++#include <intprops.h>
+ 
+ /* This code is shared between the standard stdio implementation found
+    in GNU C library and the libio implementation originally found in
+@@ -45,10 +46,6 @@
+ #include <wctype.h>
+ #endif
+ 
+-/* In some cases we need extra space for all the output which is not
+-   counted in the width of the string. We assume 32 characters is
+-   enough.  */
+-#define EXTSIZ		32
+ #define ARGCHECK(S, Format) \
+   do									      \
+     {									      \
+@@ -119,22 +116,38 @@
+   while (0)
+ #endif
+ 
+-#define done_add(val) \
+-  do {									      \
+-    unsigned int _val = val;						      \
+-    assert ((unsigned int) done < (unsigned int) INT_MAX);		      \
+-    if (__glibc_unlikely (INT_MAX - done < _val))			      \
+-      {									      \
+-	done = -1;							      \
+-	 __set_errno (EOVERFLOW);					      \
+-	goto all_done;							      \
+-      }									      \
+-    done += _val;							      \
+-  } while (0)
++/* Add LENGTH to DONE.  Return the new value of DONE, or -1 on
++   overflow (and set errno accordingly).  */
++static inline int
++done_add_func (size_t length, int done)
++{
++  if (done < 0)
++    return done;
++  int ret;
++  if (INT_ADD_WRAPV (done, length, &ret))
++    {
++      __set_errno (EOVERFLOW);
++      return -1;
++    }
++  return ret;
++}
++
++#define done_add(val)							\
++  do									\
++    {									\
++      /* Ensure that VAL has a type similar to int.  */			\
++      _Static_assert (sizeof (val) == sizeof (int), "value int size");	\
++      _Static_assert ((__typeof__ (val)) -1 < 0, "value signed");	\
++      done = done_add_func ((val), done);				\
++      if (done < 0)							\
++	goto all_done;							\
++    }									\
++  while (0)
+ 
+ #ifndef COMPILE_WPRINTF
+ # define vfprintf	__vfprintf_internal
+ # define CHAR_T		char
++# define OTHER_CHAR_T   wchar_t
+ # define UCHAR_T	unsigned char
+ # define INT_T		int
+ typedef const char *THOUSANDS_SEP_T;
+@@ -143,25 +156,14 @@ typedef const char *THOUSANDS_SEP_T;
+ # define STR_LEN(Str)	strlen (Str)
+ 
+ # define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
+-# define PAD(Padchar) \
+-  do {									      \
+-    if (width > 0)							      \
+-      {									      \
+-	ssize_t written = _IO_padn (s, (Padchar), width);		      \
+-	if (__glibc_unlikely (written != width))			      \
+-	  {								      \
+-	    done = -1;							      \
+-	    goto all_done;						      \
+-	  }								      \
+-	done_add (written);						      \
+-      }									      \
+-  } while (0)
+ # define PUTC(C, F)	_IO_putc_unlocked (C, F)
+ # define ORIENT		if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
+ 			  return -1
++# define CONVERT_FROM_OTHER_STRING __wcsrtombs
+ #else
+ # define vfprintf	__vfwprintf_internal
+ # define CHAR_T		wchar_t
++# define OTHER_CHAR_T   char
+ /* This is a hack!!!  There should be a type uwchar_t.  */
+ # define UCHAR_T	unsigned int /* uwchar_t */
+ # define INT_T		wint_t
+@@ -173,21 +175,9 @@ typedef wchar_t THOUSANDS_SEP_T;
+ # include <_itowa.h>
+ 
+ # define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
+-# define PAD(Padchar) \
+-  do {									      \
+-    if (width > 0)							      \
+-      {									      \
+-	ssize_t written = _IO_wpadn (s, (Padchar), width);		      \
+-	if (__glibc_unlikely (written != width))			      \
+-	  {								      \
+-	    done = -1;							      \
+-	    goto all_done;						      \
+-	  }								      \
+-	done_add (written);						      \
+-      }									      \
+-  } while (0)
+ # define PUTC(C, F)	_IO_putwc_unlocked (C, F)
+ # define ORIENT		if (_IO_fwide (s, 1) != 1) return -1
++# define CONVERT_FROM_OTHER_STRING __mbsrtowcs
+ 
+ # undef _itoa
+ # define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
+@@ -196,6 +186,33 @@ typedef wchar_t THOUSANDS_SEP_T;
+ # define EOF WEOF
+ #endif
+ 
++static inline int
++pad_func (FILE *s, CHAR_T padchar, int width, int done)
++{
++  if (width > 0)
++    {
++      ssize_t written;
++#ifndef COMPILE_WPRINTF
++      written = _IO_padn (s, padchar, width);
++#else
++      written = _IO_wpadn (s, padchar, width);
++#endif
++      if (__glibc_unlikely (written != width))
++	return -1;
++      return done_add_func (width, done);
++    }
++  return done;
++}
++
++#define PAD(Padchar)							\
++  do									\
++    {									\
++      done = pad_func (s, (Padchar), width, done);			\
++      if (done < 0)							\
++	goto all_done;							\
++    }									\
++  while (0)
++
+ #include "_i18n_number.h"
+ 
+ /* Include the shared code for parsing the format string.  */
+@@ -215,24 +232,115 @@ typedef wchar_t THOUSANDS_SEP_T;
+     }									      \
+   while (0)
+ 
+-#define outstring(String, Len)						      \
+-  do									      \
+-    {									      \
+-      assert ((size_t) done <= (size_t) INT_MAX);			      \
+-      if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len))		      \
+-	{								      \
+-	  done = -1;							      \
+-	  goto all_done;						      \
+-	}								      \
+-      if (__glibc_unlikely (INT_MAX - done < (Len)))			      \
+-      {									      \
+-	done = -1;							      \
+-	 __set_errno (EOVERFLOW);					      \
+-	goto all_done;							      \
+-      }									      \
+-      done += (Len);							      \
+-    }									      \
+-  while (0)
++static inline int
++outstring_func (FILE *s, const UCHAR_T *string, size_t length, int done)
++{
++  assert ((size_t) done <= (size_t) INT_MAX);
++  if ((size_t) PUT (s, string, length) != (size_t) (length))
++    return -1;
++  return done_add_func (length, done);
++}
++
++#define outstring(String, Len)						\
++  do									\
++    {									\
++      const void *string_ = (String);					\
++      done = outstring_func (s, string_, (Len), done);			\
++      if (done < 0)							\
++	goto all_done;							\
++    }									\
++   while (0)
++
++/* Write the string SRC to S.  If PREC is non-negative, write at most
++   PREC bytes.  If LEFT is true, perform left justification.  */
++static int
++outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec,
++				 int width, bool left, int done)
++{
++  /* Use a small buffer to combine processing of multiple characters.
++     CONVERT_FROM_OTHER_STRING expects the buffer size in (wide)
++     characters, and buf_length counts that.  */
++  enum { buf_length = 256 / sizeof (CHAR_T) };
++  CHAR_T buf[buf_length];
++  _Static_assert (sizeof (buf) > MB_LEN_MAX,
++		  "buffer is large enough for a single multi-byte character");
++
++  /* Add the initial padding if needed.  */
++  if (width > 0 && !left)
++    {
++      /* Make a first pass to find the output width, so that we can
++	 add the required padding.  */
++      mbstate_t mbstate = { 0 };
++      const OTHER_CHAR_T *src_copy = src;
++      size_t total_written;
++      if (prec < 0)
++	total_written = CONVERT_FROM_OTHER_STRING
++	  (NULL, &src_copy, 0, &mbstate);
++      else
++	{
++	  /* The source might not be null-terminated.  Enforce the
++	     limit manually, based on the output length.  */
++	  total_written = 0;
++	  size_t limit = prec;
++	  while (limit > 0 && src_copy != NULL)
++	    {
++	      size_t write_limit = buf_length;
++	      if (write_limit > limit)
++		write_limit = limit;
++	      size_t written = CONVERT_FROM_OTHER_STRING
++		(buf, &src_copy, write_limit, &mbstate);
++	      if (written == (size_t) -1)
++		return -1;
++	      if (written == 0)
++		break;
++	      total_written += written;
++	      limit -= written;
++	    }
++	}
++
++      /* Output initial padding.  */
++      if (total_written < width)
++	{
++	  done = pad_func (s, L_(' '), width - total_written, done);
++	  if (done < 0)
++	    return done;
++	}
++    }
++
++  /* Convert the input string, piece by piece.  */
++  size_t total_written = 0;
++  {
++    mbstate_t mbstate = { 0 };
++    /* If prec is negative, remaining is not decremented, otherwise,
++      it serves as the write limit.  */
++    size_t remaining = -1;
++    if (prec >= 0)
++      remaining = prec;
++    while (remaining > 0 && src != NULL)
++      {
++	size_t write_limit = buf_length;
++	if (remaining < write_limit)
++	  write_limit = remaining;
++	size_t written = CONVERT_FROM_OTHER_STRING
++	  (buf, &src, write_limit, &mbstate);
++	if (written == (size_t) -1)
++	  return -1;
++	if (written == 0)
++	  break;
++	done = outstring_func (s, (const UCHAR_T *) buf, written, done);
++	if (done < 0)
++	  return done;
++	total_written += written;
++	if (prec >= 0)
++	  remaining -= written;
++      }
++  }
++
++  /* Add final padding.  */
++  if (width > 0 && left && total_written < width)
++    return pad_func (s, L_(' '), width - total_written, done);
++  return done;
++}
+ 
+ /* For handling long_double and longlong we use the same flag.  If
+    `long' and `long long' are effectively the same type define it to
+@@ -1022,7 +1130,6 @@ static const uint8_t jump_table[] =
+     LABEL (form_string):						      \
+       {									      \
+ 	size_t len;							      \
+-	int string_malloced;						      \
+ 									      \
+ 	/* The string argument could in fact be `char *' or `wchar_t *'.      \
+ 	   But this should not make a difference here.  */		      \
+@@ -1034,7 +1141,6 @@ static const uint8_t jump_table[] =
+ 	/* Entry point for printing other strings.  */			      \
+       LABEL (print_string):						      \
+ 									      \
+-	string_malloced = 0;						      \
+ 	if (string == NULL)						      \
+ 	  {								      \
+ 	    /* Write "(null)" if there's space.  */			      \
+@@ -1051,41 +1157,12 @@ static const uint8_t jump_table[] =
+ 	  }								      \
+ 	else if (!is_long && spec != L_('S'))				      \
+ 	  {								      \
+-	    /* This is complicated.  We have to transform the multibyte	      \
+-	       string into a wide character string.  */			      \
+-	    const char *mbs = (const char *) string;			      \
+-	    mbstate_t mbstate;						      \
+-									      \
+-	    len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \
+-									      \
+-	    /* Allocate dynamically an array which definitely is long	      \
+-	       enough for the wide character version.  Each byte in the	      \
+-	       multi-byte string can produce at most one wide character.  */  \
+-	    if (__glibc_unlikely (len > SIZE_MAX / sizeof (wchar_t)))	      \
+-	      {								      \
+-		__set_errno (EOVERFLOW);				      \
+-		done = -1;						      \
+-		goto all_done;						      \
+-	      }								      \
+-	    else if (__libc_use_alloca (len * sizeof (wchar_t)))	      \
+-	      string = (CHAR_T *) alloca (len * sizeof (wchar_t));	      \
+-	    else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t)))    \
+-		     == NULL)						      \
+-	      {								      \
+-		done = -1;						      \
+-		goto all_done;						      \
+-	      }								      \
+-	    else							      \
+-	      string_malloced = 1;					      \
+-									      \
+-	    memset (&mbstate, '\0', sizeof (mbstate_t));		      \
+-	    len = __mbsrtowcs (string, &mbs, len, &mbstate);		      \
+-	    if (len == (size_t) -1)					      \
+-	      {								      \
+-		/* Illegal multibyte character.  */			      \
+-		done = -1;						      \
+-		goto all_done;						      \
+-	      }								      \
++	    done = outstring_converted_wide_string			      \
++	      (s, (const char *) string, prec, width, left, done);	      \
++	    if (done < 0)						      \
++	      goto all_done;						      \
++	    /* The padding has already been written.  */		      \
++	    break;							      \
+ 	  }								      \
+ 	else								      \
+ 	  {								      \
+@@ -1108,8 +1185,6 @@ static const uint8_t jump_table[] =
+ 	outstring (string, len);					      \
+ 	if (left)							      \
+ 	  PAD (L' ');							      \
+-	if (__glibc_unlikely (string_malloced))				      \
+-	  free (string);						      \
+       }									      \
+       break;
+ #else
+@@ -1158,7 +1233,6 @@ static const uint8_t jump_table[] =
+     LABEL (form_string):						      \
+       {									      \
+ 	size_t len;							      \
+-	int string_malloced;						      \
+ 									      \
+ 	/* The string argument could in fact be `char *' or `wchar_t *'.      \
+ 	   But this should not make a difference here.  */		      \
+@@ -1170,7 +1244,6 @@ static const uint8_t jump_table[] =
+ 	/* Entry point for printing other strings.  */			      \
+       LABEL (print_string):						      \
+ 									      \
+-	string_malloced = 0;						      \
+ 	if (string == NULL)						      \
+ 	  {								      \
+ 	    /* Write "(null)" if there's space.  */			      \
+@@ -1196,51 +1269,12 @@ static const uint8_t jump_table[] =
+ 	  }								      \
+ 	else								      \
+ 	  {								      \
+-	    const wchar_t *s2 = (const wchar_t *) string;		      \
+-	    mbstate_t mbstate;						      \
+-									      \
+-	    memset (&mbstate, '\0', sizeof (mbstate_t));		      \
+-									      \
+-	    if (prec >= 0)						      \
+-	      {								      \
+-		/* The string `s2' might not be NUL terminated.  */	      \
+-		if (__libc_use_alloca (prec))				      \
+-		  string = (char *) alloca (prec);			      \
+-		else if ((string = (char *) malloc (prec)) == NULL)	      \
+-		  {							      \
+-		    done = -1;						      \
+-		    goto all_done;					      \
+-		  }							      \
+-		else							      \
+-		  string_malloced = 1;					      \
+-		len = __wcsrtombs (string, &s2, prec, &mbstate);	      \
+-	      }								      \
+-	    else							      \
+-	      {								      \
+-		len = __wcsrtombs (NULL, &s2, 0, &mbstate);		      \
+-		if (len != (size_t) -1)					      \
+-		  {							      \
+-		    assert (__mbsinit (&mbstate));			      \
+-		    s2 = (const wchar_t *) string;			      \
+-		    if (__libc_use_alloca (len + 1))			      \
+-		      string = (char *) alloca (len + 1);		      \
+-		    else if ((string = (char *) malloc (len + 1)) == NULL)    \
+-		      {							      \
+-			done = -1;					      \
+-			goto all_done;					      \
+-		      }							      \
+-		    else						      \
+-		      string_malloced = 1;				      \
+-		    (void) __wcsrtombs (string, &s2, len + 1, &mbstate);      \
+-		  }							      \
+-	      }								      \
+-									      \
+-	    if (len == (size_t) -1)					      \
+-	      {								      \
+-		/* Illegal wide-character string.  */			      \
+-		done = -1;						      \
+-		goto all_done;						      \
+-	      }								      \
++	    done = outstring_converted_wide_string			      \
++	      (s, (const wchar_t *) string, prec, width, left, done);	      \
++	    if (done < 0)						      \
++	      goto all_done;						      \
++	    /* The padding has already been written.  */		      \
++	    break;							      \
+ 	  }								      \
+ 									      \
+ 	if ((width -= len) < 0)						      \
+@@ -1254,8 +1288,6 @@ static const uint8_t jump_table[] =
+ 	outstring (string, len);					      \
+ 	if (left)							      \
+ 	  PAD (' ');							      \
+-	if (__glibc_unlikely (string_malloced))			              \
+-	  free (string);						      \
+       }									      \
+       break;
+ #endif
+@@ -1307,7 +1339,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
+ 
+   /* Buffer intermediate results.  */
+   CHAR_T work_buffer[WORK_BUFFER_SIZE];
+-  CHAR_T *workstart = NULL;
+   CHAR_T *workend;
+ 
+   /* We have to save the original argument pointer.  */
+@@ -1416,7 +1447,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
+       UCHAR_T pad = L_(' ');/* Padding character.  */
+       CHAR_T spec;
+ 
+-      workstart = NULL;
+       workend = work_buffer + WORK_BUFFER_SIZE;
+ 
+       /* Get current character in format string.  */
+@@ -1508,31 +1538,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
+ 	    pad = L_(' ');
+ 	    left = 1;
+ 	  }
+-
+-	if (__glibc_unlikely (width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
+-	  {
+-	    __set_errno (EOVERFLOW);
+-	    done = -1;
+-	    goto all_done;
+-	  }
+-
+-	if (width >= WORK_BUFFER_SIZE - EXTSIZ)
+-	  {
+-	    /* We have to use a special buffer.  */
+-	    size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
+-	    if (__libc_use_alloca (needed))
+-	      workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
+-	    else
+-	      {
+-		workstart = (CHAR_T *) malloc (needed);
+-		if (workstart == NULL)
+-		  {
+-		    done = -1;
+-		    goto all_done;
+-		  }
+-		workend = workstart + width + EXTSIZ;
+-	      }
+-	  }
+       }
+       JUMP (*f, step1_jumps);
+ 
+@@ -1540,31 +1545,13 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
+     LABEL (width):
+       width = read_int (&f);
+ 
+-      if (__glibc_unlikely (width == -1
+-			    || width >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
++      if (__glibc_unlikely (width == -1))
+ 	{
+ 	  __set_errno (EOVERFLOW);
+ 	  done = -1;
+ 	  goto all_done;
+ 	}
+ 
+-      if (width >= WORK_BUFFER_SIZE - EXTSIZ)
+-	{
+-	  /* We have to use a special buffer.  */
+-	  size_t needed = ((size_t) width + EXTSIZ) * sizeof (CHAR_T);
+-	  if (__libc_use_alloca (needed))
+-	    workend = (CHAR_T *) alloca (needed) + width + EXTSIZ;
+-	  else
+-	    {
+-	      workstart = (CHAR_T *) malloc (needed);
+-	      if (workstart == NULL)
+-		{
+-		  done = -1;
+-		  goto all_done;
+-		}
+-	      workend = workstart + width + EXTSIZ;
+-	    }
+-	}
+       if (*f == L_('$'))
+ 	/* Oh, oh.  The argument comes from a positional parameter.  */
+ 	goto do_positional;
+@@ -1613,34 +1600,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
+ 	}
+       else
+ 	prec = 0;
+-      if (prec > width && prec > WORK_BUFFER_SIZE - EXTSIZ)
+-	{
+-	  /* Deallocate any previously allocated buffer because it is
+-	     too small.  */
+-	  if (__glibc_unlikely (workstart != NULL))
+-	    free (workstart);
+-	  workstart = NULL;
+-	  if (__glibc_unlikely (prec >= INT_MAX / sizeof (CHAR_T) - EXTSIZ))
+-	    {
+-	      __set_errno (EOVERFLOW);
+-	      done = -1;
+-	      goto all_done;
+-	    }
+-	  size_t needed = ((size_t) prec + EXTSIZ) * sizeof (CHAR_T);
+-
+-	  if (__libc_use_alloca (needed))
+-	    workend = (CHAR_T *) alloca (needed) + prec + EXTSIZ;
+-	  else
+-	    {
+-	      workstart = (CHAR_T *) malloc (needed);
+-	      if (workstart == NULL)
+-		{
+-		  done = -1;
+-		  goto all_done;
+-		}
+-	      workend = workstart + prec + EXTSIZ;
+-	    }
+-	}
+       JUMP (*f, step2_jumps);
+ 
+       /* Process 'h' modifier.  There might another 'h' following.  */
+@@ -1704,10 +1663,6 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
+       /* The format is correctly handled.  */
+       ++nspecs_done;
+ 
+-      if (__glibc_unlikely (workstart != NULL))
+-	free (workstart);
+-      workstart = NULL;
+-
+       /* Look for next format specifier.  */
+ #ifdef COMPILE_WPRINTF
+       f = __find_specwc ((end_of_spec = ++f));
+@@ -1725,18 +1680,11 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
+ 
+   /* Hand off processing for positional parameters.  */
+ do_positional:
+-  if (__glibc_unlikely (workstart != NULL))
+-    {
+-      free (workstart);
+-      workstart = NULL;
+-    }
+   done = printf_positional (s, format, readonly_format, ap, &ap_save,
+ 			    done, nspecs_done, lead_str_end, work_buffer,
+ 			    save_errno, grouping, thousands_sep, mode_flags);
+ 
+  all_done:
+-  if (__glibc_unlikely (workstart != NULL))
+-    free (workstart);
+   /* Unlock the stream.  */
+   _IO_funlockfile (s);
+   _IO_cleanup_region_end (0);
+@@ -1780,8 +1728,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
+   /* Just a counter.  */
+   size_t cnt;
+ 
+-  CHAR_T *workstart = NULL;
+-
+   if (grouping == (const char *) -1)
+     {
+ #ifdef COMPILE_WPRINTF
+@@ -1974,7 +1920,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
+       char pad = specs[nspecs_done].info.pad;
+       CHAR_T spec = specs[nspecs_done].info.spec;
+ 
+-      workstart = NULL;
+       CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
+ 
+       /* Fill in last information.  */
+@@ -2008,27 +1953,6 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
+ 	  prec = specs[nspecs_done].info.prec;
+ 	}
+ 
+-      /* Maybe the buffer is too small.  */
+-      if (MAX (prec, width) + EXTSIZ > WORK_BUFFER_SIZE)
+-	{
+-	  if (__libc_use_alloca ((MAX (prec, width) + EXTSIZ)
+-				 * sizeof (CHAR_T)))
+-	    workend = ((CHAR_T *) alloca ((MAX (prec, width) + EXTSIZ)
+-					  * sizeof (CHAR_T))
+-		       + (MAX (prec, width) + EXTSIZ));
+-	  else
+-	    {
+-	      workstart = (CHAR_T *) malloc ((MAX (prec, width) + EXTSIZ)
+-					     * sizeof (CHAR_T));
+-	      if (workstart == NULL)
+-		{
+-		  done = -1;
+-		  goto all_done;
+-		}
+-	      workend = workstart + (MAX (prec, width) + EXTSIZ);
+-	    }
+-	}
+-
+       /* Process format specifiers.  */
+       while (1)
+ 	{
+@@ -2102,18 +2026,12 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
+ 	  break;
+ 	}
+ 
+-      if (__glibc_unlikely (workstart != NULL))
+-	free (workstart);
+-      workstart = NULL;
+-
+       /* Write the following constant string.  */
+       outstring (specs[nspecs_done].end_of_fmt,
+ 		 specs[nspecs_done].next_fmt
+ 		 - specs[nspecs_done].end_of_fmt);
+     }
+  all_done:
+-  if (__glibc_unlikely (workstart != NULL))
+-    free (workstart);
+   scratch_buffer_free (&argsbuf);
+   scratch_buffer_free (&specsbuf);
+   return done;
+@@ -2236,7 +2154,8 @@ group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr,
+ 	    copy_rest:
+ 	      /* No further grouping to be done.  Copy the rest of the
+ 		 number.  */
+-	      memmove (w, s, (front_ptr -s) * sizeof (CHAR_T));
++	      w -= s - front_ptr;
++	      memmove (w, front_ptr, (s - front_ptr) * sizeof (CHAR_T));
+ 	      break;
+ 	    }
+ 	  else if (*grouping != '\0')
 diff --git a/stdlib/Makefile b/stdlib/Makefile
 index 45214b59e4..4615f6dfe7 100644
 --- a/stdlib/Makefile
@@ -4594,7 +5533,7 @@ index d961ac4493..02806f4ebd 100644
    printf ("%23s", "");
    FOR_EACH_IMPL (impl, 0)
 diff --git a/string/test-strnlen.c b/string/test-strnlen.c
-index 80ac9e8602..a1a6746cc9 100644
+index 80ac9e8602..ca34352b0d 100644
 --- a/string/test-strnlen.c
 +++ b/string/test-strnlen.c
 @@ -27,6 +27,7 @@
@@ -4613,46 +5552,73 @@ index 80ac9e8602..a1a6746cc9 100644
  # define CHAR wchar_t
  # define BIG_CHAR WCHAR_MAX
  # define MIDDLE_CHAR 1121
-@@ -87,6 +89,38 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
+@@ -73,7 +75,7 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
+ {
+   size_t i;
+ 
+-  align &= 63;
++  align &= (getpagesize () / sizeof (CHAR) - 1);
+   if ((align + len) * sizeof (CHAR) >= page_size)
+     return;
+ 
+@@ -87,6 +89,56 @@ do_test (size_t align, size_t len, size_t maxlen, int max_char)
      do_one_test (impl, (CHAR *) (buf + align), maxlen, MIN (len, maxlen));
  }
  
 +static void
 +do_overflow_tests (void)
 +{
-+  size_t i, j, len;
++  size_t i, j, al_idx, repeats, len;
 +  const size_t one = 1;
 +  uintptr_t buf_addr = (uintptr_t) buf1;
++  const size_t alignments[] = { 0, 1, 7, 9, 31, 33, 63, 65, 95, 97, 127, 129 };
 +
-+  for (i = 0; i < 750; ++i)
++  for (al_idx = 0; al_idx < sizeof (alignments) / sizeof (alignments[0]);
++       al_idx++)
 +    {
-+      do_test (0, i, SIZE_MAX - i, BIG_CHAR);
-+      do_test (0, i, i - buf_addr, BIG_CHAR);
-+      do_test (0, i, -buf_addr - i, BIG_CHAR);
-+      do_test (0, i, SIZE_MAX - buf_addr - i, BIG_CHAR);
-+      do_test (0, i, SIZE_MAX - buf_addr + i, BIG_CHAR);
-+
-+      len = 0;
-+      for (j = 8 * sizeof(size_t) - 1; j ; --j)
-+        {
-+          len |= one << j;
-+          do_test (0, i, len - i, BIG_CHAR);
-+          do_test (0, i, len + i, BIG_CHAR);
-+          do_test (0, i, len - buf_addr - i, BIG_CHAR);
-+          do_test (0, i, len - buf_addr + i, BIG_CHAR);
-+
-+          do_test (0, i, ~len - i, BIG_CHAR);
-+          do_test (0, i, ~len + i, BIG_CHAR);
-+          do_test (0, i, ~len - buf_addr - i, BIG_CHAR);
-+          do_test (0, i, ~len - buf_addr + i, BIG_CHAR);
-+        }
++      for (repeats = 0; repeats < 2; ++repeats)
++	{
++	  size_t align = repeats ? (getpagesize () - alignments[al_idx])
++				 : alignments[al_idx];
++	  align /= sizeof (CHAR);
++	  for (i = 0; i < 750; ++i)
++	    {
++	      do_test (align, i, SIZE_MAX, BIG_CHAR);
++
++	      do_test (align, i, SIZE_MAX - i, BIG_CHAR);
++	      do_test (align, i, i - buf_addr, BIG_CHAR);
++	      do_test (align, i, -buf_addr - i, BIG_CHAR);
++	      do_test (align, i, SIZE_MAX - buf_addr - i, BIG_CHAR);
++	      do_test (align, i, SIZE_MAX - buf_addr + i, BIG_CHAR);
++
++	      len = 0;
++	      for (j = 8 * sizeof (size_t) - 1; j; --j)
++		{
++		  len |= one << j;
++		  do_test (align, i, len, BIG_CHAR);
++		  do_test (align, i, len - i, BIG_CHAR);
++		  do_test (align, i, len + i, BIG_CHAR);
++		  do_test (align, i, len - buf_addr - i, BIG_CHAR);
++		  do_test (align, i, len - buf_addr + i, BIG_CHAR);
++
++		  do_test (align, i, ~len - i, BIG_CHAR);
++		  do_test (align, i, ~len + i, BIG_CHAR);
++		  do_test (align, i, ~len - buf_addr - i, BIG_CHAR);
++		  do_test (align, i, ~len - buf_addr + i, BIG_CHAR);
++
++		  do_test (align, i, -buf_addr, BIG_CHAR);
++		  do_test (align, i, j - buf_addr, BIG_CHAR);
++		  do_test (align, i, -buf_addr - j, BIG_CHAR);
++		}
++	    }
++	}
 +    }
 +}
 +
  static void
  do_random_tests (void)
  {
-@@ -153,7 +187,7 @@ do_page_tests (void)
+@@ -153,7 +205,7 @@ do_page_tests (void)
    size_t last_offset = (page_size / sizeof (CHAR)) - 1;
  
    CHAR *s = (CHAR *) buf2;
@@ -4661,7 +5627,7 @@ index 80ac9e8602..a1a6746cc9 100644
    s[last_offset] = 0;
  
    /* Place short strings ending at page boundary.  */
-@@ -196,6 +230,35 @@ do_page_tests (void)
+@@ -196,6 +248,35 @@ do_page_tests (void)
      }
  }
  
@@ -4697,7 +5663,7 @@ index 80ac9e8602..a1a6746cc9 100644
  int
  test_main (void)
  {
-@@ -242,6 +305,8 @@ test_main (void)
+@@ -242,6 +323,8 @@ test_main (void)
  
    do_random_tests ();
    do_page_tests ();
@@ -11886,7 +12852,7 @@ index 395e432c09..da1446d731 100644
  
  ifeq ($(subdir),debug)
 diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h
-index 69f30398ae..74189b6aa5 100644
+index 69f30398ae..925e5b61eb 100644
 --- a/sysdeps/x86_64/multiarch/ifunc-avx2.h
 +++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h
 @@ -21,16 +21,28 @@
@@ -11904,12 +12870,12 @@ index 69f30398ae..74189b6aa5 100644
 -  if (!CPU_FEATURES_ARCH_P (cpu_features, Prefer_No_VZEROUPPER)
 -      && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)
 +  if (CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)
++      && CPU_FEATURES_CPU_P (cpu_features, BMI2)
        && CPU_FEATURES_ARCH_P (cpu_features, AVX_Fast_Unaligned_Load))
 -    return OPTIMIZE (avx2);
 +    {
 +      if (CPU_FEATURES_ARCH_P (cpu_features, AVX512VL_Usable)
-+	  && CPU_FEATURES_ARCH_P (cpu_features, AVX512BW_Usable)
-+	  && CPU_FEATURES_CPU_P (cpu_features, BMI2))
++	  && CPU_FEATURES_ARCH_P (cpu_features, AVX512BW_Usable))
 +	return OPTIMIZE (evex);
 +
 +      if (CPU_FEATURES_CPU_P (cpu_features, RTM))
@@ -11922,15 +12888,20 @@ index 69f30398ae..74189b6aa5 100644
    return OPTIMIZE (sse2);
  }
 diff --git a/sysdeps/x86_64/multiarch/ifunc-impl-list.c b/sysdeps/x86_64/multiarch/ifunc-impl-list.c
-index ce7eb1eecf..56b05ee741 100644
+index ce7eb1eecf..e712b148f5 100644
 --- a/sysdeps/x86_64/multiarch/ifunc-impl-list.c
 +++ b/sysdeps/x86_64/multiarch/ifunc-impl-list.c
-@@ -43,6 +43,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -41,8 +41,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   /* Support sysdeps/x86_64/multiarch/memchr.c.  */
+   IFUNC_IMPL (i, name, memchr,
  	      IFUNC_IMPL_ADD (array, i, memchr,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __memchr_avx2)
 +	      IFUNC_IMPL_ADD (array, i, memchr,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __memchr_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, memchr,
@@ -11941,7 +12912,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, memchr, 1, __memchr_sse2))
  
    /* Support sysdeps/x86_64/multiarch/memcmp.c.  */
-@@ -51,6 +60,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -51,6 +62,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      (HAS_ARCH_FEATURE (AVX2_Usable)
  			       && HAS_CPU_FEATURE (MOVBE)),
  			      __memcmp_avx2_movbe)
@@ -11958,7 +12929,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, memcmp, HAS_CPU_FEATURE (SSE4_1),
  			      __memcmp_sse4_1)
  	      IFUNC_IMPL_ADD (array, i, memcmp, HAS_CPU_FEATURE (SSSE3),
-@@ -64,10 +83,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -64,10 +85,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      HAS_ARCH_FEATURE (AVX512F_Usable),
  			      __memmove_chk_avx512_no_vzeroupper)
  	      IFUNC_IMPL_ADD (array, i, __memmove_chk,
@@ -11971,7 +12942,7 @@ index ce7eb1eecf..56b05ee741 100644
  			      __memmove_chk_avx512_unaligned_erms)
  	      IFUNC_IMPL_ADD (array, i, __memmove_chk,
  			      HAS_ARCH_FEATURE (AVX_Usable),
-@@ -75,6 +94,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -75,6 +96,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  	      IFUNC_IMPL_ADD (array, i, __memmove_chk,
  			      HAS_ARCH_FEATURE (AVX_Usable),
  			      __memmove_chk_avx_unaligned_erms)
@@ -11992,7 +12963,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, __memmove_chk,
  			      HAS_CPU_FEATURE (SSSE3),
  			      __memmove_chk_ssse3_back)
-@@ -97,14 +130,28 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -97,14 +132,28 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  	      IFUNC_IMPL_ADD (array, i, memmove,
  			      HAS_ARCH_FEATURE (AVX_Usable),
  			      __memmove_avx_unaligned_erms)
@@ -12023,23 +12994,29 @@ index ce7eb1eecf..56b05ee741 100644
  			      __memmove_avx512_unaligned_erms)
  	      IFUNC_IMPL_ADD (array, i, memmove, HAS_CPU_FEATURE (SSSE3),
  			      __memmove_ssse3_back)
-@@ -121,6 +168,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -119,8 +168,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   /* Support sysdeps/x86_64/multiarch/memrchr.c.  */
+   IFUNC_IMPL (i, name, memrchr,
  	      IFUNC_IMPL_ADD (array, i, memrchr,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __memrchr_avx2)
 +	      IFUNC_IMPL_ADD (array, i, memrchr,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __memrchr_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, memrchr,
 +			      (HAS_ARCH_FEATURE (AVX512VL_Usable)
-+			       && HAS_ARCH_FEATURE (AVX512BW_Usable)),
++			       && HAS_ARCH_FEATURE (AVX512BW_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
 +			      __memrchr_evex)
 +
  	      IFUNC_IMPL_ADD (array, i, memrchr, 1, __memrchr_sse2))
  
  #ifdef SHARED
-@@ -139,10 +195,28 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -139,10 +200,28 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      HAS_ARCH_FEATURE (AVX2_Usable),
  			      __memset_chk_avx2_unaligned_erms)
  	      IFUNC_IMPL_ADD (array, i, __memset_chk,
@@ -12070,7 +13047,7 @@ index ce7eb1eecf..56b05ee741 100644
  			      __memset_chk_avx512_unaligned)
  	      IFUNC_IMPL_ADD (array, i, __memset_chk,
  			      HAS_ARCH_FEATURE (AVX512F_Usable),
-@@ -164,10 +238,28 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -164,10 +243,28 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      HAS_ARCH_FEATURE (AVX2_Usable),
  			      __memset_avx2_unaligned_erms)
  	      IFUNC_IMPL_ADD (array, i, memset,
@@ -12101,12 +13078,17 @@ index ce7eb1eecf..56b05ee741 100644
  			      __memset_avx512_unaligned)
  	      IFUNC_IMPL_ADD (array, i, memset,
  			      HAS_ARCH_FEATURE (AVX512F_Usable),
-@@ -179,20 +271,51 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -177,22 +274,55 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   /* Support sysdeps/x86_64/multiarch/rawmemchr.c.  */
+   IFUNC_IMPL (i, name, rawmemchr,
  	      IFUNC_IMPL_ADD (array, i, rawmemchr,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __rawmemchr_avx2)
 +	      IFUNC_IMPL_ADD (array, i, rawmemchr,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __rawmemchr_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, rawmemchr,
@@ -12155,7 +13137,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, strnlen, 1, __strnlen_sse2))
  
    /* Support sysdeps/x86_64/multiarch/stpncpy.c.  */
-@@ -201,6 +324,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -201,6 +331,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      __stpncpy_ssse3)
  	      IFUNC_IMPL_ADD (array, i, stpncpy, HAS_ARCH_FEATURE (AVX2_Usable),
  			      __stpncpy_avx2)
@@ -12170,7 +13152,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, stpncpy, 1,
  			      __stpncpy_sse2_unaligned)
  	      IFUNC_IMPL_ADD (array, i, stpncpy, 1, __stpncpy_sse2))
-@@ -211,6 +342,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -211,6 +349,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      __stpcpy_ssse3)
  	      IFUNC_IMPL_ADD (array, i, stpcpy, HAS_ARCH_FEATURE (AVX2_Usable),
  			      __stpcpy_avx2)
@@ -12185,7 +13167,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2_unaligned)
  	      IFUNC_IMPL_ADD (array, i, stpcpy, 1, __stpcpy_sse2))
  
-@@ -245,6 +384,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -245,6 +391,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
    IFUNC_IMPL (i, name, strcat,
  	      IFUNC_IMPL_ADD (array, i, strcat, HAS_ARCH_FEATURE (AVX2_Usable),
  			      __strcat_avx2)
@@ -12200,12 +13182,17 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, strcat, HAS_CPU_FEATURE (SSSE3),
  			      __strcat_ssse3)
  	      IFUNC_IMPL_ADD (array, i, strcat, 1, __strcat_sse2_unaligned)
-@@ -255,6 +402,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -253,23 +407,56 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   /* Support sysdeps/x86_64/multiarch/strchr.c.  */
+   IFUNC_IMPL (i, name, strchr,
  	      IFUNC_IMPL_ADD (array, i, strchr,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __strchr_avx2)
 +	      IFUNC_IMPL_ADD (array, i, strchr,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __strchr_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, strchr,
@@ -12216,12 +13203,16 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_sse2_no_bsf)
  	      IFUNC_IMPL_ADD (array, i, strchr, 1, __strchr_sse2))
  
-@@ -263,6 +419,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   /* Support sysdeps/x86_64/multiarch/strchrnul.c.  */
+   IFUNC_IMPL (i, name, strchrnul,
  	      IFUNC_IMPL_ADD (array, i, strchrnul,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __strchrnul_avx2)
 +	      IFUNC_IMPL_ADD (array, i, strchrnul,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __strchrnul_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, strchrnul,
@@ -12232,22 +13223,26 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, strchrnul, 1, __strchrnul_sse2))
  
    /* Support sysdeps/x86_64/multiarch/strrchr.c.  */
-@@ -270,6 +435,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   IFUNC_IMPL (i, name, strrchr,
  	      IFUNC_IMPL_ADD (array, i, strrchr,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __strrchr_avx2)
 +	      IFUNC_IMPL_ADD (array, i, strrchr,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __strrchr_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, strrchr,
 +			      (HAS_ARCH_FEATURE (AVX512VL_Usable)
-+			       && HAS_ARCH_FEATURE (AVX512BW_Usable)),
++			       && HAS_ARCH_FEATURE (AVX512BW_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
 +			      __strrchr_evex)
  	      IFUNC_IMPL_ADD (array, i, strrchr, 1, __strrchr_sse2))
  
    /* Support sysdeps/x86_64/multiarch/strcmp.c.  */
-@@ -277,6 +450,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -277,6 +464,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  	      IFUNC_IMPL_ADD (array, i, strcmp,
  			      HAS_ARCH_FEATURE (AVX2_Usable),
  			      __strcmp_avx2)
@@ -12263,7 +13258,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, strcmp, HAS_CPU_FEATURE (SSE4_2),
  			      __strcmp_sse42)
  	      IFUNC_IMPL_ADD (array, i, strcmp, HAS_CPU_FEATURE (SSSE3),
-@@ -288,6 +470,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -288,6 +484,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
    IFUNC_IMPL (i, name, strcpy,
  	      IFUNC_IMPL_ADD (array, i, strcpy, HAS_ARCH_FEATURE (AVX2_Usable),
  			      __strcpy_avx2)
@@ -12278,7 +13273,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, strcpy, HAS_CPU_FEATURE (SSSE3),
  			      __strcpy_ssse3)
  	      IFUNC_IMPL_ADD (array, i, strcpy, 1, __strcpy_sse2_unaligned)
-@@ -331,6 +521,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -331,6 +535,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
    IFUNC_IMPL (i, name, strncat,
  	      IFUNC_IMPL_ADD (array, i, strncat, HAS_ARCH_FEATURE (AVX2_Usable),
  			      __strncat_avx2)
@@ -12293,7 +13288,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, strncat, HAS_CPU_FEATURE (SSSE3),
  			      __strncat_ssse3)
  	      IFUNC_IMPL_ADD (array, i, strncat, 1,
-@@ -341,6 +539,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -341,6 +553,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
    IFUNC_IMPL (i, name, strncpy,
  	      IFUNC_IMPL_ADD (array, i, strncpy, HAS_ARCH_FEATURE (AVX2_Usable),
  			      __strncpy_avx2)
@@ -12308,12 +13303,17 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, strncpy, HAS_CPU_FEATURE (SSSE3),
  			      __strncpy_ssse3)
  	      IFUNC_IMPL_ADD (array, i, strncpy, 1,
-@@ -370,6 +576,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -368,29 +588,73 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   /* Support sysdeps/x86_64/multiarch/wcschr.c.  */
+   IFUNC_IMPL (i, name, wcschr,
  	      IFUNC_IMPL_ADD (array, i, wcschr,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __wcschr_avx2)
 +	      IFUNC_IMPL_ADD (array, i, wcschr,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __wcschr_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, wcschr,
@@ -12324,12 +13324,15 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, wcschr, 1, __wcschr_sse2))
  
    /* Support sysdeps/x86_64/multiarch/wcsrchr.c.  */
-@@ -377,6 +592,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   IFUNC_IMPL (i, name, wcsrchr,
  	      IFUNC_IMPL_ADD (array, i, wcsrchr,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __wcsrchr_avx2)
 +	      IFUNC_IMPL_ADD (array, i, wcsrchr,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __wcsrchr_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, wcsrchr,
@@ -12340,12 +13343,15 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, wcsrchr, 1, __wcsrchr_sse2))
  
    /* Support sysdeps/x86_64/multiarch/wcscmp.c.  */
-@@ -384,6 +608,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   IFUNC_IMPL (i, name, wcscmp,
  	      IFUNC_IMPL_ADD (array, i, wcscmp,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __wcscmp_avx2)
 +	      IFUNC_IMPL_ADD (array, i, wcscmp,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __wcscmp_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, wcscmp,
@@ -12356,12 +13362,15 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, wcscmp, 1, __wcscmp_sse2))
  
    /* Support sysdeps/x86_64/multiarch/wcsncmp.c.  */
-@@ -391,6 +624,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   IFUNC_IMPL (i, name, wcsncmp,
  	      IFUNC_IMPL_ADD (array, i, wcsncmp,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __wcsncmp_avx2)
 +	      IFUNC_IMPL_ADD (array, i, wcsncmp,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __wcsncmp_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, wcsncmp,
@@ -12372,7 +13381,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, wcsncmp, 1, __wcsncmp_sse2))
  
    /* Support sysdeps/x86_64/multiarch/wcscpy.c.  */
-@@ -402,15 +644,40 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -402,15 +666,40 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
    /* Support sysdeps/x86_64/multiarch/wcslen.c.  */
    IFUNC_IMPL (i, name, wcslen,
  	      IFUNC_IMPL_ADD (array, i, wcslen,
@@ -12415,12 +13424,17 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, wcsnlen,
  			      HAS_CPU_FEATURE (SSE4_1),
  			      __wcsnlen_sse4_1)
-@@ -421,6 +688,15 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -419,8 +708,19 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+   /* Support sysdeps/x86_64/multiarch/wmemchr.c.  */
+   IFUNC_IMPL (i, name, wmemchr,
  	      IFUNC_IMPL_ADD (array, i, wmemchr,
- 			      HAS_ARCH_FEATURE (AVX2_Usable),
+-			      HAS_ARCH_FEATURE (AVX2_Usable),
++			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)),
  			      __wmemchr_avx2)
 +	      IFUNC_IMPL_ADD (array, i, wmemchr,
 +			      (HAS_ARCH_FEATURE (AVX2_Usable)
++			       && HAS_CPU_FEATURE (BMI2)
 +			       && HAS_CPU_FEATURE (RTM)),
 +			      __wmemchr_avx2_rtm)
 +	      IFUNC_IMPL_ADD (array, i, wmemchr,
@@ -12431,7 +13445,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, wmemchr, 1, __wmemchr_sse2))
  
    /* Support sysdeps/x86_64/multiarch/wmemcmp.c.  */
-@@ -429,6 +705,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -429,6 +729,16 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      (HAS_ARCH_FEATURE (AVX2_Usable)
  			       && HAS_CPU_FEATURE (MOVBE)),
  			      __wmemcmp_avx2_movbe)
@@ -12448,7 +13462,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, wmemcmp, HAS_CPU_FEATURE (SSE4_1),
  			      __wmemcmp_sse4_1)
  	      IFUNC_IMPL_ADD (array, i, wmemcmp, HAS_CPU_FEATURE (SSSE3),
-@@ -443,7 +729,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -443,7 +753,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      HAS_ARCH_FEATURE (AVX2_Usable),
  			      __wmemset_avx2_unaligned)
  	      IFUNC_IMPL_ADD (array, i, wmemset,
@@ -12464,7 +13478,7 @@ index ce7eb1eecf..56b05ee741 100644
  			      __wmemset_avx512_unaligned))
  
  #ifdef SHARED
-@@ -453,10 +746,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -453,10 +770,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      HAS_ARCH_FEATURE (AVX512F_Usable),
  			      __memcpy_chk_avx512_no_vzeroupper)
  	      IFUNC_IMPL_ADD (array, i, __memcpy_chk,
@@ -12477,7 +13491,7 @@ index ce7eb1eecf..56b05ee741 100644
  			      __memcpy_chk_avx512_unaligned_erms)
  	      IFUNC_IMPL_ADD (array, i, __memcpy_chk,
  			      HAS_ARCH_FEATURE (AVX_Usable),
-@@ -464,6 +757,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -464,6 +781,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  	      IFUNC_IMPL_ADD (array, i, __memcpy_chk,
  			      HAS_ARCH_FEATURE (AVX_Usable),
  			      __memcpy_chk_avx_unaligned_erms)
@@ -12498,7 +13512,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, __memcpy_chk,
  			      HAS_CPU_FEATURE (SSSE3),
  			      __memcpy_chk_ssse3_back)
-@@ -486,6 +793,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -486,6 +817,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  	      IFUNC_IMPL_ADD (array, i, memcpy,
  			      HAS_ARCH_FEATURE (AVX_Usable),
  			      __memcpy_avx_unaligned_erms)
@@ -12519,7 +13533,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSSE3),
  			      __memcpy_ssse3_back)
  	      IFUNC_IMPL_ADD (array, i, memcpy, HAS_CPU_FEATURE (SSSE3),
-@@ -494,10 +815,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -494,10 +839,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      HAS_ARCH_FEATURE (AVX512F_Usable),
  			      __memcpy_avx512_no_vzeroupper)
  	      IFUNC_IMPL_ADD (array, i, memcpy,
@@ -12532,7 +13546,7 @@ index ce7eb1eecf..56b05ee741 100644
  			      __memcpy_avx512_unaligned_erms)
  	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_sse2_unaligned)
  	      IFUNC_IMPL_ADD (array, i, memcpy, 1,
-@@ -511,10 +832,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -511,10 +856,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      HAS_ARCH_FEATURE (AVX512F_Usable),
  			      __mempcpy_chk_avx512_no_vzeroupper)
  	      IFUNC_IMPL_ADD (array, i, __mempcpy_chk,
@@ -12545,7 +13559,7 @@ index ce7eb1eecf..56b05ee741 100644
  			      __mempcpy_chk_avx512_unaligned_erms)
  	      IFUNC_IMPL_ADD (array, i, __mempcpy_chk,
  			      HAS_ARCH_FEATURE (AVX_Usable),
-@@ -522,6 +843,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -522,6 +867,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  	      IFUNC_IMPL_ADD (array, i, __mempcpy_chk,
  			      HAS_ARCH_FEATURE (AVX_Usable),
  			      __mempcpy_chk_avx_unaligned_erms)
@@ -12566,7 +13580,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, __mempcpy_chk,
  			      HAS_CPU_FEATURE (SSSE3),
  			      __mempcpy_chk_ssse3_back)
-@@ -542,10 +877,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -542,10 +901,10 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  			      HAS_ARCH_FEATURE (AVX512F_Usable),
  			      __mempcpy_avx512_no_vzeroupper)
  	      IFUNC_IMPL_ADD (array, i, mempcpy,
@@ -12579,7 +13593,7 @@ index ce7eb1eecf..56b05ee741 100644
  			      __mempcpy_avx512_unaligned_erms)
  	      IFUNC_IMPL_ADD (array, i, mempcpy,
  			      HAS_ARCH_FEATURE (AVX_Usable),
-@@ -553,6 +888,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -553,6 +912,20 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  	      IFUNC_IMPL_ADD (array, i, mempcpy,
  			      HAS_ARCH_FEATURE (AVX_Usable),
  			      __mempcpy_avx_unaligned_erms)
@@ -12600,7 +13614,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSSE3),
  			      __mempcpy_ssse3_back)
  	      IFUNC_IMPL_ADD (array, i, mempcpy, HAS_CPU_FEATURE (SSSE3),
-@@ -568,6 +917,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -568,6 +941,14 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  	      IFUNC_IMPL_ADD (array, i, strncmp,
  			      HAS_ARCH_FEATURE (AVX2_Usable),
  			      __strncmp_avx2)
@@ -12615,7 +13629,7 @@ index ce7eb1eecf..56b05ee741 100644
  	      IFUNC_IMPL_ADD (array, i, strncmp, HAS_CPU_FEATURE (SSE4_2),
  			      __strncmp_sse42)
  	      IFUNC_IMPL_ADD (array, i, strncmp, HAS_CPU_FEATURE (SSSE3),
-@@ -582,6 +939,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
+@@ -582,6 +963,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
  	      IFUNC_IMPL_ADD (array, i, __wmemset_chk,
  			      HAS_ARCH_FEATURE (AVX2_Usable),
  			      __wmemset_chk_avx2_unaligned)
@@ -19178,10 +20192,10 @@ index 0000000000..75b4b7612c
 +
 +#include "strlen-avx2.S"
 diff --git a/sysdeps/x86_64/multiarch/strlen-avx2.S b/sysdeps/x86_64/multiarch/strlen-avx2.S
-index 73421ec1b2..45e08e64d6 100644
+index 73421ec1b2..8cfb7391b0 100644
 --- a/sysdeps/x86_64/multiarch/strlen-avx2.S
 +++ b/sysdeps/x86_64/multiarch/strlen-avx2.S
-@@ -27,370 +27,531 @@
+@@ -27,370 +27,528 @@
  # ifdef USE_AS_WCSLEN
  #  define VPCMPEQ	vpcmpeqd
  #  define VPMINU	vpminud
@@ -19924,14 +20938,11 @@ index 73421ec1b2..45e08e64d6 100644
 +L(cross_page_less_vec):
 +	tzcntl	%eax, %eax
 +#  ifdef USE_AS_WCSLEN
-+	/* NB: Multiply length by 4 to get byte count.  */
-+	sall	$2, %esi
++	/* NB: Divide by 4 to convert from byte-count to length.  */
++	shrl	$2, %eax
 +#  endif
 +	cmpq	%rax, %rsi
 +	cmovb	%esi, %eax
-+#  ifdef USE_AS_WCSLEN
-+	shrl	$2, %eax
-+#  endif
 +	VZEROUPPER_RETURN
  # endif
 -	VZEROUPPER
diff --git a/debian/patches/series b/debian/patches/series
index c72ebf30..02bd18e7 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -22,8 +22,6 @@ alpha/local-string-functions.diff
 alpha/submitted-fts64.diff
 alpha/submitted-makecontext.diff
 
-amd64/local-require-bmi-in-avx2-ifunc.diff
-
 arm/local-sigaction.diff
 arm/unsubmitted-ldconfig-cache-abi.diff
 arm/local-soname-hack.diff

--- End Message ---
--- Begin Message ---
Package: release.debian.org
Version: 11.7

Hi,

Each of the updates referred to in these requests was included in this
morning's 11.7 point release.

Regards,

Adam

--- End Message ---

Reply to: