1/* Test and measure strncasecmp functions.
2 Copyright (C) 1999-2024 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
22#define TEST_LEN (getpagesize () * 3)
23#define MIN_PAGE_SIZE (TEST_LEN + 2 * getpagesize ())
24
25#define TEST_MAIN
26#define TEST_NAME "strncasecmp"
27#define TIMEOUT (5 * 60)
28#include "test-string.h"
29
30typedef int (*proto_t) (const char *, const char *, size_t);
31static int simple_strncasecmp (const char *, const char *, size_t);
32
33IMPL (strncasecmp, 1)
34
35/* Naive implementation to verify results. */
36static int
37simple_strncasecmp (const char *s1, const char *s2, size_t n)
38{
39 int ret;
40
41 if (n == 0)
42 return 0;
43
44 while ((ret = ((unsigned char) tolower (*s1)
45 - (unsigned char) tolower (*s2))) == 0
46 && *s1++)
47 {
48 if (--n == 0)
49 return 0;
50 ++s2;
51 }
52 return ret;
53}
54
55static int
56check_result (impl_t *impl, const char *s1, const char *s2, size_t n,
57 int exp_result)
58{
59 int result = CALL (impl, s1, s2, n);
60 if ((exp_result == 0 && result != 0)
61 || (exp_result < 0 && result >= 0)
62 || (exp_result > 0 && result <= 0))
63 {
64 error (status: 0, errnum: 0, format: "Wrong result in function %s %d %d", impl->name,
65 result, exp_result);
66 ret = 1;
67 return -1;
68 }
69
70 return 0;
71}
72
73static void
74do_one_test (impl_t *impl, const char *s1, const char *s2, size_t n,
75 int exp_result)
76{
77 if (check_result (impl, s1, s2, n, exp_result) < 0)
78 return;
79}
80
81static void
82do_test (size_t align1, size_t align2, size_t n, size_t len, int max_char,
83 int exp_result)
84{
85 size_t i;
86 char *s1, *s2;
87
88 if (len == 0)
89 return;
90
91 align1 &= getpagesize () - 1;
92 if (align1 + (len + 2) >= page_size)
93 return;
94
95 align2 &= getpagesize () - 1;
96 if (align2 + (len + 2) >= page_size)
97 return;
98
99
100 s1 = (char *) (buf1 + align1);
101 s2 = (char *) (buf2 + align2);
102
103 for (i = 0; i < len; i++)
104 {
105 s1[i] = toupper (1 + 23 * i % max_char);
106 s2[i] = tolower (s1[i]);
107 }
108
109 s1[len] = s2[len] = 0;
110 s1[len + 1] = 23;
111 s2[len + 1] = 24 + exp_result;
112
113 if ((s2[len - 1] == 'z' && exp_result == -1)
114 || (s2[len - 1] == 'a' && exp_result == 1))
115 s1[len - 1] += exp_result;
116 else if ((s1[len - 1] == 'Z' + 1 && exp_result == 1)
117 || (s1[len - 1] == 'A' - 1 && exp_result == -1))
118 s1[len - 1] = tolower (s2[len - 1]) + exp_result;
119 else
120 s2[len - 1] -= exp_result;
121
122 /* For some locals this is not guaranteed yet. */
123 if (tolower (s1[len - 1]) - tolower (s2[len - 1]) != exp_result)
124 {
125 if (exp_result == -1)
126 {
127 s1[len - 1] = tolower ('a');
128 s2[len - 1] = toupper (tolower ('a') - 1);
129 }
130 else if (exp_result == 0)
131 s1[len - 1] = toupper (s2[len - 1]);
132 else
133 {
134 s1[len - 1] = tolower ('a');
135 s2[len - 1] = toupper (tolower ('a') + 1);
136 }
137 }
138
139 FOR_EACH_IMPL (impl, 0)
140 do_one_test (impl, s1, s2, n, exp_result);
141}
142
143static void
144do_page_tests (void)
145{
146 char *s1, *s2;
147 int exp_result;
148 const size_t maxoffset = 64;
149
150 s1 = (char *) buf1 + BUF1PAGES * page_size - maxoffset;
151 memset (s1, 'a', maxoffset - 1);
152 s1[maxoffset - 1] = '\0';
153
154 s2 = (char *) buf2 + page_size - maxoffset;
155 memset (s2, 'a', maxoffset - 1);
156 s2[maxoffset - 1] = '\0';
157
158 /* At this point s1 and s2 point to distinct memory regions containing
159 "aa..." with size of 63 plus '\0'. Also, both strings are bounded to a
160 page with read/write access and the next page is protected with PROT_NONE
161 (meaning that any access outside of the page regions will trigger an
162 invalid memory access).
163
164 The loop checks for all possible offsets up to maxoffset for both
165 inputs with a size larger than the string (so memory access outside
166 the expected memory regions might trigger invalid access). */
167
168 for (size_t off1 = 0; off1 < maxoffset; off1++)
169 {
170 for (size_t off2 = 0; off2 < maxoffset; off2++)
171 {
172 exp_result = (off1 == off2)
173 ? 0
174 : off1 < off2
175 ? 'a'
176 : -'a';
177
178 FOR_EACH_IMPL (impl, 0)
179 check_result (impl, s1: s1 + off1, s2: s2 + off2, n: maxoffset + 1,
180 exp_result);
181 }
182 }
183}
184
185static void
186do_random_tests (void)
187{
188 size_t i, j, n, align1, align2, pos, len1, len2;
189 int result;
190 long r;
191 unsigned char *p1 = buf1 + page_size - 512;
192 unsigned char *p2 = buf2 + page_size - 512;
193
194 for (n = 0; n < ITERATIONS; n++)
195 {
196 align1 = random () & 31;
197 if (random () & 1)
198 align2 = random () & 31;
199 else
200 align2 = align1 + (random () & 24);
201 pos = random () & 511;
202 j = align1 > align2 ? align1 : align2;
203 if (pos + j >= 511)
204 pos = 510 - j - (random () & 7);
205 len1 = random () & 511;
206 if (pos >= len1 && (random () & 1))
207 len1 = pos + (random () & 7);
208 if (len1 + j >= 512)
209 len1 = 511 - j - (random () & 7);
210 if (pos >= len1)
211 len2 = len1;
212 else
213 len2 = len1 + (len1 != 511 - j ? random () % (511 - j - len1) : 0);
214 j = (pos > len2 ? pos : len2) + align1 + 64;
215 if (j > 512)
216 j = 512;
217 for (i = 0; i < j; ++i)
218 {
219 p1[i] = tolower (random () & 255);
220 if (i < len1 + align1 && !p1[i])
221 {
222 p1[i] = tolower (random () & 255);
223 if (!p1[i])
224 p1[i] = tolower (1 + (random () & 127));
225 }
226 }
227 for (i = 0; i < j; ++i)
228 {
229 p2[i] = toupper (random () & 255);
230 if (i < len2 + align2 && !p2[i])
231 {
232 p2[i] = toupper (random () & 255);
233 if (!p2[i])
234 toupper (p2[i] = 1 + (random () & 127));
235 }
236 }
237
238 result = 0;
239 memcpy (p2 + align2, p1 + align1, pos);
240 if (pos < len1)
241 {
242 if (tolower (p2[align2 + pos]) == p1[align1 + pos])
243 {
244 p2[align2 + pos] = toupper (random () & 255);
245 if (tolower (p2[align2 + pos]) == p1[align1 + pos])
246 p2[align2 + pos] = toupper (p1[align1 + pos]
247 + 3 + (random () & 127));
248 }
249
250 if (p1[align1 + pos] < tolower (p2[align2 + pos]))
251 result = -1;
252 else
253 result = 1;
254 }
255 p1[len1 + align1] = 0;
256 p2[len2 + align2] = 0;
257
258 FOR_EACH_IMPL (impl, 1)
259 {
260 r = CALL (impl, (char *) (p1 + align1), (char *) (p2 + align2),
261 pos + 1 + (random () & 255));
262 /* Test whether on 64-bit architectures where ABI requires
263 callee to promote has the promotion been done. */
264 asm ("" : "=g" (r) : "0" (r));
265 if ((r == 0 && result)
266 || (r < 0 && result >= 0)
267 || (r > 0 && result <= 0))
268 {
269 error (status: 0, errnum: 0, format: "Iteration %zd - wrong result in function %s (%zd, %zd, %zd, %zd, %zd) %ld != %d, p1 %p p2 %p",
270 n, impl->name, align1, align2, len1, len2, pos, r, result, p1, p2);
271 ret = 1;
272 }
273 }
274 }
275}
276
277/* Regression test for BZ #12205 */
278static void
279bz12205 (void)
280{
281 static char cp [4096+16] __attribute__ ((aligned(4096)));
282 static char gotrel[4096] __attribute__ ((aligned(4096)));
283 char *s1 = cp + 0xffa;
284 char *s2 = gotrel + 0xcbe;
285 int exp_result;
286 size_t n = 6;
287
288 strcpy (s1, "gottpoff");
289 strcpy (s2, "GOTPLT");
290
291 exp_result = simple_strncasecmp (s1, s2, n);
292 FOR_EACH_IMPL (impl, 0)
293 check_result (impl, s1, s2, n, exp_result);
294}
295
296/* Regression test for BZ #14195 */
297static void
298bz14195 (void)
299{
300 const char *empty_string = "";
301 FOR_EACH_IMPL (impl, 0)
302 check_result (impl, s1: empty_string, s2: "", n: 5, exp_result: 0);
303}
304
305static void
306test_locale (const char *locale, int extra_tests)
307{
308 size_t i, j, k;
309 const size_t test_len = MIN(TEST_LEN, 3 * 4096);
310 if (setlocale (LC_CTYPE, locale) == NULL)
311 {
312 error (status: 0, errnum: 0, format: "cannot set locale \"%s\"", locale);
313 ret = 1;
314 }
315
316 bz12205 ();
317 bz14195 ();
318
319 printf (format: "%23s", locale);
320 FOR_EACH_IMPL (impl, 0)
321 printf (format: "\t%s", impl->name);
322 putchar (c: '\n');
323
324 for (i = 1; i < 16; ++i)
325 {
326 do_test (align1: i, align2: i, n: i - 1, len: i, max_char: 127, exp_result: 0);
327
328 do_test (align1: i, align2: i, n: i, len: i, max_char: 127, exp_result: 0);
329 do_test (align1: i, align2: i, n: i, len: i, max_char: 127, exp_result: 1);
330 do_test (align1: i, align2: i, n: i, len: i, max_char: 127, exp_result: -1);
331
332 do_test (align1: i, align2: i, n: i + 1, len: i, max_char: 127, exp_result: 0);
333 do_test (align1: i, align2: i, n: i + 1, len: i, max_char: 127, exp_result: 1);
334 do_test (align1: i, align2: i, n: i + 1, len: i, max_char: 127, exp_result: -1);
335 }
336
337 for (i = 1; i < 10; ++i)
338 {
339 do_test (align1: 0, align2: 0, n: (2 << i) - 1, len: 2 << i, max_char: 127, exp_result: 0);
340 do_test (align1: 0, align2: 0, n: 2 << i, len: 2 << i, max_char: 254, exp_result: 0);
341 do_test (align1: 0, align2: 0, n: (2 << i) + 1, len: 2 << i, max_char: 127, exp_result: 0);
342
343 do_test (align1: 0, align2: 0, n: (2 << i) + 1, len: 2 << i, max_char: 254, exp_result: 0);
344
345 do_test (align1: 0, align2: 0, n: 2 << i, len: 2 << i, max_char: 127, exp_result: 1);
346 do_test (align1: 0, align2: 0, n: (2 << i) + 10, len: 2 << i, max_char: 127, exp_result: 1);
347
348 do_test (align1: 0, align2: 0, n: 2 << i, len: 2 << i, max_char: 254, exp_result: 1);
349 do_test (align1: 0, align2: 0, n: (2 << i) + 10, len: 2 << i, max_char: 254, exp_result: 1);
350
351 do_test (align1: 0, align2: 0, n: 2 << i, len: 2 << i, max_char: 127, exp_result: -1);
352 do_test (align1: 0, align2: 0, n: (2 << i) + 10, len: 2 << i, max_char: 127, exp_result: -1);
353
354 do_test (align1: 0, align2: 0, n: 2 << i, len: 2 << i, max_char: 254, exp_result: -1);
355 do_test (align1: 0, align2: 0, n: (2 << i) + 10, len: 2 << i, max_char: 254, exp_result: -1);
356 }
357
358 for (i = 1; i < 8; ++i)
359 {
360 do_test (align1: i, align2: 2 * i, n: (8 << i) - 1, len: 8 << i, max_char: 127, exp_result: 0);
361 do_test (align1: i, align2: 2 * i, n: 8 << i, len: 8 << i, max_char: 127, exp_result: 0);
362 do_test (align1: i, align2: 2 * i, n: (8 << i) + 100, len: 8 << i, max_char: 127, exp_result: 0);
363
364 do_test (align1: 2 * i, align2: i, n: (8 << i) - 1, len: 8 << i, max_char: 254, exp_result: 0);
365 do_test (align1: 2 * i, align2: i, n: 8 << i, len: 8 << i, max_char: 254, exp_result: 0);
366 do_test (align1: 2 * i, align2: i, n: (8 << i) + 100, len: 8 << i, max_char: 254, exp_result: 0);
367
368 do_test (align1: i, align2: 2 * i, n: 8 << i, len: 8 << i, max_char: 127, exp_result: 1);
369 do_test (align1: i, align2: 2 * i, n: (8 << i) + 100, len: 8 << i, max_char: 127, exp_result: 1);
370
371 do_test (align1: 2 * i, align2: i, n: 8 << i, len: 8 << i, max_char: 254, exp_result: 1);
372 do_test (align1: 2 * i, align2: i, n: (8 << i) + 100, len: 8 << i, max_char: 254, exp_result: 1);
373
374 do_test (align1: i, align2: 2 * i, n: 8 << i, len: 8 << i, max_char: 127, exp_result: -1);
375 do_test (align1: i, align2: 2 * i, n: (8 << i) + 100, len: 8 << i, max_char: 127, exp_result: -1);
376
377 do_test (align1: 2 * i, align2: i, n: 8 << i, len: 8 << i, max_char: 254, exp_result: -1);
378 do_test (align1: 2 * i, align2: i, n: (8 << i) + 100, len: 8 << i, max_char: 254, exp_result: -1);
379 }
380
381 for (j = 0; extra_tests && j < 160; ++j)
382 {
383 for (i = 0; i < test_len;)
384 {
385 do_test (align1: getpagesize () - j - 1, align2: 0, n: i + 1, len: i, max_char: 127, exp_result: 0);
386 do_test (align1: getpagesize () - j - 1, align2: 0, n: i + 1, len: i, max_char: 127, exp_result: 1);
387 do_test (align1: getpagesize () - j - 1, align2: 0, n: i + 1, len: i, max_char: 127, exp_result: -1);
388
389 do_test (align1: getpagesize () - j - 1, align2: 0, n: i, len: i, max_char: 127, exp_result: 0);
390 do_test (align1: getpagesize () - j - 1, align2: 0, n: i - 1, len: i, max_char: 127, exp_result: 0);
391
392 do_test (align1: getpagesize () - j - 1, align2: 0, ULONG_MAX, len: i, max_char: 127, exp_result: 0);
393 do_test (align1: getpagesize () - j - 1, align2: 0, ULONG_MAX, len: i, max_char: 127, exp_result: 1);
394 do_test (align1: getpagesize () - j - 1, align2: 0, ULONG_MAX, len: i, max_char: 127, exp_result: -1);
395
396 do_test (align1: getpagesize () - j - 1, align2: 0, ULONG_MAX - i, len: i, max_char: 127, exp_result: 0);
397 do_test (align1: getpagesize () - j - 1, align2: 0, ULONG_MAX - i, len: i, max_char: 127, exp_result: 1);
398 do_test (align1: getpagesize () - j - 1, align2: 0, ULONG_MAX - i, len: i, max_char: 127, exp_result: -1);
399
400 do_test (align1: getpagesize () - j - 1, align2: j, n: i + 1, len: i, max_char: 127, exp_result: 0);
401 do_test (align1: getpagesize () - j - 1, align2: j, n: i + 1, len: i, max_char: 127, exp_result: 1);
402 do_test (align1: getpagesize () - j - 1, align2: j, n: i + 1, len: i, max_char: 127, exp_result: -1);
403
404 do_test (align1: getpagesize () - j - 1, align2: j, n: i, len: i, max_char: 127, exp_result: 0);
405 do_test (align1: getpagesize () - j - 1, align2: j, n: i - 1, len: i, max_char: 127, exp_result: 0);
406
407 do_test (align1: getpagesize () - j - 1, align2: j, ULONG_MAX, len: i, max_char: 127, exp_result: 0);
408 do_test (align1: getpagesize () - j - 1, align2: j, ULONG_MAX, len: i, max_char: 127, exp_result: 1);
409 do_test (align1: getpagesize () - j - 1, align2: j, ULONG_MAX, len: i, max_char: 127, exp_result: -1);
410
411 do_test (align1: getpagesize () - j - 1, align2: j, ULONG_MAX - i, len: i, max_char: 127, exp_result: 0);
412 do_test (align1: getpagesize () - j - 1, align2: j, ULONG_MAX - i, len: i, max_char: 127, exp_result: 1);
413 do_test (align1: getpagesize () - j - 1, align2: j, ULONG_MAX - i, len: i, max_char: 127, exp_result: -1);
414
415 do_test (align1: 0, align2: getpagesize () - j - 1, n: i + 1, len: i, max_char: 127, exp_result: 0);
416 do_test (align1: 0, align2: getpagesize () - j - 1, n: i + 1, len: i, max_char: 127, exp_result: 1);
417 do_test (align1: 0, align2: getpagesize () - j - 1, n: i + 1, len: i, max_char: 127, exp_result: -1);
418
419 do_test (align1: 0, align2: getpagesize () - j - 1, n: i, len: i, max_char: 127, exp_result: 0);
420 do_test (align1: 0, align2: getpagesize () - j - 1, n: i - 1, len: i, max_char: 127, exp_result: 0);
421
422 do_test (align1: 0, align2: getpagesize () - j - 1, ULONG_MAX, len: i, max_char: 127, exp_result: 0);
423 do_test (align1: 0, align2: getpagesize () - j - 1, ULONG_MAX, len: i, max_char: 127, exp_result: 1);
424 do_test (align1: 0, align2: getpagesize () - j - 1, ULONG_MAX, len: i, max_char: 127, exp_result: -1);
425
426 do_test (align1: 0, align2: getpagesize () - j - 1, ULONG_MAX - i, len: i, max_char: 127, exp_result: 0);
427 do_test (align1: 0, align2: getpagesize () - j - 1, ULONG_MAX - i, len: i, max_char: 127, exp_result: 1);
428 do_test (align1: 0, align2: getpagesize () - j - 1, ULONG_MAX - i, len: i, max_char: 127, exp_result: -1);
429
430 do_test (align1: j, align2: getpagesize () - j - 1, n: i + 1, len: i, max_char: 127, exp_result: 0);
431 do_test (align1: j, align2: getpagesize () - j - 1, n: i + 1, len: i, max_char: 127, exp_result: 1);
432 do_test (align1: j, align2: getpagesize () - j - 1, n: i + 1, len: i, max_char: 127, exp_result: -1);
433
434 do_test (align1: j, align2: getpagesize () - j - 1, n: i, len: i, max_char: 127, exp_result: 0);
435 do_test (align1: j, align2: getpagesize () - j - 1, n: i - 1, len: i, max_char: 127, exp_result: 0);
436
437 do_test (align1: j, align2: getpagesize () - j - 1, ULONG_MAX, len: i, max_char: 127, exp_result: 0);
438 do_test (align1: j, align2: getpagesize () - j - 1, ULONG_MAX, len: i, max_char: 127, exp_result: 1);
439 do_test (align1: j, align2: getpagesize () - j - 1, ULONG_MAX, len: i, max_char: 127, exp_result: -1);
440
441 do_test (align1: j, align2: getpagesize () - j - 1, ULONG_MAX - i, len: i, max_char: 127, exp_result: 0);
442 do_test (align1: j, align2: getpagesize () - j - 1, ULONG_MAX - i, len: i, max_char: 127, exp_result: 1);
443 do_test (align1: j, align2: getpagesize () - j - 1, ULONG_MAX - i, len: i, max_char: 127, exp_result: -1);
444
445 for (k = 2; k <= 128; k += k)
446 {
447 do_test (align1: getpagesize () - k, align2: getpagesize () - j - 1, n: i - 1, len: i,
448 max_char: 127, exp_result: 0);
449 do_test (align1: getpagesize () - k - 1, align2: getpagesize () - j - 1, n: i - 1,
450 len: i, max_char: 127, exp_result: 0);
451 do_test (align1: getpagesize () - k, align2: getpagesize () - j - 1, n: i + 1, len: i,
452 max_char: 127, exp_result: 0);
453 do_test (align1: getpagesize () - k - 1, align2: getpagesize () - j - 1, n: i + 1,
454 len: i, max_char: 127, exp_result: 0);
455 do_test (align1: getpagesize () - k, align2: getpagesize () - j - 1, n: i, len: i, max_char: 127,
456 exp_result: 0);
457 do_test (align1: getpagesize () - k - 1, align2: getpagesize () - j - 1, n: i, len: i,
458 max_char: 127, exp_result: 0);
459 do_test (align1: getpagesize () - k, align2: getpagesize () - j - 1, n: i + 1, len: i,
460 max_char: 127, exp_result: -1);
461 do_test (align1: getpagesize () - k - 1, align2: getpagesize () - j - 1, n: i + 1,
462 len: i, max_char: 127, exp_result: -1);
463 do_test (align1: getpagesize () - k, align2: getpagesize () - j - 1, n: i + 1, len: i,
464 max_char: 127, exp_result: 1);
465 do_test (align1: getpagesize () - k - 1, align2: getpagesize () - j - 1, n: i + 1,
466 len: i, max_char: 127, exp_result: 1);
467 }
468 if (i < 32)
469 {
470 i += 1;
471 }
472 else if (i < 161)
473 {
474 i += 7;
475 }
476 else if (i + 161 < test_len)
477 {
478 i += 31;
479 i *= 17;
480 i /= 16;
481 if (i + 161 > test_len)
482 {
483 i = test_len - 160;
484 }
485 }
486 else if (i + 32 < test_len)
487 {
488 i += 7;
489 }
490 else
491 {
492 i += 1;
493 }
494 }
495 }
496
497 do_random_tests ();
498 do_page_tests ();
499}
500
501int
502test_main (void)
503{
504 test_init ();
505
506 test_locale (locale: "C", extra_tests: 1);
507 test_locale (locale: "en_US.ISO-8859-1", extra_tests: 0);
508 test_locale (locale: "en_US.UTF-8", extra_tests: 0);
509 test_locale (locale: "tr_TR.ISO-8859-9", extra_tests: 0);
510 test_locale (locale: "tr_TR.UTF-8", extra_tests: 0);
511
512 return ret;
513}
514
515#include <support/test-driver.c>
516

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