1/* Test and measure strncasecmp functions.
2 Copyright (C) 1999-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <locale.h>
20#include <ctype.h>
21#define TEST_MAIN
22#define TEST_NAME "strncasecmp"
23#include "test-string.h"
24
25typedef int (*proto_t) (const char *, const char *, size_t);
26static int simple_strncasecmp (const char *, const char *, size_t);
27static int stupid_strncasecmp (const char *, const char *, size_t);
28
29IMPL (stupid_strncasecmp, 0)
30IMPL (simple_strncasecmp, 0)
31IMPL (strncasecmp, 1)
32
33static int
34simple_strncasecmp (const char *s1, const char *s2, size_t n)
35{
36 int ret;
37
38 if (n == 0)
39 return 0;
40
41 while ((ret = ((unsigned char) tolower (*s1)
42 - (unsigned char) tolower (*s2))) == 0
43 && *s1++)
44 {
45 if (--n == 0)
46 return 0;
47 ++s2;
48 }
49 return ret;
50}
51
52static int
53stupid_strncasecmp (const char *s1, const char *s2, size_t max)
54{
55 size_t ns1 = strlen (s1) + 1;
56 size_t ns2 = strlen (s2) + 1;
57 size_t n = ns1 < ns2 ? ns1 : ns2;
58 if (n > max)
59 n = max;
60 int ret = 0;
61
62 while (n--)
63 {
64 if ((ret = ((unsigned char) tolower (*s1)
65 - (unsigned char) tolower (*s2))) != 0)
66 break;
67 ++s1;
68 ++s2;
69 }
70 return ret;
71}
72
73static int
74check_result (impl_t *impl, const char *s1, const char *s2, size_t n,
75 int exp_result)
76{
77 int result = CALL (impl, s1, s2, n);
78 if ((exp_result == 0 && result != 0)
79 || (exp_result < 0 && result >= 0)
80 || (exp_result > 0 && result <= 0))
81 {
82 error (status: 0, errnum: 0, format: "Wrong result in function %s %d %d", impl->name,
83 result, exp_result);
84 ret = 1;
85 return -1;
86 }
87
88 return 0;
89}
90
91static void
92do_one_test (impl_t *impl, const char *s1, const char *s2, size_t n,
93 int exp_result)
94{
95 if (check_result (impl, s1, s2, n, exp_result) < 0)
96 return;
97}
98
99static void
100do_test (size_t align1, size_t align2, size_t n, size_t len, int max_char,
101 int exp_result)
102{
103 size_t i;
104 char *s1, *s2;
105
106 if (len == 0)
107 return;
108
109 align1 &= 7;
110 if (align1 + len + 1 >= page_size)
111 return;
112
113 align2 &= 7;
114 if (align2 + len + 1 >= page_size)
115 return;
116
117 s1 = (char *) (buf1 + align1);
118 s2 = (char *) (buf2 + align2);
119
120 for (i = 0; i < len; i++)
121 {
122 s1[i] = toupper (1 + 23 * i % max_char);
123 s2[i] = tolower (s1[i]);
124 }
125
126 s1[len] = s2[len] = 0;
127 s1[len + 1] = 23;
128 s2[len + 1] = 24 + exp_result;
129 if ((s2[len - 1] == 'z' && exp_result == -1)
130 || (s2[len - 1] == 'a' && exp_result == 1))
131 s1[len - 1] += exp_result;
132 else
133 s2[len - 1] -= exp_result;
134
135 FOR_EACH_IMPL (impl, 0)
136 do_one_test (impl, s1, s2, n, exp_result);
137}
138
139static void
140do_page_tests (void)
141{
142 char *s1, *s2;
143 int exp_result;
144 const size_t maxoffset = 64;
145
146 s1 = (char *) buf1 + BUF1PAGES * page_size - maxoffset;
147 memset (s1, 'a', maxoffset - 1);
148 s1[maxoffset - 1] = '\0';
149
150 s2 = (char *) buf2 + page_size - maxoffset;
151 memset (s2, 'a', maxoffset - 1);
152 s2[maxoffset - 1] = '\0';
153
154 /* At this point s1 and s2 point to distinct memory regions containing
155 "aa..." with size of 63 plus '\0'. Also, both strings are bounded to a
156 page with read/write access and the next page is protected with PROT_NONE
157 (meaning that any access outside of the page regions will trigger an
158 invalid memory access).
159
160 The loop checks for all possible offsets up to maxoffset for both
161 inputs with a size larger than the string (so memory access outside
162 the expected memory regions might trigger invalid access). */
163
164 for (size_t off1 = 0; off1 < maxoffset; off1++)
165 {
166 for (size_t off2 = 0; off2 < maxoffset; off2++)
167 {
168 exp_result = (off1 == off2)
169 ? 0
170 : off1 < off2
171 ? 'a'
172 : -'a';
173
174 FOR_EACH_IMPL (impl, 0)
175 check_result (impl, s1: s1 + off1, s2: s2 + off2, n: maxoffset + 1,
176 exp_result);
177 }
178 }
179}
180
181static void
182do_random_tests (void)
183{
184 size_t i, j, n, align1, align2, pos, len1, len2;
185 int result;
186 long r;
187 unsigned char *p1 = buf1 + page_size - 512;
188 unsigned char *p2 = buf2 + page_size - 512;
189
190 for (n = 0; n < ITERATIONS; n++)
191 {
192 align1 = random () & 31;
193 if (random () & 1)
194 align2 = random () & 31;
195 else
196 align2 = align1 + (random () & 24);
197 pos = random () & 511;
198 j = align1 > align2 ? align1 : align2;
199 if (pos + j >= 511)
200 pos = 510 - j - (random () & 7);
201 len1 = random () & 511;
202 if (pos >= len1 && (random () & 1))
203 len1 = pos + (random () & 7);
204 if (len1 + j >= 512)
205 len1 = 511 - j - (random () & 7);
206 if (pos >= len1)
207 len2 = len1;
208 else
209 len2 = len1 + (len1 != 511 - j ? random () % (511 - j - len1) : 0);
210 j = (pos > len2 ? pos : len2) + align1 + 64;
211 if (j > 512)
212 j = 512;
213 for (i = 0; i < j; ++i)
214 {
215 p1[i] = tolower (random () & 255);
216 if (i < len1 + align1 && !p1[i])
217 {
218 p1[i] = tolower (random () & 255);
219 if (!p1[i])
220 p1[i] = tolower (1 + (random () & 127));
221 }
222 }
223 for (i = 0; i < j; ++i)
224 {
225 p2[i] = toupper (random () & 255);
226 if (i < len2 + align2 && !p2[i])
227 {
228 p2[i] = toupper (random () & 255);
229 if (!p2[i])
230 toupper (p2[i] = 1 + (random () & 127));
231 }
232 }
233
234 result = 0;
235 memcpy (p2 + align2, p1 + align1, pos);
236 if (pos < len1)
237 {
238 if (tolower (p2[align2 + pos]) == p1[align1 + pos])
239 {
240 p2[align2 + pos] = toupper (random () & 255);
241 if (tolower (p2[align2 + pos]) == p1[align1 + pos])
242 p2[align2 + pos] = toupper (p1[align1 + pos]
243 + 3 + (random () & 127));
244 }
245
246 if (p1[align1 + pos] < tolower (p2[align2 + pos]))
247 result = -1;
248 else
249 result = 1;
250 }
251 p1[len1 + align1] = 0;
252 p2[len2 + align2] = 0;
253
254 FOR_EACH_IMPL (impl, 1)
255 {
256 r = CALL (impl, (char *) (p1 + align1), (char *) (p2 + align2),
257 pos + 1 + (random () & 255));
258 /* Test whether on 64-bit architectures where ABI requires
259 callee to promote has the promotion been done. */
260 asm ("" : "=g" (r) : "0" (r));
261 if ((r == 0 && result)
262 || (r < 0 && result >= 0)
263 || (r > 0 && result <= 0))
264 {
265 error (status: 0, errnum: 0, format: "Iteration %zd - wrong result in function %s (%zd, %zd, %zd, %zd, %zd) %ld != %d, p1 %p p2 %p",
266 n, impl->name, align1, align2, len1, len2, pos, r, result, p1, p2);
267 ret = 1;
268 }
269 }
270 }
271}
272
273/* Regression test for BZ #12205 */
274static void
275bz12205 (void)
276{
277 static char cp [4096+16] __attribute__ ((aligned(4096)));
278 static char gotrel[4096] __attribute__ ((aligned(4096)));
279 char *s1 = cp + 0xffa;
280 char *s2 = gotrel + 0xcbe;
281 int exp_result;
282 size_t n = 6;
283
284 strcpy (s1, "gottpoff");
285 strcpy (s2, "GOTPLT");
286
287 exp_result = simple_strncasecmp (s1, s2, n);
288 FOR_EACH_IMPL (impl, 0)
289 check_result (impl, s1, s2, n, exp_result);
290}
291
292/* Regression test for BZ #14195 */
293static void
294bz14195 (void)
295{
296 const char *empty_string = "";
297 FOR_EACH_IMPL (impl, 0)
298 check_result (impl, s1: empty_string, s2: "", n: 5, exp_result: 0);
299}
300
301static void
302test_locale (const char *locale)
303{
304 size_t i;
305
306 if (setlocale (LC_CTYPE, locale) == NULL)
307 {
308 error (status: 0, errnum: 0, format: "cannot set locale \"%s\"", locale);
309 ret = 1;
310 }
311
312 bz12205 ();
313 bz14195 ();
314
315 printf (format: "%23s", locale);
316 FOR_EACH_IMPL (impl, 0)
317 printf (format: "\t%s", impl->name);
318 putchar (c: '\n');
319
320 for (i = 1; i < 16; ++i)
321 {
322 do_test (align1: i, align2: i, n: i - 1, len: i, max_char: 127, exp_result: 0);
323
324 do_test (align1: i, align2: i, n: i, len: i, max_char: 127, exp_result: 0);
325 do_test (align1: i, align2: i, n: i, len: i, max_char: 127, exp_result: 1);
326 do_test (align1: i, align2: i, n: i, len: i, max_char: 127, exp_result: -1);
327
328 do_test (align1: i, align2: i, n: i + 1, len: i, max_char: 127, exp_result: 0);
329 do_test (align1: i, align2: i, n: i + 1, len: i, max_char: 127, exp_result: 1);
330 do_test (align1: i, align2: i, n: i + 1, len: i, max_char: 127, exp_result: -1);
331 }
332
333 for (i = 1; i < 10; ++i)
334 {
335 do_test (align1: 0, align2: 0, n: (2 << i) - 1, len: 2 << i, max_char: 127, exp_result: 0);
336 do_test (align1: 0, align2: 0, n: 2 << i, len: 2 << i, max_char: 254, exp_result: 0);
337 do_test (align1: 0, align2: 0, n: (2 << i) + 1, len: 2 << i, max_char: 127, exp_result: 0);
338
339 do_test (align1: 0, align2: 0, n: (2 << i) + 1, len: 2 << i, max_char: 254, exp_result: 0);
340
341 do_test (align1: 0, align2: 0, n: 2 << i, len: 2 << i, max_char: 127, exp_result: 1);
342 do_test (align1: 0, align2: 0, n: (2 << i) + 10, len: 2 << i, max_char: 127, exp_result: 1);
343
344 do_test (align1: 0, align2: 0, n: 2 << i, len: 2 << i, max_char: 254, exp_result: 1);
345 do_test (align1: 0, align2: 0, n: (2 << i) + 10, len: 2 << i, max_char: 254, exp_result: 1);
346
347 do_test (align1: 0, align2: 0, n: 2 << i, len: 2 << i, max_char: 127, exp_result: -1);
348 do_test (align1: 0, align2: 0, n: (2 << i) + 10, len: 2 << i, max_char: 127, exp_result: -1);
349
350 do_test (align1: 0, align2: 0, n: 2 << i, len: 2 << i, max_char: 254, exp_result: -1);
351 do_test (align1: 0, align2: 0, n: (2 << i) + 10, len: 2 << i, max_char: 254, exp_result: -1);
352 }
353
354 for (i = 1; i < 8; ++i)
355 {
356 do_test (align1: i, align2: 2 * i, n: (8 << i) - 1, len: 8 << i, max_char: 127, exp_result: 0);
357 do_test (align1: i, align2: 2 * i, n: 8 << i, len: 8 << i, max_char: 127, exp_result: 0);
358 do_test (align1: i, align2: 2 * i, n: (8 << i) + 100, len: 8 << i, max_char: 127, exp_result: 0);
359
360 do_test (align1: 2 * i, align2: i, n: (8 << i) - 1, len: 8 << i, max_char: 254, exp_result: 0);
361 do_test (align1: 2 * i, align2: i, n: 8 << i, len: 8 << i, max_char: 254, exp_result: 0);
362 do_test (align1: 2 * i, align2: i, n: (8 << i) + 100, len: 8 << i, max_char: 254, exp_result: 0);
363
364 do_test (align1: i, align2: 2 * i, n: 8 << i, len: 8 << i, max_char: 127, exp_result: 1);
365 do_test (align1: i, align2: 2 * i, n: (8 << i) + 100, len: 8 << i, max_char: 127, exp_result: 1);
366
367 do_test (align1: 2 * i, align2: i, n: 8 << i, len: 8 << i, max_char: 254, exp_result: 1);
368 do_test (align1: 2 * i, align2: i, n: (8 << i) + 100, len: 8 << i, max_char: 254, exp_result: 1);
369
370 do_test (align1: i, align2: 2 * i, n: 8 << i, len: 8 << i, max_char: 127, exp_result: -1);
371 do_test (align1: i, align2: 2 * i, n: (8 << i) + 100, len: 8 << i, max_char: 127, exp_result: -1);
372
373 do_test (align1: 2 * i, align2: i, n: 8 << i, len: 8 << i, max_char: 254, exp_result: -1);
374 do_test (align1: 2 * i, align2: i, n: (8 << i) + 100, len: 8 << i, max_char: 254, exp_result: -1);
375 }
376
377 do_random_tests ();
378 do_page_tests ();
379}
380
381int
382test_main (void)
383{
384 test_init ();
385
386 test_locale (locale: "C");
387 test_locale (locale: "en_US.ISO-8859-1");
388 test_locale (locale: "en_US.UTF-8");
389 test_locale (locale: "tr_TR.ISO-8859-9");
390 test_locale (locale: "tr_TR.UTF-8");
391
392 return ret;
393}
394
395#include <support/test-driver.c>
396

source code of glibc/string/test-strncasecmp.c