]>
Commit | Line | Data |
---|---|---|
d183b96e | 1 | /* Test strncpy functions. |
dff8da6b | 2 | Copyright (C) 1999-2024 Free Software Foundation, Inc. |
58ef9ef7 | 3 | This file is part of the GNU C Library. |
58ef9ef7 RM |
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 | |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
58ef9ef7 | 18 | |
d183b96e SL |
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 | ||
58ef9ef7 RM |
39 | #ifndef STRNCPY_RESULT |
40 | # define STRNCPY_RESULT(dst, len, n) dst | |
41 | # define TEST_MAIN | |
d183b96e SL |
42 | # ifndef WIDE |
43 | # define TEST_NAME "strncpy" | |
44 | # else | |
45 | # define TEST_NAME "wcsncpy" | |
46 | # endif /* WIDE */ | |
58ef9ef7 | 47 | # include "test-string.h" |
d183b96e SL |
48 | # ifndef WIDE |
49 | # define SIMPLE_STRNCPY simple_strncpy | |
d183b96e SL |
50 | # define STRNCPY strncpy |
51 | # else | |
52 | # define SIMPLE_STRNCPY simple_wcsncpy | |
d183b96e SL |
53 | # define STRNCPY wcsncpy |
54 | # endif /* WIDE */ | |
58ef9ef7 | 55 | |
58ef9ef7 | 56 | |
d183b96e | 57 | IMPL (STRNCPY, 1) |
58ef9ef7 | 58 | |
67e3b0c6 | 59 | /* Naive implementation to verify results. */ |
d183b96e SL |
60 | CHAR * |
61 | SIMPLE_STRNCPY (CHAR *dst, const CHAR *src, size_t n) | |
58ef9ef7 | 62 | { |
d183b96e | 63 | CHAR *ret = dst; |
58ef9ef7 RM |
64 | while (n--) |
65 | if ((*dst++ = *src++) == '\0') | |
66 | { | |
67 | while (n--) | |
68 | *dst++ = '\0'; | |
69 | return ret; | |
70 | } | |
71 | return ret; | |
72 | } | |
e8c1660f | 73 | |
d183b96e | 74 | #endif /* !STRNCPY_RESULT */ |
58ef9ef7 | 75 | |
d183b96e | 76 | typedef CHAR *(*proto_t) (CHAR *, const CHAR *, size_t); |
58ef9ef7 RM |
77 | |
78 | static void | |
d183b96e | 79 | do_one_test (impl_t *impl, CHAR *dst, const CHAR *src, size_t len, size_t n) |
58ef9ef7 RM |
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 | ||
d183b96e | 89 | if (memcmp (dst, src, (len > n ? n : len) * sizeof (CHAR)) != 0) |
58ef9ef7 RM |
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 | } | |
58ef9ef7 RM |
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; | |
d183b96e | 114 | CHAR *s1, *s2; |
58ef9ef7 | 115 | |
d183b96e SL |
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)). */ | |
58ef9ef7 | 118 | align1 &= 7; |
d183b96e | 119 | if ((align1 + len) * sizeof (CHAR) >= page_size) |
58ef9ef7 RM |
120 | return; |
121 | ||
122 | align2 &= 7; | |
d183b96e | 123 | if ((align2 + len) * sizeof (CHAR) >= page_size) |
58ef9ef7 RM |
124 | return; |
125 | ||
d183b96e SL |
126 | s1 = (CHAR *) (buf1) + align1; |
127 | s2 = (CHAR *) (buf2) + align2; | |
58ef9ef7 RM |
128 | |
129 | for (i = 0; i < len; ++i) | |
130 | s1[i] = 32 + 23 * i % (max_char - 32); | |
131 | s1[len] = 0; | |
d183b96e SL |
132 | for (i = len + 1; (i + align1) * sizeof (CHAR) < page_size && i < len + 64; |
133 | ++i) | |
58ef9ef7 RM |
134 | s1[i] = 32 + 32 * i % (max_char - 32); |
135 | ||
58ef9ef7 RM |
136 | FOR_EACH_IMPL (impl, 0) |
137 | do_one_test (impl, s2, s1, len, n); | |
58ef9ef7 RM |
138 | } |
139 | ||
5df6ebcf RMZ |
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 | ||
58ef9ef7 RM |
174 | static void |
175 | do_random_tests (void) | |
176 | { | |
739ca690 | 177 | size_t i, j, n, align1, align2, len, size, mode; |
d183b96e SL |
178 | UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512; |
179 | UCHAR *p2 = (UCHAR *) (buf2 + page_size) - 512; | |
180 | UCHAR *res; | |
58ef9ef7 RM |
181 | |
182 | for (n = 0; n < ITERATIONS; n++) | |
183 | { | |
d183b96e SL |
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 | ||
739ca690 UD |
188 | mode = random (); |
189 | if (mode & 1) | |
58ef9ef7 | 190 | { |
739ca690 UD |
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; | |
58ef9ef7 RM |
209 | } |
210 | else | |
739ca690 UD |
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) | |
d183b96e | 225 | size = 512 - j - (random () & 31); |
739ca690 UD |
226 | } |
227 | else | |
228 | size = 512 - j; | |
229 | if ((mode & 8) && len + j >= 512) | |
230 | len = 512 - j - (random () & 7); | |
231 | } | |
58ef9ef7 RM |
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 | { | |
d183b96e | 241 | p1[i] = random () & BIG_CHAR; |
58ef9ef7 | 242 | if (i >= align1 && i < len + align1 && !p1[i]) |
d183b96e | 243 | p1[i] = (random () & SMALL_CHAR) + 3; |
58ef9ef7 RM |
244 | } |
245 | } | |
246 | ||
247 | FOR_EACH_IMPL (impl, 1) | |
248 | { | |
d183b96e SL |
249 | MEMSET (p2 - 64, '\1', 512 + 64); |
250 | res = (UCHAR *) CALL (impl, (CHAR *) (p2 + align2), | |
251 | (CHAR *) (p1 + align1), size); | |
58ef9ef7 RM |
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; | |
d183b96e | 293 | if (MEMCMP (p1 + align1, p2 + align2, j)) |
58ef9ef7 RM |
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 | { | |
d183b96e SL |
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); | |
58ef9ef7 RM |
325 | } |
326 | ||
327 | for (i = 1; i < 8; ++i) | |
328 | { | |
d183b96e SL |
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); | |
58ef9ef7 RM |
333 | } |
334 | ||
335 | do_random_tests (); | |
5df6ebcf | 336 | do_page_tests (); |
58ef9ef7 RM |
337 | return ret; |
338 | } | |
339 | ||
fb82116f | 340 | #include <support/test-driver.c> |