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 
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 
30 typedef int (*proto_t) (const char *, const char *, size_t);
31 static int simple_strncasecmp (const char *, const char *, size_t);
32 
33 IMPL (strncasecmp, 1)
34 
35 /* Naive implementation to verify results.  */
36 static int
simple_strncasecmp(const char * s1,const char * s2,size_t n)37 simple_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 
55 static int
check_result(impl_t * impl,const char * s1,const char * s2,size_t n,int exp_result)56 check_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 (0, 0, "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 
73 static void
do_one_test(impl_t * impl,const char * s1,const char * s2,size_t n,int exp_result)74 do_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 
81 static void
do_test(size_t align1,size_t align2,size_t n,size_t len,int max_char,int exp_result)82 do_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 guranteed 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 
143 static void
do_page_tests(void)144 do_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 + off1, s2 + off2, maxoffset + 1,
180 			  exp_result);
181 	}
182     }
183 }
184 
185 static void
do_random_tests(void)186 do_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 (0, 0, "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 */
278 static void
bz12205(void)279 bz12205 (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 */
297 static void
bz14195(void)298 bz14195 (void)
299 {
300   const char *empty_string  = "";
301   FOR_EACH_IMPL (impl, 0)
302     check_result (impl, empty_string, "", 5, 0);
303 }
304 
305 static void
test_locale(const char * locale,int extra_tests)306 test_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 (0, 0, "cannot set locale \"%s\"", locale);
313       ret = 1;
314     }
315 
316   bz12205 ();
317   bz14195 ();
318 
319   printf ("%23s", locale);
320   FOR_EACH_IMPL (impl, 0)
321     printf ("\t%s", impl->name);
322   putchar ('\n');
323 
324   for (i = 1; i < 16; ++i)
325     {
326       do_test (i, i, i - 1, i, 127, 0);
327 
328       do_test (i, i, i, i, 127, 0);
329       do_test (i, i, i, i, 127, 1);
330       do_test (i, i, i, i, 127, -1);
331 
332       do_test (i, i, i + 1, i, 127, 0);
333       do_test (i, i, i + 1, i, 127, 1);
334       do_test (i, i, i + 1, i, 127, -1);
335     }
336 
337   for (i = 1; i < 10; ++i)
338     {
339       do_test (0, 0, (2 << i) - 1, 2 << i, 127, 0);
340       do_test (0, 0, 2 << i, 2 << i, 254, 0);
341       do_test (0, 0, (2 << i) + 1, 2 << i, 127, 0);
342 
343       do_test (0, 0, (2 << i) + 1, 2 << i, 254, 0);
344 
345       do_test (0, 0, 2 << i, 2 << i, 127, 1);
346       do_test (0, 0, (2 << i) + 10, 2 << i, 127, 1);
347 
348       do_test (0, 0, 2 << i, 2 << i, 254, 1);
349       do_test (0, 0, (2 << i) + 10, 2 << i, 254, 1);
350 
351       do_test (0, 0, 2 << i, 2 << i, 127, -1);
352       do_test (0, 0, (2 << i) + 10, 2 << i, 127, -1);
353 
354       do_test (0, 0, 2 << i, 2 << i, 254, -1);
355       do_test (0, 0, (2 << i) + 10, 2 << i, 254, -1);
356     }
357 
358   for (i = 1; i < 8; ++i)
359     {
360       do_test (i, 2 * i, (8 << i) - 1, 8 << i, 127, 0);
361       do_test (i, 2 * i, 8 << i, 8 << i, 127, 0);
362       do_test (i, 2 * i, (8 << i) + 100, 8 << i, 127, 0);
363 
364       do_test (2 * i, i, (8 << i) - 1, 8 << i, 254, 0);
365       do_test (2 * i, i, 8 << i, 8 << i, 254, 0);
366       do_test (2 * i, i, (8 << i) + 100, 8 << i, 254, 0);
367 
368       do_test (i, 2 * i, 8 << i, 8 << i, 127, 1);
369       do_test (i, 2 * i, (8 << i) + 100, 8 << i, 127, 1);
370 
371       do_test (2 * i, i, 8 << i, 8 << i, 254, 1);
372       do_test (2 * i, i, (8 << i) + 100, 8 << i, 254, 1);
373 
374       do_test (i, 2 * i, 8 << i, 8 << i, 127, -1);
375       do_test (i, 2 * i, (8 << i) + 100, 8 << i, 127, -1);
376 
377       do_test (2 * i, i, 8 << i, 8 << i, 254, -1);
378       do_test (2 * i, i, (8 << i) + 100, 8 << i, 254, -1);
379     }
380 
381   for (j = 0; extra_tests && j < 160; ++j)
382     {
383       for (i = 0; i < test_len;)
384         {
385             do_test (getpagesize () - j - 1, 0, i + 1, i, 127, 0);
386             do_test (getpagesize () - j - 1, 0, i + 1, i, 127, 1);
387             do_test (getpagesize () - j - 1, 0, i + 1, i, 127, -1);
388 
389             do_test (getpagesize () - j - 1, 0, i, i, 127, 0);
390             do_test (getpagesize () - j - 1, 0, i - 1, i, 127, 0);
391 
392             do_test (getpagesize () - j - 1, 0, ULONG_MAX, i, 127, 0);
393             do_test (getpagesize () - j - 1, 0, ULONG_MAX, i, 127, 1);
394             do_test (getpagesize () - j - 1, 0, ULONG_MAX, i, 127, -1);
395 
396             do_test (getpagesize () - j - 1, 0, ULONG_MAX - i, i, 127, 0);
397             do_test (getpagesize () - j - 1, 0, ULONG_MAX - i, i, 127, 1);
398             do_test (getpagesize () - j - 1, 0, ULONG_MAX - i, i, 127, -1);
399 
400             do_test (getpagesize () - j - 1, j, i + 1, i, 127, 0);
401             do_test (getpagesize () - j - 1, j, i + 1, i, 127, 1);
402             do_test (getpagesize () - j - 1, j, i + 1, i, 127, -1);
403 
404             do_test (getpagesize () - j - 1, j, i, i, 127, 0);
405             do_test (getpagesize () - j - 1, j, i - 1, i, 127, 0);
406 
407             do_test (getpagesize () - j - 1, j, ULONG_MAX, i, 127, 0);
408             do_test (getpagesize () - j - 1, j, ULONG_MAX, i, 127, 1);
409             do_test (getpagesize () - j - 1, j, ULONG_MAX, i, 127, -1);
410 
411             do_test (getpagesize () - j - 1, j, ULONG_MAX - i, i, 127, 0);
412             do_test (getpagesize () - j - 1, j, ULONG_MAX - i, i, 127, 1);
413             do_test (getpagesize () - j - 1, j, ULONG_MAX - i, i, 127, -1);
414 
415             do_test (0, getpagesize () - j - 1, i + 1, i, 127, 0);
416             do_test (0, getpagesize () - j - 1, i + 1, i, 127, 1);
417             do_test (0, getpagesize () - j - 1, i + 1, i, 127, -1);
418 
419             do_test (0, getpagesize () - j - 1, i, i, 127, 0);
420             do_test (0, getpagesize () - j - 1, i - 1, i, 127, 0);
421 
422             do_test (0, getpagesize () - j - 1, ULONG_MAX, i, 127, 0);
423             do_test (0, getpagesize () - j - 1, ULONG_MAX, i, 127, 1);
424             do_test (0, getpagesize () - j - 1, ULONG_MAX, i, 127, -1);
425 
426             do_test (0, getpagesize () - j - 1, ULONG_MAX - i, i, 127, 0);
427             do_test (0, getpagesize () - j - 1, ULONG_MAX - i, i, 127, 1);
428             do_test (0, getpagesize () - j - 1, ULONG_MAX - i, i, 127, -1);
429 
430             do_test (j, getpagesize () - j - 1, i + 1, i, 127, 0);
431             do_test (j, getpagesize () - j - 1, i + 1, i, 127, 1);
432             do_test (j, getpagesize () - j - 1, i + 1, i, 127, -1);
433 
434             do_test (j, getpagesize () - j - 1, i, i, 127, 0);
435             do_test (j, getpagesize () - j - 1, i - 1, i, 127, 0);
436 
437             do_test (j, getpagesize () - j - 1, ULONG_MAX, i, 127, 0);
438             do_test (j, getpagesize () - j - 1, ULONG_MAX, i, 127, 1);
439             do_test (j, getpagesize () - j - 1, ULONG_MAX, i, 127, -1);
440 
441             do_test (j, getpagesize () - j - 1, ULONG_MAX - i, i, 127, 0);
442             do_test (j, getpagesize () - j - 1, ULONG_MAX - i, i, 127, 1);
443             do_test (j, getpagesize () - j - 1, ULONG_MAX - i, i, 127, -1);
444 
445           for (k = 2; k <= 128; k += k)
446             {
447               do_test (getpagesize () - k, getpagesize () - j - 1, i - 1, i,
448                        127, 0);
449               do_test (getpagesize () - k - 1, getpagesize () - j - 1, i - 1,
450                        i, 127, 0);
451               do_test (getpagesize () - k, getpagesize () - j - 1, i + 1, i,
452                        127, 0);
453               do_test (getpagesize () - k - 1, getpagesize () - j - 1, i + 1,
454                        i, 127, 0);
455               do_test (getpagesize () - k, getpagesize () - j - 1, i, i, 127,
456                        0);
457               do_test (getpagesize () - k - 1, getpagesize () - j - 1, i, i,
458                        127, 0);
459               do_test (getpagesize () - k, getpagesize () - j - 1, i + 1, i,
460                        127, -1);
461               do_test (getpagesize () - k - 1, getpagesize () - j - 1, i + 1,
462                        i, 127, -1);
463               do_test (getpagesize () - k, getpagesize () - j - 1, i + 1, i,
464                        127, 1);
465               do_test (getpagesize () - k - 1, getpagesize () - j - 1, i + 1,
466                        i, 127, 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 
501 int
test_main(void)502 test_main (void)
503 {
504   test_init ();
505 
506   test_locale ("C", 1);
507   test_locale ("en_US.ISO-8859-1", 0);
508   test_locale ("en_US.UTF-8", 0);
509   test_locale ("tr_TR.ISO-8859-9", 0);
510   test_locale ("tr_TR.UTF-8", 0);
511 
512   return ret;
513 }
514 
515 #include <support/test-driver.c>
516