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