1 /* Test and measure strncasecmp functions.
2    Copyright (C) 1999-2021 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 
25 typedef int (*proto_t) (const char *, const char *, size_t);
26 static int simple_strncasecmp (const char *, const char *, size_t);
27 static int stupid_strncasecmp (const char *, const char *, size_t);
28 
29 IMPL (stupid_strncasecmp, 0)
30 IMPL (simple_strncasecmp, 0)
31 IMPL (strncasecmp, 1)
32 
33 static int
simple_strncasecmp(const char * s1,const char * s2,size_t n)34 simple_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 
52 static int
stupid_strncasecmp(const char * s1,const char * s2,size_t max)53 stupid_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 
73 static int
check_result(impl_t * impl,const char * s1,const char * s2,size_t n,int exp_result)74 check_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 (0, 0, "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 
91 static void
do_one_test(impl_t * impl,const char * s1,const char * s2,size_t n,int exp_result)92 do_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 
99 static void
do_test(size_t align1,size_t align2,size_t n,size_t len,int max_char,int exp_result)100 do_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 
139 static void
do_page_tests(void)140 do_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 + off1, s2 + off2, maxoffset + 1,
176 			  exp_result);
177 	}
178     }
179 }
180 
181 static void
do_random_tests(void)182 do_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 (0, 0, "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 */
274 static void
bz12205(void)275 bz12205 (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 */
293 static void
bz14195(void)294 bz14195 (void)
295 {
296   const char *empty_string  = "";
297   FOR_EACH_IMPL (impl, 0)
298     check_result (impl, empty_string, "", 5, 0);
299 }
300 
301 static void
test_locale(const char * locale)302 test_locale (const char *locale)
303 {
304   size_t i;
305 
306   if (setlocale (LC_CTYPE, locale) == NULL)
307     {
308       error (0, 0, "cannot set locale \"%s\"", locale);
309       ret = 1;
310     }
311 
312   bz12205 ();
313   bz14195 ();
314 
315   printf ("%23s", locale);
316   FOR_EACH_IMPL (impl, 0)
317     printf ("\t%s", impl->name);
318   putchar ('\n');
319 
320   for (i = 1; i < 16; ++i)
321     {
322       do_test (i, i, i - 1, i, 127, 0);
323 
324       do_test (i, i, i, i, 127, 0);
325       do_test (i, i, i, i, 127, 1);
326       do_test (i, i, i, i, 127, -1);
327 
328       do_test (i, i, i + 1, i, 127, 0);
329       do_test (i, i, i + 1, i, 127, 1);
330       do_test (i, i, i + 1, i, 127, -1);
331     }
332 
333   for (i = 1; i < 10; ++i)
334     {
335       do_test (0, 0, (2 << i) - 1, 2 << i, 127, 0);
336       do_test (0, 0, 2 << i, 2 << i, 254, 0);
337       do_test (0, 0, (2 << i) + 1, 2 << i, 127, 0);
338 
339       do_test (0, 0, (2 << i) + 1, 2 << i, 254, 0);
340 
341       do_test (0, 0, 2 << i, 2 << i, 127, 1);
342       do_test (0, 0, (2 << i) + 10, 2 << i, 127, 1);
343 
344       do_test (0, 0, 2 << i, 2 << i, 254, 1);
345       do_test (0, 0, (2 << i) + 10, 2 << i, 254, 1);
346 
347       do_test (0, 0, 2 << i, 2 << i, 127, -1);
348       do_test (0, 0, (2 << i) + 10, 2 << i, 127, -1);
349 
350       do_test (0, 0, 2 << i, 2 << i, 254, -1);
351       do_test (0, 0, (2 << i) + 10, 2 << i, 254, -1);
352     }
353 
354   for (i = 1; i < 8; ++i)
355     {
356       do_test (i, 2 * i, (8 << i) - 1, 8 << i, 127, 0);
357       do_test (i, 2 * i, 8 << i, 8 << i, 127, 0);
358       do_test (i, 2 * i, (8 << i) + 100, 8 << i, 127, 0);
359 
360       do_test (2 * i, i, (8 << i) - 1, 8 << i, 254, 0);
361       do_test (2 * i, i, 8 << i, 8 << i, 254, 0);
362       do_test (2 * i, i, (8 << i) + 100, 8 << i, 254, 0);
363 
364       do_test (i, 2 * i, 8 << i, 8 << i, 127, 1);
365       do_test (i, 2 * i, (8 << i) + 100, 8 << i, 127, 1);
366 
367       do_test (2 * i, i, 8 << i, 8 << i, 254, 1);
368       do_test (2 * i, i, (8 << i) + 100, 8 << i, 254, 1);
369 
370       do_test (i, 2 * i, 8 << i, 8 << i, 127, -1);
371       do_test (i, 2 * i, (8 << i) + 100, 8 << i, 127, -1);
372 
373       do_test (2 * i, i, 8 << i, 8 << i, 254, -1);
374       do_test (2 * i, i, (8 << i) + 100, 8 << i, 254, -1);
375     }
376 
377   do_random_tests ();
378   do_page_tests ();
379 }
380 
381 int
test_main(void)382 test_main (void)
383 {
384   test_init ();
385 
386   test_locale ("C");
387   test_locale ("en_US.ISO-8859-1");
388   test_locale ("en_US.UTF-8");
389   test_locale ("tr_TR.ISO-8859-9");
390   test_locale ("tr_TR.UTF-8");
391 
392   return ret;
393 }
394 
395 #include <support/test-driver.c>
396