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