x86: Fix bug in strchrnul-evex512 [BZ #32078]

(cherry picked from commit b3df4ce3b9d85aa30006b64edcc3c2979ee5e143)
This commit is contained in:
liqingqing_1229 2024-08-22 10:55:43 +08:00 committed by openeuler-sync-bot
parent a9d0715685
commit 4089d6917a
2 changed files with 167 additions and 1 deletions

View File

@ -67,7 +67,7 @@
##############################################################################
Name: glibc
Version: 2.38
Release: 34
Release: 35
Summary: The GNU libc libraries
License: %{all_license}
URL: http://www.gnu.org/software/glibc/
@ -213,6 +213,7 @@ Patch123: 0010-Add-mremap-tests.patch
Patch124: 0011-Update-syscall-lists-for-Linux-6.5.patch
Patch125: 0012-resolv-Fix-tst-resolv-short-response-for-older-GCC-b.patch
Patch126: Fix-name-space-violation-in-fortify-wrappers-bug-320.patch
Patch127: x86-Fix-bug-in-strchrnul-evex512-BZ-32078.patch
#openEuler patch list
Patch9000: turn-default-value-of-x86_rep_stosb_threshold_form_2K_to_1M.patch
@ -1446,6 +1447,9 @@ fi
%endif
%changelog
* Thu Aug 22 2024 Qingqing Li <liqingqing3@huawei.com> - 2.38-35
- x86: Fix bug in strchrnul-evex512 [BZ #32078]
* Fri Aug 9 2024 taoyuxiang <taoyuxiang2@huawei.com> - 2.38-34
- Specify the GFDL version to GFDL-1.3-ONLY in spec

View File

@ -0,0 +1,162 @@
From c005d1bd6f0e88ab4b822844d75d10c8978f5404 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n@gmail.com>
Date: Tue, 13 Aug 2024 23:29:14 +0800
Subject: [PATCH] x86: Fix bug in strchrnul-evex512 [BZ #32078]
Issue was we were expecting not matches with CHAR before the start of
the string in the page cross case.
The check code in the page cross case:
```
and $0xffffffffffffffc0,%rax
vmovdqa64 (%rax),%zmm17
vpcmpneqb %zmm17,%zmm16,%k1
vptestmb %zmm17,%zmm17,%k0{%k1}
kmovq %k0,%rax
inc %rax
shr %cl,%rax
je L(continue)
```
expects that all characters that neither match null nor CHAR will be
1s in `rax` prior to the `inc`. Then the `inc` will overflow all of
the 1s where no relevant match was found.
This is incorrect in the page-cross case, as the
`vmovdqa64 (%rax),%zmm17` loads from before the start of the input
string.
If there are matches with CHAR before the start of the string, `rax`
won't properly overflow.
The fix is quite simple. Just replace:
```
inc %rax
shr %cl,%rax
```
With:
```
sar %cl,%rax
inc %rax
```
The arithmetic shift will clear any matches prior to the start of the
string while maintaining the signbit so the 1s can properly overflow
to zero in the case of no matches.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 7da08862471dfec6fdae731c2a5f351ad485c71f)
---
string/test-strchr.c | 65 ++++++++++++++++++++-
sysdeps/x86_64/multiarch/strchr-evex-base.S | 8 +--
2 files changed, 68 insertions(+), 5 deletions(-)
diff --git a/string/test-strchr.c b/string/test-strchr.c
index 933fc0bbba..2bfcf901fa 100644
--- a/string/test-strchr.c
+++ b/string/test-strchr.c
@@ -248,6 +248,69 @@ check1 (void)
check_result (impl, s, c, exp_result);
}
+static void
+check2 (void)
+{
+ CHAR *s = (CHAR *) (buf1 + getpagesize () - 4 * sizeof (CHAR));
+ CHAR *s_begin = (CHAR *) (buf1 + getpagesize () - 64);
+#ifndef USE_FOR_STRCHRNUL
+ CHAR *exp_result = NULL;
+#else
+ CHAR *exp_result = s + 1;
+#endif
+ CHAR val = 0x12;
+ for (; s_begin != s; ++s_begin)
+ *s_begin = val;
+
+ s[0] = val + 1;
+ s[1] = 0;
+ s[2] = val + 1;
+ s[3] = val + 1;
+
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+ s[3] = val;
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+ exp_result = s;
+ s[0] = val;
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+
+ s[3] = val + 1;
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+
+ s[0] = val + 1;
+ s[1] = val + 1;
+ s[2] = val + 1;
+ s[3] = val + 1;
+ s[4] = val;
+ exp_result = s + 4;
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+ s[4] = 0;
+#ifndef USE_FOR_STRCHRNUL
+ exp_result = NULL;
+#else
+ exp_result = s + 4;
+#endif
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+}
+
int
test_main (void)
{
@@ -256,7 +319,7 @@ test_main (void)
test_init ();
check1 ();
-
+ check2 ();
printf ("%20s", "");
FOR_EACH_IMPL (impl, 0)
printf ("\t%s", impl->name);
diff --git a/sysdeps/x86_64/multiarch/strchr-evex-base.S b/sysdeps/x86_64/multiarch/strchr-evex-base.S
index 7209435caf..da6d0eafbb 100644
--- a/sysdeps/x86_64/multiarch/strchr-evex-base.S
+++ b/sysdeps/x86_64/multiarch/strchr-evex-base.S
@@ -124,13 +124,13 @@ L(page_cross):
VPCMPNE %VMM(1), %VMM(0), %k1
VPTEST %VMM(1), %VMM(1), %k0{%k1}
KMOV %k0, %VRAX
-# ifdef USE_AS_WCSCHR
+ sar %cl, %VRAX
+#ifdef USE_AS_WCSCHR
sub $VEC_MATCH_MASK, %VRAX
-# else
+#else
inc %VRAX
-# endif
+#endif
/* Ignore number of character for alignment adjustment. */
- shr %cl, %VRAX
jz L(align_more)
bsf %VRAX, %VRAX
--
2.33.0