1 | /* Test and measure memcmp functions. |
2 | Copyright (C) 1999-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 | #ifdef TEST_MEMCMPEQ |
21 | # define TEST_NAME "__memcmpeq" |
22 | #elif defined WIDE |
23 | # define TEST_NAME "wmemcmp" |
24 | #else |
25 | # define TEST_NAME "memcmp" |
26 | #endif |
27 | |
28 | #include "test-string.h" |
29 | #ifdef WIDE |
30 | # include <inttypes.h> |
31 | # include <wchar.h> |
32 | |
33 | # define MEMCMP wmemcmp |
34 | # define MEMCPY wmemcpy |
35 | # define SIMPLE_MEMCMP simple_wmemcmp |
36 | # define CHAR wchar_t |
37 | # define UCHAR wchar_t |
38 | # define CHARBYTES 4 |
39 | # define CHAR__MIN WCHAR_MIN |
40 | # define CHAR__MAX WCHAR_MAX |
41 | |
42 | int |
43 | SIMPLE_MEMCMP (const wchar_t *s1, const wchar_t *s2, size_t n) |
44 | { |
45 | int ret = 0; |
46 | /* Warning! |
47 | wmemcmp has to use SIGNED comparison for elements. |
48 | memcmp has to use UNSIGNED comparison for elements. |
49 | */ |
50 | while (n-- && (ret = *s1 < *s2 ? -1 : *s1 == *s2 ? 0 : 1) == 0) {s1++; s2++;} |
51 | return ret; |
52 | } |
53 | #else |
54 | # include <limits.h> |
55 | # ifdef TEST_MEMCMPEQ |
56 | # define MEMCMP __memcmpeq |
57 | # define SIMPLE_MEMCMP simple_memcmpeq |
58 | # else |
59 | # define MEMCMP memcmp |
60 | # define SIMPLE_MEMCMP simple_memcmp |
61 | # endif |
62 | # define MEMCPY memcpy |
63 | # define CHAR char |
64 | # define MAX_CHAR 255 |
65 | # define UCHAR unsigned char |
66 | # define CHARBYTES 1 |
67 | # define CHAR__MIN CHAR_MIN |
68 | # define CHAR__MAX CHAR_MAX |
69 | |
70 | int |
71 | SIMPLE_MEMCMP (const char *s1, const char *s2, size_t n) |
72 | { |
73 | int ret = 0; |
74 | |
75 | while (n-- && (ret = *(unsigned char *) s1++ - *(unsigned char *) s2++) == 0); |
76 | return ret; |
77 | } |
78 | #endif |
79 | |
80 | #ifndef BAD_RESULT |
81 | # define BAD_RESULT(result, expec) \ |
82 | (((result) == 0 && (expec)) || ((result) < 0 && (expec) >= 0) || \ |
83 | ((result) > 0 && (expec) <= 0)) |
84 | # endif |
85 | |
86 | typedef int (*proto_t) (const CHAR *, const CHAR *, size_t); |
87 | |
88 | IMPL (MEMCMP, 1) |
89 | |
90 | static int |
91 | check_result (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t len, |
92 | int exp_result) |
93 | { |
94 | int result = CALL (impl, s1, s2, len); |
95 | if (BAD_RESULT(result, exp_result)) |
96 | { |
97 | error (status: 0, errnum: 0, format: "Wrong result in function %s %d %d" , impl->name, |
98 | result, exp_result); |
99 | ret = 1; |
100 | return -1; |
101 | } |
102 | |
103 | return 0; |
104 | } |
105 | |
106 | static void |
107 | do_one_test (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t len, |
108 | int exp_result) |
109 | { |
110 | if (check_result (impl, s1, s2, len, exp_result) < 0) |
111 | return; |
112 | } |
113 | |
114 | static void |
115 | do_test (size_t align1, size_t align2, size_t len, int exp_result) |
116 | { |
117 | size_t i; |
118 | CHAR *s1, *s2; |
119 | |
120 | align1 &= (4096 - CHARBYTES); |
121 | if (align1 + (len + 1) * CHARBYTES >= page_size) |
122 | return; |
123 | |
124 | align2 &= (4096 - CHARBYTES); |
125 | if (align2 + (len + 1) * CHARBYTES >= page_size) |
126 | return; |
127 | |
128 | s1 = (CHAR *) (buf1 + align1); |
129 | s2 = (CHAR *) (buf2 + align2); |
130 | |
131 | for (i = 0; i < len; i++) |
132 | s1[i] = s2[i] = 1 + (23 << ((CHARBYTES - 1) * 8)) * i % CHAR__MAX; |
133 | |
134 | if (len) |
135 | { |
136 | s1[len] = align1; |
137 | s2[len] = align2; |
138 | s2[len - 1] -= exp_result; |
139 | } |
140 | else |
141 | { |
142 | exp_result = 0; |
143 | } |
144 | |
145 | FOR_EACH_IMPL (impl, 0) |
146 | do_one_test (impl, s1, s2, len, exp_result); |
147 | } |
148 | |
149 | static void |
150 | do_random_tests (void) |
151 | { |
152 | size_t i, j, n, align1, align2, pos, len; |
153 | int result; |
154 | long r; |
155 | UCHAR *p1 = (UCHAR *) (buf1 + page_size - 512 * CHARBYTES); |
156 | UCHAR *p2 = (UCHAR *) (buf2 + page_size - 512 * CHARBYTES); |
157 | |
158 | for (n = 0; n < ITERATIONS; n++) |
159 | { |
160 | align1 = random () & 31; |
161 | if (random () & 1) |
162 | align2 = random () & 31; |
163 | else |
164 | align2 = align1 + (random () & 24); |
165 | pos = random () & 511; |
166 | j = align1; |
167 | if (align2 > j) |
168 | j = align2; |
169 | if (pos + j >= 512) |
170 | pos = 511 - j - (random () & 7); |
171 | len = random () & 511; |
172 | if (len + j >= 512) |
173 | len = 511 - j - (random () & 7); |
174 | j = len + align1 + 64; |
175 | if (j > 512) j = 512; |
176 | for (i = 0; i < j; ++i) |
177 | p1[i] = random () & 255; |
178 | for (i = 0; i < j; ++i) |
179 | p2[i] = random () & 255; |
180 | |
181 | result = 0; |
182 | if (pos >= len) |
183 | MEMCPY ((CHAR *) p2 + align2, (const CHAR *) p1 + align1, len); |
184 | else |
185 | { |
186 | MEMCPY ((CHAR *) p2 + align2, (const CHAR *) p1 + align1, pos); |
187 | if (p2[align2 + pos] == p1[align1 + pos]) |
188 | { |
189 | p2[align2 + pos] = random () & 255; |
190 | if (p2[align2 + pos] == p1[align1 + pos]) |
191 | p2[align2 + pos] = p1[align1 + pos] + 3 + (random () & 127); |
192 | } |
193 | |
194 | if (p1[align1 + pos] < p2[align2 + pos]) |
195 | result = -1; |
196 | else |
197 | result = 1; |
198 | } |
199 | |
200 | FOR_EACH_IMPL (impl, 1) |
201 | { |
202 | r = CALL (impl, (CHAR *) p1 + align1, (const CHAR *) p2 + align2, |
203 | len); |
204 | if (BAD_RESULT(r, result)) |
205 | { |
206 | error (status: 0, errnum: 0, format: "Iteration %zd - wrong result in function %s (%zd, %zd, %zd, %zd) %ld != %d, p1 %p p2 %p" , |
207 | n, impl->name, align1 * CHARBYTES & 63, align2 * CHARBYTES & 63, len, pos, r, result, p1, p2); |
208 | ret = 1; |
209 | } |
210 | } |
211 | } |
212 | } |
213 | |
214 | static void |
215 | check1 (void) |
216 | { |
217 | CHAR s1[116], s2[116]; |
218 | int n, exp_result; |
219 | |
220 | s1[0] = -108; |
221 | s2[0] = -108; |
222 | s1[1] = 99; |
223 | s2[1] = 99; |
224 | s1[2] = -113; |
225 | s2[2] = -113; |
226 | s1[3] = 1; |
227 | s2[3] = 1; |
228 | s1[4] = 116; |
229 | s2[4] = 116; |
230 | s1[5] = 99; |
231 | s2[5] = 99; |
232 | s1[6] = -113; |
233 | s2[6] = -113; |
234 | s1[7] = 1; |
235 | s2[7] = 1; |
236 | s1[8] = 84; |
237 | s2[8] = 84; |
238 | s1[9] = 99; |
239 | s2[9] = 99; |
240 | s1[10] = -113; |
241 | s2[10] = -113; |
242 | s1[11] = 1; |
243 | s2[11] = 1; |
244 | s1[12] = 52; |
245 | s2[12] = 52; |
246 | s1[13] = 99; |
247 | s2[13] = 99; |
248 | s1[14] = -113; |
249 | s2[14] = -113; |
250 | s1[15] = 1; |
251 | s2[15] = 1; |
252 | s1[16] = -76; |
253 | s2[16] = -76; |
254 | s1[17] = -14; |
255 | s2[17] = -14; |
256 | s1[18] = -109; |
257 | s2[18] = -109; |
258 | s1[19] = 1; |
259 | s2[19] = 1; |
260 | s1[20] = -108; |
261 | s2[20] = -108; |
262 | s1[21] = -14; |
263 | s2[21] = -14; |
264 | s1[22] = -109; |
265 | s2[22] = -109; |
266 | s1[23] = 1; |
267 | s2[23] = 1; |
268 | s1[24] = 84; |
269 | s2[24] = 84; |
270 | s1[25] = -15; |
271 | s2[25] = -15; |
272 | s1[26] = -109; |
273 | s2[26] = -109; |
274 | s1[27] = 1; |
275 | s2[27] = 1; |
276 | s1[28] = 52; |
277 | s2[28] = 52; |
278 | s1[29] = -15; |
279 | s2[29] = -15; |
280 | s1[30] = -109; |
281 | s2[30] = -109; |
282 | s1[31] = 1; |
283 | s2[31] = 1; |
284 | s1[32] = 20; |
285 | s2[32] = 20; |
286 | s1[33] = -15; |
287 | s2[33] = -15; |
288 | s1[34] = -109; |
289 | s2[34] = -109; |
290 | s1[35] = 1; |
291 | s2[35] = 1; |
292 | s1[36] = 20; |
293 | s2[36] = 20; |
294 | s1[37] = -14; |
295 | s2[37] = -14; |
296 | s1[38] = -109; |
297 | s2[38] = -109; |
298 | s1[39] = 1; |
299 | s2[39] = 1; |
300 | s1[40] = 52; |
301 | s2[40] = 52; |
302 | s1[41] = -14; |
303 | s2[41] = -14; |
304 | s1[42] = -109; |
305 | s2[42] = -109; |
306 | s1[43] = 1; |
307 | s2[43] = 1; |
308 | s1[44] = 84; |
309 | s2[44] = 84; |
310 | s1[45] = -14; |
311 | s2[45] = -14; |
312 | s1[46] = -109; |
313 | s2[46] = -109; |
314 | s1[47] = 1; |
315 | s2[47] = 1; |
316 | s1[48] = 116; |
317 | s2[48] = 116; |
318 | s1[49] = -14; |
319 | s2[49] = -14; |
320 | s1[50] = -109; |
321 | s2[50] = -109; |
322 | s1[51] = 1; |
323 | s2[51] = 1; |
324 | s1[52] = 116; |
325 | s2[52] = 116; |
326 | s1[53] = -15; |
327 | s2[53] = -15; |
328 | s1[54] = -109; |
329 | s2[54] = -109; |
330 | s1[55] = 1; |
331 | s2[55] = 1; |
332 | s1[56] = -44; |
333 | s2[56] = -44; |
334 | s1[57] = -14; |
335 | s2[57] = -14; |
336 | s1[58] = -109; |
337 | s2[58] = -109; |
338 | s1[59] = 1; |
339 | s2[59] = 1; |
340 | s1[60] = -108; |
341 | s2[60] = -108; |
342 | s1[61] = -15; |
343 | s2[61] = -15; |
344 | s1[62] = -109; |
345 | s2[62] = -109; |
346 | s1[63] = 1; |
347 | s2[63] = 1; |
348 | s1[64] = -76; |
349 | s2[64] = -76; |
350 | s1[65] = -15; |
351 | s2[65] = -15; |
352 | s1[66] = -109; |
353 | s2[66] = -109; |
354 | s1[67] = 1; |
355 | s2[67] = 1; |
356 | s1[68] = -44; |
357 | s2[68] = -44; |
358 | s1[69] = -15; |
359 | s2[69] = -15; |
360 | s1[70] = -109; |
361 | s2[70] = -109; |
362 | s1[71] = 1; |
363 | s2[71] = 1; |
364 | s1[72] = -12; |
365 | s2[72] = -12; |
366 | s1[73] = -15; |
367 | s2[73] = -15; |
368 | s1[74] = -109; |
369 | s2[74] = -109; |
370 | s1[75] = 1; |
371 | s2[75] = 1; |
372 | s1[76] = -12; |
373 | s2[76] = -12; |
374 | s1[77] = -14; |
375 | s2[77] = -14; |
376 | s1[78] = -109; |
377 | s2[78] = -109; |
378 | s1[79] = 1; |
379 | s2[79] = 1; |
380 | s1[80] = 20; |
381 | s2[80] = -68; |
382 | s1[81] = -12; |
383 | s2[81] = 64; |
384 | s1[82] = -109; |
385 | s2[82] = -106; |
386 | s1[83] = 1; |
387 | s2[83] = 1; |
388 | s1[84] = -12; |
389 | s2[84] = -12; |
390 | s1[85] = -13; |
391 | s2[85] = -13; |
392 | s1[86] = -109; |
393 | s2[86] = -109; |
394 | s1[87] = 1; |
395 | s2[87] = 1; |
396 | s1[88] = -44; |
397 | s2[88] = -44; |
398 | s1[89] = -13; |
399 | s2[89] = -13; |
400 | s1[90] = -109; |
401 | s2[90] = -109; |
402 | s1[91] = 1; |
403 | s2[91] = 1; |
404 | s1[92] = -76; |
405 | s2[92] = -76; |
406 | s1[93] = -13; |
407 | s2[93] = -13; |
408 | s1[94] = -109; |
409 | s2[94] = -109; |
410 | s1[95] = 1; |
411 | s2[95] = 1; |
412 | s1[96] = -108; |
413 | s2[96] = -108; |
414 | s1[97] = -13; |
415 | s2[97] = -13; |
416 | s1[98] = -109; |
417 | s2[98] = -109; |
418 | s1[99] = 1; |
419 | s2[99] = 1; |
420 | s1[100] = 116; |
421 | s2[100] = 116; |
422 | s1[101] = CHAR__MIN; |
423 | s2[101] = CHAR__MAX; |
424 | s1[102] = -109; |
425 | s2[102] = -109; |
426 | s1[103] = 1; |
427 | s2[103] = 1; |
428 | s1[104] = 84; |
429 | s2[104] = 84; |
430 | s1[105] = -13; |
431 | s2[105] = -13; |
432 | s1[106] = -109; |
433 | s2[106] = -109; |
434 | s1[107] = 1; |
435 | s2[107] = 1; |
436 | s1[108] = 52; |
437 | s2[108] = 52; |
438 | s1[109] = -13; |
439 | s2[109] = -13; |
440 | s1[110] = -109; |
441 | s2[110] = -109; |
442 | s1[111] = 1; |
443 | s2[111] = 1; |
444 | s1[112] = CHAR__MAX; |
445 | s2[112] = CHAR__MIN; |
446 | s1[113] = -13; |
447 | s2[113] = -13; |
448 | s1[114] = -109; |
449 | s2[114] = -109; |
450 | s1[115] = 1; |
451 | s2[115] = 1; |
452 | |
453 | n = 116; |
454 | for (size_t i = 0; i < n; i++) |
455 | for (size_t len = 0; len <= n - i; ++len) |
456 | { |
457 | exp_result = SIMPLE_MEMCMP (s1: s1 + i, s2: s2 + i, n: len); |
458 | FOR_EACH_IMPL (impl, 0) |
459 | check_result (impl, s1: s1 + i, s2: s2 + i, len, exp_result); |
460 | } |
461 | } |
462 | |
463 | /* This test checks that memcmp doesn't overrun buffers. */ |
464 | static void |
465 | check2 (void) |
466 | { |
467 | size_t max_length = page_size / sizeof (CHAR); |
468 | |
469 | /* Initialize buf2 to the same values as buf1. The bug requires the |
470 | last compared byte to be different. */ |
471 | memcpy (buf2, buf1, page_size); |
472 | ((char *) buf2)[page_size - 1] ^= 0x11; |
473 | |
474 | for (size_t length = 1; length < max_length; length++) |
475 | { |
476 | CHAR *s1 = (CHAR *) buf1 + max_length - length; |
477 | CHAR *s2 = (CHAR *) buf2 + max_length - length; |
478 | |
479 | const int exp_result = SIMPLE_MEMCMP (s1, s2, n: length); |
480 | |
481 | FOR_EACH_IMPL (impl, 0) |
482 | check_result (impl, s1, s2, len: length, exp_result); |
483 | } |
484 | } |
485 | |
486 | int |
487 | test_main (void) |
488 | { |
489 | size_t i; |
490 | |
491 | test_init (); |
492 | |
493 | check1 (); |
494 | check2 (); |
495 | |
496 | printf (format: "%23s" , "" ); |
497 | FOR_EACH_IMPL (impl, 0) |
498 | printf (format: "\t%s" , impl->name); |
499 | putchar (c: '\n'); |
500 | |
501 | for (i = 1; i < 32; ++i) |
502 | { |
503 | do_test (align1: i * CHARBYTES, align2: i * CHARBYTES, len: i, exp_result: 0); |
504 | do_test (align1: i * CHARBYTES, align2: i * CHARBYTES, len: i, exp_result: 1); |
505 | do_test (align1: i * CHARBYTES, align2: i * CHARBYTES, len: i, exp_result: -1); |
506 | } |
507 | |
508 | for (i = 0; i < 32; ++i) |
509 | { |
510 | do_test (align1: 0, align2: 0, len: i, exp_result: 0); |
511 | do_test (align1: 0, align2: 0, len: i, exp_result: 1); |
512 | do_test (align1: 0, align2: 0, len: i, exp_result: -1); |
513 | do_test (align1: 4096 - i, align2: 0, len: i, exp_result: 0); |
514 | do_test (align1: 4096 - i, align2: 0, len: i, exp_result: 1); |
515 | do_test (align1: 4096 - i, align2: 0, len: i, exp_result: -1); |
516 | do_test (align1: 4095, align2: 0, len: i, exp_result: 0); |
517 | do_test (align1: 4095, align2: 0, len: i, exp_result: 1); |
518 | do_test (align1: 4095, align2: 0, len: i, exp_result: -1); |
519 | do_test (align1: 4095, align2: 4095, len: i, exp_result: 0); |
520 | do_test (align1: 4095, align2: 4095, len: i, exp_result: 1); |
521 | do_test (align1: 4095, align2: 4095, len: i, exp_result: -1); |
522 | do_test (align1: 4000, align2: 95, len: i, exp_result: 0); |
523 | do_test (align1: 4000, align2: 95, len: i, exp_result: 1); |
524 | do_test (align1: 4000, align2: 95, len: i, exp_result: -1); |
525 | } |
526 | |
527 | for (i = 33; i < 385; i += 32) |
528 | { |
529 | do_test (align1: 0, align2: 0, len: i, exp_result: 0); |
530 | do_test (align1: 0, align2: 0, len: i, exp_result: 1); |
531 | do_test (align1: 0, align2: 0, len: i, exp_result: -1); |
532 | do_test (align1: i, align2: 0, len: i, exp_result: 0); |
533 | do_test (align1: 0, align2: i, len: i, exp_result: 1); |
534 | do_test (align1: i, align2: i, len: i, exp_result: -1); |
535 | } |
536 | |
537 | for (i = 1; i < 10; ++i) |
538 | { |
539 | do_test (align1: 0, align2: 0, len: 2 << i, exp_result: 0); |
540 | do_test (align1: 0, align2: 0, len: 2 << i, exp_result: 1); |
541 | do_test (align1: 0, align2: 0, len: 2 << i, exp_result: -1); |
542 | do_test (align1: (8 - i) * CHARBYTES, align2: (2 * i) * CHARBYTES, len: 16 << i, exp_result: 0); |
543 | do_test (align1: 0, align2: 0, len: 16 << i, exp_result: 0); |
544 | do_test (align1: 0, align2: 0, len: 16 << i, exp_result: 1); |
545 | do_test (align1: 0, align2: 0, len: 16 << i, exp_result: -1); |
546 | do_test (align1: i, align2: 0, len: 2 << i, exp_result: 0); |
547 | do_test (align1: 0, align2: i, len: 2 << i, exp_result: 1); |
548 | do_test (align1: i, align2: i, len: 2 << i, exp_result: -1); |
549 | do_test (align1: i, align2: 0, len: 16 << i, exp_result: 0); |
550 | do_test (align1: 0, align2: i, len: 16 << i, exp_result: 1); |
551 | do_test (align1: i, align2: i, len: 16 << i, exp_result: -1); |
552 | } |
553 | |
554 | for (i = 1; i < 10; ++i) |
555 | { |
556 | do_test (align1: i * CHARBYTES, align2: 2 * (i * CHARBYTES), len: 8 << i, exp_result: 0); |
557 | do_test (align1: i * CHARBYTES, align2: 2 * (i * CHARBYTES), len: 8 << i, exp_result: 1); |
558 | do_test (align1: i * CHARBYTES, align2: 2 * (i * CHARBYTES), len: 8 << i, exp_result: -1); |
559 | } |
560 | |
561 | do_random_tests (); |
562 | return ret; |
563 | } |
564 | |
565 | #include <support/test-driver.c> |
566 | |