Bug#1034548: bullseye-pu: package glibc/2.31-13+deb11u6
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
Reply to: