1 | /* Tester for string functions. |
2 | Copyright (C) 1995-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 | #ifndef _GNU_SOURCE |
20 | #define _GNU_SOURCE |
21 | #endif |
22 | |
23 | /* Make sure we don't test the optimized inline functions if we want to |
24 | test the real implementation. */ |
25 | #if !defined DO_STRING_INLINES |
26 | #undef __USE_STRING_INLINES |
27 | #endif |
28 | |
29 | #include <sys/cdefs.h> |
30 | #include <libc-diag.h> |
31 | |
32 | /* Triggered by strncpy fortify wrapper when it is enabled. */ |
33 | #if __GNUC_PREREQ (8, 0) |
34 | DIAG_IGNORE_NEEDS_COMMENT (8, "-Wstringop-truncation" ); |
35 | #endif |
36 | |
37 | /* When building with fortify enabled, GCC < 12 issues a warning on the |
38 | fortify strncat wrapper might overflow the destination buffer (the |
39 | failure is tied to -Werror). |
40 | Triggered by strncat fortify wrapper when it is enabled. */ |
41 | #if __GNUC_PREREQ (11, 0) |
42 | DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overread" ); |
43 | #endif |
44 | |
45 | #include <errno.h> |
46 | #include <stdint.h> |
47 | #include <stdio.h> |
48 | #include <stdlib.h> |
49 | #include <string.h> |
50 | #include <strings.h> |
51 | #include <fcntl.h> |
52 | |
53 | /* This file tests a range of corner cases of string functions, |
54 | including cases where truncation occurs or where sizes specified |
55 | are larger than the actual buffers, which result in various |
56 | warnings. */ |
57 | DIAG_IGNORE_NEEDS_COMMENT (8, "-Warray-bounds" ); |
58 | DIAG_IGNORE_NEEDS_COMMENT (5.0, "-Wmemset-transposed-args" ); |
59 | #if __GNUC_PREREQ (7, 0) |
60 | DIAG_IGNORE_NEEDS_COMMENT (9, "-Wrestrict" ); |
61 | DIAG_IGNORE_NEEDS_COMMENT (7, "-Wstringop-overflow=" ); |
62 | #endif |
63 | |
64 | |
65 | #define STREQ(a, b) (strcmp((a), (b)) == 0) |
66 | |
67 | const char *it = "<UNSET>" ; /* Routine name for message routines. */ |
68 | size_t errors = 0; |
69 | |
70 | /* Complain if condition is not true. */ |
71 | static void |
72 | check (int thing, int number) |
73 | { |
74 | if (!thing) |
75 | { |
76 | printf (format: "%s flunked test %d\n" , it, number); |
77 | ++errors; |
78 | } |
79 | } |
80 | |
81 | /* Complain if first two args don't strcmp as equal. */ |
82 | static void |
83 | equal (const char *a, const char *b, int number) |
84 | { |
85 | check (thing: a != NULL && b != NULL && STREQ (a, b), number); |
86 | } |
87 | |
88 | char one[50]; |
89 | char two[50]; |
90 | char *cp; |
91 | |
92 | static void |
93 | test_strcmp (void) |
94 | { |
95 | it = "strcmp" ; |
96 | check (thing: strcmp ("" , "" ) == 0, number: 1); /* Trivial case. */ |
97 | check (thing: strcmp ("a" , "a" ) == 0, number: 2); /* Identity. */ |
98 | check (thing: strcmp ("abc" , "abc" ) == 0, number: 3); /* Multicharacter. */ |
99 | check (thing: strcmp ("abc" , "abcd" ) < 0, number: 4); /* Length mismatches. */ |
100 | check (thing: strcmp ("abcd" , "abc" ) > 0, number: 5); |
101 | check (thing: strcmp ("abcd" , "abce" ) < 0, number: 6); /* Honest miscompares. */ |
102 | check (thing: strcmp ("abce" , "abcd" ) > 0, number: 7); |
103 | check (thing: strcmp ("a\203" , "a" ) > 0, number: 8); /* Tricky if char signed. */ |
104 | check (thing: strcmp ("a\203" , "a\003" ) > 0, number: 9); |
105 | |
106 | { |
107 | char buf1[0x40], buf2[0x40]; |
108 | int i, j; |
109 | for (i=0; i < 0x10; i++) |
110 | for (j = 0; j < 0x10; j++) |
111 | { |
112 | int k; |
113 | for (k = 0; k < 0x3f; k++) |
114 | { |
115 | buf1[k] = '0' ^ (k & 4); |
116 | buf2[k] = '4' ^ (k & 4); |
117 | } |
118 | buf1[i] = buf1[0x3f] = 0; |
119 | buf2[j] = buf2[0x3f] = 0; |
120 | for (k = 0; k < 0xf; k++) |
121 | { |
122 | int cnum = 0x10+0x10*k+0x100*j+0x1000*i; |
123 | check (thing: strcmp (buf1+i,buf2+j) == 0, number: cnum); |
124 | buf1[i+k] = 'A' + i + k; |
125 | buf1[i+k+1] = 0; |
126 | check (thing: strcmp (buf1+i,buf2+j) > 0, number: cnum+1); |
127 | check (thing: strcmp (buf2+j,buf1+i) < 0, number: cnum+2); |
128 | buf2[j+k] = 'B' + i + k; |
129 | buf2[j+k+1] = 0; |
130 | check (thing: strcmp (buf1+i,buf2+j) < 0, number: cnum+3); |
131 | check (thing: strcmp (buf2+j,buf1+i) > 0, number: cnum+4); |
132 | buf2[j+k] = 'A' + i + k; |
133 | buf1[i] = 'A' + i + 0x80; |
134 | check (thing: strcmp (buf1+i,buf2+j) > 0, number: cnum+5); |
135 | check (thing: strcmp (buf2+j,buf1+i) < 0, number: cnum+6); |
136 | buf1[i] = 'A' + i; |
137 | } |
138 | } |
139 | } |
140 | } |
141 | |
142 | #define SIMPLE_COPY(fn, n, str, ntest) \ |
143 | do { \ |
144 | int __n; \ |
145 | char *cp; \ |
146 | for (__n = 0; __n < (int) sizeof (one); ++__n) \ |
147 | one[__n] = 'Z'; \ |
148 | fn (one, str); \ |
149 | for (cp = one, __n = 0; __n < n; ++__n, ++cp) \ |
150 | check (*cp == '0' + (n % 10), ntest); \ |
151 | check (*cp == '\0', ntest); \ |
152 | } while (0) |
153 | |
154 | static void |
155 | test_strcpy (void) |
156 | { |
157 | int i; |
158 | it = "strcpy" ; |
159 | check (thing: strcpy (one, "abcd" ) == one, number: 1); /* Returned value. */ |
160 | equal (a: one, b: "abcd" , number: 2); /* Basic test. */ |
161 | |
162 | (void) strcpy (one, "x" ); |
163 | equal (a: one, b: "x" , number: 3); /* Writeover. */ |
164 | equal (a: one+2, b: "cd" , number: 4); /* Wrote too much? */ |
165 | |
166 | (void) strcpy (two, "hi there" ); |
167 | (void) strcpy (one, two); |
168 | equal (a: one, b: "hi there" , number: 5); /* Basic test encore. */ |
169 | equal (a: two, b: "hi there" , number: 6); /* Stomped on source? */ |
170 | |
171 | (void) strcpy (one, "" ); |
172 | equal (a: one, b: "" , number: 7); /* Boundary condition. */ |
173 | |
174 | for (i = 0; i < 16; i++) |
175 | { |
176 | (void) strcpy (one + i, "hi there" ); /* Unaligned destination. */ |
177 | equal (a: one + i, b: "hi there" , number: 8 + (i * 2)); |
178 | (void) strcpy (two, one + i); /* Unaligned source. */ |
179 | equal (a: two, b: "hi there" , number: 9 + (i * 2)); |
180 | } |
181 | |
182 | SIMPLE_COPY(strcpy, 0, "" , 41); |
183 | SIMPLE_COPY(strcpy, 1, "1" , 42); |
184 | SIMPLE_COPY(strcpy, 2, "22" , 43); |
185 | SIMPLE_COPY(strcpy, 3, "333" , 44); |
186 | SIMPLE_COPY(strcpy, 4, "4444" , 45); |
187 | SIMPLE_COPY(strcpy, 5, "55555" , 46); |
188 | SIMPLE_COPY(strcpy, 6, "666666" , 47); |
189 | SIMPLE_COPY(strcpy, 7, "7777777" , 48); |
190 | SIMPLE_COPY(strcpy, 8, "88888888" , 49); |
191 | SIMPLE_COPY(strcpy, 9, "999999999" , 50); |
192 | SIMPLE_COPY(strcpy, 10, "0000000000" , 51); |
193 | SIMPLE_COPY(strcpy, 11, "11111111111" , 52); |
194 | SIMPLE_COPY(strcpy, 12, "222222222222" , 53); |
195 | SIMPLE_COPY(strcpy, 13, "3333333333333" , 54); |
196 | SIMPLE_COPY(strcpy, 14, "44444444444444" , 55); |
197 | SIMPLE_COPY(strcpy, 15, "555555555555555" , 56); |
198 | SIMPLE_COPY(strcpy, 16, "6666666666666666" , 57); |
199 | |
200 | /* Simple test using implicitly coerced `void *' arguments. */ |
201 | const void *src = "frobozz" ; |
202 | void *dst = one; |
203 | check (thing: strcpy (dst, src) == dst, number: 1); |
204 | equal (a: dst, b: "frobozz" , number: 2); |
205 | } |
206 | |
207 | static void |
208 | test_stpcpy (void) |
209 | { |
210 | it = "stpcpy" ; |
211 | check (thing: (stpcpy (one, "a" ) - one) == 1, number: 1); |
212 | equal (a: one, b: "a" , number: 2); |
213 | |
214 | check (thing: (stpcpy (one, "ab" ) - one) == 2, number: 3); |
215 | equal (a: one, b: "ab" , number: 4); |
216 | |
217 | check (thing: (stpcpy (one, "abc" ) - one) == 3, number: 5); |
218 | equal (a: one, b: "abc" , number: 6); |
219 | |
220 | check (thing: (stpcpy (one, "abcd" ) - one) == 4, number: 7); |
221 | equal (a: one, b: "abcd" , number: 8); |
222 | |
223 | check (thing: (stpcpy (one, "abcde" ) - one) == 5, number: 9); |
224 | equal (a: one, b: "abcde" , number: 10); |
225 | |
226 | check (thing: (stpcpy (one, "abcdef" ) - one) == 6, number: 11); |
227 | equal (a: one, b: "abcdef" , number: 12); |
228 | |
229 | check (thing: (stpcpy (one, "abcdefg" ) - one) == 7, number: 13); |
230 | equal (a: one, b: "abcdefg" , number: 14); |
231 | |
232 | check (thing: (stpcpy (one, "abcdefgh" ) - one) == 8, number: 15); |
233 | equal (a: one, b: "abcdefgh" , number: 16); |
234 | |
235 | check (thing: (stpcpy (one, "abcdefghi" ) - one) == 9, number: 17); |
236 | equal (a: one, b: "abcdefghi" , number: 18); |
237 | |
238 | check (thing: (stpcpy (one, "x" ) - one) == 1, number: 19); |
239 | equal (a: one, b: "x" , number: 20); /* Writeover. */ |
240 | equal (a: one+2, b: "cdefghi" , number: 21); /* Wrote too much? */ |
241 | |
242 | check (thing: (stpcpy (one, "xx" ) - one) == 2, number: 22); |
243 | equal (a: one, b: "xx" , number: 23); /* Writeover. */ |
244 | equal (a: one+3, b: "defghi" , number: 24); /* Wrote too much? */ |
245 | |
246 | check (thing: (stpcpy (one, "xxx" ) - one) == 3, number: 25); |
247 | equal (a: one, b: "xxx" , number: 26); /* Writeover. */ |
248 | equal (a: one+4, b: "efghi" , number: 27); /* Wrote too much? */ |
249 | |
250 | check (thing: (stpcpy (one, "xxxx" ) - one) == 4, number: 28); |
251 | equal (a: one, b: "xxxx" , number: 29); /* Writeover. */ |
252 | equal (a: one+5, b: "fghi" , number: 30); /* Wrote too much? */ |
253 | |
254 | check (thing: (stpcpy (one, "xxxxx" ) - one) == 5, number: 31); |
255 | equal (a: one, b: "xxxxx" , number: 32); /* Writeover. */ |
256 | equal (a: one+6, b: "ghi" , number: 33); /* Wrote too much? */ |
257 | |
258 | check (thing: (stpcpy (one, "xxxxxx" ) - one) == 6, number: 34); |
259 | equal (a: one, b: "xxxxxx" , number: 35); /* Writeover. */ |
260 | equal (a: one+7, b: "hi" , number: 36); /* Wrote too much? */ |
261 | |
262 | check (thing: (stpcpy (one, "xxxxxxx" ) - one) == 7, number: 37); |
263 | equal (a: one, b: "xxxxxxx" , number: 38); /* Writeover. */ |
264 | equal (a: one+8, b: "i" , number: 39); /* Wrote too much? */ |
265 | |
266 | check (thing: (stpcpy (stpcpy (stpcpy (one, "a" ), "b" ), "c" ) - one) == 3, number: 40); |
267 | equal (a: one, b: "abc" , number: 41); |
268 | equal (a: one + 4, b: "xxx" , number: 42); |
269 | |
270 | SIMPLE_COPY(stpcpy, 0, "" , 43); |
271 | SIMPLE_COPY(stpcpy, 1, "1" , 44); |
272 | SIMPLE_COPY(stpcpy, 2, "22" , 45); |
273 | SIMPLE_COPY(stpcpy, 3, "333" , 46); |
274 | SIMPLE_COPY(stpcpy, 4, "4444" , 47); |
275 | SIMPLE_COPY(stpcpy, 5, "55555" , 48); |
276 | SIMPLE_COPY(stpcpy, 6, "666666" , 49); |
277 | SIMPLE_COPY(stpcpy, 7, "7777777" , 50); |
278 | SIMPLE_COPY(stpcpy, 8, "88888888" , 51); |
279 | SIMPLE_COPY(stpcpy, 9, "999999999" , 52); |
280 | SIMPLE_COPY(stpcpy, 10, "0000000000" , 53); |
281 | SIMPLE_COPY(stpcpy, 11, "11111111111" , 54); |
282 | SIMPLE_COPY(stpcpy, 12, "222222222222" , 55); |
283 | SIMPLE_COPY(stpcpy, 13, "3333333333333" , 56); |
284 | SIMPLE_COPY(stpcpy, 14, "44444444444444" , 57); |
285 | SIMPLE_COPY(stpcpy, 15, "555555555555555" , 58); |
286 | SIMPLE_COPY(stpcpy, 16, "6666666666666666" , 59); |
287 | } |
288 | |
289 | static void |
290 | test_stpncpy (void) |
291 | { |
292 | it = "stpncpy" ; |
293 | memset (one, 'x', sizeof (one)); |
294 | check (thing: stpncpy (dest: one, src: "abc" , n: 2) == one + 2, number: 1); |
295 | check (thing: stpncpy (dest: one, src: "abc" , n: 3) == one + 3, number: 2); |
296 | check (thing: stpncpy (dest: one, src: "abc" , n: 4) == one + 3, number: 3); |
297 | check (thing: one[3] == '\0' && one[4] == 'x', number: 4); |
298 | check (thing: stpncpy (dest: one, src: "abcd" , n: 5) == one + 4, number: 5); |
299 | check (thing: one[4] == '\0' && one[5] == 'x', number: 6); |
300 | check (thing: stpncpy (dest: one, src: "abcd" , n: 6) == one + 4, number: 7); |
301 | check (thing: one[4] == '\0' && one[5] == '\0' && one[6] == 'x', number: 8); |
302 | } |
303 | |
304 | static void |
305 | test_strcat (void) |
306 | { |
307 | it = "strcat" ; |
308 | (void) strcpy (one, "ijk" ); |
309 | check (thing: strcat (one, "lmn" ) == one, number: 1); /* Returned value. */ |
310 | equal (a: one, b: "ijklmn" , number: 2); /* Basic test. */ |
311 | |
312 | (void) strcpy (one, "x" ); |
313 | (void) strcat (one, "yz" ); |
314 | equal (a: one, b: "xyz" , number: 3); /* Writeover. */ |
315 | equal (a: one+4, b: "mn" , number: 4); /* Wrote too much? */ |
316 | |
317 | (void) strcpy (one, "gh" ); |
318 | (void) strcpy (two, "ef" ); |
319 | (void) strcat (one, two); |
320 | equal (a: one, b: "ghef" , number: 5); /* Basic test encore. */ |
321 | equal (a: two, b: "ef" , number: 6); /* Stomped on source? */ |
322 | |
323 | (void) strcpy (one, "" ); |
324 | (void) strcat (one, "" ); |
325 | equal (a: one, b: "" , number: 7); /* Boundary conditions. */ |
326 | (void) strcpy (one, "ab" ); |
327 | (void) strcat (one, "" ); |
328 | equal (a: one, b: "ab" , number: 8); |
329 | (void) strcpy (one, "" ); |
330 | (void) strcat (one, "cd" ); |
331 | equal (a: one, b: "cd" , number: 9); |
332 | |
333 | int ntest = 10; |
334 | char buf1[80] __attribute__ ((aligned (16))); |
335 | char buf2[32] __attribute__ ((aligned (16))); |
336 | for (size_t n1 = 0; n1 < 16; ++n1) |
337 | for (size_t n2 = 0; n2 < 16; ++n2) |
338 | for (size_t n3 = 0; n3 < 32; ++n3) |
339 | { |
340 | size_t olderrors = errors; |
341 | |
342 | memset (buf1, 'b', sizeof (buf1)); |
343 | |
344 | memset (buf1 + n2, 'a', n3); |
345 | buf1[n2 + n3] = '\0'; |
346 | strcpy (buf2 + n1, "123" ); |
347 | |
348 | check (thing: strcat (buf1 + n2, buf2 + n1) == buf1 + n2, number: ntest); |
349 | if (errors == olderrors) |
350 | for (size_t i = 0; i < sizeof (buf1); ++i) |
351 | { |
352 | if (i < n2) |
353 | check (thing: buf1[i] == 'b', number: ntest); |
354 | else if (i < n2 + n3) |
355 | check (thing: buf1[i] == 'a', number: ntest); |
356 | else if (i < n2 + n3 + 3) |
357 | check (thing: buf1[i] == "123" [i - (n2 + n3)], number: ntest); |
358 | else if (i == n2 + n3 + 3) |
359 | check (thing: buf1[i] == '\0', number: ntest); |
360 | else |
361 | check (thing: buf1[i] == 'b', number: ntest); |
362 | |
363 | if (errors != olderrors) |
364 | { |
365 | printf (format: "n1=%zu, n2=%zu, n3=%zu, buf1=%02hhx" , |
366 | n1, n2, n3, buf1[0]); |
367 | for (size_t j = 1; j < sizeof (buf1); ++j) |
368 | printf (format: ",%02hhx" , buf1[j]); |
369 | putchar_unlocked (c: '\n'); |
370 | break; |
371 | } |
372 | } |
373 | } |
374 | } |
375 | |
376 | static void |
377 | test_strncat (void) |
378 | { |
379 | /* First test it as strcat, with big counts, then test the count |
380 | mechanism. */ |
381 | it = "strncat" ; |
382 | (void) strcpy (one, "ijk" ); |
383 | check (thing: strncat (dest: one, src: "lmn" , n: 99) == one, number: 1); /* Returned value. */ |
384 | equal (a: one, b: "ijklmn" , number: 2); /* Basic test. */ |
385 | |
386 | (void) strcpy (one, "x" ); |
387 | (void) strncat (dest: one, src: "yz" , n: 99); |
388 | equal (a: one, b: "xyz" , number: 3); /* Writeover. */ |
389 | equal (a: one+4, b: "mn" , number: 4); /* Wrote too much? */ |
390 | |
391 | (void) strcpy (one, "gh" ); |
392 | (void) strcpy (two, "ef" ); |
393 | /* When building with fortify enabled, GCC 6 issues an warning the fortify |
394 | wrapper might overflow the destination buffer. However, GCC does not |
395 | provide a specific flag to disable the warning (the failure is tied to |
396 | -Werror). So to avoid disable all errors, only enable the check for |
397 | GCC 7 or newer. */ |
398 | #if __GNUC_PREREQ (7, 0) |
399 | (void) strncat (one, two, 99); |
400 | equal (one, "ghef" , 5); /* Basic test encore. */ |
401 | #else |
402 | equal (a: one, b: "gh" , number: 2); |
403 | #endif |
404 | equal (a: two, b: "ef" , number: 6); /* Stomped on source? */ |
405 | |
406 | (void) strcpy (one, "" ); |
407 | (void) strncat (dest: one, src: "" , n: 99); |
408 | equal (a: one, b: "" , number: 7); /* Boundary conditions. */ |
409 | (void) strcpy (one, "ab" ); |
410 | (void) strncat (dest: one, src: "" , n: 99); |
411 | equal (a: one, b: "ab" , number: 8); |
412 | (void) strcpy (one, "" ); |
413 | (void) strncat (dest: one, src: "cd" , n: 99); |
414 | equal (a: one, b: "cd" , number: 9); |
415 | |
416 | (void) strcpy (one, "ab" ); |
417 | (void) strncat (dest: one, src: "cdef" , n: 2); |
418 | equal (a: one, b: "abcd" , number: 10); /* Count-limited. */ |
419 | |
420 | (void) strncat (dest: one, src: "gh" , n: 0); |
421 | equal (a: one, b: "abcd" , number: 11); /* Zero count. */ |
422 | |
423 | (void) strncat (dest: one, src: "gh" , n: 2); |
424 | equal (a: one, b: "abcdgh" , number: 12); /* Count and length equal. */ |
425 | |
426 | (void) strncat (dest: one, src: "ij" , n: (size_t)-1); /* set sign bit in count */ |
427 | equal (a: one, b: "abcdghij" , number: 13); |
428 | |
429 | int ntest = 14; |
430 | char buf1[80] __attribute__ ((aligned (16))); |
431 | char buf2[32] __attribute__ ((aligned (16))); |
432 | for (size_t n1 = 0; n1 < 16; ++n1) |
433 | for (size_t n2 = 0; n2 < 16; ++n2) |
434 | for (size_t n3 = 0; n3 < 32; ++n3) |
435 | for (size_t n4 = 0; n4 < 16; ++n4) |
436 | { |
437 | size_t olderrors = errors; |
438 | |
439 | memset (buf1, 'b', sizeof (buf1)); |
440 | |
441 | memset (buf1 + n2, 'a', n3); |
442 | buf1[n2 + n3] = '\0'; |
443 | strcpy (buf2 + n1, "123" ); |
444 | |
445 | check (thing: strncat (dest: buf1 + n2, src: buf2 + n1, n: ~((size_t) 0) - n4) |
446 | == buf1 + n2, number: ntest); |
447 | if (errors == olderrors) |
448 | for (size_t i = 0; i < sizeof (buf1); ++i) |
449 | { |
450 | if (i < n2) |
451 | check (thing: buf1[i] == 'b', number: ntest); |
452 | else if (i < n2 + n3) |
453 | check (thing: buf1[i] == 'a', number: ntest); |
454 | else if (i < n2 + n3 + 3) |
455 | check (thing: buf1[i] == "123" [i - (n2 + n3)], number: ntest); |
456 | else if (i == n2 + n3 + 3) |
457 | check (thing: buf1[i] == '\0', number: ntest); |
458 | else |
459 | check (thing: buf1[i] == 'b', number: ntest); |
460 | |
461 | if (errors != olderrors) |
462 | { |
463 | printf (format: "n1=%zu, n2=%zu, n3=%zu, n4=%zu, buf1=%02hhx" , |
464 | n1, n2, n3, n4, buf1[0]); |
465 | for (size_t j = 1; j < sizeof (buf1); ++j) |
466 | printf (format: ",%02hhx" , buf1[j]); |
467 | putchar_unlocked (c: '\n'); |
468 | break; |
469 | } |
470 | } |
471 | } |
472 | } |
473 | |
474 | static void |
475 | test_strncmp (void) |
476 | { |
477 | /* First test as strcmp with big counts, then test count code. */ |
478 | it = "strncmp" ; |
479 | check (thing: strncmp ("" , "" , 99) == 0, number: 1); /* Trivial case. */ |
480 | check (thing: strncmp ("a" , "a" , 99) == 0, number: 2); /* Identity. */ |
481 | check (thing: strncmp ("abc" , "abc" , 99) == 0, number: 3); /* Multicharacter. */ |
482 | check (thing: strncmp ("abc" , "abcd" , 99) < 0, number: 4); /* Length unequal. */ |
483 | check (thing: strncmp ("abcd" , "abc" , 99) > 0, number: 5); |
484 | check (thing: strncmp ("abcd" , "abce" , 99) < 0, number: 6); /* Honestly unequal. */ |
485 | check (thing: strncmp ("abce" , "abcd" , 99) > 0, number: 7); |
486 | check (thing: strncmp ("a\203" , "a" , 2) > 0, number: 8); /* Tricky if '\203' < 0 */ |
487 | check (thing: strncmp ("a\203" , "a\003" , 2) > 0, number: 9); |
488 | check (thing: strncmp ("abce" , "abcd" , 3) == 0, number: 10); /* Count limited. */ |
489 | check (thing: strncmp ("abce" , "abc" , 3) == 0, number: 11); /* Count == length. */ |
490 | check (thing: strncmp ("abcd" , "abce" , 4) < 0, number: 12); /* Nudging limit. */ |
491 | check (thing: strncmp ("abc" , "def" , 0) == 0, number: 13); /* Zero count. */ |
492 | check (thing: strncmp ("abc" , "" , (size_t)-1) > 0, number: 14); /* set sign bit in count */ |
493 | check (thing: strncmp ("abc" , "abc" , (size_t)-2) == 0, number: 15); |
494 | } |
495 | |
496 | static void |
497 | test_strncpy (void) |
498 | { |
499 | /* Testing is a bit different because of odd semantics. */ |
500 | it = "strncpy" ; |
501 | check (thing: strncpy (one, "abc" , 4) == one, number: 1); /* Returned value. */ |
502 | equal (a: one, b: "abc" , number: 2); /* Did the copy go right? */ |
503 | |
504 | (void) strcpy (one, "abcdefgh" ); |
505 | (void) strncpy (one, "xyz" , 2); |
506 | equal (a: one, b: "xycdefgh" , number: 3); /* Copy cut by count. */ |
507 | |
508 | (void) strcpy (one, "abcdefgh" ); |
509 | (void) strncpy (one, "xyz" , 3); /* Copy cut just before NUL. */ |
510 | equal (a: one, b: "xyzdefgh" , number: 4); |
511 | |
512 | (void) strcpy (one, "abcdefgh" ); |
513 | (void) strncpy (one, "xyz" , 4); /* Copy just includes NUL. */ |
514 | equal (a: one, b: "xyz" , number: 5); |
515 | equal (a: one+4, b: "efgh" , number: 6); /* Wrote too much? */ |
516 | |
517 | (void) strcpy (one, "abcdefgh" ); |
518 | (void) strncpy (one, "xyz" , 5); /* Copy includes padding. */ |
519 | equal (a: one, b: "xyz" , number: 7); |
520 | equal (a: one+4, b: "" , number: 8); |
521 | equal (a: one+5, b: "fgh" , number: 9); |
522 | |
523 | (void) strcpy (one, "abc" ); |
524 | (void) strncpy (one, "xyz" , 0); /* Zero-length copy. */ |
525 | equal (a: one, b: "abc" , number: 10); |
526 | |
527 | (void) strncpy (one, "" , 2); /* Zero-length source. */ |
528 | equal (a: one, b: "" , number: 11); |
529 | equal (a: one+1, b: "" , number: 12); |
530 | equal (a: one+2, b: "c" , number: 13); |
531 | |
532 | (void) strcpy (one, "hi there" ); |
533 | (void) strncpy (two, one, 9); |
534 | equal (a: two, b: "hi there" , number: 14); /* Just paranoia. */ |
535 | equal (a: one, b: "hi there" , number: 15); /* Stomped on source? */ |
536 | } |
537 | |
538 | static void |
539 | test_strlen (void) |
540 | { |
541 | it = "strlen" ; |
542 | check (thing: strlen ("" ) == 0, number: 1); /* Empty. */ |
543 | check (thing: strlen ("a" ) == 1, number: 2); /* Single char. */ |
544 | check (thing: strlen ("abcd" ) == 4, number: 3); /* Multiple chars. */ |
545 | { |
546 | char buf[4096]; |
547 | int i; |
548 | char *p; |
549 | for (i=0; i < 0x100; i++) |
550 | { |
551 | p = (char *) ((uintptr_t)(buf + 0xff) & ~0xff) + i; |
552 | strcpy (p, "OK" ); |
553 | strcpy (p+3, "BAD/WRONG" ); |
554 | check (thing: strlen (p) == 2, number: 4+i); |
555 | } |
556 | } |
557 | } |
558 | |
559 | static void |
560 | test_strnlen (void) |
561 | { |
562 | it = "strnlen" ; |
563 | check (thing: strnlen ("" , 10) == 0, number: 1); /* Empty. */ |
564 | check (thing: strnlen ("a" , 10) == 1, number: 2); /* Single char. */ |
565 | check (thing: strnlen ("abcd" , 10) == 4, number: 3); /* Multiple chars. */ |
566 | check (thing: strnlen ("foo" , (size_t) -1) == 3, number: 4); /* limits of n. */ |
567 | check (thing: strnlen ("abcd" , 0) == 0, number: 5); /* Restricted. */ |
568 | check (thing: strnlen ("abcd" , 1) == 1, number: 6); /* Restricted. */ |
569 | check (thing: strnlen ("abcd" , 2) == 2, number: 7); /* Restricted. */ |
570 | check (thing: strnlen ("abcd" , 3) == 3, number: 8); /* Restricted. */ |
571 | check (thing: strnlen ("abcd" , 4) == 4, number: 9); /* Restricted. */ |
572 | |
573 | char buf[4096]; |
574 | for (int i = 0; i < 0x100; ++i) |
575 | { |
576 | char *p = (char *) ((uintptr_t)(buf + 0xff) & ~0xff) + i; |
577 | strcpy (p, "OK" ); |
578 | strcpy (p + 3, "BAD/WRONG" ); |
579 | check (thing: strnlen (p, 100) == 2, number: 10 + i); |
580 | } |
581 | } |
582 | |
583 | static void |
584 | test_strchr (void) |
585 | { |
586 | it = "strchr" ; |
587 | check (thing: strchr ("abcd" , 'z') == NULL, number: 1); /* Not found. */ |
588 | (void) strcpy (one, "abcd" ); |
589 | check (thing: strchr (one, 'c') == one+2, number: 2); /* Basic test. */ |
590 | check (thing: strchr (one, 'd') == one+3, number: 3); /* End of string. */ |
591 | check (thing: strchr (one, 'a') == one, number: 4); /* Beginning. */ |
592 | check (thing: strchr (one, '\0') == one+4, number: 5); /* Finding NUL. */ |
593 | (void) strcpy (one, "ababa" ); |
594 | check (thing: strchr (one, 'b') == one+1, number: 6); /* Finding first. */ |
595 | (void) strcpy (one, "" ); |
596 | check (thing: strchr (one, 'b') == NULL, number: 7); /* Empty string. */ |
597 | check (thing: strchr (one, '\0') == one, number: 8); /* NUL in empty string. */ |
598 | { |
599 | char buf[4096]; |
600 | int i; |
601 | char *p; |
602 | for (i=0; i < 0x100; i++) |
603 | { |
604 | p = (char *) ((uintptr_t) (buf + 0xff) & ~0xff) + i; |
605 | strcpy (p, "OK" ); |
606 | strcpy (p+3, "BAD/WRONG" ); |
607 | check (thing: strchr (p, '/') == NULL, number: 9+i); |
608 | } |
609 | } |
610 | } |
611 | |
612 | static void |
613 | test_strchrnul (void) |
614 | { |
615 | const char *os; |
616 | it = "strchrnul" ; |
617 | cp = strchrnul (s: (os = "abcd" ), c: 'z'); |
618 | check (thing: *cp == '\0', number: 1); /* Not found. */ |
619 | check (thing: cp == os + 4, number: 2); |
620 | (void) strcpy (one, "abcd" ); |
621 | check (thing: strchrnul (s: one, c: 'c') == one+2, number: 3); /* Basic test. */ |
622 | check (thing: strchrnul (s: one, c: 'd') == one+3, number: 4); /* End of string. */ |
623 | check (thing: strchrnul (s: one, c: 'a') == one, number: 5); /* Beginning. */ |
624 | check (thing: strchrnul (s: one, c: '\0') == one+4, number: 6); /* Finding NUL. */ |
625 | (void) strcpy (one, "ababa" ); |
626 | check (thing: strchrnul (s: one, c: 'b') == one+1, number: 7); /* Finding first. */ |
627 | (void) strcpy (one, "" ); |
628 | check (thing: strchrnul (s: one, c: 'b') == one, number: 8); /* Empty string. */ |
629 | check (thing: strchrnul (s: one, c: '\0') == one, number: 9); /* NUL in empty string. */ |
630 | { |
631 | char buf[4096]; |
632 | int i; |
633 | char *p; |
634 | for (i=0; i < 0x100; i++) |
635 | { |
636 | p = (char *) ((uintptr_t) (buf + 0xff) & ~0xff) + i; |
637 | strcpy (p, "OK" ); |
638 | strcpy (p+3, "BAD/WRONG" ); |
639 | cp = strchrnul (s: p, c: '/'); |
640 | check (thing: *cp == '\0', number: 9+2*i); |
641 | check (thing: cp == p+2, number: 10+2*i); |
642 | } |
643 | } |
644 | } |
645 | |
646 | static void |
647 | test_rawmemchr (void) |
648 | { |
649 | it = "rawmemchr" ; |
650 | (void) strcpy (one, "abcd" ); |
651 | check (thing: rawmemchr (s: one, c: 'c') == one+2, number: 1); /* Basic test. */ |
652 | check (thing: rawmemchr (s: one, c: 'd') == one+3, number: 2); /* End of string. */ |
653 | check (thing: rawmemchr (s: one, c: 'a') == one, number: 3); /* Beginning. */ |
654 | check (thing: rawmemchr (s: one, c: '\0') == one+4, number: 4); /* Finding NUL. */ |
655 | (void) strcpy (one, "ababa" ); |
656 | check (thing: rawmemchr (s: one, c: 'b') == one+1, number: 5); /* Finding first. */ |
657 | (void) strcpy (one, "" ); |
658 | check (thing: rawmemchr (s: one, c: '\0') == one, number: 6); /* NUL in empty string. */ |
659 | { |
660 | char buf[4096]; |
661 | int i; |
662 | char *p; |
663 | for (i=0; i < 0x100; i++) |
664 | { |
665 | p = (char *) ((uintptr_t) (buf + 0xff) & ~0xff) + i; |
666 | strcpy (p, "OK" ); |
667 | strcpy (p+3, "BAD/WRONG" ); |
668 | check (thing: rawmemchr (s: p, c: 'R') == p+8, number: 6+i); |
669 | } |
670 | } |
671 | } |
672 | |
673 | static void |
674 | test_index (void) |
675 | { |
676 | it = "index" ; |
677 | check (thing: index (s: "abcd" , c: 'z') == NULL, number: 1); /* Not found. */ |
678 | (void) strcpy (one, "abcd" ); |
679 | check (thing: index (s: one, c: 'c') == one+2, number: 2); /* Basic test. */ |
680 | check (thing: index (s: one, c: 'd') == one+3, number: 3); /* End of string. */ |
681 | check (thing: index (s: one, c: 'a') == one, number: 4); /* Beginning. */ |
682 | check (thing: index (s: one, c: '\0') == one+4, number: 5); /* Finding NUL. */ |
683 | (void) strcpy (one, "ababa" ); |
684 | check (thing: index (s: one, c: 'b') == one+1, number: 6); /* Finding first. */ |
685 | (void) strcpy (one, "" ); |
686 | check (thing: index (s: one, c: 'b') == NULL, number: 7); /* Empty string. */ |
687 | check (thing: index (s: one, c: '\0') == one, number: 8); /* NUL in empty string. */ |
688 | } |
689 | |
690 | static void |
691 | test_strrchr (void) |
692 | { |
693 | it = "strrchr" ; |
694 | check (thing: strrchr ("abcd" , 'z') == NULL, number: 1); /* Not found. */ |
695 | (void) strcpy (one, "abcd" ); |
696 | check (thing: strrchr (one, 'c') == one+2, number: 2); /* Basic test. */ |
697 | check (thing: strrchr (one, 'd') == one+3, number: 3); /* End of string. */ |
698 | check (thing: strrchr (one, 'a') == one, number: 4); /* Beginning. */ |
699 | check (thing: strrchr (one, '\0') == one+4, number: 5); /* Finding NUL. */ |
700 | (void) strcpy (one, "ababa" ); |
701 | check (thing: strrchr (one, 'b') == one+3, number: 6); /* Finding last. */ |
702 | (void) strcpy (one, "" ); |
703 | check (thing: strrchr (one, 'b') == NULL, number: 7); /* Empty string. */ |
704 | check (thing: strrchr (one, '\0') == one, number: 8); /* NUL in empty string. */ |
705 | { |
706 | char buf[4096]; |
707 | int i; |
708 | char *p; |
709 | for (i=0; i < 0x100; i++) |
710 | { |
711 | p = (char *) ((uintptr_t) (buf + 0xff) & ~0xff) + i; |
712 | strcpy (p, "OK" ); |
713 | strcpy (p+3, "BAD/WRONG" ); |
714 | check (thing: strrchr (p, '/') == NULL, number: 9+i); |
715 | } |
716 | } |
717 | } |
718 | |
719 | static void |
720 | test_memrchr (void) |
721 | { |
722 | size_t l; |
723 | it = "memrchr" ; |
724 | check (thing: memrchr (s: "abcd" , c: 'z', n: 5) == NULL, number: 1); /* Not found. */ |
725 | (void) strcpy (one, "abcd" ); |
726 | l = strlen (one) + 1; |
727 | check (thing: memrchr (s: one, c: 'c', n: l) == one+2, number: 2); /* Basic test. */ |
728 | check (thing: memrchr (s: one, c: 'd', n: l) == one+3, number: 3); /* End of string. */ |
729 | check (thing: memrchr (s: one, c: 'a', n: l) == one, number: 4); /* Beginning. */ |
730 | check (thing: memrchr (s: one, c: '\0', n: l) == one+4, number: 5); /* Finding NUL. */ |
731 | (void) strcpy (one, "ababa" ); |
732 | l = strlen (one) + 1; |
733 | check (thing: memrchr (s: one, c: 'b', n: l) == one+3, number: 6); /* Finding last. */ |
734 | (void) strcpy (one, "" ); |
735 | l = strlen (one) + 1; |
736 | check (thing: memrchr (s: one, c: 'b', n: l) == NULL, number: 7); /* Empty string. */ |
737 | check (thing: memrchr (s: one, c: '\0', n: l) == one, number: 8); /* NUL in empty string. */ |
738 | |
739 | /* now test all possible alignment and length combinations to catch |
740 | bugs due to unrolled loops (assuming unrolling is limited to no |
741 | more than 128 byte chunks: */ |
742 | { |
743 | char buf[128 + sizeof (long)]; |
744 | long align, len, i, pos, n = 9; |
745 | |
746 | for (align = 0; align < (long) sizeof (long); ++align) { |
747 | for (len = 0; len < (long) (sizeof (buf) - align); ++len) { |
748 | for (i = 0; i < len; ++i) |
749 | buf[align + i] = 'x'; /* don't depend on memset... */ |
750 | |
751 | for (pos = len - 1; pos >= 0; --pos) { |
752 | #if 0 |
753 | printf("align %d, len %d, pos %d\n" , align, len, pos); |
754 | #endif |
755 | check(thing: memrchr(s: buf + align, c: 'x', n: len) == buf + align + pos, number: n++); |
756 | check(thing: memrchr(s: buf + align + pos + 1, c: 'x', n: len - (pos + 1)) == NULL, |
757 | number: n++); |
758 | buf[align + pos] = '-'; |
759 | } |
760 | } |
761 | } |
762 | } |
763 | } |
764 | |
765 | static void |
766 | test_rindex (void) |
767 | { |
768 | it = "rindex" ; |
769 | check (thing: rindex (s: "abcd" , c: 'z') == NULL, number: 1); /* Not found. */ |
770 | (void) strcpy (one, "abcd" ); |
771 | check (thing: rindex (s: one, c: 'c') == one+2, number: 2); /* Basic test. */ |
772 | check (thing: rindex (s: one, c: 'd') == one+3, number: 3); /* End of string. */ |
773 | check (thing: rindex (s: one, c: 'a') == one, number: 4); /* Beginning. */ |
774 | check (thing: rindex (s: one, c: '\0') == one+4, number: 5); /* Finding NUL. */ |
775 | (void) strcpy (one, "ababa" ); |
776 | check (thing: rindex (s: one, c: 'b') == one+3, number: 6); /* Finding last. */ |
777 | (void) strcpy (one, "" ); |
778 | check (thing: rindex (s: one, c: 'b') == NULL, number: 7); /* Empty string. */ |
779 | check (thing: rindex (s: one, c: '\0') == one, number: 8); /* NUL in empty string. */ |
780 | } |
781 | |
782 | static void |
783 | test_strpbrk (void) |
784 | { |
785 | it = "strpbrk" ; |
786 | check(thing: strpbrk("abcd" , "z" ) == NULL, number: 1); /* Not found. */ |
787 | (void) strcpy(one, "abcd" ); |
788 | check(thing: strpbrk(one, "c" ) == one+2, number: 2); /* Basic test. */ |
789 | check(thing: strpbrk(one, "d" ) == one+3, number: 3); /* End of string. */ |
790 | check(thing: strpbrk(one, "a" ) == one, number: 4); /* Beginning. */ |
791 | check(thing: strpbrk(one, "" ) == NULL, number: 5); /* Empty search list. */ |
792 | check(thing: strpbrk(one, "cb" ) == one+1, number: 6); /* Multiple search. */ |
793 | (void) strcpy(one, "abcabdea" ); |
794 | check(thing: strpbrk(one, "b" ) == one+1, number: 7); /* Finding first. */ |
795 | check(thing: strpbrk(one, "cb" ) == one+1, number: 8); /* With multiple search. */ |
796 | check(thing: strpbrk(one, "db" ) == one+1, number: 9); /* Another variant. */ |
797 | (void) strcpy(one, "" ); |
798 | check(thing: strpbrk(one, "bc" ) == NULL, number: 10); /* Empty string. */ |
799 | (void) strcpy(one, "" ); |
800 | check(thing: strpbrk(one, "bcd" ) == NULL, number: 11); /* Empty string. */ |
801 | (void) strcpy(one, "" ); |
802 | check(thing: strpbrk(one, "bcde" ) == NULL, number: 12); /* Empty string. */ |
803 | check(thing: strpbrk(one, "" ) == NULL, number: 13); /* Both strings empty. */ |
804 | (void) strcpy(one, "abcabdea" ); |
805 | check(thing: strpbrk(one, "befg" ) == one+1, number: 14); /* Finding first. */ |
806 | check(thing: strpbrk(one, "cbr" ) == one+1, number: 15); /* With multiple search. */ |
807 | check(thing: strpbrk(one, "db" ) == one+1, number: 16); /* Another variant. */ |
808 | check(thing: strpbrk(one, "efgh" ) == one+6, number: 17); /* And yet another. */ |
809 | } |
810 | |
811 | static void |
812 | test_strstr (void) |
813 | { |
814 | it = "strstr" ; |
815 | check(thing: strstr("abcd" , "z" ) == NULL, number: 1); /* Not found. */ |
816 | check(thing: strstr("abcd" , "abx" ) == NULL, number: 2); /* Dead end. */ |
817 | (void) strcpy(one, "abcd" ); |
818 | check(thing: strstr(one, "c" ) == one+2, number: 3); /* Basic test. */ |
819 | check(thing: strstr(one, "bc" ) == one+1, number: 4); /* Multichar. */ |
820 | check(thing: strstr(one, "d" ) == one+3, number: 5); /* End of string. */ |
821 | check(thing: strstr(one, "cd" ) == one+2, number: 6); /* Tail of string. */ |
822 | check(thing: strstr(one, "abc" ) == one, number: 7); /* Beginning. */ |
823 | check(thing: strstr(one, "abcd" ) == one, number: 8); /* Exact match. */ |
824 | check(thing: strstr(one, "abcde" ) == NULL, number: 9); /* Too long. */ |
825 | check(thing: strstr(one, "de" ) == NULL, number: 10); /* Past end. */ |
826 | check(thing: strstr(one, "" ) == one, number: 11); /* Finding empty. */ |
827 | (void) strcpy(one, "ababa" ); |
828 | check(thing: strstr(one, "ba" ) == one+1, number: 12); /* Finding first. */ |
829 | (void) strcpy(one, "" ); |
830 | check(thing: strstr(one, "b" ) == NULL, number: 13); /* Empty string. */ |
831 | check(thing: strstr(one, "" ) == one, number: 14); /* Empty in empty string. */ |
832 | (void) strcpy(one, "bcbca" ); |
833 | check(thing: strstr(one, "bca" ) == one+2, number: 15); /* False start. */ |
834 | (void) strcpy(one, "bbbcabbca" ); |
835 | check(thing: strstr(one, "bbca" ) == one+1, number: 16); /* With overlap. */ |
836 | } |
837 | |
838 | static void |
839 | test_strspn (void) |
840 | { |
841 | it = "strspn" ; |
842 | check(thing: strspn("abcba" , "abc" ) == 5, number: 1); /* Whole string. */ |
843 | check(thing: strspn("abcba" , "ab" ) == 2, number: 2); /* Partial. */ |
844 | check(thing: strspn("abc" , "qx" ) == 0, number: 3); /* None. */ |
845 | check(thing: strspn("" , "ab" ) == 0, number: 4); /* Null string. */ |
846 | check(thing: strspn("abc" , "" ) == 0, number: 5); /* Null search list. */ |
847 | } |
848 | |
849 | static void |
850 | test_strcspn (void) |
851 | { |
852 | it = "strcspn" ; |
853 | check(thing: strcspn("abcba" , "qx" ) == 5, number: 1); /* Whole string. */ |
854 | check(thing: strcspn("abcba" , "cx" ) == 2, number: 2); /* Partial. */ |
855 | check(thing: strcspn("abc" , "abc" ) == 0, number: 3); /* None. */ |
856 | check(thing: strcspn("" , "ab" ) == 0, number: 4); /* Null string. */ |
857 | check(thing: strcspn("abc" , "" ) == 3, number: 5); /* Null search list. */ |
858 | } |
859 | |
860 | static void |
861 | test_strtok (void) |
862 | { |
863 | it = "strtok" ; |
864 | (void) strcpy(one, "first, second, third" ); |
865 | equal(a: strtok(s: one, delim: ", " ), b: "first" , number: 1); /* Basic test. */ |
866 | equal(a: one, b: "first" , number: 2); |
867 | equal(a: strtok(s: (char *)NULL, delim: ", " ), b: "second" , number: 3); |
868 | equal(a: strtok(s: (char *)NULL, delim: ", " ), b: "third" , number: 4); |
869 | check(thing: strtok(s: (char *)NULL, delim: ", " ) == NULL, number: 5); |
870 | (void) strcpy(one, ", first, " ); |
871 | equal(a: strtok(s: one, delim: ", " ), b: "first" , number: 6); /* Extra delims, 1 tok. */ |
872 | check(thing: strtok(s: (char *)NULL, delim: ", " ) == NULL, number: 7); |
873 | (void) strcpy(one, "1a, 1b; 2a, 2b" ); |
874 | equal(a: strtok(s: one, delim: ", " ), b: "1a" , number: 8); /* Changing delim lists. */ |
875 | equal(a: strtok(s: (char *)NULL, delim: "; " ), b: "1b" , number: 9); |
876 | equal(a: strtok(s: (char *)NULL, delim: ", " ), b: "2a" , number: 10); |
877 | (void) strcpy(two, "x-y" ); |
878 | equal(a: strtok(s: two, delim: "-" ), b: "x" , number: 11); /* New string before done. */ |
879 | equal(a: strtok(s: (char *)NULL, delim: "-" ), b: "y" , number: 12); |
880 | check(thing: strtok(s: (char *)NULL, delim: "-" ) == NULL, number: 13); |
881 | (void) strcpy(one, "a,b, c,, ,d" ); |
882 | equal(a: strtok(s: one, delim: ", " ), b: "a" , number: 14); /* Different separators. */ |
883 | equal(a: strtok(s: (char *)NULL, delim: ", " ), b: "b" , number: 15); |
884 | equal(a: strtok(s: (char *)NULL, delim: " ," ), b: "c" , number: 16); /* Permute list too. */ |
885 | equal(a: strtok(s: (char *)NULL, delim: " ," ), b: "d" , number: 17); |
886 | check(thing: strtok(s: (char *)NULL, delim: ", " ) == NULL, number: 18); |
887 | check(thing: strtok(s: (char *)NULL, delim: ", " ) == NULL, number: 19); /* Persistence. */ |
888 | (void) strcpy(one, ", " ); |
889 | check(thing: strtok(s: one, delim: ", " ) == NULL, number: 20); /* No tokens. */ |
890 | (void) strcpy(one, "" ); |
891 | check(thing: strtok(s: one, delim: ", " ) == NULL, number: 21); /* Empty string. */ |
892 | (void) strcpy(one, "abc" ); |
893 | equal(a: strtok(s: one, delim: ", " ), b: "abc" , number: 22); /* No delimiters. */ |
894 | check(thing: strtok(s: (char *)NULL, delim: ", " ) == NULL, number: 23); |
895 | (void) strcpy(one, "abc" ); |
896 | equal(a: strtok(s: one, delim: "" ), b: "abc" , number: 24); /* Empty delimiter list. */ |
897 | check(thing: strtok(s: (char *)NULL, delim: "" ) == NULL, number: 25); |
898 | (void) strcpy(one, "abcdefgh" ); |
899 | (void) strcpy(one, "a,b,c" ); |
900 | equal(a: strtok(s: one, delim: "," ), b: "a" , number: 26); /* Basics again... */ |
901 | equal(a: strtok(s: (char *)NULL, delim: "," ), b: "b" , number: 27); |
902 | equal(a: strtok(s: (char *)NULL, delim: "," ), b: "c" , number: 28); |
903 | check(thing: strtok(s: (char *)NULL, delim: "," ) == NULL, number: 29); |
904 | equal(a: one+6, b: "gh" , number: 30); /* Stomped past end? */ |
905 | equal(a: one, b: "a" , number: 31); /* Stomped old tokens? */ |
906 | equal(a: one+2, b: "b" , number: 32); |
907 | equal(a: one+4, b: "c" , number: 33); |
908 | } |
909 | |
910 | static void |
911 | test_strtok_r (void) |
912 | { |
913 | it = "strtok_r" ; |
914 | (void) strcpy(one, "first, second, third" ); |
915 | cp = NULL; /* Always initialize cp to make sure it doesn't point to some old data. */ |
916 | equal(a: strtok_r(s: one, delim: ", " , save_ptr: &cp), b: "first" , number: 1); /* Basic test. */ |
917 | equal(a: one, b: "first" , number: 2); |
918 | equal(a: strtok_r(s: (char *)NULL, delim: ", " , save_ptr: &cp), b: "second" , number: 3); |
919 | equal(a: strtok_r(s: (char *)NULL, delim: ", " , save_ptr: &cp), b: "third" , number: 4); |
920 | check(thing: strtok_r(s: (char *)NULL, delim: ", " , save_ptr: &cp) == NULL, number: 5); |
921 | (void) strcpy(one, ", first, " ); |
922 | cp = NULL; |
923 | equal(a: strtok_r(s: one, delim: ", " , save_ptr: &cp), b: "first" , number: 6); /* Extra delims, 1 tok. */ |
924 | check(thing: strtok_r(s: (char *)NULL, delim: ", " , save_ptr: &cp) == NULL, number: 7); |
925 | (void) strcpy(one, "1a, 1b; 2a, 2b" ); |
926 | cp = NULL; |
927 | equal(a: strtok_r(s: one, delim: ", " , save_ptr: &cp), b: "1a" , number: 8); /* Changing delim lists. */ |
928 | equal(a: strtok_r(s: (char *)NULL, delim: "; " , save_ptr: &cp), b: "1b" , number: 9); |
929 | equal(a: strtok_r(s: (char *)NULL, delim: ", " , save_ptr: &cp), b: "2a" , number: 10); |
930 | (void) strcpy(two, "x-y" ); |
931 | cp = NULL; |
932 | equal(a: strtok_r(s: two, delim: "-" , save_ptr: &cp), b: "x" , number: 11); /* New string before done. */ |
933 | equal(a: strtok_r(s: (char *)NULL, delim: "-" , save_ptr: &cp), b: "y" , number: 12); |
934 | check(thing: strtok_r(s: (char *)NULL, delim: "-" , save_ptr: &cp) == NULL, number: 13); |
935 | (void) strcpy(one, "a,b, c,, ,d" ); |
936 | cp = NULL; |
937 | equal(a: strtok_r(s: one, delim: ", " , save_ptr: &cp), b: "a" , number: 14); /* Different separators. */ |
938 | equal(a: strtok_r(s: (char *)NULL, delim: ", " , save_ptr: &cp), b: "b" , number: 15); |
939 | equal(a: strtok_r(s: (char *)NULL, delim: " ," , save_ptr: &cp), b: "c" , number: 16); /* Permute list too. */ |
940 | equal(a: strtok_r(s: (char *)NULL, delim: " ," , save_ptr: &cp), b: "d" , number: 17); |
941 | check(thing: strtok_r(s: (char *)NULL, delim: ", " , save_ptr: &cp) == NULL, number: 18); |
942 | check(thing: strtok_r(s: (char *)NULL, delim: ", " , save_ptr: &cp) == NULL, number: 19); /* Persistence. */ |
943 | (void) strcpy(one, ", " ); |
944 | cp = NULL; |
945 | check(thing: strtok_r(s: one, delim: ", " , save_ptr: &cp) == NULL, number: 20); /* No tokens. */ |
946 | (void) strcpy(one, "" ); |
947 | cp = NULL; |
948 | check(thing: strtok_r(s: one, delim: ", " , save_ptr: &cp) == NULL, number: 21); /* Empty string. */ |
949 | check(thing: strtok_r(s: (char *)NULL, delim: ", " , save_ptr: &cp) == NULL, number: 22); /* Persistence. */ |
950 | (void) strcpy(one, "abc" ); |
951 | cp = NULL; |
952 | equal(a: strtok_r(s: one, delim: ", " , save_ptr: &cp), b: "abc" , number: 23); /* No delimiters. */ |
953 | check(thing: strtok_r(s: (char *)NULL, delim: ", " , save_ptr: &cp) == NULL, number: 24); |
954 | (void) strcpy(one, "abc" ); |
955 | cp = NULL; |
956 | equal(a: strtok_r(s: one, delim: "" , save_ptr: &cp), b: "abc" , number: 25); /* Empty delimiter list. */ |
957 | check(thing: strtok_r(s: (char *)NULL, delim: "" , save_ptr: &cp) == NULL, number: 26); |
958 | (void) strcpy(one, "abcdefgh" ); |
959 | (void) strcpy(one, "a,b,c" ); |
960 | cp = NULL; |
961 | equal(a: strtok_r(s: one, delim: "," , save_ptr: &cp), b: "a" , number: 27); /* Basics again... */ |
962 | equal(a: strtok_r(s: (char *)NULL, delim: "," , save_ptr: &cp), b: "b" , number: 28); |
963 | equal(a: strtok_r(s: (char *)NULL, delim: "," , save_ptr: &cp), b: "c" , number: 29); |
964 | check(thing: strtok_r(s: (char *)NULL, delim: "," , save_ptr: &cp) == NULL, number: 30); |
965 | equal(a: one+6, b: "gh" , number: 31); /* Stomped past end? */ |
966 | equal(a: one, b: "a" , number: 32); /* Stomped old tokens? */ |
967 | equal(a: one+2, b: "b" , number: 33); |
968 | equal(a: one+4, b: "c" , number: 34); |
969 | strcpy (one, ":::" ); |
970 | cp = NULL; |
971 | check (thing: strtok_r (s: one, delim: ":" , save_ptr: &cp) == NULL, number: 35); /* Must store pointer in cp. */ |
972 | check (thing: strtok_r (NULL, delim: ":" , save_ptr: &cp) == NULL, number: 36); |
973 | } |
974 | |
975 | static void |
976 | test_strsep (void) |
977 | { |
978 | char *ptr; |
979 | it = "strsep" ; |
980 | cp = strcpy(one, "first, second, third" ); |
981 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "first" , number: 1); /* Basic test. */ |
982 | equal(a: one, b: "first" , number: 2); |
983 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 3); |
984 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "second" , number: 4); |
985 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 5); |
986 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "third" , number: 6); |
987 | check(thing: strsep(stringp: &cp, delim: ", " ) == NULL, number: 7); |
988 | cp = strcpy(one, ", first, " ); |
989 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 8); |
990 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 9); |
991 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "first" , number: 10); /* Extra delims, 1 tok. */ |
992 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 11); |
993 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 12); |
994 | check(thing: strsep(stringp: &cp, delim: ", " ) == NULL, number: 13); |
995 | cp = strcpy(one, "1a, 1b; 2a, 2b" ); |
996 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "1a" , number: 14); /* Changing delim lists. */ |
997 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 15); |
998 | equal(a: strsep(stringp: &cp, delim: "; " ), b: "1b" , number: 16); |
999 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 17); |
1000 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "2a" , number: 18); |
1001 | cp = strcpy(two, "x-y" ); |
1002 | equal(a: strsep(stringp: &cp, delim: "-" ), b: "x" , number: 19); /* New string before done. */ |
1003 | equal(a: strsep(stringp: &cp, delim: "-" ), b: "y" , number: 20); |
1004 | check(thing: strsep(stringp: &cp, delim: "-" ) == NULL, number: 21); |
1005 | cp = strcpy(one, "a,b, c,, ,d " ); |
1006 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "a" , number: 22); /* Different separators. */ |
1007 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "b" , number: 23); |
1008 | equal(a: strsep(stringp: &cp, delim: " ," ), b: "" , number: 24); |
1009 | equal(a: strsep(stringp: &cp, delim: " ," ), b: "c" , number: 25); /* Permute list too. */ |
1010 | equal(a: strsep(stringp: &cp, delim: " ," ), b: "" , number: 26); |
1011 | equal(a: strsep(stringp: &cp, delim: " ," ), b: "" , number: 27); |
1012 | equal(a: strsep(stringp: &cp, delim: " ," ), b: "" , number: 28); |
1013 | equal(a: strsep(stringp: &cp, delim: " ," ), b: "d" , number: 29); |
1014 | equal(a: strsep(stringp: &cp, delim: " ," ), b: "" , number: 30); |
1015 | check(thing: strsep(stringp: &cp, delim: ", " ) == NULL, number: 31); |
1016 | check(thing: strsep(stringp: &cp, delim: ", " ) == NULL, number: 32); /* Persistence. */ |
1017 | cp = strcpy(one, ", " ); |
1018 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 33); |
1019 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 34); |
1020 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 35); |
1021 | check(thing: strsep(stringp: &cp, delim: ", " ) == NULL, number: 36); /* No tokens. */ |
1022 | cp = strcpy(one, "" ); |
1023 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "" , number: 37); |
1024 | check(thing: strsep(stringp: &cp, delim: ", " ) == NULL, number: 38); /* Empty string. */ |
1025 | cp = strcpy(one, "abc" ); |
1026 | equal(a: strsep(stringp: &cp, delim: ", " ), b: "abc" , number: 39); /* No delimiters. */ |
1027 | check(thing: strsep(stringp: &cp, delim: ", " ) == NULL, number: 40); |
1028 | cp = strcpy(one, "abc" ); |
1029 | equal(a: strsep(stringp: &cp, delim: "" ), b: "abc" , number: 41); /* Empty delimiter list. */ |
1030 | check(thing: strsep(stringp: &cp, delim: "" ) == NULL, number: 42); |
1031 | (void) strcpy(one, "abcdefgh" ); |
1032 | cp = strcpy(one, "a,b,c" ); |
1033 | equal(a: strsep(stringp: &cp, delim: "," ), b: "a" , number: 43); /* Basics again... */ |
1034 | equal(a: strsep(stringp: &cp, delim: "," ), b: "b" , number: 44); |
1035 | equal(a: strsep(stringp: &cp, delim: "," ), b: "c" , number: 45); |
1036 | check(thing: strsep(stringp: &cp, delim: "," ) == NULL, number: 46); |
1037 | equal(a: one+6, b: "gh" , number: 47); /* Stomped past end? */ |
1038 | equal(a: one, b: "a" , number: 48); /* Stomped old tokens? */ |
1039 | equal(a: one+2, b: "b" , number: 49); |
1040 | equal(a: one+4, b: "c" , number: 50); |
1041 | |
1042 | { |
1043 | char text[] = "This,is,a,test" ; |
1044 | char *list = strdupa (text); |
1045 | equal (a: strsep (stringp: &list, delim: "," ), b: "This" , number: 51); |
1046 | equal (a: strsep (stringp: &list, delim: "," ), b: "is" , number: 52); |
1047 | equal (a: strsep (stringp: &list, delim: "," ), b: "a" , number: 53); |
1048 | equal (a: strsep (stringp: &list, delim: "," ), b: "test" , number: 54); |
1049 | check (thing: strsep (stringp: &list, delim: "," ) == NULL, number: 55); |
1050 | } |
1051 | |
1052 | cp = strcpy(one, "a,b, c,, ,d," ); |
1053 | equal(a: strsep(stringp: &cp, delim: "," ), b: "a" , number: 56); /* Different separators. */ |
1054 | equal(a: strsep(stringp: &cp, delim: "," ), b: "b" , number: 57); |
1055 | equal(a: strsep(stringp: &cp, delim: "," ), b: " c" , number: 58); /* Permute list too. */ |
1056 | equal(a: strsep(stringp: &cp, delim: "," ), b: "" , number: 59); |
1057 | equal(a: strsep(stringp: &cp, delim: "," ), b: " " , number: 60); |
1058 | equal(a: strsep(stringp: &cp, delim: "," ), b: "d" , number: 61); |
1059 | equal(a: strsep(stringp: &cp, delim: "," ), b: "" , number: 62); |
1060 | check(thing: strsep(stringp: &cp, delim: "," ) == NULL, number: 63); |
1061 | check(thing: strsep(stringp: &cp, delim: "," ) == NULL, number: 64); /* Persistence. */ |
1062 | |
1063 | cp = strcpy(one, "a,b, c,, ,d," ); |
1064 | equal(a: strsep(stringp: &cp, delim: "xy," ), b: "a" , number: 65); /* Different separators. */ |
1065 | equal(a: strsep(stringp: &cp, delim: "x,y" ), b: "b" , number: 66); |
1066 | equal(a: strsep(stringp: &cp, delim: ",xy" ), b: " c" , number: 67); /* Permute list too. */ |
1067 | equal(a: strsep(stringp: &cp, delim: "xy," ), b: "" , number: 68); |
1068 | equal(a: strsep(stringp: &cp, delim: "x,y" ), b: " " , number: 69); |
1069 | equal(a: strsep(stringp: &cp, delim: ",xy" ), b: "d" , number: 70); |
1070 | equal(a: strsep(stringp: &cp, delim: "xy," ), b: "" , number: 71); |
1071 | check(thing: strsep(stringp: &cp, delim: "x,y" ) == NULL, number: 72); |
1072 | check(thing: strsep(stringp: &cp, delim: ",xy" ) == NULL, number: 73); /* Persistence. */ |
1073 | |
1074 | cp = strcpy(one, "ABC" ); |
1075 | one[4] = ':'; |
1076 | equal(a: strsep(stringp: &cp, delim: "C" ), b: "AB" , number: 74); /* Access beyond NUL. */ |
1077 | ptr = strsep(stringp: &cp, delim: ":" ); |
1078 | equal(a: ptr, b: "" , number: 75); |
1079 | check(thing: ptr == one + 3, number: 76); |
1080 | check(thing: cp == NULL, number: 77); |
1081 | |
1082 | cp = strcpy(one, "ABC" ); |
1083 | one[4] = ':'; |
1084 | equal(a: strsep(stringp: &cp, delim: "CD" ), b: "AB" , number: 78); /* Access beyond NUL. */ |
1085 | ptr = strsep(stringp: &cp, delim: ":." ); |
1086 | equal(a: ptr, b: "" , number: 79); |
1087 | check(thing: ptr == one + 3, number: 80); |
1088 | |
1089 | cp = strcpy(one, "ABC" ); /* No token in string. */ |
1090 | equal(a: strsep(stringp: &cp, delim: "," ), b: "ABC" , number: 81); |
1091 | check(thing: cp == NULL, number: 82); |
1092 | |
1093 | *one = '\0'; /* Empty string. */ |
1094 | cp = one; |
1095 | ptr = strsep(stringp: &cp, delim: "," ); |
1096 | equal(a: ptr, b: "" , number: 83); |
1097 | check(thing: ptr == one, number: 84); |
1098 | check(thing: cp == NULL, number: 85); |
1099 | |
1100 | *one = '\0'; /* Empty string and no token. */ |
1101 | cp = one; |
1102 | ptr = strsep(stringp: &cp, delim: "" ); |
1103 | equal(a: ptr, b: "" , number: 86); |
1104 | check(thing: ptr == one , number: 87); |
1105 | check(thing: cp == NULL, number: 88); |
1106 | } |
1107 | |
1108 | static void |
1109 | test_memcmp (void) |
1110 | { |
1111 | int cnt = 1; |
1112 | char one[21]; |
1113 | char two[21]; |
1114 | |
1115 | it = "memcmp" ; |
1116 | check(thing: memcmp("a" , "a" , 1) == 0, number: cnt++); /* Identity. */ |
1117 | check(thing: memcmp("abc" , "abc" , 3) == 0, number: cnt++); /* Multicharacter. */ |
1118 | check(thing: memcmp("abcd" , "abcf" , 4) < 0, number: cnt++); /* Honestly unequal. */ |
1119 | check(thing: memcmp("abcf" , "abcd" , 4) > 0, number: cnt++); |
1120 | check(thing: memcmp("alph" , "cold" , 4) < 0, number: cnt++); |
1121 | check(thing: memcmp("a\203" , "a\003" , 2) > 0, number: cnt++); |
1122 | check(thing: memcmp("a\003" , "a\203" , 2) < 0, number: cnt++); |
1123 | check(thing: memcmp("a\003bc" , "a\203bc" , 2) < 0, number: cnt++); |
1124 | check(thing: memcmp("abc\203" , "abc\003" , 4) > 0, number: cnt++); |
1125 | check(thing: memcmp("abc\003" , "abc\203" , 4) < 0, number: cnt++); |
1126 | check(thing: memcmp("abcf" , "abcd" , 3) == 0, number: cnt++); /* Count limited. */ |
1127 | check(thing: memcmp("abc" , "def" , 0) == 0, number: cnt++); /* Zero count. */ |
1128 | /* Comparisons with shifting 4-byte boundaries. */ |
1129 | for (int i = 0; i < 4; ++i) |
1130 | { |
1131 | char *a = one + i; |
1132 | char *b = two + i; |
1133 | memcpy(a, "--------11112222" , 16); |
1134 | memcpy(b, "--------33334444" , 16); |
1135 | check(thing: memcmp(b, a, 16) > 0, number: cnt++); |
1136 | check(thing: memcmp(a, b, 16) < 0, number: cnt++); |
1137 | } |
1138 | } |
1139 | |
1140 | static void |
1141 | test_memchr (void) |
1142 | { |
1143 | it = "memchr" ; |
1144 | check(thing: memchr("abcd" , 'z', 4) == NULL, number: 1); /* Not found. */ |
1145 | (void) strcpy(one, "abcd" ); |
1146 | check(thing: memchr(one, 'c', 4) == one+2, number: 2); /* Basic test. */ |
1147 | check(thing: memchr(one, ~0xff|'c', 4) == one+2, number: 2); /* ignore highorder bits. */ |
1148 | check(thing: memchr(one, 'd', 4) == one+3, number: 3); /* End of string. */ |
1149 | check(thing: memchr(one, 'a', 4) == one, number: 4); /* Beginning. */ |
1150 | check(thing: memchr(one, '\0', 5) == one+4, number: 5); /* Finding NUL. */ |
1151 | (void) strcpy(one, "ababa" ); |
1152 | check(thing: memchr(one, 'b', 5) == one+1, number: 6); /* Finding first. */ |
1153 | check(thing: memchr(one, 'b', 0) == NULL, number: 7); /* Zero count. */ |
1154 | check(thing: memchr(one, 'a', 1) == one, number: 8); /* Singleton case. */ |
1155 | (void) strcpy(one, "a\203b" ); |
1156 | check(thing: memchr(one, 0203, 3) == one+1, number: 9); /* Unsignedness. */ |
1157 | |
1158 | /* now test all possible alignment and length combinations to catch |
1159 | bugs due to unrolled loops (assuming unrolling is limited to no |
1160 | more than 128 byte chunks: */ |
1161 | { |
1162 | char buf[128 + sizeof (long)]; |
1163 | long align, len, i, pos; |
1164 | |
1165 | for (align = 0; align < (long) sizeof (long); ++align) { |
1166 | for (len = 0; len < (long) (sizeof (buf) - align); ++len) { |
1167 | for (i = 0; i < len; ++i) { |
1168 | buf[align + i] = 'x'; /* don't depend on memset... */ |
1169 | } |
1170 | for (pos = 0; pos < len; ++pos) { |
1171 | #if 0 |
1172 | printf("align %d, len %d, pos %d\n" , align, len, pos); |
1173 | #endif |
1174 | check(thing: memchr(buf + align, 'x', len) == buf + align + pos, number: 10); |
1175 | check(thing: memchr(buf + align, 'x', pos) == NULL, number: 11); |
1176 | buf[align + pos] = '-'; |
1177 | } |
1178 | } |
1179 | } |
1180 | } |
1181 | } |
1182 | |
1183 | static void |
1184 | test_memcpy (void) |
1185 | { |
1186 | int i; |
1187 | it = "memcpy" ; |
1188 | check(thing: memcpy(one, "abc" , 4) == one, number: 1); /* Returned value. */ |
1189 | equal(a: one, b: "abc" , number: 2); /* Did the copy go right? */ |
1190 | |
1191 | (void) strcpy(one, "abcdefgh" ); |
1192 | (void) memcpy(one+1, "xyz" , 2); |
1193 | equal(a: one, b: "axydefgh" , number: 3); /* Basic test. */ |
1194 | |
1195 | (void) strcpy(one, "abc" ); |
1196 | (void) memcpy(one, "xyz" , 0); |
1197 | equal(a: one, b: "abc" , number: 4); /* Zero-length copy. */ |
1198 | |
1199 | (void) strcpy(one, "hi there" ); |
1200 | (void) strcpy(two, "foo" ); |
1201 | (void) memcpy(two, one, 9); |
1202 | equal(a: two, b: "hi there" , number: 5); /* Just paranoia. */ |
1203 | equal(a: one, b: "hi there" , number: 6); /* Stomped on source? */ |
1204 | |
1205 | for (i = 0; i < 16; i++) |
1206 | { |
1207 | const char *x = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ; |
1208 | strcpy (one, x); |
1209 | check (thing: memcpy (one + i, "hi there" , 9) == one + i, |
1210 | number: 7 + (i * 6)); /* Unaligned destination. */ |
1211 | check (thing: memcmp (one, x, i) == 0, number: 8 + (i * 6)); /* Wrote under? */ |
1212 | equal (a: one + i, b: "hi there" , number: 9 + (i * 6)); |
1213 | check (thing: one[i + 9] == 'x', number: 10 + (i * 6)); /* Wrote over? */ |
1214 | check (thing: memcpy (two, one + i, 9) == two, |
1215 | number: 11 + (i * 6)); /* Unaligned source. */ |
1216 | equal (a: two, b: "hi there" , number: 12 + (i * 6)); |
1217 | } |
1218 | } |
1219 | |
1220 | static void |
1221 | test_mempcpy (void) |
1222 | { |
1223 | int i; |
1224 | it = "mempcpy" ; |
1225 | check(thing: mempcpy(one, "abc" , 4) == one + 4, number: 1); /* Returned value. */ |
1226 | equal(a: one, b: "abc" , number: 2); /* Did the copy go right? */ |
1227 | |
1228 | (void) strcpy(one, "abcdefgh" ); |
1229 | (void) mempcpy(one+1, "xyz" , 2); |
1230 | equal(a: one, b: "axydefgh" , number: 3); /* Basic test. */ |
1231 | |
1232 | (void) strcpy(one, "abc" ); |
1233 | (void) mempcpy(one, "xyz" , 0); |
1234 | equal(a: one, b: "abc" , number: 4); /* Zero-length copy. */ |
1235 | |
1236 | (void) strcpy(one, "hi there" ); |
1237 | (void) strcpy(two, "foo" ); |
1238 | (void) mempcpy(two, one, 9); |
1239 | equal(a: two, b: "hi there" , number: 5); /* Just paranoia. */ |
1240 | equal(a: one, b: "hi there" , number: 6); /* Stomped on source? */ |
1241 | |
1242 | for (i = 0; i < 16; i++) |
1243 | { |
1244 | const char *x = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ; |
1245 | strcpy (one, x); |
1246 | check (thing: mempcpy (one + i, "hi there" , 9) == one + i + 9, |
1247 | number: 7 + (i * 6)); /* Unaligned destination. */ |
1248 | check (thing: memcmp (one, x, i) == 0, number: 8 + (i * 6)); /* Wrote under? */ |
1249 | equal (a: one + i, b: "hi there" , number: 9 + (i * 6)); |
1250 | check (thing: one[i + 9] == 'x', number: 10 + (i * 6)); /* Wrote over? */ |
1251 | check (thing: mempcpy (two, one + i, 9) == two + 9, |
1252 | number: 11 + (i * 6)); /* Unaligned source. */ |
1253 | equal (a: two, b: "hi there" , number: 12 + (i * 6)); |
1254 | } |
1255 | } |
1256 | |
1257 | static void |
1258 | test_memmove (void) |
1259 | { |
1260 | it = "memmove" ; |
1261 | check(thing: memmove(one, "abc" , 4) == one, number: 1); /* Returned value. */ |
1262 | equal(a: one, b: "abc" , number: 2); /* Did the copy go right? */ |
1263 | |
1264 | (void) strcpy(one, "abcdefgh" ); |
1265 | (void) memmove(one+1, "xyz" , 2); |
1266 | equal(a: one, b: "axydefgh" , number: 3); /* Basic test. */ |
1267 | |
1268 | (void) strcpy(one, "abc" ); |
1269 | (void) memmove(one, "xyz" , 0); |
1270 | equal(a: one, b: "abc" , number: 4); /* Zero-length copy. */ |
1271 | |
1272 | (void) strcpy(one, "hi there" ); |
1273 | (void) strcpy(two, "foo" ); |
1274 | (void) memmove(two, one, 9); |
1275 | equal(a: two, b: "hi there" , number: 5); /* Just paranoia. */ |
1276 | equal(a: one, b: "hi there" , number: 6); /* Stomped on source? */ |
1277 | |
1278 | (void) strcpy(one, "abcdefgh" ); |
1279 | (void) memmove(one+1, one, 9); |
1280 | equal(a: one, b: "aabcdefgh" , number: 7); /* Overlap, right-to-left. */ |
1281 | |
1282 | (void) strcpy(one, "abcdefgh" ); |
1283 | (void) memmove(one+1, one+2, 7); |
1284 | equal(a: one, b: "acdefgh" , number: 8); /* Overlap, left-to-right. */ |
1285 | |
1286 | (void) strcpy(one, "abcdefgh" ); |
1287 | (void) memmove(one, one, 9); |
1288 | equal(a: one, b: "abcdefgh" , number: 9); /* 100% overlap. */ |
1289 | } |
1290 | |
1291 | static void |
1292 | test_memccpy (void) |
1293 | { |
1294 | /* First test like memcpy, then the search part The SVID, the only |
1295 | place where memccpy is mentioned, says overlap might fail, so we |
1296 | don't try it. Besides, it's hard to see the rationale for a |
1297 | non-left-to-right memccpy. */ |
1298 | it = "memccpy" ; |
1299 | check(thing: memccpy(dest: one, src: "abc" , c: 'q', n: 4) == NULL, number: 1); /* Returned value. */ |
1300 | equal(a: one, b: "abc" , number: 2); /* Did the copy go right? */ |
1301 | |
1302 | (void) strcpy(one, "abcdefgh" ); |
1303 | (void) memccpy(dest: one+1, src: "xyz" , c: 'q', n: 2); |
1304 | equal(a: one, b: "axydefgh" , number: 3); /* Basic test. */ |
1305 | |
1306 | (void) strcpy(one, "abc" ); |
1307 | (void) memccpy(dest: one, src: "xyz" , c: 'q', n: 0); |
1308 | equal(a: one, b: "abc" , number: 4); /* Zero-length copy. */ |
1309 | |
1310 | (void) strcpy(one, "hi there" ); |
1311 | (void) strcpy(two, "foo" ); |
1312 | (void) memccpy(dest: two, src: one, c: 'q', n: 9); |
1313 | equal(a: two, b: "hi there" , number: 5); /* Just paranoia. */ |
1314 | equal(a: one, b: "hi there" , number: 6); /* Stomped on source? */ |
1315 | |
1316 | (void) strcpy(one, "abcdefgh" ); |
1317 | (void) strcpy(two, "horsefeathers" ); |
1318 | check(thing: memccpy(dest: two, src: one, c: 'f', n: 9) == two+6, number: 7); /* Returned value. */ |
1319 | equal(a: one, b: "abcdefgh" , number: 8); /* Source intact? */ |
1320 | equal(a: two, b: "abcdefeathers" , number: 9); /* Copy correct? */ |
1321 | |
1322 | (void) strcpy(one, "abcd" ); |
1323 | (void) strcpy(two, "bumblebee" ); |
1324 | check(thing: memccpy(dest: two, src: one, c: 'a', n: 4) == two+1, number: 10); /* First char. */ |
1325 | equal(a: two, b: "aumblebee" , number: 11); |
1326 | check(thing: memccpy(dest: two, src: one, c: 'd', n: 4) == two+4, number: 12); /* Last char. */ |
1327 | equal(a: two, b: "abcdlebee" , number: 13); |
1328 | (void) strcpy(one, "xyz" ); |
1329 | check(thing: memccpy(dest: two, src: one, c: 'x', n: 1) == two+1, number: 14); /* Singleton. */ |
1330 | equal(a: two, b: "xbcdlebee" , number: 15); |
1331 | } |
1332 | |
1333 | static void |
1334 | test_memset (void) |
1335 | { |
1336 | int i; |
1337 | |
1338 | it = "memset" ; |
1339 | (void) strcpy(one, "abcdefgh" ); |
1340 | check(thing: memset(one+1, 'x', 3) == one+1, number: 1); /* Return value. */ |
1341 | equal(a: one, b: "axxxefgh" , number: 2); /* Basic test. */ |
1342 | |
1343 | (void) memset(one+2, 'y', 0); |
1344 | equal(a: one, b: "axxxefgh" , number: 3); /* Zero-length set. */ |
1345 | |
1346 | (void) memset(one+5, 0, 1); |
1347 | equal(a: one, b: "axxxe" , number: 4); /* Zero fill. */ |
1348 | equal(a: one+6, b: "gh" , number: 5); /* And the leftover. */ |
1349 | |
1350 | (void) memset(one+2, 010045, 1); |
1351 | equal(a: one, b: "ax\045xe" , number: 6); /* Unsigned char convert. */ |
1352 | |
1353 | /* Non-8bit fill character. */ |
1354 | memset (one, 0x101, sizeof (one)); |
1355 | for (i = 0; i < (int) sizeof (one); ++i) |
1356 | check (thing: one[i] == '\01', number: 7); |
1357 | |
1358 | /* Test for more complex versions of memset, for all alignments and |
1359 | lengths up to 256. This test takes a little while, perhaps it should |
1360 | be made weaker? */ |
1361 | { |
1362 | char data[512]; |
1363 | int j; |
1364 | int k; |
1365 | int c; |
1366 | |
1367 | for (i = 0; i < 512; i++) |
1368 | data[i] = 'x'; |
1369 | for (c = 0; c <= 'y'; c += 'y') /* check for memset(,0,) and |
1370 | memset(,'y',) */ |
1371 | for (j = 0; j < 256; j++) |
1372 | for (i = 0; i < 256; i++) |
1373 | { |
1374 | memset (data + i, c, j); |
1375 | for (k = 0; k < i; k++) |
1376 | if (data[k] != 'x') |
1377 | goto fail; |
1378 | for (k = i; k < i+j; k++) |
1379 | { |
1380 | if (data[k] != c) |
1381 | goto fail; |
1382 | data[k] = 'x'; |
1383 | } |
1384 | for (k = i+j; k < 512; k++) |
1385 | if (data[k] != 'x') |
1386 | goto fail; |
1387 | continue; |
1388 | |
1389 | fail: |
1390 | check (thing: 0, number: 8 + i + j * 256 + (c != 0) * 256 * 256); |
1391 | } |
1392 | } |
1393 | } |
1394 | |
1395 | static void |
1396 | test_bcopy (void) |
1397 | { |
1398 | /* Much like memcpy. Berklix manual is silent about overlap, so |
1399 | don't test it. */ |
1400 | it = "bcopy" ; |
1401 | (void) bcopy(src: "abc" , dest: one, n: 4); |
1402 | equal(a: one, b: "abc" , number: 1); /* Simple copy. */ |
1403 | |
1404 | (void) strcpy(one, "abcdefgh" ); |
1405 | (void) bcopy(src: "xyz" , dest: one+1, n: 2); |
1406 | equal(a: one, b: "axydefgh" , number: 2); /* Basic test. */ |
1407 | |
1408 | (void) strcpy(one, "abc" ); |
1409 | (void) bcopy(src: "xyz" , dest: one, n: 0); |
1410 | equal(a: one, b: "abc" , number: 3); /* Zero-length copy. */ |
1411 | |
1412 | (void) strcpy(one, "hi there" ); |
1413 | (void) strcpy(two, "foo" ); |
1414 | (void) bcopy(src: one, dest: two, n: 9); |
1415 | equal(a: two, b: "hi there" , number: 4); /* Just paranoia. */ |
1416 | equal(a: one, b: "hi there" , number: 5); /* Stomped on source? */ |
1417 | } |
1418 | |
1419 | static void |
1420 | test_bzero (void) |
1421 | { |
1422 | it = "bzero" ; |
1423 | (void) strcpy(one, "abcdef" ); |
1424 | bzero(s: one+2, n: 2); |
1425 | equal(a: one, b: "ab" , number: 1); /* Basic test. */ |
1426 | equal(a: one+3, b: "" , number: 2); |
1427 | equal(a: one+4, b: "ef" , number: 3); |
1428 | |
1429 | (void) strcpy(one, "abcdef" ); |
1430 | bzero(s: one+2, n: 0); |
1431 | equal(a: one, b: "abcdef" , number: 4); /* Zero-length copy. */ |
1432 | } |
1433 | |
1434 | static void |
1435 | test_strndup (void) |
1436 | { |
1437 | char *p, *q; |
1438 | it = "strndup" ; |
1439 | p = strndup(string: "abcdef" , n: 12); |
1440 | check(thing: p != NULL, number: 1); |
1441 | if (p != NULL) |
1442 | { |
1443 | equal(a: p, b: "abcdef" , number: 2); |
1444 | q = strndup(string: p + 1, n: 2); |
1445 | check(thing: q != NULL, number: 3); |
1446 | if (q != NULL) |
1447 | equal(a: q, b: "bc" , number: 4); |
1448 | free (ptr: q); |
1449 | } |
1450 | free (ptr: p); |
1451 | p = strndup(string: "abc def" , n: 3); |
1452 | check(thing: p != NULL, number: 5); |
1453 | if (p != NULL) |
1454 | equal(a: p, b: "abc" , number: 6); |
1455 | free (ptr: p); |
1456 | } |
1457 | |
1458 | static void |
1459 | test_bcmp (void) |
1460 | { |
1461 | it = "bcmp" ; |
1462 | check(thing: bcmp(s1: "a" , s2: "a" , n: 1) == 0, number: 1); /* Identity. */ |
1463 | check(thing: bcmp(s1: "abc" , s2: "abc" , n: 3) == 0, number: 2); /* Multicharacter. */ |
1464 | check(thing: bcmp(s1: "abcd" , s2: "abce" , n: 4) != 0, number: 3); /* Honestly unequal. */ |
1465 | check(thing: bcmp(s1: "abce" , s2: "abcd" , n: 4) != 0, number: 4); |
1466 | check(thing: bcmp(s1: "alph" , s2: "beta" , n: 4) != 0, number: 5); |
1467 | check(thing: bcmp(s1: "abce" , s2: "abcd" , n: 3) == 0, number: 6); /* Count limited. */ |
1468 | check(thing: bcmp(s1: "abc" , s2: "def" , n: 0) == 0, number: 8); /* Zero count. */ |
1469 | } |
1470 | |
1471 | static void |
1472 | test_memcmpeq (void) |
1473 | { |
1474 | it = "__memcmpeq" ; |
1475 | check (thing: __memcmpeq ("a" , "a" , 1) == 0, number: 1); /* Identity. */ |
1476 | check (thing: __memcmpeq ("abc" , "abc" , 3) == 0, number: 2); /* Multicharacter. */ |
1477 | check (thing: __memcmpeq ("abcd" , "abce" , 4) != 0, number: 3); /* Honestly unequal. */ |
1478 | check (thing: __memcmpeq ("abce" , "abcd" , 4) != 0, number: 4); |
1479 | check (thing: __memcmpeq ("alph" , "beta" , 4) != 0, number: 5); |
1480 | check (thing: __memcmpeq ("abce" , "abcd" , 3) == 0, number: 6); /* Count limited. */ |
1481 | check (thing: __memcmpeq ("abc" , "def" , 0) == 0, number: 8); /* Zero count. */ |
1482 | } |
1483 | |
1484 | static void |
1485 | test_strerror (void) |
1486 | { |
1487 | it = "strerror" ; |
1488 | check(thing: strerror(EDOM) != 0, number: 1); |
1489 | check(thing: strerror(ERANGE) != 0, number: 2); |
1490 | check(thing: strerror(ENOENT) != 0, number: 3); |
1491 | } |
1492 | |
1493 | static void |
1494 | test_strcasecmp (void) |
1495 | { |
1496 | it = "strcasecmp" ; |
1497 | /* Note that the locale is "C". */ |
1498 | check(thing: strcasecmp(s1: "a" , s2: "a" ) == 0, number: 1); |
1499 | check(thing: strcasecmp(s1: "a" , s2: "A" ) == 0, number: 2); |
1500 | check(thing: strcasecmp(s1: "A" , s2: "a" ) == 0, number: 3); |
1501 | check(thing: strcasecmp(s1: "a" , s2: "b" ) < 0, number: 4); |
1502 | check(thing: strcasecmp(s1: "c" , s2: "b" ) > 0, number: 5); |
1503 | check(thing: strcasecmp(s1: "abc" , s2: "AbC" ) == 0, number: 6); |
1504 | check(thing: strcasecmp(s1: "0123456789" , s2: "0123456789" ) == 0, number: 7); |
1505 | check(thing: strcasecmp(s1: "" , s2: "0123456789" ) < 0, number: 8); |
1506 | check(thing: strcasecmp(s1: "AbC" , s2: "" ) > 0, number: 9); |
1507 | check(thing: strcasecmp(s1: "AbC" , s2: "A" ) > 0, number: 10); |
1508 | check(thing: strcasecmp(s1: "AbC" , s2: "Ab" ) > 0, number: 11); |
1509 | check(thing: strcasecmp(s1: "AbC" , s2: "ab" ) > 0, number: 12); |
1510 | } |
1511 | |
1512 | static void |
1513 | test_strncasecmp (void) |
1514 | { |
1515 | it = "strncasecmp" ; |
1516 | /* Note that the locale is "C". */ |
1517 | check(thing: strncasecmp(s1: "a" , s2: "a" , n: 5) == 0, number: 1); |
1518 | check(thing: strncasecmp(s1: "a" , s2: "A" , n: 5) == 0, number: 2); |
1519 | check(thing: strncasecmp(s1: "A" , s2: "a" , n: 5) == 0, number: 3); |
1520 | check(thing: strncasecmp(s1: "a" , s2: "b" , n: 5) < 0, number: 4); |
1521 | check(thing: strncasecmp(s1: "c" , s2: "b" , n: 5) > 0, number: 5); |
1522 | check(thing: strncasecmp(s1: "abc" , s2: "AbC" , n: 5) == 0, number: 6); |
1523 | check(thing: strncasecmp(s1: "0123456789" , s2: "0123456789" , n: 10) == 0, number: 7); |
1524 | check(thing: strncasecmp(s1: "" , s2: "0123456789" , n: 10) < 0, number: 8); |
1525 | check(thing: strncasecmp(s1: "AbC" , s2: "" , n: 5) > 0, number: 9); |
1526 | check(thing: strncasecmp(s1: "AbC" , s2: "A" , n: 5) > 0, number: 10); |
1527 | check(thing: strncasecmp(s1: "AbC" , s2: "Ab" , n: 5) > 0, number: 11); |
1528 | check(thing: strncasecmp(s1: "AbC" , s2: "ab" , n: 5) > 0, number: 12); |
1529 | check(thing: strncasecmp(s1: "0123456789" , s2: "AbC" , n: 0) == 0, number: 13); |
1530 | check(thing: strncasecmp(s1: "AbC" , s2: "abc" , n: 1) == 0, number: 14); |
1531 | check(thing: strncasecmp(s1: "AbC" , s2: "abc" , n: 2) == 0, number: 15); |
1532 | check(thing: strncasecmp(s1: "AbC" , s2: "abc" , n: 3) == 0, number: 16); |
1533 | check(thing: strncasecmp(s1: "AbC" , s2: "abcd" , n: 3) == 0, number: 17); |
1534 | check(thing: strncasecmp(s1: "AbC" , s2: "abcd" , n: 4) < 0, number: 18); |
1535 | check(thing: strncasecmp(s1: "ADC" , s2: "abcd" , n: 1) == 0, number: 19); |
1536 | check(thing: strncasecmp(s1: "ADC" , s2: "abcd" , n: 2) > 0, number: 20); |
1537 | } |
1538 | |
1539 | int |
1540 | main (void) |
1541 | { |
1542 | int status; |
1543 | |
1544 | /* Test strcmp first because we use it to test other things. */ |
1545 | test_strcmp (); |
1546 | |
1547 | /* Test strcpy next because we need it to set up other tests. */ |
1548 | test_strcpy (); |
1549 | |
1550 | /* A closely related function is stpcpy. */ |
1551 | test_stpcpy (); |
1552 | |
1553 | /* stpncpy. */ |
1554 | test_stpncpy (); |
1555 | |
1556 | /* strcat. */ |
1557 | test_strcat (); |
1558 | |
1559 | /* strncat. */ |
1560 | test_strncat (); |
1561 | |
1562 | /* strncmp. */ |
1563 | test_strncmp (); |
1564 | |
1565 | /* strncpy. */ |
1566 | test_strncpy (); |
1567 | |
1568 | /* strlen. */ |
1569 | test_strlen (); |
1570 | |
1571 | /* strnlen. */ |
1572 | test_strnlen (); |
1573 | |
1574 | /* strchr. */ |
1575 | test_strchr (); |
1576 | |
1577 | /* strchrnul. */ |
1578 | test_strchrnul (); |
1579 | |
1580 | /* rawmemchr. */ |
1581 | test_rawmemchr (); |
1582 | |
1583 | /* index - just like strchr. */ |
1584 | test_index (); |
1585 | |
1586 | /* strrchr. */ |
1587 | test_strrchr (); |
1588 | |
1589 | /* memrchr. */ |
1590 | test_memrchr (); |
1591 | |
1592 | /* rindex - just like strrchr. */ |
1593 | test_rindex (); |
1594 | |
1595 | /* strpbrk - somewhat like strchr. */ |
1596 | test_strpbrk (); |
1597 | |
1598 | /* strstr - somewhat like strchr. */ |
1599 | test_strstr (); |
1600 | |
1601 | /* strspn. */ |
1602 | test_strspn (); |
1603 | |
1604 | /* strcspn. */ |
1605 | test_strcspn (); |
1606 | |
1607 | /* strtok - the hard one. */ |
1608 | test_strtok (); |
1609 | |
1610 | /* strtok_r. */ |
1611 | test_strtok_r (); |
1612 | |
1613 | /* strsep. */ |
1614 | test_strsep (); |
1615 | |
1616 | /* memcmp. */ |
1617 | test_memcmp (); |
1618 | |
1619 | /* memchr. */ |
1620 | test_memchr (); |
1621 | |
1622 | /* memcpy - need not work for overlap. */ |
1623 | test_memcpy (); |
1624 | |
1625 | /* memmove - must work on overlap. */ |
1626 | test_memmove (); |
1627 | |
1628 | /* mempcpy */ |
1629 | test_mempcpy (); |
1630 | |
1631 | /* memccpy. */ |
1632 | test_memccpy (); |
1633 | |
1634 | /* memset. */ |
1635 | test_memset (); |
1636 | |
1637 | /* bcopy. */ |
1638 | test_bcopy (); |
1639 | |
1640 | /* bzero. */ |
1641 | test_bzero (); |
1642 | |
1643 | /* bcmp - somewhat like memcmp. */ |
1644 | test_bcmp (); |
1645 | |
1646 | /* __memcmpeq - somewhat like memcmp. */ |
1647 | test_memcmpeq (); |
1648 | |
1649 | /* strndup. */ |
1650 | test_strndup (); |
1651 | |
1652 | /* strerror - VERY system-dependent. */ |
1653 | test_strerror (); |
1654 | |
1655 | /* strcasecmp. Without locale dependencies. */ |
1656 | test_strcasecmp (); |
1657 | |
1658 | /* strncasecmp. Without locale dependencies. */ |
1659 | test_strncasecmp (); |
1660 | |
1661 | if (errors == 0) |
1662 | { |
1663 | status = EXIT_SUCCESS; |
1664 | puts(s: "No errors." ); |
1665 | } |
1666 | else |
1667 | { |
1668 | status = EXIT_FAILURE; |
1669 | printf(format: "%zd errors.\n" , errors); |
1670 | } |
1671 | |
1672 | return status; |
1673 | } |
1674 | |