import CS git glibc-2.39-126.el10_2

This commit is contained in:
AlmaLinux RelEng Bot 2026-06-30 05:19:17 -04:00
parent fdc4cd2558
commit 87498b9d2b
9 changed files with 7254 additions and 5791 deletions

123
glibc-RHEL-172694-1.patch Normal file
View File

@ -0,0 +1,123 @@
commit 839898777226a3ed88c0859f25ffe712519b4ead
Author: Rocket Ma <marocketbd@gmail.com>
Date: Fri Apr 17 23:48:41 2026 -0700
stdio-common: Fix buffer overflow in scanf %mc [BZ #34008]
* stdio-common/vfscanf-internal.c: When enlarging allocated buffer with
format %mc or %mC, glibc allocates one byte less, leading to
user-controlled one byte overflow. This commit fixes BZ #34008, or
CVE-2026-5450.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Signed-off-by: Rocket Ma <marocketbd@gmail.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 210944837e..0c0085e607 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -349,6 +349,7 @@ tests := \
tst-vfprintf-user-type \
tst-vfprintf-width-i18n \
tst-vfprintf-width-prec-alloc \
+ tst-vfscanf-bz34008 \
tst-wc-printf \
tstdiomisc \
tstgetln \
@@ -564,6 +565,9 @@ tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace \
tst-vfprintf-width-prec-ENV = \
MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+tst-vfscanf-bz34008-ENV = \
+ MALLOC_CHECK_=3 \
+ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
tst-printf-bz25691-ENV = \
MALLOC_TRACE=$(objpfx)tst-printf-bz25691.mtrace \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
diff --git a/stdio-common/tst-vfscanf-bz34008.c b/stdio-common/tst-vfscanf-bz34008.c
new file mode 100644
index 0000000000..48371c8a3d
--- /dev/null
+++ b/stdio-common/tst-vfscanf-bz34008.c
@@ -0,0 +1,48 @@
+/* Regression test for vfscanf %Nmc out-of-bound write (BZ #34008)
+ Copyright (C) 2026 The GNU Toolchain Authors.
+ 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 "malloc/mcheck.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <support/check.h>
+
+#define WIDTH 0x410
+#define SCANFSTR "%1040mc"
+static int
+do_test (void)
+{
+ mcheck_pedantic (NULL);
+ char *input = malloc (WIDTH + 1);
+ TEST_VERIFY (input != NULL);
+ memset (input, 'A', WIDTH);
+ input[WIDTH] = '\0';
+
+ char *buf = NULL;
+ TEST_VERIFY (sscanf (input, SCANFSTR, &buf) != -1);
+ TEST_VERIFY (buf != NULL);
+
+ free (buf);
+ free (input);
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index 59fc8208aa..3d11ac261e 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -855,8 +855,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
{
/* Enlarge the buffer. */
size_t newsize
- = strsize
- + (strsize >= width ? width - 1 : strsize);
+ = strsize + (strsize >= width ? width : strsize);
str = (char *) realloc (*strptr, newsize);
if (str == NULL)
@@ -929,7 +928,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& wstr == (wchar_t *) *strptr + strsize)
{
size_t newsize
- = strsize + (strsize > width ? width - 1 : strsize);
+ = strsize + (strsize >= width ? width : strsize);
/* Enlarge the buffer. */
wstr = (wchar_t *) realloc (*strptr,
newsize * sizeof (wchar_t));
@@ -984,7 +983,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
&& wstr == (wchar_t *) *strptr + strsize)
{
size_t newsize
- = strsize + (strsize > width ? width - 1 : strsize);
+ = strsize + (strsize >= width ? width : strsize);
/* Enlarge the buffer. */
wstr = (wchar_t *) realloc (*strptr,
newsize * sizeof (wchar_t));

76
glibc-RHEL-172694-2.patch Normal file
View File

@ -0,0 +1,76 @@
commit b866ef29773b22a1343ff9084374775114350b78
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Wed May 27 12:57:10 2026 -0400
support: Implement 'xfmemopen' for seamless 'fmemopen' use
Add 'xfmemopen' wrapper for seamless 'fmemopen' use in tests, following
'xfopen', 'xfclose', etc., and providing a standardized error reporting
facility.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit fe709cc24578ecfd2ff5b07e10e3829fcb55075b)
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/support/Makefile b/support/Makefile
index d41278eeab..f67f38130a 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -134,6 +134,7 @@ libsupport-routines = \
xfclose \
xfdopendir \
xfgets \
+ xfmemopen \
xfopen \
xfork \
xfread \
diff --git a/support/xfmemopen.c b/support/xfmemopen.c
new file mode 100644
index 0000000000..f1dbc72c67
--- /dev/null
+++ b/support/xfmemopen.c
@@ -0,0 +1,31 @@
+/* fmemopen with error checking.
+ Copyright (C) 2025 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 <support/xstdio.h>
+
+#include <support/check.h>
+#include <stdlib.h>
+
+FILE *
+xfmemopen (void *mem, size_t len, const char *mode)
+{
+ FILE *fp = fmemopen (mem, len, mode);
+ if (fp == NULL)
+ FAIL_EXIT1 ("fmemopen (mode \"%s\"): %m", mode);
+ return fp;
+}
diff --git a/support/xstdio.h b/support/xstdio.h
index c3fdf9496f..70b83f11da 100644
--- a/support/xstdio.h
+++ b/support/xstdio.h
@@ -27,6 +27,7 @@ __BEGIN_DECLS
FILE *xfopen (const char *path, const char *mode);
void xfclose (FILE *);
FILE *xfreopen (const char *path, const char *mode, FILE *stream);
+FILE *xfmemopen (void *mem, size_t len, const char *mode);
void xfread (void *ptr, size_t size, size_t nmemb, FILE *stream);
char *xfgets (char *s, int size, FILE *stream);

457
glibc-RHEL-172694-3.patch Normal file
View File

@ -0,0 +1,457 @@
commit 97926e9017f3faeaacce9337f1288460f5e6ec7d
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Wed May 27 12:57:10 2026 -0400
stdio-common: Reject insufficient character data in scanf [BZ #12701]
Reject invalid formatted scanf character data with the 'c' conversion
where there is not enough input available to satisfy the field width
requested. It is required by ISO C that this conversion matches a
sequence of characters of exactly the number specified by the field
width and it is also already documented as such in our own manual:
"It reads precisely the next N characters, and fails if it cannot get
that many."
Currently a matching success is instead incorrectly produced where the
EOF condition is encountered before the required number of characters
has been retrieved, and the characters actually obtained are stored in
the buffer provided.
Add test cases accordingly and remove placeholders from 'c' conversion
input data for the existing scanf tests.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
[This is a modified version of commit 2b16c76609, which tests for the
old behavior and only includes the test cases, for older branches
and downstream backports - DJ]
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
localedata/Makefile
(usual test differences)
diff -Nrup a/localedata/Makefile b/localedata/Makefile
--- a/localedata/Makefile 2024-01-30 19:34:58.000000000 -0500
+++ b/localedata/Makefile 2026-06-18 17:22:24.351290348 -0400
@@ -234,6 +234,7 @@ tests = \
bug-iconv-trans \
bug-setlocale1 \
bug-usesetlocale \
+ tst-bz12701-lc \
tst-c-utf8-consistency \
tst-digits \
tst-iconv-emojis-trans \
diff --git a/localedata/tst-bz12701-lc.c b/localedata/tst-bz12701-lc.c
new file mode 100644
index 0000000000..23c2ab7d2a
--- /dev/null
+++ b/localedata/tst-bz12701-lc.c
@@ -0,0 +1,218 @@
+/* Verify scanf field width handling with the 'lc' conversion (BZ #12701).
+ Copyright (C) 2025-2026 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 <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <libc-diag.h>
+#include <support/check.h>
+#include <support/next_to_fault.h>
+#include <support/xstdio.h>
+
+/* Compare character-wise the initial part of the wide character object
+ pointed to by WS corresponding to wide characters obtained by the
+ conversion of first N bytes of the multibyte character object pointed
+ to by S. */
+
+static int
+tst_bz12701_lc_memcmp (const wchar_t *ds, const char *s, size_t n)
+{
+ size_t nc = mbsnrtowcs (NULL, &s, n, 0, NULL);
+
+ struct support_next_to_fault ntf;
+ ntf = support_next_to_fault_allocate (nc * sizeof (wchar_t));
+ wchar_t *ss = (wchar_t *) ntf.buffer;
+
+ mbsnrtowcs (ss, &s, n, nc, NULL);
+ int r = wmemcmp (ds, ss, nc);
+
+ support_next_to_fault_free (&ntf);
+
+ return r;
+}
+
+/* Verify various aspects of field width handling, including the data
+ obtained, the number of bytes consumed, and the stream position. */
+
+static int
+do_test (void)
+{
+ if (setlocale (LC_ALL, "pl_PL.UTF-8") == NULL)
+ FAIL_EXIT1 ("setlocale (LC_ALL, \"pl_PL.UTF-8\")");
+
+ /* Part of a tongue-twister in Polish, which says:
+ "On a rainy morning cuckoos and warblers, rather than starting
+ on earthworms, stuffed themselves fasted with the flesh of cress." */
+ static const char s[126] = "Dżdżystym rankiem gżegżółki i piegże, "
+ "zamiast wziąć się za dżdżownice, "
+ "nażarły się na czczo miąższu rzeżuchy";
+
+ const char *sp = s;
+ size_t nc;
+ TEST_VERIFY_EXIT ((nc = mbsnrtowcs (NULL, &sp, sizeof (s), 0, NULL)) == 108);
+
+ struct support_next_to_fault ntfo, ntfi;
+ ntfo = support_next_to_fault_allocate (nc * sizeof (wchar_t));
+ ntfi = support_next_to_fault_allocate (sizeof (s));
+ wchar_t *e = (wchar_t *) ntfo.buffer + nc;
+ char *b = ntfi.buffer;
+
+ wchar_t *c;
+ FILE *f;
+ int ic;
+ int n;
+ int i;
+
+ memcpy (ntfi.buffer, s, sizeof (s));
+
+ ic = i = 0;
+ f = xfmemopen (b, sizeof (s), "r");
+
+ c = e - 1;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ /* Avoid: "warning: zero width in gnu_scanf format [-Werror=format=]". */
+ DIAG_PUSH_NEEDS_COMMENT;
+ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wformat");
+ TEST_VERIFY_EXIT (fscanf (f, "%0lc%n", c, &n) == 1);
+ DIAG_POP_NEEDS_COMMENT;
+ TEST_VERIFY_EXIT (n == 1);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
+ ic += 1;
+ i += n;
+
+ c = e - 1;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%lc%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 2);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
+ ic += 1;
+ i += n;
+
+ c = e - 1;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%1lc%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 1);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
+ ic += 1;
+ i += n;
+
+ c = e - 2;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%2lc%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 3);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
+ ic += 2;
+ i += n;
+
+ c = e - 4;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%4lc%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 4);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
+ ic += 4;
+ i += n;
+
+ c = e - 8;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%8lc%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 8);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
+ ic += 8;
+ i += n;
+
+ c = e - 16;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%16lc%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 20);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
+ ic += 16;
+ i += n;
+
+ c = e - 32;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%32lc%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 38);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
+ ic += 32;
+ i += n;
+
+ c = e - (nc - ic);
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_COMPARE (fscanf (f, "%64lc%n", c, &n), 1);
+ TEST_COMPARE (n , 49);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, sizeof (s) - i) == 0);
+
+ TEST_VERIFY_EXIT (ftell (f) == sizeof (s));
+ TEST_VERIFY_EXIT (feof (f) != 0);
+
+ xfclose (f);
+
+ ic = i = 0;
+ f = xfmemopen (b, 3, "r");
+
+ c = e - 2;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%2lc%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 3);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
+ ic += 2;
+ i += n;
+
+ c = e - (nc - ic);
+ TEST_VERIFY_EXIT (feof (f) == 0);
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%2lc%n", c, &n) == EOF);
+ TEST_VERIFY_EXIT (n == 3);
+
+ TEST_VERIFY_EXIT (ftell (f) == 3);
+ TEST_VERIFY_EXIT (feof (f) != 0);
+
+ xfclose (f);
+
+ ic = i = 0;
+ f = xfmemopen (b, 3, "r");
+
+ c = e - 1;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%lc%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 1);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, n) == 0);
+ ic += 1;
+ i += n;
+
+ c = e - (nc - ic);
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%2lc%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 2);
+ TEST_VERIFY_EXIT (tst_bz12701_lc_memcmp (c, s + i, 3 - i) == 0);
+
+ TEST_VERIFY_EXIT (ftell (f) == 3);
+ TEST_VERIFY_EXIT (feof (f) != 0);
+
+ xfclose (f);
+
+ support_next_to_fault_free (&ntfi);
+ support_next_to_fault_free (&ntfo);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index e52c333808..fdb545242e 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -260,6 +260,7 @@ tests := \
tllformat \
tst-bz11319 \
tst-bz11319-fortify2 \
+ tst-bz12701-c \
tst-cookie \
tst-dprintf-length \
tst-fclose-devzero \
diff --git a/stdio-common/tst-bz12701-c.c b/stdio-common/tst-bz12701-c.c
new file mode 100644
index 0000000000..4f3616fbfd
--- /dev/null
+++ b/stdio-common/tst-bz12701-c.c
@@ -0,0 +1,169 @@
+/* Verify scanf field width handling with the 'c' conversion (BZ #12701).
+ Copyright (C) 2025-2026 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 <string.h>
+
+#include <libc-diag.h>
+#include <support/check.h>
+#include <support/next_to_fault.h>
+#include <support/xstdio.h>
+
+/* Verify various aspects of field width handling, including the data
+ obtained, the number of bytes consumed, and the stream position. */
+
+static int
+do_test (void)
+{
+ static const char s[43] = "The quick brown fox jumps over the lazy dog";
+ struct support_next_to_fault ntfo, ntfi;
+ ntfo = support_next_to_fault_allocate (sizeof (s));
+ ntfi = support_next_to_fault_allocate (sizeof (s));
+ char *e = ntfo.buffer + sizeof (s);
+ char *b = ntfi.buffer;
+
+ char *c;
+ FILE *f;
+ int n;
+ int i;
+
+ memcpy (ntfi.buffer, s, sizeof (s));
+
+ i = 0;
+ f = xfmemopen (b, sizeof (s), "r");
+
+ c = e - 1;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ /* Avoid: "warning: zero width in gnu_scanf format [-Werror=format=]". */
+ DIAG_PUSH_NEEDS_COMMENT;
+ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wformat");
+ TEST_VERIFY_EXIT (fscanf (f, "%0c%n", c, &n) == 1);
+ DIAG_POP_NEEDS_COMMENT;
+ TEST_VERIFY_EXIT (n == 1);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
+ i += n;
+
+ c = e - 1;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 1);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
+ i += n;
+
+ c = e - 1;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%1c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 1);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
+ i += n;
+
+ c = e - 2;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%2c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 2);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
+ i += n;
+
+ c = e - 4;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%4c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 4);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
+ i += n;
+
+ c = e - 8;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%8c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 8);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
+ i += n;
+
+ c = e - 16;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%16c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 16);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
+ i += n;
+
+ c = e - (sizeof (s) - i);
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%32c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 10);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, sizeof (s) - i) == 0);
+
+ TEST_VERIFY_EXIT (ftell (f) == sizeof (s));
+ TEST_VERIFY_EXIT (feof (f) != 0);
+
+ xfclose (f);
+
+ i = 0;
+ f = xfmemopen (b, 3, "r");
+
+ c = e - 1;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 1);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
+ i += n;
+
+ c = e - 2;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%2c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 2);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
+ i += n;
+
+ c = e - (3 - i);
+ TEST_VERIFY_EXIT (feof (f) == 0);
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%2c%n", c, &n) == EOF);
+ TEST_VERIFY_EXIT (n == 2);
+
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (feof (f) != 0);
+
+ xfclose (f);
+
+ i = 0;
+ f = xfmemopen (b, 3, "r");
+
+ c = e - 2;
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%2c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 2);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, n) == 0);
+ i += n;
+
+ c = e - (3 - i);
+ TEST_VERIFY_EXIT (ftell (f) == i);
+ TEST_VERIFY_EXIT (fscanf (f, "%2c%n", c, &n) == 1);
+ TEST_VERIFY_EXIT (n == 1);
+ TEST_VERIFY_EXIT (memcmp (c, s + i, 3 - i) == 0);
+
+ TEST_VERIFY_EXIT (ftell (f) == 3);
+ TEST_VERIFY_EXIT (feof (f) != 0);
+
+ xfclose (f);
+
+ support_next_to_fault_free (&ntfi);
+ support_next_to_fault_free (&ntfo);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

