<string.h>: Make strchrnul, strcasestr, memmem available by default
[platform/upstream/glibc.git] / string / test-strncpy.c
1 /* Test strncpy functions.
2    Copyright (C) 1999-2023 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 #ifdef WIDE
20 # include <wchar.h>
21 # define CHAR wchar_t
22 # define UCHAR wchar_t
23 # define BIG_CHAR WCHAR_MAX
24 # define SMALL_CHAR 1273
25 # define MEMCMP wmemcmp
26 # define MEMSET wmemset
27 # define STRNLEN wcsnlen
28 #else
29 # define CHAR char
30 # define UCHAR unsigned char
31 # define BIG_CHAR CHAR_MAX
32 # define SMALL_CHAR 127
33 # define MEMCMP memcmp
34 # define MEMSET memset
35 # define STRNLEN strnlen
36 #endif /* !WIDE */
37
38
39 #ifndef STRNCPY_RESULT
40 # define STRNCPY_RESULT(dst, len, n) dst
41 # define TEST_MAIN
42 # ifndef WIDE
43 #  define TEST_NAME "strncpy"
44 # else
45 #  define TEST_NAME "wcsncpy"
46 # endif /* WIDE */
47 # include "test-string.h"
48 # ifndef WIDE
49 #  define SIMPLE_STRNCPY simple_strncpy
50 #  define STRNCPY strncpy
51 # else
52 #  define SIMPLE_STRNCPY simple_wcsncpy
53 #  define STRNCPY wcsncpy
54 # endif /* WIDE */
55
56
57 IMPL (STRNCPY, 1)
58
59 /* Naive implementation to verify results.  */
60 CHAR *
61 SIMPLE_STRNCPY (CHAR *dst, const CHAR *src, size_t n)
62 {
63   CHAR *ret = dst;
64   while (n--)
65     if ((*dst++ = *src++) == '\0')
66       {
67         while (n--)
68           *dst++ = '\0';
69         return ret;
70       }
71   return ret;
72 }
73
74 #endif /* !STRNCPY_RESULT */
75
76 typedef CHAR *(*proto_t) (CHAR *, const CHAR *, size_t);
77
78 static void
79 do_one_test (impl_t *impl, CHAR *dst, const CHAR *src, size_t len, size_t n)
80 {
81   if (CALL (impl, dst, src, n) != STRNCPY_RESULT (dst, len, n))
82     {
83       error (0, 0, "Wrong result in function %s %p %p", impl->name,
84              CALL (impl, dst, src, n), dst);
85       ret = 1;
86       return;
87     }
88
89   if (memcmp (dst, src, (len > n ? n : len) * sizeof (CHAR)) != 0)
90     {
91       error (0, 0, "Wrong result in function %s", impl->name);
92       ret = 1;
93       return;
94     }
95
96   if (n > len)
97     {
98       size_t i;
99
100       for (i = len; i < n; ++i)
101         if (dst [i] != '\0')
102           {
103             error (0, 0, "Wrong result in function %s", impl->name);
104             ret = 1;
105             return;
106           }
107     }
108 }
109
110 static void
111 do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char)
112 {
113   size_t i;
114   CHAR *s1, *s2;
115
116 /* For wcsncpy: align1 and align2 here mean alignment not in bytes,
117    but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t)).  */
118   align1 &= 7;
119   if ((align1 + len) * sizeof (CHAR) >= page_size)
120     return;
121
122   align2 &= 7;
123   if ((align2 + len) * sizeof (CHAR) >= page_size)
124     return;
125
126   s1 = (CHAR *) (buf1) + align1;
127   s2 = (CHAR *) (buf2) + align2;
128
129   for (i = 0; i < len; ++i)
130     s1[i] = 32 + 23 * i % (max_char - 32);
131   s1[len] = 0;
132   for (i = len + 1; (i + align1) * sizeof (CHAR) < page_size && i < len + 64;
133        ++i)
134     s1[i] = 32 + 32 * i % (max_char - 32);
135
136   FOR_EACH_IMPL (impl, 0)
137     do_one_test (impl, s2, s1, len, n);
138 }
139
140 static void
141 do_page_tests (void)
142 {
143   CHAR *s1, *s2;
144   const size_t maxoffset = 64;
145
146   /* Put s1 at the maxoffset from the edge of buf1's last page.  */
147   s1 = (CHAR *) buf1 + BUF1PAGES * page_size / sizeof(CHAR) - maxoffset;
148   /* s2 needs room to put a string with size of maxoffset + 1 at s2 +
149      (maxoffset - 1).  */
150   s2 = (CHAR *) buf2 + page_size / sizeof(CHAR) - maxoffset * 2;
151
152   MEMSET (s1, 'a', maxoffset - 1);
153   s1[maxoffset - 1] = '\0';
154
155   /* Both strings are bounded to a page with read/write access and the next
156      page is protected with PROT_NONE (meaning that any access outside of the
157      page regions will trigger an invalid memory access).
158
159      The loop copies the string s1 for all possible offsets up to maxoffset
160      for both inputs with a size larger than s1 (so memory access outside the
161      expected memory regions might trigger invalid access).  */
162
163   for (size_t off1 = 0; off1 < maxoffset; off1++)
164     {
165       for (size_t off2 = 0; off2 < maxoffset; off2++)
166         {
167           FOR_EACH_IMPL (impl, 0)
168             do_one_test (impl, s2 + off2, s1 + off1, maxoffset - off1 - 1,
169                          maxoffset + (maxoffset - off2));
170         }
171     }
172 }
173
174 static void
175 do_random_tests (void)
176 {
177   size_t i, j, n, align1, align2, len, size, mode;
178   UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512;
179   UCHAR *p2 = (UCHAR *) (buf2 + page_size) - 512;
180   UCHAR *res;
181
182   for (n = 0; n < ITERATIONS; n++)
183     {
184       /* For wcsncpy: align1 and align2 here mean align not in bytes,
185          but in wchar_ts, in bytes it will equal to align * (sizeof
186          (wchar_t)).  */
187
188       mode = random ();
189       if (mode & 1)
190         {
191           size = random () & 255;
192           align1 = 512 - size - (random () & 15);
193           if (mode & 2)
194             align2 = align1 - (random () & 24);
195           else
196             align2 = align1 - (random () & 31);
197           if (mode & 4)
198             {
199               j = align1;
200               align1 = align2;
201               align2 = j;
202             }
203           if (mode & 8)
204             len = size - (random () & 31);
205           else
206             len = 512;
207           if (len >= 512)
208             len = random () & 511;
209         }
210       else
211         {
212           align1 = random () & 31;
213           if (mode & 2)
214             align2 = random () & 31;
215           else
216             align2 = align1 + (random () & 24);
217           len = random () & 511;
218           j = align1;
219           if (align2 > j)
220             j = align2;
221           if (mode & 4)
222             {
223               size = random () & 511;
224               if (size + j > 512)
225                 size = 512 - j - (random () & 31);
226             }
227           else
228             size = 512 - j;
229           if ((mode & 8) && len + j >= 512)
230             len = 512 - j - (random () & 7);
231         }
232       j = len + align1 + 64;
233       if (j > 512)
234         j = 512;
235       for (i = 0; i < j; i++)
236         {
237           if (i == len + align1)
238             p1[i] = 0;
239           else
240             {
241               p1[i] = random () & BIG_CHAR;
242               if (i >= align1 && i < len + align1 && !p1[i])
243                 p1[i] = (random () & SMALL_CHAR) + 3;
244             }
245         }
246
247       FOR_EACH_IMPL (impl, 1)
248         {
249           MEMSET (p2 - 64, '\1', 512 + 64);
250           res = (UCHAR *) CALL (impl, (CHAR *) (p2 + align2),
251                                 (CHAR *) (p1 + align1), size);
252           if (res != STRNCPY_RESULT (p2 + align2, len, size))
253             {
254               error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p",
255                      n, impl->name, align1, align2, len, res,
256                      STRNCPY_RESULT (p2 + align2, len, size));
257               ret = 1;
258             }
259           for (j = 0; j < align2 + 64; ++j)
260             {
261               if (p2[j - 64] != '\1')
262                 {
263                   error (0, 0, "Iteration %zd - garbage before, %s (%zd, %zd, %zd)",
264                          n, impl->name, align1, align2, len);
265                   ret = 1;
266                   break;
267                 }
268             }
269           j = align2 + len + 1;
270           if (size + align2 > j)
271             j = size + align2;
272           for (; j < 512; ++j)
273             {
274               if (p2[j] != '\1')
275                 {
276                   error (0, 0, "Iteration %zd - garbage after, %s (%zd, %zd, %zd)",
277                          n, impl->name, align1, align2, len);
278                   ret = 1;
279                   break;
280                 }
281             }
282           for (j = align2 + len + 1; j < align2 + size; ++j)
283             if (p2[j])
284               {
285                 error (0, 0, "Iteration %zd - garbage after size, %s (%zd, %zd, %zd)",
286                        n, impl->name, align1, align2, len);
287                 ret = 1;
288                 break;
289               }
290           j = len + 1;
291           if (size < j)
292             j = size;
293           if (MEMCMP (p1 + align1, p2 + align2, j))
294             {
295               error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)",
296                      n, impl->name, align1, align2, len);
297               ret = 1;
298             }
299         }
300     }
301 }
302
303 int
304 test_main (void)
305 {
306   size_t i;
307
308   test_init ();
309
310   printf ("%28s", "");
311   FOR_EACH_IMPL (impl, 0)
312     printf ("\t%s", impl->name);
313   putchar ('\n');
314
315   for (i = 1; i < 8; ++i)
316     {
317       do_test (i, i, 16, 16, SMALL_CHAR);
318       do_test (i, i, 16, 16, BIG_CHAR);
319       do_test (i, 2 * i, 16, 16, SMALL_CHAR);
320       do_test (2 * i, i, 16, 16, BIG_CHAR);
321       do_test (8 - i, 2 * i, 1 << i, 2 << i, SMALL_CHAR);
322       do_test (2 * i, 8 - i, 2 << i, 1 << i, SMALL_CHAR);
323       do_test (8 - i, 2 * i, 1 << i, 2 << i, BIG_CHAR);
324       do_test (2 * i, 8 - i, 2 << i, 1 << i, BIG_CHAR);
325     }
326
327   for (i = 1; i < 8; ++i)
328     {
329       do_test (0, 0, 4 << i, 8 << i, SMALL_CHAR);
330       do_test (0, 0, 16 << i, 8 << i, SMALL_CHAR);
331       do_test (8 - i, 2 * i, 4 << i, 8 << i, SMALL_CHAR);
332       do_test (8 - i, 2 * i, 16 << i, 8 << i, SMALL_CHAR);
333     }
334
335   do_random_tests ();
336   do_page_tests ();
337   return ret;
338 }
339
340 #include <support/test-driver.c>