1 /* Test and measure memmove 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 #define TEST_MAIN
20 #ifdef TEST_BCOPY
21 # define TEST_NAME "bcopy"
22 #else
23 # define TEST_NAME "memmove"
24 #endif
25 #include "test-string.h"
26 #include <support/test-driver.h>
27 
28 char *simple_memmove (char *, const char *, size_t);
29 
30 #ifdef TEST_BCOPY
31 typedef void (*proto_t) (const char *, char *, size_t);
32 
33 IMPL (bcopy, 1)
34 
35 /* Naive implementation to verify results.  */
36 void
simple_bcopy(const char * src,char * dst,size_t n)37 simple_bcopy (const char *src, char *dst, size_t n)
38 {
39   simple_memmove (dst, src, n);
40 }
41 
42 #else
43 typedef char *(*proto_t) (char *, const char *, size_t);
44 
45 IMPL (memmove, 1)
46 #endif
47 
48 /* Naive implementation to verify results.  */
49 char *
50 inhibit_loop_to_libcall
simple_memmove(char * dst,const char * src,size_t n)51 simple_memmove (char *dst, const char *src, size_t n)
52 {
53   char *ret = dst;
54   if (src < dst)
55     {
56       dst += n;
57       src += n;
58       while (n--)
59 	*--dst = *--src;
60     }
61   else
62     while (n--)
63       *dst++ = *src++;
64   return ret;
65 }
66 
67 static void
do_one_test(impl_t * impl,char * dst,char * src,const char * orig_src,size_t len)68 do_one_test (impl_t *impl, char *dst, char *src, const char *orig_src,
69 	     size_t len)
70 {
71   /* This also clears the destination buffer set by the previous run.  */
72   memcpy (src, orig_src, len);
73 #ifdef TEST_BCOPY
74   CALL (impl, src, dst, len);
75 #else
76   char *res;
77 
78   res = CALL (impl, dst, src, len);
79   if (res != dst)
80     {
81       error (0, 0, "Wrong result in function %s %p %p", impl->name,
82 	     res, dst);
83       ret = 1;
84       return;
85     }
86 #endif
87 
88   if (memcmp (dst, orig_src, len) != 0)
89     {
90       error (0, 0, "Wrong result in function %s dst \"%s\" src \"%s\"",
91 	     impl->name, dst, src);
92       ret = 1;
93       return;
94     }
95 }
96 
97 static void
do_test(size_t align1,size_t align2,size_t len)98 do_test (size_t align1, size_t align2, size_t len)
99 {
100   size_t i, j;
101   char *s1, *s2;
102 
103   align1 &= (getpagesize() - 1);
104   if (align1 + len >= page_size)
105     return;
106 
107   align2 &= (getpagesize() - 1);
108   if (align2 + len >= page_size)
109     return;
110 
111   s1 = (char *) (buf1 + align1);
112   s2 = (char *) (buf2 + align2);
113 
114   for (i = 0, j = 1; i < len; i++, j += 23)
115     s1[i] = j;
116 
117   FOR_EACH_IMPL (impl, 0)
118     do_one_test (impl, s2, (char *) (buf2 + align1), s1, len);
119 }
120 
121 static void
do_random_tests(void)122 do_random_tests (void)
123 {
124   size_t i, n, align1, align2, len, size;
125   size_t srcstart, srcend, dststart, dstend;
126   int c;
127   unsigned char *p1, *p2;
128 #ifndef TEST_BCOPY
129   unsigned char *res;
130 #endif
131 
132   for (n = 0; n < ITERATIONS; n++)
133     {
134       if ((random () & 255) == 0)
135 	size = 65536;
136       else
137 	size = 512;
138       if (size > page_size)
139 	size = page_size;
140       if ((random () & 3) == 0)
141 	{
142 	  len = random () & (size - 1);
143 	  align1 = size - len - (random () & 31);
144 	  align2 = size - len - (random () & 31);
145 	  if (align1 > size)
146 	    align1 = 0;
147 	  if (align2 > size)
148 	    align2 = 0;
149 	}
150       else
151 	{
152 	  align1 = random () & (size / 2 - 1);
153 	  align2 = random () & (size / 2 - 1);
154 	  len = random () & (size - 1);
155 	  if (align1 + len > size)
156 	    align1 = size - len;
157 	  if (align2 + len > size)
158 	    align2 = size - len;
159 	}
160 
161       p1 = buf1 + page_size - size;
162       p2 = buf2 + page_size - size;
163       c = random () & 255;
164       srcend = align1 + len + 256;
165       if (srcend > size)
166 	srcend = size;
167       if (align1 > 256)
168 	srcstart = align1 - 256;
169       else
170 	srcstart = 0;
171       for (i = srcstart; i < srcend; ++i)
172 	p1[i] = random () & 255;
173       dstend = align2 + len + 256;
174       if (dstend > size)
175 	dstend = size;
176       if (align2 > 256)
177 	dststart = align2 - 256;
178       else
179 	dststart = 0;
180 
181       FOR_EACH_IMPL (impl, 1)
182 	{
183 	  memset (p2 + dststart, c, dstend - dststart);
184 	  memcpy (p2 + srcstart, p1 + srcstart, srcend - srcstart);
185 #ifdef TEST_BCOPY
186 	  CALL (impl, (char *) (p2 + align1), (char *) (p2 + align2), len);
187 #else
188 	  res = (unsigned char *) CALL (impl,
189 					(char *) (p2 + align2),
190 					(char *) (p2 + align1), len);
191 	  if (res != p2 + align2)
192 	    {
193 	      error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p",
194 		     n, impl->name, align1, align2, len, res, p2 + align2);
195 	      ret = 1;
196 	    }
197 #endif
198 	  if (memcmp (p1 + align1, p2 + align2, len))
199 	    {
200 	      error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)",
201 		     n, impl->name, align1, align2, len);
202 	      ret = 1;
203 	    }
204 	  for (i = dststart; i < dstend; ++i)
205 	    {
206 	      if (i >= align2 && i < align2 + len)
207 		{
208 		  i = align2 + len - 1;
209 		  continue;
210 		}
211 	      if (i >= srcstart && i < srcend)
212 		{
213 		  i = srcend - 1;
214 		  continue;
215 		}
216 	      if (p2[i] != c)
217 		{
218 		  error (0, 0, "Iteration %zd - garbage in memset area, %s (%zd, %zd, %zd)",
219 			 n, impl->name, align1, align2, len);
220 		  ret = 1;
221 		  break;
222 		}
223 	    }
224 
225 	  if (srcstart < align2
226 	      && memcmp (p2 + srcstart, p1 + srcstart,
227 			 (srcend > align2 ? align2 : srcend) - srcstart))
228 	    {
229 	      error (0, 0, "Iteration %zd - garbage before dst, %s (%zd, %zd, %zd)",
230 		     n, impl->name, align1, align2, len);
231 	      ret = 1;
232 	      break;
233 	    }
234 
235 	  i = srcstart > align2 + len ? srcstart : align2 + len;
236 	  if (srcend > align2 + len
237 	      && memcmp (p2 + i, p1 + i, srcend - i))
238 	    {
239 	      error (0, 0, "Iteration %zd - garbage after dst, %s (%zd, %zd, %zd)",
240 		     n, impl->name, align1, align2, len);
241 	      ret = 1;
242 	      break;
243 	    }
244 	}
245     }
246 }
247 
248 static void
do_test2(size_t offset)249 do_test2 (size_t offset)
250 {
251   size_t size = 0x20000000;
252   uint32_t * large_buf;
253 
254   large_buf = mmap ((void*) 0x70000000, size, PROT_READ | PROT_WRITE,
255 		    MAP_PRIVATE | MAP_ANON, -1, 0);
256 
257   if (large_buf == MAP_FAILED)
258     error (EXIT_UNSUPPORTED, errno, "Large mmap failed");
259 
260   if ((uintptr_t) large_buf > 0x80000000 - 128
261       || 0x80000000 - (uintptr_t) large_buf > 0x20000000)
262     {
263       error (0, 0, "Large mmap allocated improperly");
264       ret = EXIT_UNSUPPORTED;
265       munmap ((void *) large_buf, size);
266       return;
267     }
268 
269   size_t bytes_move = 0x80000000 - (uintptr_t) large_buf;
270   if (bytes_move + offset * sizeof (uint32_t) > size)
271     {
272       munmap ((void *) large_buf, size);
273       return;
274     }
275   size_t arr_size = bytes_move / sizeof (uint32_t);
276   size_t i;
277   size_t repeats;
278   uint32_t * src = large_buf;
279   uint32_t * dst = &large_buf[offset];
280   for (repeats = 0; repeats < 2; ++repeats)
281     {
282       FOR_EACH_IMPL (impl, 0)
283         {
284           for (i = 0; i < arr_size; i++)
285             src[i] = (uint32_t) i;
286 
287 
288 #ifdef TEST_BCOPY
289           CALL (impl, (char *) src, (char *) dst, bytes_move);
290 #else
291           CALL (impl, (char *) dst, (char *) src, bytes_move);
292 #endif
293 
294           for (i = 0; i < arr_size; i++)
295 	    {
296 	      if (dst[i] != (uint32_t) i)
297 		{
298 		  error (0, 0,
299 			 "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"",
300 			 impl->name, dst, src, i);
301 		  ret = 1;
302 		  munmap ((void *) large_buf, size);
303 		  return;
304 		}
305 	    }
306 	}
307       src = dst;
308       dst = large_buf;
309     }
310 
311   munmap ((void *) large_buf, size);
312 }
313 
314 static void
do_test3(size_t bytes_move,size_t offset)315 do_test3 (size_t bytes_move, size_t offset)
316 {
317   size_t size = bytes_move * 3;
318   uint32_t *buf;
319 
320   buf = mmap (NULL, size, PROT_READ | PROT_WRITE,
321 	      MAP_PRIVATE | MAP_ANON, -1, 0);
322 
323   if (buf == MAP_FAILED)
324     error (EXIT_UNSUPPORTED, errno, "mmap failed");
325 
326   size_t arr_size = bytes_move / sizeof (uint32_t);
327   size_t i;
328 
329   FOR_EACH_IMPL (impl, 0)
330     {
331       for (i = 0; i < arr_size; i++)
332         buf[i] = (uint32_t) i;
333 
334       uint32_t *dst = &buf[arr_size + offset];
335 
336 #ifdef TEST_BCOPY
337       CALL (impl, (char *) buf, (char *) dst, bytes_move);
338 #else
339       CALL (impl, (char *) dst, (char *) buf, bytes_move);
340 #endif
341 
342       for (i = 0; i < arr_size; i++)
343 	{
344 	  if (dst[i] != (uint32_t) i)
345 	    {
346 	      error (0, 0,
347 		     "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"",
348 		     impl->name, dst, buf, i);
349 	      ret = 1;
350 	      break;
351 	    }
352 	}
353     }
354 
355   munmap ((void *) buf, size);
356 }
357 
358 static void
do_test4(size_t bytes_move,size_t offset1,size_t offset2)359 do_test4 (size_t bytes_move, size_t offset1, size_t offset2)
360 {
361   size_t size, repeats, i;
362   uint8_t *buf, *dst, *src;
363 
364   size = bytes_move + MAX(offset1, offset2);
365   buf  = mmap(NULL, size, PROT_READ | PROT_WRITE,
366              MAP_PRIVATE | MAP_ANON, -1, 0);
367 
368   if (buf == MAP_FAILED)
369     error (EXIT_UNSUPPORTED, errno, "mmap failed");
370 
371   dst = &buf[offset1];
372   src = &buf[offset2];
373   for (repeats = 0; repeats < 2; ++repeats)
374     {
375       FOR_EACH_IMPL (impl, 0)
376         {
377           for (i = 0; i < bytes_move; i++)
378               src[i] = (uint8_t) i;
379 #ifdef TEST_BCOPY
380           CALL (impl, (char *) src, (char *) dst, bytes_move);
381 #else
382           CALL (impl, (char *) dst, (char *) src, bytes_move);
383 #endif
384           for (i = 0; i < bytes_move; i++)
385             {
386               if (dst[i] != (uint8_t) i)
387                 {
388                   error (0, 0,
389                          "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"",
390                          impl->name, dst, buf, i);
391                   ret = 1;
392                   break;
393                 }
394             }
395         }
396       dst = &buf[offset2];
397       src = &buf[offset1];
398     }
399   munmap ((void *) buf, size);
400 }
401 
402 
403 int
test_main(void)404 test_main (void)
405 {
406   size_t i;
407 
408   test_init ();
409 
410   printf ("%23s", "");
411   FOR_EACH_IMPL (impl, 0)
412     printf ("\t%s", impl->name);
413   putchar ('\n');
414 
415   for (i = 0; i < 14; ++i)
416     {
417       do_test (0, 32, 1 << i);
418       do_test (32, 0, 1 << i);
419       do_test (0, i, 1 << i);
420       do_test (i, 0, 1 << i);
421     }
422 
423   for (i = 0; i < 32; ++i)
424     {
425       do_test (0, 32, i);
426       do_test (32, 0, i);
427       do_test (0, i, i);
428       do_test (i, 0, i);
429     }
430 
431   for (i = 3; i < 32; ++i)
432     {
433       if ((i & (i - 1)) == 0)
434 	continue;
435       do_test (0, 32, 16 * i);
436       do_test (32, 0, 16 * i);
437       do_test (0, i, 16 * i);
438       do_test (i, 0, 16 * i);
439     }
440 
441   do_random_tests ();
442 
443   do_test2 (0);
444   do_test2 (33);
445   do_test2 (0x200000 - 1);
446   do_test2 (0x200000);
447   do_test2 (0x200000 + 1);
448   do_test2 (0x1000000 - 1);
449   do_test2 (0x1000000);
450   do_test2 (0x1000000 + 1);
451   do_test2 (0x4000000 - 1);
452   do_test2 (0x4000000);
453   do_test2 (0x4000000 + 1);
454 
455   /* Copy 16KB data.  */
456   do_test3 (16384, 3);
457   for (i = 4096; i <= 16384; i <<= 1)
458     {
459       do_test4 (i, 0, i);
460       do_test4 (i, 0, i - 1);
461       do_test4 (i, 0, i + 1);
462       do_test4 (i, 63, i + 63);
463       do_test4 (i, 63, i + 64);
464       do_test4 (i, 63, i);
465 
466       do_test4 (i, 0, 1);
467       do_test4 (i, 0, 15);
468       do_test4 (i, 0, 31);
469       do_test4 (i, 0, 63);
470       do_test4 (i, 0, 64);
471       do_test4 (i, 0, 65);
472       do_test4 (i, 0, 127);
473       do_test4 (i, 0, 129);
474     }
475 
476 
477   return ret;
478 }
479 
480 #include <support/test-driver.c>
481