1/* Test strlcpy functions.
2 Copyright (C) 2023-2024 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#ifndef WIDE
21# define TEST_NAME "strlcpy"
22#else
23# define TEST_NAME "wcslcpy"
24#endif /* WIDE */
25#include "test-string.h"
26
27#ifdef WIDE
28# include <wchar.h>
29# define BIG_CHAR WCHAR_MAX
30# define CHAR wchar_t
31# define MEMCMP wmemcmp
32# define MEMSET wmemset
33# define SIMPLE_STRLCPY simple_wcslcpy
34# define SMALL_CHAR 1273
35# define STRLCPY wcslcpy
36# define STRLEN wcslen
37#else
38# define BIG_CHAR CHAR_MAX
39# define CHAR char
40# define MEMCMP memcmp
41# define MEMSET memset
42# define SIMPLE_STRLCPY simple_strlcpy
43# define SMALL_CHAR 127
44# define STRLCPY strlcpy
45# define STRLEN strlen
46#endif /* !WIDE */
47
48/* Naive implementation to verify results. */
49size_t
50SIMPLE_STRLCPY (CHAR *dst, const CHAR *src, size_t n)
51{
52 size_t ret = STRLEN (src);
53
54 if (!n)
55 return ret;
56
57 while (--n)
58 if ((*dst++ = *src++) == '\0')
59 return ret;
60 *dst = '\0';
61 return ret;
62}
63
64IMPL (SIMPLE_STRLCPY, 0)
65IMPL (STRLCPY, 1)
66
67typedef size_t (*proto_t) (CHAR *, const CHAR *, size_t);
68
69static void
70do_one_test (impl_t *impl, CHAR *dst, const CHAR *src, size_t len, size_t n)
71{
72 if (CALL (impl, dst, src, n) != len)
73 {
74 error (status: 0, errnum: 0, format: "Wrong result in function %s %zd %zd", impl->name,
75 CALL (impl, dst, src, n), len);
76 ret = 1;
77 return;
78 }
79
80 if (n == 0)
81 return;
82
83 len = (len >= n ? n - 1 : len);
84 if (MEMCMP (dst, src, len) != 0)
85 {
86 error (status: 0, errnum: 0, format: "Wrong result in function1 %s", impl->name);
87 ret = 1;
88 return;
89 }
90
91 if (dst [len] != '\0')
92 {
93 error (status: 0, errnum: 0, format: "Wrong result in function2 %s", impl->name);
94 ret = 1;
95 return;
96 }
97}
98
99static void
100do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char)
101{
102 size_t i;
103 CHAR *s1, *s2;
104
105 /* For wcslcpy: align1 and align2 here mean alignment not in bytes,
106 but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t)). */
107 align1 &= 7;
108 if ((align1 + len) * sizeof (CHAR) >= page_size)
109 return;
110
111 align2 &= 7;
112 if ((align2 + len) * sizeof (CHAR) >= page_size)
113 return;
114
115 s1 = (CHAR *) (buf1) + align1;
116 s2 = (CHAR *) (buf2) + align2;
117
118 for (i = 0; i < len; ++i)
119 s1[i] = 32 + 23 * i % (max_char - 32);
120 s1[len] = 0;
121
122 FOR_EACH_IMPL (impl, 0)
123 do_one_test (impl, dst: s2, src: s1, len, n);
124}
125
126static void
127do_page_tests (void)
128{
129 CHAR *s1, *s2;
130 const size_t maxoffset = 64;
131
132 /* Put s1 at the maxoffset from the edge of buf1's last page. */
133 s1 = (CHAR *) buf1 + BUF1PAGES * page_size / sizeof(CHAR) - maxoffset;
134 /* s2 needs room to put a string with size of maxoffset + 1 at s2 +
135 (maxoffset - 1). */
136 s2 = (CHAR *) buf2 + page_size / sizeof(CHAR) - maxoffset * 2;
137
138 MEMSET (s1, 'a', maxoffset - 1);
139 s1[maxoffset - 1] = '\0';
140
141 /* Both strings are bounded to a page with read/write access and the next
142 page is protected with PROT_NONE (meaning that any access outside of the
143 page regions will trigger an invalid memory access).
144
145 The loop copies the string s1 for all possible offsets up to maxoffset
146 for both inputs with a size larger than s1 (so memory access outside the
147 expected memory regions might trigger invalid access). */
148
149 for (size_t off1 = 0; off1 < maxoffset; off1++)
150 {
151 for (size_t off2 = 0; off2 < maxoffset; off2++)
152 {
153 FOR_EACH_IMPL (impl, 0)
154 do_one_test (impl, dst: s2 + off2, src: s1 + off1, len: maxoffset - off1 - 1,
155 n: maxoffset + (maxoffset - off2));
156 }
157 }
158}
159
160static void
161do_random_tests (void)
162{
163 size_t i, j, n, align1, align2, len, size, mode;
164 CHAR *p1 = (CHAR *) (buf1 + page_size) - 1024;
165 CHAR *p2 = (CHAR *) (buf2 + page_size) - 1024;
166 size_t res;
167
168 for (n = 0; n < ITERATIONS; n++)
169 {
170 /* For wcslcpy: align1 and align2 here mean align not in bytes,
171 but in wchar_ts, in bytes it will equal to align * (sizeof
172 (wchar_t)). */
173
174 mode = random ();
175 if (mode & 1)
176 {
177 size = random () & 255;
178 align1 = 512 - size - (random () & 15);
179 if (mode & 2)
180 align2 = align1 - (random () & 24);
181 else
182 align2 = align1 - (random () & 31);
183 if (mode & 4)
184 {
185 j = align1;
186 align1 = align2;
187 align2 = j;
188 }
189 if (mode & 8)
190 len = size - (random () & 31);
191 else
192 len = 512;
193 if (len >= 512)
194 len = random () & 511;
195 }
196 else
197 {
198 align1 = random () & 31;
199 if (mode & 2)
200 align2 = random () & 31;
201 else
202 align2 = align1 + (random () & 24);
203 len = random () & 511;
204 j = align1;
205 if (align2 > j)
206 j = align2;
207 if (mode & 4)
208 {
209 size = random () & 511;
210 if (size + j > 512)
211 size = 512 - j - (random () & 31);
212 }
213 else
214 size = 512 - j;
215 if ((mode & 8) && len + j >= 512)
216 len = 512 - j - (random () & 7);
217 }
218 j = len + align1;
219 for (i = 0; i < j; i++)
220 {
221 p1[i] = random () & BIG_CHAR;
222 if (i >= align1 && i < len + align1 && !p1[i])
223 p1[i] = (random () & SMALL_CHAR) + 3;
224 }
225 p1[i] = 0;
226
227 FOR_EACH_IMPL (impl, 1)
228 {
229 MEMSET (p2 - 64, '\1', 512 + 64);
230 res = CALL (impl, (CHAR *) (p2 + align2),
231 (CHAR *) (p1 + align1), size);
232 if (res != len)
233 {
234 error (status: 0, errnum: 0, format: "Iteration %zd - wrong result in function %s (%zd, %zd) %zd != %zd",
235 n, impl->name, align1, align2, len, res);
236 ret = 1;
237 }
238 for (j = 0; j < align2 + 64; ++j)
239 {
240 if (p2[j - 64] != '\1')
241 {
242 error (status: 0, errnum: 0, format: "Iteration %zd - garbage before, %s (%zd, %zd, %zd)",
243 n, impl->name, align1, align2, len);
244 ret = 1;
245 break;
246 }
247 }
248 j = align2 + len + 1;
249 if (size + align2 > j)
250 j = size + align2;
251 for (; j < 512; ++j)
252 {
253 if (p2[j] != '\1')
254 {
255 error (status: 0, errnum: 0, format: "Iteration %zd - garbage after, %s (%zd, %zd, %zd)",
256 n, impl->name, align1, align2, len);
257 ret = 1;
258 break;
259 }
260 }
261 j = len;
262 /* Check for zero size. */
263 if (size)
264 {
265 if (size <= j)
266 j = size - 1;
267 if (MEMCMP (p1 + align1, p2 + align2, j))
268 {
269 error (status: 0, errnum: 0, format: "Iteration %zd - different strings, %s (%zd, %zd, %zd)",
270 n, impl->name, align1, align2, len);
271 ret = 1;
272 }
273 if (p2[align2 + j])
274 {
275 error (status: 0, errnum: 0, format: "Iteration %zd - garbage after size, %s (%zd, %zd, %zd)",
276 n, impl->name, align1, align2, len);
277 ret = 1;
278 break;
279 }
280 }
281 }
282 }
283}
284
285int
286test_main (void)
287{
288 size_t i;
289
290 test_init ();
291
292 printf (format: "%28s", "");
293 FOR_EACH_IMPL (impl, 0)
294 printf (format: "\t%s", impl->name);
295 putchar (c: '\n');
296
297 for (i = 1; i < 8; ++i)
298 {
299 do_test (align1: i, align2: i, len: 16, n: 16, SMALL_CHAR);
300 do_test (align1: i, align2: i, len: 16, n: 16, BIG_CHAR);
301 do_test (align1: i, align2: 2 * i, len: 16, n: 16, SMALL_CHAR);
302 do_test (align1: 2 * i, align2: i, len: 16, n: 16, BIG_CHAR);
303 do_test (align1: 8 - i, align2: 2 * i, len: 1 << i, n: 2 << i, SMALL_CHAR);
304 do_test (align1: 2 * i, align2: 8 - i, len: 2 << i, n: 1 << i, SMALL_CHAR);
305 do_test (align1: 8 - i, align2: 2 * i, len: 1 << i, n: 2 << i, BIG_CHAR);
306 do_test (align1: 2 * i, align2: 8 - i, len: 2 << i, n: 1 << i, BIG_CHAR);
307 }
308
309 for (i = 1; i < 8; ++i)
310 {
311 do_test (align1: 0, align2: 0, len: 4 << i, n: 8 << i, SMALL_CHAR);
312 do_test (align1: 0, align2: 0, len: 16 << i, n: 8 << i, SMALL_CHAR);
313 do_test (align1: 8 - i, align2: 2 * i, len: 4 << i, n: 8 << i, SMALL_CHAR);
314 do_test (align1: 8 - i, align2: 2 * i, len: 16 << i, n: 8 << i, SMALL_CHAR);
315 }
316
317 do_random_tests ();
318 do_page_tests ();
319 return ret;
320}
321
322#include <support/test-driver.c>
323

source code of glibc/string/tst-strlcpy2.c