summaryrefslogtreecommitdiff
path: root/x86-Fix-bug-in-strchrnul-evex512-BZ-32078.patch
blob: 85af57b6a60a7ca9685d14d38e5f20d7b47a8786 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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