| /* Alignment/padding coverage test for string comparison. |
| Copyright (C) 2016-2018 Free Software Foundation, Inc. |
| This file is part of the GNU C Library. |
| |
| The GNU C Library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| The GNU C Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with the GNU C Library; if not, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* This performs test comparisons with various (mis)alignments and |
| characters in the padding. It is partly a regression test for bug |
| 20327. */ |
| |
| #include <limits.h> |
| #include <malloc.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| static int |
| signum (int val) |
| { |
| if (val < 0) |
| return -1; |
| if (val > 0) |
| return 1; |
| else |
| return 0; |
| } |
| |
| static size_t |
| max_size_t (size_t left, size_t right) |
| { |
| if (left > right) |
| return left; |
| else |
| return right; |
| } |
| |
| /* Wrappers for strncmp and strncasecmp which determine the maximum |
| string length in some, either based on the input string length, or |
| using fixed constants. */ |
| |
| static int |
| strncmp_no_terminator (const char *left, const char *right) |
| { |
| size_t left_len = strlen (left); |
| size_t right_len = strlen (right); |
| return strncmp (left, right, max_size_t (left_len, right_len)); |
| } |
| |
| static int |
| strncasecmp_no_terminator (const char *left, const char *right) |
| { |
| size_t left_len = strlen (left); |
| size_t right_len = strlen (right); |
| return strncasecmp (left, right, max_size_t (left_len, right_len)); |
| } |
| |
| static int |
| strncmp_terminator (const char *left, const char *right) |
| { |
| size_t left_len = strlen (left); |
| size_t right_len = strlen (right); |
| return strncmp (left, right, max_size_t (left_len, right_len)); |
| } |
| |
| static int |
| strncasecmp_terminator (const char *left, const char *right) |
| { |
| size_t left_len = strlen (left); |
| size_t right_len = strlen (right); |
| return strncasecmp (left, right, max_size_t (left_len, right_len)); |
| } |
| |
| static int |
| strncmp_64 (const char *left, const char *right) |
| { |
| return strncmp (left, right, 64); |
| } |
| |
| static int |
| strncasecmp_64 (const char *left, const char *right) |
| { |
| return strncasecmp (left, right, 64); |
| } |
| |
| static int |
| strncmp_max (const char *left, const char *right) |
| { |
| return strncmp (left, right, SIZE_MAX); |
| } |
| |
| static int |
| strncasecmp_max (const char *left, const char *right) |
| { |
| return strncasecmp (left, right, SIZE_MAX); |
| } |
| |
| int |
| do_test (void) |
| { |
| enum { |
| max_align = 64, |
| max_string_length = 33 |
| }; |
| size_t blob_size = max_align + max_string_length + 1; |
| char *left = memalign (max_align, blob_size); |
| char *right = memalign (max_align, blob_size); |
| if (left == NULL || right == NULL) |
| { |
| printf ("error: out of memory\n"); |
| return 1; |
| } |
| |
| const struct |
| { |
| const char *name; |
| int (*implementation) (const char *, const char *); |
| } functions[] = |
| { |
| { "strcmp", strcmp }, |
| { "strcasecmp", strcasecmp }, |
| { "strncmp (without NUL)", strncmp_no_terminator}, |
| { "strncasecmp (without NUL)", strncasecmp_no_terminator}, |
| { "strncmp (with NUL)", strncmp_terminator}, |
| { "strncasecmp (with NUL)", strncasecmp_terminator}, |
| { "strncmp (length 64)", strncmp_64}, |
| { "strncasecmp (length 64)", strncasecmp_64}, |
| { "strncmp (length SIZE_MAX)", strncmp_max}, |
| { "strncasecmp (length SIZE_MAX)", strncasecmp_max}, |
| { NULL, NULL } |
| }; |
| const char *const strings[] = |
| { |
| "", |
| "0", |
| "01", |
| "01234567", |
| "0123456789abcde", |
| "0123456789abcdef", |
| "0123456789abcdefg", |
| "1", |
| "10", |
| "123456789abcdef", |
| "123456789abcdefg", |
| "23456789abcdef", |
| "23456789abcdefg", |
| "abcdefghijklmnopqrstuvwxyzABCDEF", |
| NULL |
| }; |
| const unsigned char pads[] = |
| { 0, 1, 32, 64, 128, '0', '1', 'e', 'f', 'g', 127, 192, 255 }; |
| |
| bool errors = false; |
| for (int left_idx = 0; strings[left_idx] != NULL; ++left_idx) |
| for (int left_align = 0; left_align < max_align; ++left_align) |
| for (unsigned pad_left = 0; pad_left < sizeof (pads); ++pad_left) |
| { |
| memset (left, pads[pad_left], blob_size); |
| strcpy (left + left_align, strings[left_idx]); |
| |
| for (int right_idx = 0; strings[right_idx] != NULL; ++right_idx) |
| for (unsigned pad_right = 0; pad_right < sizeof (pads); |
| ++pad_right) |
| for (int right_align = 0; right_align < max_align; |
| ++right_align) |
| { |
| memset (right, pads[pad_right], blob_size); |
| strcpy (right + right_align, strings[right_idx]); |
| |
| for (int func = 0; functions[func].name != NULL; ++func) |
| { |
| int expected = left_idx - right_idx; |
| int actual = functions[func].implementation |
| (left + left_align, right + right_align); |
| if (signum (actual) != signum (expected)) |
| { |
| printf ("error: mismatch for %s: %d\n" |
| " left: \"%s\"\n" |
| " right: \"%s\"\n" |
| " pad_left = %u, pad_right = %u,\n" |
| " left_align = %d, right_align = %d\n", |
| functions[func].name, actual, |
| strings[left_idx], strings[right_idx], |
| pad_left, pad_right, |
| left_align, right_align); |
| errors = true; |
| } |
| } |
| } |
| } |
| free (right); |
| free (left); |
| return errors; |
| } |
| |
| /* The nested loops need a long time to complete on slower |
| machines. */ |
| #define TIMEOUT 600 |
| |
| #include <support/test-driver.c> |