1 /* Test strncpy 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 #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 *
SIMPLE_STRNCPY(CHAR * dst,const CHAR * src,size_t n)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
do_one_test(impl_t * impl,CHAR * dst,const CHAR * src,size_t len,size_t n)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
do_test(size_t align1,size_t align2,size_t len,size_t n,int max_char)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
do_page_tests(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
do_random_tests(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
test_main(void)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>
341