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