1 /* Alignment/padding coverage test for string comparison.
2 Copyright (C) 2016-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 /* This performs test comparisons with various (mis)alignments and
20 characters in the padding. It is partly a regression test for bug
21 20327. */
22
23 #include <limits.h>
24 #include <malloc.h>
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <libc-diag.h>
30
31 static int
signum(int val)32 signum (int val)
33 {
34 if (val < 0)
35 return -1;
36 if (val > 0)
37 return 1;
38 else
39 return 0;
40 }
41
42 static size_t
max_size_t(size_t left,size_t right)43 max_size_t (size_t left, size_t right)
44 {
45 if (left > right)
46 return left;
47 else
48 return right;
49 }
50
51 /* Wrappers for strncmp and strncasecmp which determine the maximum
52 string length in some, either based on the input string length, or
53 using fixed constants. */
54
55 static int
strncmp_no_terminator(const char * left,const char * right)56 strncmp_no_terminator (const char *left, const char *right)
57 {
58 size_t left_len = strlen (left);
59 size_t right_len = strlen (right);
60 return strncmp (left, right, max_size_t (left_len, right_len));
61 }
62
63 static int
strncasecmp_no_terminator(const char * left,const char * right)64 strncasecmp_no_terminator (const char *left, const char *right)
65 {
66 size_t left_len = strlen (left);
67 size_t right_len = strlen (right);
68 return strncasecmp (left, right, max_size_t (left_len, right_len));
69 }
70
71 static int
strncmp_terminator(const char * left,const char * right)72 strncmp_terminator (const char *left, const char *right)
73 {
74 size_t left_len = strlen (left);
75 size_t right_len = strlen (right);
76 return strncmp (left, right, max_size_t (left_len, right_len));
77 }
78
79 static int
strncasecmp_terminator(const char * left,const char * right)80 strncasecmp_terminator (const char *left, const char *right)
81 {
82 size_t left_len = strlen (left);
83 size_t right_len = strlen (right);
84 return strncasecmp (left, right, max_size_t (left_len, right_len));
85 }
86
87 static int
strncmp_64(const char * left,const char * right)88 strncmp_64 (const char *left, const char *right)
89 {
90 return strncmp (left, right, 64);
91 }
92
93 static int
strncasecmp_64(const char * left,const char * right)94 strncasecmp_64 (const char *left, const char *right)
95 {
96 return strncasecmp (left, right, 64);
97 }
98
99 static int
strncmp_max(const char * left,const char * right)100 strncmp_max (const char *left, const char *right)
101 {
102 DIAG_PUSH_NEEDS_COMMENT;
103 #if __GNUC_PREREQ (7, 0)
104 /* GCC 9 warns about the size passed to strncmp being larger than
105 PTRDIFF_MAX; the use of SIZE_MAX is deliberate here. */
106 DIAG_IGNORE_NEEDS_COMMENT (9, "-Wstringop-overflow=");
107 #endif
108 #if __GNUC_PREREQ (11, 0)
109 /* Likewise GCC 11, with a different warning option. */
110 DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overread");
111 #endif
112 return strncmp (left, right, SIZE_MAX);
113 DIAG_POP_NEEDS_COMMENT;
114 }
115
116 static int
strncasecmp_max(const char * left,const char * right)117 strncasecmp_max (const char *left, const char *right)
118 {
119 DIAG_PUSH_NEEDS_COMMENT;
120 #if __GNUC_PREREQ (7, 0)
121 /* GCC 9 warns about the size passed to strncasecmp being larger
122 than PTRDIFF_MAX; the use of SIZE_MAX is deliberate here. */
123 DIAG_IGNORE_NEEDS_COMMENT (9, "-Wstringop-overflow=");
124 #endif
125 #if __GNUC_PREREQ (11, 0)
126 /* Likewise GCC 11, with a different warning option. */
127 DIAG_IGNORE_NEEDS_COMMENT (11, "-Wstringop-overread");
128 #endif
129 return strncasecmp (left, right, SIZE_MAX);
130 DIAG_POP_NEEDS_COMMENT;
131 }
132
133 int
do_test(void)134 do_test (void)
135 {
136 enum {
137 max_align = 64,
138 max_string_length = 33
139 };
140 size_t blob_size = max_align + max_string_length + 1;
141 char *left = memalign (max_align, blob_size);
142 char *right = memalign (max_align, blob_size);
143 if (left == NULL || right == NULL)
144 {
145 printf ("error: out of memory\n");
146 return 1;
147 }
148
149 const struct
150 {
151 const char *name;
152 int (*implementation) (const char *, const char *);
153 } functions[] =
154 {
155 { "strcmp", strcmp },
156 { "strcasecmp", strcasecmp },
157 { "strncmp (without NUL)", strncmp_no_terminator},
158 { "strncasecmp (without NUL)", strncasecmp_no_terminator},
159 { "strncmp (with NUL)", strncmp_terminator},
160 { "strncasecmp (with NUL)", strncasecmp_terminator},
161 { "strncmp (length 64)", strncmp_64},
162 { "strncasecmp (length 64)", strncasecmp_64},
163 { "strncmp (length SIZE_MAX)", strncmp_max},
164 { "strncasecmp (length SIZE_MAX)", strncasecmp_max},
165 { NULL, NULL }
166 };
167 const char *const strings[] =
168 {
169 "",
170 "0",
171 "01",
172 "01234567",
173 "0123456789abcde",
174 "0123456789abcdef",
175 "0123456789abcdefg",
176 "1",
177 "10",
178 "123456789abcdef",
179 "123456789abcdefg",
180 "23456789abcdef",
181 "23456789abcdefg",
182 "abcdefghijklmnopqrstuvwxyzABCDEF",
183 NULL
184 };
185 const unsigned char pads[] =
186 { 0, 1, 32, 64, 128, '0', '1', 'e', 'f', 'g', 127, 192, 255 };
187
188 bool errors = false;
189 for (int left_idx = 0; strings[left_idx] != NULL; ++left_idx)
190 for (int left_align = 0; left_align < max_align; ++left_align)
191 for (unsigned pad_left = 0; pad_left < sizeof (pads); ++pad_left)
192 {
193 memset (left, pads[pad_left], blob_size);
194 strcpy (left + left_align, strings[left_idx]);
195
196 for (int right_idx = 0; strings[right_idx] != NULL; ++right_idx)
197 for (unsigned pad_right = 0; pad_right < sizeof (pads);
198 ++pad_right)
199 for (int right_align = 0; right_align < max_align;
200 ++right_align)
201 {
202 memset (right, pads[pad_right], blob_size);
203 strcpy (right + right_align, strings[right_idx]);
204
205 for (int func = 0; functions[func].name != NULL; ++func)
206 {
207 int expected = left_idx - right_idx;
208 int actual = functions[func].implementation
209 (left + left_align, right + right_align);
210 if (signum (actual) != signum (expected))
211 {
212 printf ("error: mismatch for %s: %d\n"
213 " left: \"%s\"\n"
214 " right: \"%s\"\n"
215 " pad_left = %u, pad_right = %u,\n"
216 " left_align = %d, right_align = %d\n",
217 functions[func].name, actual,
218 strings[left_idx], strings[right_idx],
219 pad_left, pad_right,
220 left_align, right_align);
221 errors = true;
222 }
223 }
224 }
225 }
226 free (right);
227 free (left);
228 return errors;
229 }
230
231 /* The nested loops need a long time to complete on slower
232 machines. */
233 #define TIMEOUT 600
234
235 #include <support/test-driver.c>
236