193
glibc-RHEL-172694-4.patch Normal file
View File

@ -0,0 +1,193 @@
commit 6cebb0b80fd783e442a8ad27c3f52cde52a9cac7
Author: DJ Delorie <dj@redhat.com>
Date: Wed May 27 12:57:10 2026 -0400
stdio-common: Allow partially-filled %mc buffers [BZ #12701]
This is a backwards-compatible alternative to the main solution to
the %mc part of 12701. The allocated buffer is expanded to the
requested size and NUL padded, but truncated reads are allowed.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
localedata/Makefile
(usual test differences)
diff -Nrup a/localedata/Makefile b/localedata/Makefile
--- a/localedata/Makefile 2026-06-18 17:24:13.116929727 -0400
+++ b/localedata/Makefile 2026-06-18 17:24:46.030126591 -0400
@@ -235,6 +235,7 @@ tests = \
bug-setlocale1 \
bug-usesetlocale \
tst-bz12701-lc \
+ tst-bz12701-lc2 \
tst-c-utf8-consistency \
tst-digits \
tst-iconv-emojis-trans \
diff --git a/localedata/tst-bz12701-lc2.c b/localedata/tst-bz12701-lc2.c
new file mode 100644
index 0000000000..b24e86df0b
--- /dev/null
+++ b/localedata/tst-bz12701-lc2.c
@@ -0,0 +1,47 @@
+/* Verify scanf memory handling with the 'c' conversion (BZ #12701).
+ Copyright (C) 2026 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 <malloc.h>
+#include <string.h>
+
+#include <libc-diag.h>
+#include <support/check.h>
+#include <support/next_to_fault.h>
+#include <support/xstdio.h>
+
+static int
+do_test (void)
+{
+ wchar_t *c = NULL;
+ int i;
+
+ TEST_VERIFY (sscanf ("1234", "%30mlc", &c) == 1);
+
+ TEST_VERIFY (c != NULL);
+ TEST_COMPARE_BLOB (c, 5 * sizeof (wchar_t),
+ L"1234\0", 5 * sizeof (wchar_t));
+ for (i = 5; i < 30; i ++)
+ TEST_VERIFY (c[i] == L'\0');
+
+ TEST_VERIFY (malloc_usable_size (c) >= 30 * sizeof(wchar_t));
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index fdb545242e..27e7ea20f0 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -261,6 +261,7 @@ tests := \
tst-bz11319 \
tst-bz11319-fortify2 \
tst-bz12701-c \
+ tst-bz12701-c2 \
tst-cookie \
tst-dprintf-length \
tst-fclose-devzero \
diff --git a/stdio-common/tst-bz12701-c2.c b/stdio-common/tst-bz12701-c2.c
new file mode 100644
index 0000000000..5f9ca7c592
--- /dev/null
+++ b/stdio-common/tst-bz12701-c2.c
@@ -0,0 +1,46 @@
+/* Verify scanf memory handling with the 'c' conversion (BZ #12701).
+ Copyright (C) 2026 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 <malloc.h>
+#include <string.h>
+
+#include <libc-diag.h>
+#include <support/check.h>
+#include <support/next_to_fault.h>
+#include <support/xstdio.h>
+
+static int
+do_test (void)
+{
+ char *c = NULL;
+ int i;
+
+ TEST_VERIFY (sscanf ("1234", "%30mc", &c) == 1);
+
+ TEST_VERIFY (c != NULL);
+ TEST_COMPARE_BLOB (c, 5, "1234\0", 5);
+ for (i = 5; i < 30; i ++)
+ TEST_VERIFY (c[i] == '\0');
+
+ TEST_VERIFY (malloc_usable_size (c) >= 30);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/stdio-common/vfscanf-internal.c b/stdio-common/vfscanf-internal.c
index 17b5565d0f..90a1886951 100644
--- a/stdio-common/vfscanf-internal.c
+++ b/stdio-common/vfscanf-internal.c
@@ -780,9 +780,9 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
conv_error (); \
} while (0)
#ifdef COMPILE_WSCANF
- STRING_ARG (str, char, 100);
+ STRING_ARG (str, char, (width > 0 ? width : 1));
#else
- STRING_ARG (str, char, (width > 1024 ? 1024 : width));
+ STRING_ARG (str, char, (width > 0 ? width : 1));
#endif
c = inchar ();
@@ -891,6 +891,11 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
if (!(flags & SUPPRESS))
{
+ /* If the buffer isn't completely filled, pad it with NULs. */
+ if (flags & MALLOC)
+ while (width-- > 0)
+ *str++ = '\0';
+
if ((flags & MALLOC) && str - *strptr != strsize)
{
char *cp = (char *) realloc (*strptr, str - *strptr);
@@ -908,7 +913,7 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
if (width == -1)
width = 1;
- STRING_ARG (wstr, wchar_t, (width > 1024 ? 1024 : width));
+ STRING_ARG (wstr, wchar_t, (width > 0 ? width : 1));
c = inchar ();
if (__glibc_unlikely (c == EOF))
@@ -1044,6 +1049,11 @@ __vfscanf_internal (FILE *s, const char *format, va_list argptr,
if (!(flags & SUPPRESS))
{
+ /* If the buffer isn't completely filled, pad it with NULs. */
+ if (flags & MALLOC)
+ while (width-- > 0)
+ *wstr++ = L'\0';
+
if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize)
{
wchar_t *cp = (wchar_t *) realloc (*strptr,

199
glibc-RHEL-174869-1.patch Normal file
View File

@ -0,0 +1,199 @@
commit f446d90fe6605ac473aaa6cd17a1800e72dcc1a2
Author: Noah Goldstein <goldstein.w.n@gmail.com>
Date: Wed Aug 14 14:37:31 2024 +0800
x86: Add `Avoid_STOSB` tunable to allow NT memset without ERMS
The goal of this flag is to allow targets which don't prefer/have ERMS
to still access the non-temporal memset implementation.
There are 4 cases for tuning memset:
1) `Avoid_STOSB && Avoid_Non_Temporal_Memset`
- Memset with temporal stores
2) `Avoid_STOSB && !Avoid_Non_Temporal_Memset`
- Memset with temporal/non-temporal stores. Non-temporal path
goes through `rep stosb` path. We accomplish this by setting
`x86_rep_stosb_threshold` to
`x86_memset_non_temporal_threshold`.
3) `!Avoid_STOSB && Avoid_Non_Temporal_Memset`
- Memset with temporal stores/`rep stosb`
3) `!Avoid_STOSB && !Avoid_Non_Temporal_Memset`
- Memset with temporal stores/`rep stosb`/non-temporal stores.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index f87d6d354924f3d9..e0728cb010aae637 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -1103,6 +1103,10 @@ disable_tsx:
if (CPU_FEATURES_CPU_P (cpu_features, CMOV))
cpu_features->preferred[index_arch_I686] |= bit_arch_I686;
+ /* No ERMS, we want to avoid stosb for memset. */
+ if (!CPU_FEATURE_USABLE_P (cpu_features, ERMS))
+ cpu_features->preferred[index_arch_Avoid_STOSB] |= bit_arch_Avoid_STOSB;
+
#if !HAS_CPUID
no_cpuid:
#endif
diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c
index a0b31d80f64127c5..98da2c54a5c58851 100644
--- a/sysdeps/x86/cpu-tunables.c
+++ b/sysdeps/x86/cpu-tunables.c
@@ -195,6 +195,8 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
11);
CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, Prefer_FSRM,
11);
+ CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features, Avoid_STOSB,
+ 11);
CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH (n, cpu_features,
Slow_SSE4_2,
SSE4_2,
diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
index ebfea0a32ce0cff6..e21592e166a041dd 100644
--- a/sysdeps/x86/dl-cacheinfo.h
+++ b/sysdeps/x86/dl-cacheinfo.h
@@ -1039,18 +1039,42 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
slightly better than ERMS. */
rep_stosb_threshold = SIZE_MAX;
+ /*
+ For memset, the non-temporal implementation is only accessed through the
+ stosb code. ie:
+ ```
+ if (size >= rep_stosb_thresh)
+ {
+ if (size >= non_temporal_thresh)
+ {
+ do_non_temporal ();
+ }
+ do_stosb ();
+ }
+ do_normal_vec_loop ();
+ ```
+ So if we prefer non-temporal, set `rep_stosb_thresh = non_temporal_thresh`
+ to enable the implementation. If `rep_stosb_thresh = non_temporal_thresh`,
+ `rep stosb` will never be used.
+ */
+ TUNABLE_SET_WITH_BOUNDS (x86_memset_non_temporal_threshold,
+ memset_non_temporal_threshold,
+ minimum_non_temporal_threshold, SIZE_MAX);
+ /* Do `rep_stosb_thresh = non_temporal_thresh` after setting/getting the
+ final value of `x86_memset_non_temporal_threshold`. In some cases this can
+ be a matter of correctness. */
+ if (CPU_FEATURES_ARCH_P (cpu_features, Avoid_STOSB))
+ rep_stosb_threshold
+ = TUNABLE_GET (x86_memset_non_temporal_threshold, long int, NULL);
+ TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1,
+ SIZE_MAX);
TUNABLE_SET_WITH_BOUNDS (x86_data_cache_size, data, 0, SIZE_MAX);
TUNABLE_SET_WITH_BOUNDS (x86_shared_cache_size, shared, 0, SIZE_MAX);
TUNABLE_SET_WITH_BOUNDS (x86_non_temporal_threshold, non_temporal_threshold,
minimum_non_temporal_threshold,
maximum_non_temporal_threshold);
- TUNABLE_SET_WITH_BOUNDS (x86_memset_non_temporal_threshold,
- memset_non_temporal_threshold,
- minimum_non_temporal_threshold, SIZE_MAX);
TUNABLE_SET_WITH_BOUNDS (x86_rep_movsb_threshold, rep_movsb_threshold,
minimum_rep_movsb_threshold, SIZE_MAX);
- TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1,
- SIZE_MAX);
unsigned long int rep_movsb_stop_threshold;
/* Setting the upper bound of ERMS to the computed value of
diff --git a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
index 61bbbc2e8983482e..2a58000147d22ddb 100644
--- a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
+++ b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
@@ -34,3 +34,4 @@ BIT (MathVec_Prefer_No_AVX512)
BIT (Prefer_FSRM)
BIT (Avoid_Short_Distance_REP_MOVSB)
BIT (Avoid_Non_Temporal_Memset)
+BIT (Avoid_STOSB)
diff --git a/sysdeps/x86/tst-hwcap-tunables.c b/sysdeps/x86/tst-hwcap-tunables.c
index 94307283d7cdbdc7..1920f5057e69c48a 100644
--- a/sysdeps/x86/tst-hwcap-tunables.c
+++ b/sysdeps/x86/tst-hwcap-tunables.c
@@ -60,7 +60,8 @@ static const struct test_t
/* Disable everything. */
"-Prefer_ERMS,-Prefer_FSRM,-AVX,-AVX2,-AVX512F,-AVX512VL,"
"-SSE4_1,-SSE4_2,-SSSE3,-Fast_Unaligned_Load,-ERMS,"
- "-AVX_Fast_Unaligned_Load,-Avoid_Non_Temporal_Memset",
+ "-AVX_Fast_Unaligned_Load,-Avoid_Non_Temporal_Memset,"
+ "-Avoid_STOSB",
test_1,
array_length (test_1)
},
@@ -68,7 +69,8 @@ static const struct test_t
/* Same as before, but with some empty suboptions. */
",-,-Prefer_ERMS,-Prefer_FSRM,-AVX,-AVX2,-AVX512F,-AVX512VL,"
"-SSE4_1,-SSE4_2,-SSSE3,-Fast_Unaligned_Load,,-,"
- "-ERMS,-AVX_Fast_Unaligned_Load,-Avoid_Non_Temporal_Memset,-,",
+ "-ERMS,-AVX_Fast_Unaligned_Load,-Avoid_Non_Temporal_Memset,"
+ "-Avoid_STOSB,-,",
test_1,
array_length (test_1)
}
diff --git a/sysdeps/x86_64/multiarch/ifunc-memset.h b/sysdeps/x86_64/multiarch/ifunc-memset.h
index 7a637ef7ca286694..8dc3d7ab5abaaecb 100644
--- a/sysdeps/x86_64/multiarch/ifunc-memset.h
+++ b/sysdeps/x86_64/multiarch/ifunc-memset.h
@@ -46,6 +46,13 @@ extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned)
extern __typeof (REDIRECT_NAME) OPTIMIZE (sse2_unaligned_erms)
attribute_hidden;
+static inline int
+prefer_erms_nt_impl (const struct cpu_features *cpu_features)
+{
+ return CPU_FEATURE_USABLE_P (cpu_features, ERMS)
+ || !CPU_FEATURES_ARCH_P (cpu_features, Avoid_Non_Temporal_Memset);
+}
+
static inline void *
IFUNC_SELECTOR (void)
{
@@ -61,7 +68,7 @@ IFUNC_SELECTOR (void)
&& X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
&& X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2))
{
- if (CPU_FEATURE_USABLE_P (cpu_features, ERMS))
+ if (prefer_erms_nt_impl (cpu_features))
return OPTIMIZE (avx512_unaligned_erms);
return OPTIMIZE (avx512_unaligned);
@@ -76,7 +83,7 @@ IFUNC_SELECTOR (void)
&& X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW)
&& X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, BMI2))
{
- if (CPU_FEATURE_USABLE_P (cpu_features, ERMS))
+ if (prefer_erms_nt_impl (cpu_features))
return OPTIMIZE (evex_unaligned_erms);
return OPTIMIZE (evex_unaligned);
@@ -84,7 +91,7 @@ IFUNC_SELECTOR (void)
if (CPU_FEATURE_USABLE_P (cpu_features, RTM))
{
- if (CPU_FEATURE_USABLE_P (cpu_features, ERMS))
+ if (prefer_erms_nt_impl (cpu_features))
return OPTIMIZE (avx2_unaligned_erms_rtm);
return OPTIMIZE (avx2_unaligned_rtm);
@@ -93,14 +100,15 @@ IFUNC_SELECTOR (void)
if (X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
Prefer_No_VZEROUPPER, !))
{
- if (CPU_FEATURE_USABLE_P (cpu_features, ERMS))
+ if (prefer_erms_nt_impl (cpu_features))
return OPTIMIZE (avx2_unaligned_erms);
return OPTIMIZE (avx2_unaligned);
}
}
- if (CPU_FEATURE_USABLE_P (cpu_features, ERMS))
+ if (CPU_FEATURE_USABLE_P (cpu_features, ERMS)
+ || !CPU_FEATURES_ARCH_P (cpu_features, Avoid_Non_Temporal_Memset))
return OPTIMIZE (sse2_unaligned_erms);
return OPTIMIZE (sse2_unaligned);

