1 /* Test strncmp and wcsncmp 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 #define TEST_MAIN
20 #ifdef WIDE
21 # define TEST_NAME "wcsncmp"
22 #else
23 # define TEST_NAME "strncmp"
24 #endif
25 #include "test-string.h"
26 
27 #ifdef WIDE
28 # include <wchar.h>
29 
30 # define L(str) L##str
31 # define STRNCMP wcsncmp
32 # define STRCPY wcscpy
33 # define STRDUP wcsdup
34 # define MEMCPY wmemcpy
35 # define SIMPLE_STRNCMP simple_wcsncmp
36 # define STUPID_STRNCMP stupid_wcsncmp
37 # define CHAR wchar_t
38 # define UCHAR wchar_t
39 # define CHARBYTES 4
40 # define CHAR__MAX WCHAR_MAX
41 # define CHAR__MIN WCHAR_MIN
42 
43 /* Wcsncmp uses signed semantics for comparison, not unsigned.
44    Avoid using substraction since possible overflow */
45 int
simple_wcsncmp(const CHAR * s1,const CHAR * s2,size_t n)46 simple_wcsncmp (const CHAR *s1, const CHAR *s2, size_t n)
47 {
48   wchar_t c1, c2;
49 
50   while (n--)
51     {
52       c1 = *s1++;
53       c2 = *s2++;
54       if (c1 == L('\0') || c1 != c2)
55 	return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
56     }
57   return 0;
58 }
59 
60 int
stupid_wcsncmp(const CHAR * s1,const CHAR * s2,size_t n)61 stupid_wcsncmp (const CHAR *s1, const CHAR *s2, size_t n)
62 {
63   wchar_t c1, c2;
64   size_t ns1 = wcsnlen (s1, n) + 1, ns2 = wcsnlen (s2, n) + 1;
65 
66   n = ns1 < n ? ns1 : n;
67   n = ns2 < n ? ns2 : n;
68 
69   while (n--)
70     {
71       c1 = *s1++;
72       c2 = *s2++;
73       if (c1 != c2)
74 	return c1 > c2 ? 1 : -1;
75     }
76   return 0;
77 }
78 
79 #else
80 # define L(str) str
81 # define STRNCMP strncmp
82 # define STRCPY strcpy
83 # define STRDUP strdup
84 # define MEMCPY memcpy
85 # define SIMPLE_STRNCMP simple_strncmp
86 # define STUPID_STRNCMP stupid_strncmp
87 # define CHAR char
88 # define UCHAR unsigned char
89 # define CHARBYTES 1
90 # define CHAR__MAX CHAR_MAX
91 # define CHAR__MIN CHAR_MIN
92 
93 /* Strncmp uses unsigned semantics for comparison. */
94 int
simple_strncmp(const char * s1,const char * s2,size_t n)95 simple_strncmp (const char *s1, const char *s2, size_t n)
96 {
97   int ret = 0;
98 
99   while (n-- && (ret = *(unsigned char *) s1 - * (unsigned char *) s2++) == 0
100 	 && *s1++);
101   return ret;
102 }
103 
104 int
stupid_strncmp(const char * s1,const char * s2,size_t n)105 stupid_strncmp (const char *s1, const char *s2, size_t n)
106 {
107   size_t ns1 = strnlen (s1, n) + 1, ns2 = strnlen (s2, n) + 1;
108   int ret = 0;
109 
110   n = ns1 < n ? ns1 : n;
111   n = ns2 < n ? ns2 : n;
112   while (n-- && (ret = *(unsigned char *) s1++ - * (unsigned char *) s2++) == 0);
113   return ret;
114 }
115 
116 #endif
117 
118 typedef int (*proto_t) (const CHAR *, const CHAR *, size_t);
119 
120 IMPL (STUPID_STRNCMP, 0)
121 IMPL (SIMPLE_STRNCMP, 0)
122 IMPL (STRNCMP, 1)
123 
124 
125 static int
check_result(impl_t * impl,const CHAR * s1,const CHAR * s2,size_t n,int exp_result)126 check_result (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t n,
127 	     int exp_result)
128 {
129   int result = CALL (impl, s1, s2, n);
130   if ((exp_result == 0 && result != 0)
131       || (exp_result < 0 && result >= 0)
132       || (exp_result > 0 && result <= 0))
133     {
134       error (0, 0, "Wrong result in function %s %d %d", impl->name,
135 	     result, exp_result);
136       ret = 1;
137       return -1;
138     }
139 
140   return 0;
141 }
142 
143 static void
do_one_test(impl_t * impl,const CHAR * s1,const CHAR * s2,size_t n,int exp_result)144 do_one_test (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t n,
145 	     int exp_result)
146 {
147   if (check_result (impl, s1, s2, n, exp_result) < 0)
148     return;
149 }
150 
151 static void
do_test_limit(size_t align1,size_t align2,size_t len,size_t n,int max_char,int exp_result)152 do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char,
153 	 int exp_result)
154 {
155   size_t i, align_n;
156   CHAR *s1, *s2;
157 
158   align1 &= ~(CHARBYTES - 1);
159   align2 &= ~(CHARBYTES - 1);
160 
161   if (n == 0)
162     {
163       s1 = (CHAR *) (buf1 + page_size);
164       s2 = (CHAR *) (buf2 + page_size);
165 
166       FOR_EACH_IMPL (impl, 0)
167 	do_one_test (impl, s1, s2, n, 0);
168 
169       return;
170     }
171 
172   align1 &= 15;
173   align2 &= 15;
174   align_n = (page_size - n * CHARBYTES) & 15;
175 
176   s1 = (CHAR *) (buf1 + page_size - n * CHARBYTES);
177   s2 = (CHAR *) (buf2 + page_size - n * CHARBYTES);
178 
179   if (align1 < align_n)
180     s1 = (CHAR *) ((char *) s1 - (align_n - align1));
181 
182   if (align2 < align_n)
183     s2 = (CHAR *) ((char *) s2 - (align_n - align2));
184 
185   for (i = 0; i < n; i++)
186     s1[i] = s2[i] = 1 + 23 * i % max_char;
187 
188   if (len < n)
189     {
190       s1[len] = 0;
191       s2[len] = 0;
192       if (exp_result < 0)
193 	s2[len] = 32;
194       else if (exp_result > 0)
195 	s1[len] = 64;
196     }
197 
198   FOR_EACH_IMPL (impl, 0)
199     do_one_test (impl, s1, s2, n, exp_result);
200 }
201 
202 static void
do_test(size_t align1,size_t align2,size_t len,size_t n,int max_char,int exp_result)203 do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char,
204 	 int exp_result)
205 {
206   size_t i;
207   CHAR *s1, *s2;
208 
209   align1 &= ~(CHARBYTES - 1);
210   align2 &= ~(CHARBYTES - 1);
211 
212   if (n == 0)
213     return;
214 
215   align1 &= 63;
216   if (align1 + (n + 1) * CHARBYTES >= page_size)
217     return;
218 
219   align2 &= 63;
220   if (align2 + (n + 1) * CHARBYTES >= page_size)
221     return;
222 
223   s1 = (CHAR *) (buf1 + align1);
224   s2 = (CHAR *) (buf2 + align2);
225 
226   for (i = 0; i < n; i++)
227     s1[i] = s2[i] = 1 + (23 << ((CHARBYTES - 1) * 8)) * i % max_char;
228 
229   s1[n] = 24 + exp_result;
230   s2[n] = 23;
231   s1[len] = 0;
232   s2[len] = 0;
233   if (exp_result < 0)
234     s2[len] = 32;
235   else if (exp_result > 0)
236     s1[len] = 64;
237   if (len >= n)
238     s2[n - 1] -= exp_result;
239 
240   FOR_EACH_IMPL (impl, 0)
241     do_one_test (impl, s1, s2, n, exp_result);
242 }
243 
244 static void
do_page_test(size_t offset1,size_t offset2,CHAR * s2)245 do_page_test (size_t offset1, size_t offset2, CHAR *s2)
246 {
247   CHAR *s1;
248   int exp_result;
249 
250   if (offset1 * CHARBYTES  >= page_size || offset2 * CHARBYTES >= page_size)
251     return;
252 
253   s1 = (CHAR *) buf1;
254   s1 += offset1;
255   s2 += offset2;
256 
257   exp_result= *s1;
258 
259   FOR_EACH_IMPL (impl, 0)
260     {
261       check_result (impl, s1, s2, page_size, -exp_result);
262       check_result (impl, s2, s1, page_size, exp_result);
263     }
264 }
265 
266 static void
do_random_tests(void)267 do_random_tests (void)
268 {
269   size_t i, j, n, align1, align2, pos, len1, len2, size;
270   int result;
271   long r;
272   UCHAR *p1 = (UCHAR *) (buf1 + page_size - 512 * CHARBYTES);
273   UCHAR *p2 = (UCHAR *) (buf2 + page_size - 512 * CHARBYTES);
274 
275   for (n = 0; n < ITERATIONS; n++)
276     {
277       align1 = random () & 31;
278       if (random () & 1)
279 	align2 = random () & 31;
280       else
281 	align2 = align1 + (random () & 24);
282       pos = random () & 511;
283       size = random () & 511;
284       j = align1 > align2 ? align1 : align2;
285       if (pos + j >= 511)
286 	pos = 510 - j - (random () & 7);
287       len1 = random () & 511;
288       if (pos >= len1 && (random () & 1))
289 	len1 = pos + (random () & 7);
290       if (len1 + j >= 512)
291 	len1 = 511 - j - (random () & 7);
292       if (pos >= len1)
293 	len2 = len1;
294       else
295 	len2 = len1 + (len1 != 511 - j ? random () % (511 - j - len1) : 0);
296       j = (pos > len2 ? pos : len2) + align1 + 64;
297       if (j > 512)
298 	j = 512;
299       for (i = 0; i < j; ++i)
300 	{
301 	  p1[i] = random () & 255;
302 	  if (i < len1 + align1 && !p1[i])
303 	    {
304 	      p1[i] = random () & 255;
305 	      if (!p1[i])
306 		p1[i] = 1 + (random () & 127);
307 	    }
308 	}
309       for (i = 0; i < j; ++i)
310 	{
311 	  p2[i] = random () & 255;
312 	  if (i < len2 + align2 && !p2[i])
313 	    {
314 	      p2[i] = random () & 255;
315 	      if (!p2[i])
316 		p2[i] = 1 + (random () & 127);
317 	    }
318 	}
319 
320       result = 0;
321       MEMCPY (p2 + align2, p1 + align1, pos);
322       if (pos < len1)
323 	{
324 	  if (p2[align2 + pos] == p1[align1 + pos])
325 	    {
326 	      p2[align2 + pos] = random () & 255;
327 	      if (p2[align2 + pos] == p1[align1 + pos])
328 		p2[align2 + pos] = p1[align1 + pos] + 3 + (random () & 127);
329 	    }
330 
331 	  if (pos < size)
332 	    {
333 	      if (p1[align1 + pos] < p2[align2 + pos])
334 		result = -1;
335 	      else
336 		result = 1;
337 	    }
338 	}
339       p1[len1 + align1] = 0;
340       p2[len2 + align2] = 0;
341 
342       FOR_EACH_IMPL (impl, 1)
343 	{
344 	  r = CALL (impl, (CHAR *) (p1 + align1), (CHAR *) (p2 + align2), size);
345 	  /* Test whether on 64-bit architectures where ABI requires
346 	     callee to promote has the promotion been done.  */
347 	  asm ("" : "=g" (r) : "0" (r));
348 	  if ((r == 0 && result)
349 	      || (r < 0 && result >= 0)
350 	      || (r > 0 && result <= 0))
351 	    {
352 	      error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd, %zd, %zd, %zd) %ld != %d, p1 %p p2 %p",
353 		     n, impl->name, align1, align2, len1, len2, pos, size, r, result, p1, p2);
354 	      ret = 1;
355 	    }
356 	}
357     }
358 }
359 
360 static void
check1(void)361 check1 (void)
362 {
363   CHAR *s1 = (CHAR *) (buf1 + 0xb2c);
364   CHAR *s2 = (CHAR *) (buf1 + 0xfd8);
365   size_t i, offset;
366   int exp_result;
367 
368   STRCPY(s1, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs"));
369   STRCPY(s2, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkLMNOPQRSTUV"));
370 
371   /* Check possible overflow bug for wcsncmp */
372   s1[4] = CHAR__MAX;
373   s2[4] = CHAR__MIN;
374 
375   for (offset = 0; offset < 6; offset++)
376     {
377       for (i = 0; i < 80; i++)
378 	{
379 	  exp_result = SIMPLE_STRNCMP (s1 + offset, s2 + offset, i);
380 	  FOR_EACH_IMPL (impl, 0)
381 	    check_result (impl, s1 + offset, s2 + offset, i, exp_result);
382 	}
383     }
384 }
385 
386 static void
check2(void)387 check2 (void)
388 {
389   size_t i;
390   CHAR *s1, *s2;
391 
392   s1 = (CHAR *) buf1;
393   for (i = 0; i < (page_size / CHARBYTES) - 1; i++)
394     s1[i] = 23;
395   s1[i] = 0;
396 
397   s2 = STRDUP (s1);
398 
399   for (i = 0; i < 64; ++i)
400     do_page_test ((3988 / CHARBYTES) + i, (2636 / CHARBYTES), s2);
401 
402   free (s2);
403 }
404 
405 static void
check3(void)406 check3 (void)
407 {
408   /* To trigger bug 25933, we need a size that is equal to the vector
409      length times 4. In the case of AVX2 for Intel, we need 32 * 4.  We
410      make this test generic and run it for all architectures as additional
411      boundary testing for such related algorithms.  */
412   size_t size = 32 * 4;
413   CHAR *s1 = (CHAR *) (buf1 + (BUF1PAGES - 1) * page_size);
414   CHAR *s2 = (CHAR *) (buf2 + (BUF1PAGES - 1) * page_size);
415   int exp_result;
416 
417   memset (s1, 'a', page_size);
418   memset (s2, 'a', page_size);
419   s1[(page_size / CHARBYTES) - 1] = (CHAR) 0;
420 
421   /* Iterate over a size that is just below where we expect the bug to
422      trigger up to the size we expect will trigger the bug e.g. [99-128].
423      Likewise iterate the start of two strings between 30 and 31 bytes
424      away from the boundary to simulate alignment changes.  */
425   for (size_t s = 99; s <= size; s++)
426     for (size_t s1a = 30; s1a < 32; s1a++)
427       for (size_t s2a = 30; s2a < 32; s2a++)
428 	{
429 	  CHAR *s1p = s1 + (page_size / CHARBYTES - s) - s1a;
430 	  CHAR *s2p = s2 + (page_size / CHARBYTES - s) - s2a;
431 	  exp_result = SIMPLE_STRNCMP (s1p, s2p, s);
432 	  FOR_EACH_IMPL (impl, 0)
433 	    check_result (impl, s1p, s2p, s, exp_result);
434 	}
435 }
436 
437 int
test_main(void)438 test_main (void)
439 {
440   size_t i;
441 
442   test_init ();
443 
444   check1 ();
445   check2 ();
446   check3 ();
447 
448   printf ("%23s", "");
449   FOR_EACH_IMPL (impl, 0)
450     printf ("\t%s", impl->name);
451   putchar ('\n');
452 
453   for (i =0; i < 16; ++i)
454     {
455       do_test (0, 0, 8, i, 127, 0);
456       do_test (0, 0, 8, i, 127, -1);
457       do_test (0, 0, 8, i, 127, 1);
458       do_test (i, i, 8, i, 127, 0);
459       do_test (i, i, 8, i, 127, 1);
460       do_test (i, i, 8, i, 127, -1);
461       do_test (i, 2 * i, 8, i, 127, 0);
462       do_test (2 * i, i, 8, i, 127, 1);
463       do_test (i, 3 * i, 8, i, 127, -1);
464       do_test (0, 0, 8, i, 255, 0);
465       do_test (0, 0, 8, i, 255, -1);
466       do_test (0, 0, 8, i, 255, 1);
467       do_test (i, i, 8, i, 255, 0);
468       do_test (i, i, 8, i, 255, 1);
469       do_test (i, i, 8, i, 255, -1);
470       do_test (i, 2 * i, 8, i, 255, 0);
471       do_test (2 * i, i, 8, i, 255, 1);
472       do_test (i, 3 * i, 8, i, 255, -1);
473     }
474 
475   for (i = 1; i < 8; ++i)
476     {
477       do_test (0, 0, 8 << i, 16 << i, 127, 0);
478       do_test (0, 0, 8 << i, 16 << i, 127, 1);
479       do_test (0, 0, 8 << i, 16 << i, 127, -1);
480       do_test (0, 0, 8 << i, 16 << i, 255, 0);
481       do_test (0, 0, 8 << i, 16 << i, 255, 1);
482       do_test (0, 0, 8 << i, 16 << i, 255, -1);
483       do_test (8 - i, 2 * i, 8 << i, 16 << i, 127, 0);
484       do_test (8 - i, 2 * i, 8 << i, 16 << i, 127, 1);
485       do_test (2 * i, i, 8 << i, 16 << i, 255, 0);
486       do_test (2 * i, i, 8 << i, 16 << i, 255, 1);
487     }
488 
489   do_test_limit (0, 0, 0, 0, 127, 0);
490   do_test_limit (4, 0, 21, 20, 127, 0);
491   do_test_limit (0, 4, 21, 20, 127, 0);
492   do_test_limit (8, 0, 25, 24, 127, 0);
493   do_test_limit (0, 8, 25, 24, 127, 0);
494 
495   for (i = 0; i < 8; ++i)
496     {
497       do_test_limit (0, 0, 17 - i, 16 - i, 127, 0);
498       do_test_limit (0, 0, 17 - i, 16 - i, 255, 0);
499       do_test_limit (0, 0, 15 - i, 16 - i, 127, 0);
500       do_test_limit (0, 0, 15 - i, 16 - i, 127, 1);
501       do_test_limit (0, 0, 15 - i, 16 - i, 127, -1);
502       do_test_limit (0, 0, 15 - i, 16 - i, 255, 0);
503       do_test_limit (0, 0, 15 - i, 16 - i, 255, 1);
504       do_test_limit (0, 0, 15 - i, 16 - i, 255, -1);
505     }
506 
507   do_random_tests ();
508   return ret;
509 }
510 
511 #include <support/test-driver.c>
512