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 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
58CHAR *SIMPLE_STRNCPY (CHAR *, const CHAR *, size_t);
59CHAR *STUPID_STRNCPY (CHAR *, const CHAR *, size_t);
60
61IMPL (STUPID_STRNCPY, 0)
62IMPL (SIMPLE_STRNCPY, 0)
63IMPL (STRNCPY, 1)
64
65CHAR *
66SIMPLE_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
79CHAR *
80STUPID_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
93typedef CHAR *(*proto_t) (CHAR *, const CHAR *, size_t);
94
95static void
96do_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 (status: 0, errnum: 0, format: "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 (status: 0, errnum: 0, format: "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 (status: 0, errnum: 0, format: "Wrong result in function %s", impl->name);
121 ret = 1;
122 return;
123 }
124 }
125}
126
127static void
128do_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, dst: s2, src: s1, len, n);
155}
156
157static void
158do_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, dst: s2 + off2, src: s1 + off1, len: maxoffset - off1 - 1,
186 n: maxoffset + (maxoffset - off2));
187 }
188 }
189}
190
191static void
192do_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 (status: 0, errnum: 0, format: "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 (status: 0, errnum: 0, format: "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 (status: 0, errnum: 0, format: "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 (status: 0, errnum: 0, format: "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 (status: 0, errnum: 0, format: "Iteration %zd - different strings, %s (%zd, %zd, %zd)",
313 n, impl->name, align1, align2, len);
314 ret = 1;
315 }
316 }
317 }
318}
319
320int
321test_main (void)
322{
323 size_t i;
324
325 test_init ();
326
327 printf (format: "%28s", "");
328 FOR_EACH_IMPL (impl, 0)
329 printf (format: "\t%s", impl->name);
330 putchar (c: '\n');
331
332 for (i = 1; i < 8; ++i)
333 {
334 do_test (align1: i, align2: i, len: 16, n: 16, SMALL_CHAR);
335 do_test (align1: i, align2: i, len: 16, n: 16, BIG_CHAR);
336 do_test (align1: i, align2: 2 * i, len: 16, n: 16, SMALL_CHAR);
337 do_test (align1: 2 * i, align2: i, len: 16, n: 16, BIG_CHAR);
338 do_test (align1: 8 - i, align2: 2 * i, len: 1 << i, n: 2 << i, SMALL_CHAR);
339 do_test (align1: 2 * i, align2: 8 - i, len: 2 << i, n: 1 << i, SMALL_CHAR);
340 do_test (align1: 8 - i, align2: 2 * i, len: 1 << i, n: 2 << i, BIG_CHAR);
341 do_test (align1: 2 * i, align2: 8 - i, len: 2 << i, n: 1 << i, BIG_CHAR);
342 }
343
344 for (i = 1; i < 8; ++i)
345 {
346 do_test (align1: 0, align2: 0, len: 4 << i, n: 8 << i, SMALL_CHAR);
347 do_test (align1: 0, align2: 0, len: 16 << i, n: 8 << i, SMALL_CHAR);
348 do_test (align1: 8 - i, align2: 2 * i, len: 4 << i, n: 8 << i, SMALL_CHAR);
349 do_test (align1: 8 - i, align2: 2 * i, len: 16 << i, n: 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

source code of glibc/string/test-strncpy.c