246
glibc-RHEL-174869-2.patch Normal file
View File

@ -0,0 +1,246 @@
commit cd5fda114ece002945ace3d54a8f80a4f67d1fbb
Author: Sajan Karumanchi <sajan.karumanchi@gmail.com>
Date: Thu Mar 26 09:21:30 2026 +0000
x86_64: Prefer EVEX512 code-path on AMD Zen5 CPUs
Introduced a synthetic architecture preference flag (Prefer_EVEX512)
and enabled it for AMD Zen5 (CPUID Family 0x1A) when AVX-512 is supported.
This flag modifies IFUNC dispatch to prefer 512-bit EVEX variants over
256-bit EVEX variants for string and memory functions on Zen5 processors,
leveraging their native 512-bit execution units for improved throughput.
When Prefer_EVEX512 is set, the dispatcher selects evex512 implementations;
otherwise, it falls back to evex (256-bit) variants.
The implementation updates the IFUNC selection logic in ifunc-avx2.h and
ifunc-evex.h to check for the Prefer_EVEX512 flag before dispatching to
EVEX512 implementations. This change affects six string/memory functions:
- strchr
- strlen
- strnlen
- strrchr
- strchrnul
- memchr
Benchmarks conducted on AMD Zen5 hardware demonstrate significant
performance improvements across all affected functions:
Function Baseline Patched Avg Avg Avg Max
Variant Variant Baseline Patched Change Improve
(ns) (ns) % %
------------+----------+----------+-----------+----------+--------+--------
STRCHR evex evex512 16.408 12.293 25.08% 37.69%
STRLEN evex evex512 16.862 11.436 32.18% 56.74%
STRNLEN evex evex512 18.493 11.762 36.40% 64.40%
STRRCHR evex evex512 15.154 10.874 28.24% 44.38%
STRCHRNUL evex evex512 16.464 12.605 23.44% 45.56%
MEMCHR evex evex512 9.984 8.268 17.19% 39.99%
Additionally, a tunable option (glibc.cpu.x86_cpu_features.preferred)
is provided to allow runtime control of the Prefer_EVEX512 flag for testing
and compatibility.
Reviewed-by: Ganesh Gopalasubramanian <Ganesh.Gopalasubramanian@amd.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
index e0728cb010aae637..55c952dded4c1030 100644
--- a/sysdeps/x86/cpu-features.c
+++ b/sysdeps/x86/cpu-features.c
@@ -1013,6 +1013,12 @@ disable_tsx:
cpu_features->preferred[index_arch_Avoid_Non_Temporal_Memset]
&= ~bit_arch_Avoid_Non_Temporal_Memset;
+ /* Prefer EVEX512 string/memory variants on AMD Zen5 (Family 0x1A)
+ when AVX-512 is usable. */
+ if (family == 0x1A && CPU_FEATURE_USABLE_P (cpu_features, AVX512F))
+ cpu_features->preferred[index_arch_Prefer_EVEX512]
+ |= bit_arch_Prefer_EVEX512;
+
if (CPU_FEATURE_USABLE_P (cpu_features, AVX))
{
/* Since the FMA4 bit is in CPUID_INDEX_80000001 and
diff --git a/sysdeps/x86/cpu-tunables.c b/sysdeps/x86/cpu-tunables.c
index 98da2c54a5c58851..4627748670f6da84 100644
--- a/sysdeps/x86/cpu-tunables.c
+++ b/sysdeps/x86/cpu-tunables.c
@@ -203,6 +203,12 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
11);
}
break;
+ case 14:
+ {
+ CHECK_GLIBC_IFUNC_PREFERRED_NEED_BOTH
+ (n, cpu_features, Prefer_EVEX512, AVX512F, 14);
+ }
+ break;
case 15:
{
CHECK_GLIBC_IFUNC_PREFERRED_BOTH (n, cpu_features,
diff --git a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
index 2a58000147d22ddb..25e535af62615449 100644
--- a/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
+++ b/sysdeps/x86/include/cpu-features-preferred_feature_index_1.def
@@ -35,3 +35,4 @@ BIT (Prefer_FSRM)
BIT (Avoid_Short_Distance_REP_MOVSB)
BIT (Avoid_Non_Temporal_Memset)
BIT (Avoid_STOSB)
+BIT (Prefer_EVEX512)
diff --git a/sysdeps/x86_64/multiarch/ifunc-avx2.h b/sysdeps/x86_64/multiarch/ifunc-avx2.h
index 4174928dab666878..5566e9760933ad2d 100644
--- a/sysdeps/x86_64/multiarch/ifunc-avx2.h
+++ b/sysdeps/x86_64/multiarch/ifunc-avx2.h
@@ -1,4 +1,4 @@
-/* Common definition for ifunc selections optimized with SSE2 and AVX2.
+/* Common definition for ifunc selections optimized with SSE2, AVX2 and EVEX512.
All versions must be listed in ifunc-impl-list.c.
Copyright (C) 2017-2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -25,6 +25,10 @@
extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden;
+#ifdef USE_EVEX512
+extern __typeof (REDIRECT_NAME) OPTIMIZE (evex512) attribute_hidden;
+#endif
+
extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden;
extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden;
@@ -44,8 +48,13 @@ IFUNC_SELECTOR (void)
{
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)
&& X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW))
- return OPTIMIZE (evex);
-
+ {
+#ifdef USE_EVEX512
+ if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_EVEX512))
+ return OPTIMIZE (evex512);
+#endif
+ return OPTIMIZE (evex);
+ }
if (CPU_FEATURE_USABLE_P (cpu_features, RTM))
return OPTIMIZE (avx2_rtm);
diff --git a/sysdeps/x86_64/multiarch/ifunc-evex.h b/sysdeps/x86_64/multiarch/ifunc-evex.h
index bbd1e3115f2e3a7c..643817a515b3fd71 100644
--- a/sysdeps/x86_64/multiarch/ifunc-evex.h
+++ b/sysdeps/x86_64/multiarch/ifunc-evex.h
@@ -1,4 +1,4 @@
-/* Common definition for ifunc selection optimized with EVEX.
+/* Common definition for ifunc selection optimized with EVEX and EVEX512.
All versions must be listed in ifunc-impl-list.c.
Copyright (C) 2017-2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -22,6 +22,10 @@
extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden;
extern __typeof (REDIRECT_NAME) OPTIMIZE (evex_rtm) attribute_hidden;
+#ifdef USE_EVEX512
+extern __typeof (REDIRECT_NAME) OPTIMIZE (evex512) attribute_hidden;
+#endif
+
extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden;
extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden;
@@ -42,6 +46,11 @@ IFUNC_SELECTOR (void)
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)
&& X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW))
{
+#ifdef USE_EVEX512
+ if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_EVEX512))
+ return OPTIMIZE (evex512);
+#endif
+
if (CPU_FEATURE_USABLE_P (cpu_features, RTM))
return OPTIMIZE (evex_rtm);
diff --git a/sysdeps/x86_64/multiarch/memchr.c b/sysdeps/x86_64/multiarch/memchr.c
index 2c7754e759d2f1dd..9f915861a40498d8 100644
--- a/sysdeps/x86_64/multiarch/memchr.c
+++ b/sysdeps/x86_64/multiarch/memchr.c
@@ -24,6 +24,7 @@
# undef memchr
# define SYMBOL_NAME memchr
+# define USE_EVEX512 1
# include "ifunc-evex.h"
libc_ifunc_redirected (__redirect_memchr, memchr, IFUNC_SELECTOR ());
diff --git a/sysdeps/x86_64/multiarch/strchr.c b/sysdeps/x86_64/multiarch/strchr.c
index 4b15d53e97e682db..2d3d084aa8d3bdd1 100644
--- a/sysdeps/x86_64/multiarch/strchr.c
+++ b/sysdeps/x86_64/multiarch/strchr.c
@@ -27,6 +27,7 @@
# include <init-arch.h>
extern __typeof (REDIRECT_NAME) OPTIMIZE (evex) attribute_hidden;
+extern __typeof (REDIRECT_NAME) OPTIMIZE (evex512) attribute_hidden;
extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2) attribute_hidden;
extern __typeof (REDIRECT_NAME) OPTIMIZE (avx2_rtm) attribute_hidden;
@@ -46,7 +47,12 @@ IFUNC_SELECTOR (void)
{
if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512VL)
&& X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX512BW))
- return OPTIMIZE (evex);
+ {
+ if (CPU_FEATURES_ARCH_P (cpu_features, Prefer_EVEX512))
+ return OPTIMIZE (evex512);
+
+ return OPTIMIZE (evex);
+ }
if (CPU_FEATURE_USABLE_P (cpu_features, RTM))
return OPTIMIZE (avx2_rtm);
diff --git a/sysdeps/x86_64/multiarch/strchrnul.c b/sysdeps/x86_64/multiarch/strchrnul.c
index 663819918e103083..e3fb2503eade9764 100644
--- a/sysdeps/x86_64/multiarch/strchrnul.c
+++ b/sysdeps/x86_64/multiarch/strchrnul.c
@@ -26,6 +26,7 @@
# undef strchrnul
# define SYMBOL_NAME strchrnul
+# define USE_EVEX512 1
# include "ifunc-avx2.h"
libc_ifunc_redirected (__redirect_strchrnul, __strchrnul,
diff --git a/sysdeps/x86_64/multiarch/strlen.c b/sysdeps/x86_64/multiarch/strlen.c
index a362c2bf8bce9dcf..9b39da5c760a9fa4 100644
--- a/sysdeps/x86_64/multiarch/strlen.c
+++ b/sysdeps/x86_64/multiarch/strlen.c
@@ -24,6 +24,7 @@
# undef strlen
# define SYMBOL_NAME strlen
+# define USE_EVEX512 1
# include "ifunc-avx2.h"
libc_ifunc_redirected (__redirect_strlen, strlen, IFUNC_SELECTOR ());
diff --git a/sysdeps/x86_64/multiarch/strnlen.c b/sysdeps/x86_64/multiarch/strnlen.c
index d1537e039052551d..a09ff4bea54bb0d1 100644
--- a/sysdeps/x86_64/multiarch/strnlen.c
+++ b/sysdeps/x86_64/multiarch/strnlen.c
@@ -26,6 +26,7 @@
# undef strnlen
# define SYMBOL_NAME strnlen
+# define USE_EVEX512 1
# include "ifunc-avx2.h"
libc_ifunc_redirected (__redirect_strnlen, __strnlen, IFUNC_SELECTOR ());
diff --git a/sysdeps/x86_64/multiarch/strrchr.c b/sysdeps/x86_64/multiarch/strrchr.c
index f14237d1ffeb8e11..2ad1192d3ec013d8 100644
--- a/sysdeps/x86_64/multiarch/strrchr.c
+++ b/sysdeps/x86_64/multiarch/strrchr.c
@@ -23,6 +23,7 @@
# undef strrchr
# define SYMBOL_NAME strrchr
+# define USE_EVEX512 1
# include "ifunc-avx2.h"
libc_ifunc_redirected (__redirect_strrchr, strrchr, IFUNC_SELECTOR ());

50
glibc-RHEL-174869-3.patch Normal file
View File

@ -0,0 +1,50 @@
commit 54abc8566fea592e795cb443949266ef206462a8
Author: zombie12138 <zombie12139@gmail.com>
Date: Tue May 5 22:38:01 2026 -0700
x86: Fix non-temporal memset unreachable on AMD Zen 3/4/5
On AMD Zen 3/4/5 with ERMS, the non-temporal memset path is unreachable
because rep_stosb_threshold is set to SIZE_MAX (vectorized loop is faster
than ERMS on these CPUs), but the non-temporal code path is nested inside
the rep_stosb branch.
The existing rescue logic at the Avoid_STOSB check only covers the case
where the CPU lacks ERMS hardware support. It does not cover AMD Zen 3+
where ERMS is supported but deliberately unused for performance reasons.
Extend the condition to also lower rep_stosb_threshold when:
- The user has not explicitly set x86_rep_stosb_threshold (respect tunables)
- rep_stosb_threshold is higher than memset_non_temporal_threshold (NT gated)
This makes the non-temporal path reachable for large memset operations,
providing ~2x speedup on pre-faulted buffers larger than L3 cache.
Tested on AMD Ryzen 7 8745HS (Zen 4):
- Pre-faulted 64MB memset: 2.02 ms -> 0.94 ms (2.15x faster)
- First-touch 64MB memset: 19.3 ms -> 21.3 ms (11% regression, expected:
kernel clear_page cache warming bypassed by NT stores)
* sysdeps/x86/dl-cacheinfo.h (dl_init_cacheinfo): Extend
rep_stosb_threshold lowering condition to cover AMD Zen 3/4/5
where ERMS is supported but stosb is disabled via threshold.
Signed-off-by: zombie12138 <zombie12139@gmail.com>
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34129
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
index e21592e166a041dd..f3477a1c5e190dc9 100644
--- a/sysdeps/x86/dl-cacheinfo.h
+++ b/sysdeps/x86/dl-cacheinfo.h
@@ -1063,7 +1063,9 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
/* Do `rep_stosb_thresh = non_temporal_thresh` after setting/getting the
final value of `x86_memset_non_temporal_threshold`. In some cases this can
be a matter of correctness. */
- if (CPU_FEATURES_ARCH_P (cpu_features, Avoid_STOSB))
+ if (CPU_FEATURES_ARCH_P (cpu_features, Avoid_STOSB)
+ || (!TUNABLE_IS_INITIALIZED (x86_rep_stosb_threshold)
+ && rep_stosb_threshold > memset_non_temporal_threshold))
rep_stosb_threshold
= TUNABLE_GET (x86_memset_non_temporal_threshold, long int, NULL);
TUNABLE_SET_WITH_BOUNDS (x86_rep_stosb_threshold, rep_stosb_threshold, 1,

View File

@ -1,2 +1,2 @@
8f42d24c37304d4db88237907d86b220cf0ecf3c
50833c84b12427684b80cf68765ce770d76bca88
v1

File diff suppressed because it is too large Load Diff