1 /* Support for testing and measuring memcpy 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 /* This fail contains the actual memcpy test functions. It is included
20    in test-memcpy.c and test-memcpy-large.c.  They are split because
21    the tests take a long time to run and splitting them allows for
22    simpler parallel testing.  */
23 
24 #ifndef MEMCPY_RESULT
25 #define MEMCPY_RESULT(dst, len) dst
26 #define MIN_PAGE_SIZE 131072
27 #define TEST_MAIN
28 #define TEST_NAME "memcpy"
29 #define TIMEOUT (8 * 60)
30 #include "test-string.h"
31 
32 char *simple_memcpy (char *, const char *, size_t);
33 char *builtin_memcpy (char *, const char *, size_t);
34 
35 IMPL (simple_memcpy, 0)
36 IMPL (builtin_memcpy, 0)
37 IMPL (memcpy, 1)
38 char *
simple_memcpy(char * dst,const char * src,size_t n)39 simple_memcpy (char *dst, const char *src, size_t n)
40 {
41   char *ret = dst;
42   while (n--)
43     *dst++ = *src++;
44   return ret;
45 }
46 
47 char *
builtin_memcpy(char * dst,const char * src,size_t n)48 builtin_memcpy (char *dst, const char *src, size_t n)
49 {
50   return __builtin_memcpy (dst, src, n);
51 }
52 #endif
53 typedef char *(*proto_t) (char *, const char *, size_t);
54 typedef uint32_t __attribute__ ((may_alias, aligned (1))) unaligned_uint32_t;
55 
56 static void
do_one_test(impl_t * impl,char * dst,const char * src,size_t len)57 do_one_test (impl_t *impl, char *dst, const char *src, size_t len)
58 {
59   size_t i;
60 
61   /* Must clear the destination buffer set by the previous run.  */
62   for (i = 0; i < len; i++)
63     dst[i] = 0;
64 
65   if (CALL (impl, dst, src, len) != MEMCPY_RESULT (dst, len))
66     {
67       error (0, 0, "Wrong result in function %s %p %p", impl->name,
68              CALL (impl, dst, src, len), MEMCPY_RESULT (dst, len));
69       ret = 1;
70       return;
71     }
72 
73   if (memcmp (dst, src, len) != 0)
74     {
75       error (0, 0,
76              "Wrong result in function %s dst %p \"%.*s\" src %p \"%.*s\" len "
77              "%zu",
78              impl->name, dst, (int)len, dst, src, (int)len, src, len);
79       ret = 1;
80       return;
81     }
82 }
83 
84 static void
do_test(size_t align1,size_t align2,size_t len)85 do_test (size_t align1, size_t align2, size_t len)
86 {
87   size_t i, j, repeats;
88   char *s1, *s2;
89 
90   align1 &= 4095;
91   if (align1 + len >= page_size)
92     return;
93 
94   align2 &= 4095;
95   if (align2 + len >= page_size)
96     return;
97 
98   s1 = (char *)(buf1 + align1);
99   s2 = (char *)(buf2 + align2);
100   for (repeats = 0; repeats < 2; ++repeats)
101     {
102       for (i = 0, j = 1; i < len; i++, j += 23)
103         s1[i] = j;
104 
105       FOR_EACH_IMPL (impl, 0)
106       do_one_test (impl, s2, s1, len);
107     }
108 }
109 
110 static void
do_test1(size_t align1,size_t align2,size_t size)111 do_test1 (size_t align1, size_t align2, size_t size)
112 {
113   void *large_buf;
114   size_t mmap_size, region_size;
115 
116   align1 &= (page_size - 1);
117   if (align1 == 0)
118     align1 = page_size;
119 
120   align2 &= (page_size - 1);
121   if (align2 == 0)
122     align2 = page_size;
123 
124   region_size = (size + page_size - 1) & (~(page_size - 1));
125 
126   mmap_size = region_size * 2 + 3 * page_size;
127   large_buf = mmap (NULL, mmap_size, PROT_READ | PROT_WRITE,
128                     MAP_PRIVATE | MAP_ANON, -1, 0);
129   if (large_buf == MAP_FAILED)
130     {
131       puts ("Failed to allocate large_buf, skipping do_test");
132       return;
133     }
134   if (mprotect (large_buf + region_size + page_size, page_size, PROT_NONE))
135     error (EXIT_FAILURE, errno, "mprotect failed");
136 
137   size_t array_size = size / sizeof (uint32_t);
138   unaligned_uint32_t *dest = large_buf + align1;
139   unaligned_uint32_t *src = large_buf + region_size + 2 * page_size + align2;
140   size_t i;
141   size_t repeats;
142   for (repeats = 0; repeats < 2; repeats++)
143     {
144       for (i = 0; i < array_size; i++)
145         src[i] = (uint32_t)i;
146       FOR_EACH_IMPL (impl, 0)
147       {
148         memset (dest, -1, size);
149         CALL (impl, (char *)dest, (char *)src, size);
150         if (memcmp (src, dest, size))
151           {
152             for (i = 0; i < array_size; i++)
153               if (dest[i] != src[i])
154                 {
155                   error (0, 0,
156                          "Wrong result in function %s dst \"%p\" src \"%p\" "
157                          "offset \"%zd\"",
158                          impl->name, dest, src, i);
159                   ret = 1;
160                   munmap ((void *)large_buf, mmap_size);
161                   return;
162                 }
163           }
164       }
165       dest = large_buf + region_size + 2 * page_size + align1;
166       src = large_buf + align2;
167     }
168   munmap ((void *)large_buf, mmap_size);
169 }
170