maint: update copyright
[gnulib.git] / tests / test-memmem.c
1 /*
2  * Copyright (C) 2004, 2007-2014 Free Software Foundation, Inc.
3  * Written by Bruno Haible and Eric Blake
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program 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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 #include <config.h>
19
20 #include <string.h>
21
22 #include "signature.h"
23 SIGNATURE_CHECK (memmem, void *, (void const *, size_t, void const *, size_t));
24
25 #include <signal.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28
29 #include "zerosize-ptr.h"
30 #include "macros.h"
31
32 static void *
33 null_ptr (void)
34 {
35   return NULL;
36 }
37
38 int
39 main (int argc, char *argv[])
40 {
41 #if HAVE_DECL_ALARM
42   /* Declare failure if test takes too long, by using default abort
43      caused by SIGALRM.  All known platforms that lack alarm also lack
44      memmem, and the replacement memmem is known to not take too
45      long.  */
46   int alarm_value = 100;
47   signal (SIGALRM, SIG_DFL);
48   alarm (alarm_value);
49 #endif
50
51   {
52     const char input[] = "foo";
53     const char *result = memmem (input, strlen (input), "", 0);
54     ASSERT (result == input);
55   }
56
57   {
58     const char input[] = "foo";
59     const char *result = memmem (input, strlen (input), "o", 1);
60     ASSERT (result == input + 1);
61   }
62
63   {
64     const char input[] = "ABC ABCDAB ABCDABCDABDE";
65     const char *result = memmem (input, strlen (input), "ABCDABD", 7);
66     ASSERT (result == input + 15);
67   }
68
69   {
70     const char input[] = "ABC ABCDAB ABCDABCDABDE";
71     const char *result = memmem (input, strlen (input), "ABCDABE", 7);
72     ASSERT (result == NULL);
73   }
74
75   {
76     const char input[] = "ABC ABCDAB ABCDABCDABDE";
77     const char *result = memmem (input, strlen (input), "ABCDABCD", 8);
78     ASSERT (result == input + 11);
79   }
80
81   /* Check that length 0 does not dereference the pointer.  */
82   {
83     const char *result = memmem (zerosize_ptr (), 0, "foo", 3);
84     ASSERT (result == NULL);
85   }
86
87   {
88     const char input[] = "foo";
89     const char *result = memmem (input, strlen (input), null_ptr (), 0);
90     ASSERT (result == input);
91   }
92
93   /* Check that a long periodic needle does not cause false positives.  */
94   {
95     const char input[] = ("F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD"
96                           "_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD"
97                           "_C3_A7_20_EF_BF_BD");
98     const char need[] = "_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD";
99     const char *result = memmem (input, strlen (input), need, strlen (need));
100     ASSERT (result == NULL);
101   }
102   {
103     const char input[] = ("F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD"
104                           "_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD"
105                           "_C3_A7_20_EF_BF_BD_DA_B5_C2_A6_20"
106                           "_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD");
107     const char need[] = "_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD";
108     const char *result = memmem (input, strlen (input), need, strlen (need));
109     ASSERT (result == input + 115);
110   }
111
112   /* Check that a very long haystack is handled quickly if the needle is
113      short and occurs near the beginning.  */
114   {
115     size_t repeat = 10000;
116     size_t m = 1000000;
117     const char *needle =
118       "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
119       "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
120     size_t n = strlen (needle);
121     char *haystack = (char *) malloc (m + 1);
122     if (haystack != NULL)
123       {
124         memset (haystack, 'A', m);
125         haystack[0] = 'B';
126
127         for (; repeat > 0; repeat--)
128           {
129             ASSERT (memmem (haystack, m, needle, n) == haystack + 1);
130           }
131
132         free (haystack);
133       }
134   }
135
136   /* Check that a very long needle is discarded quickly if the haystack is
137      short.  */
138   {
139     size_t repeat = 10000;
140     size_t m = 1000000;
141     const char *haystack =
142       "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
143       "ABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB";
144     size_t n = strlen (haystack);
145     char *needle = (char *) malloc (m + 1);
146     if (needle != NULL)
147       {
148         memset (needle, 'A', m);
149
150         for (; repeat > 0; repeat--)
151           {
152             ASSERT (memmem (haystack, n, needle, m) == NULL);
153           }
154
155         free (needle);
156       }
157   }
158
159   /* Check that the asymptotic worst-case complexity is not quadratic.  */
160   {
161     size_t m = 1000000;
162     char *haystack = (char *) malloc (2 * m + 1);
163     char *needle = (char *) malloc (m + 1);
164     if (haystack != NULL && needle != NULL)
165       {
166         const char *result;
167
168         memset (haystack, 'A', 2 * m);
169         haystack[2 * m] = 'B';
170
171         memset (needle, 'A', m);
172         needle[m] = 'B';
173
174         result = memmem (haystack, 2 * m + 1, needle, m + 1);
175         ASSERT (result == haystack + m);
176       }
177     free (needle);
178     free (haystack);
179   }
180
181   /* Check that long needles not present in a haystack can be handled
182      with sublinear speed.  */
183   {
184     size_t repeat = 10000;
185     size_t m = 1000000;
186     size_t n = 1000;
187     char *haystack = (char *) malloc (m);
188     char *needle = (char *) malloc (n);
189     if (haystack != NULL && needle != NULL)
190       {
191         const char *result;
192
193         memset (haystack, 'A', m);
194         memset (needle, 'B', n);
195
196         for (; repeat > 0; repeat--)
197           {
198             result = memmem (haystack, m, needle, n);
199             ASSERT (result == NULL);
200           }
201       }
202     free (haystack);
203     free (needle);
204   }
205
206   {
207     /* Ensure that with a barely periodic "short" needle, memmem's
208        search does not mistakenly skip just past the match point.
209        This use of memmem would mistakenly return NULL before
210        gnulib v0.0-4927.  */
211     const char *haystack =
212       "\n"
213       "with_build_libsubdir\n"
214       "with_local_prefix\n"
215       "with_gxx_include_dir\n"
216       "with_cpp_install_dir\n"
217       "enable_generated_files_in_srcdir\n"
218       "with_gnu_ld\n"
219       "with_ld\n"
220       "with_demangler_in_ld\n"
221       "with_gnu_as\n"
222       "with_as\n"
223       "enable_largefile\n"
224       "enable_werror_always\n"
225       "enable_checking\n"
226       "enable_coverage\n"
227       "enable_gather_detailed_mem_stats\n"
228       "enable_build_with_cxx\n"
229       "with_stabs\n"
230       "enable_multilib\n"
231       "enable___cxa_atexit\n"
232       "enable_decimal_float\n"
233       "enable_fixed_point\n"
234       "enable_threads\n"
235       "enable_tls\n"
236       "enable_objc_gc\n"
237       "with_dwarf2\n"
238       "enable_shared\n"
239       "with_build_sysroot\n"
240       "with_sysroot\n"
241       "with_specs\n"
242       "with_pkgversion\n"
243       "with_bugurl\n"
244       "enable_languages\n"
245       "with_multilib_list\n";
246     const char *needle = "\n"
247       "with_gnu_ld\n";
248     const char* p = memmem (haystack, strlen (haystack),
249                             needle, strlen (needle));
250     ASSERT (p - haystack == 114);
251   }
252
253   {
254     /* Same bug, shorter trigger.  */
255     const char *haystack = "..wi.d.";
256     const char *needle = ".d.";
257     const char* p = memmem (haystack, strlen (haystack),
258                             needle, strlen (needle));
259     ASSERT (p - haystack == 4);
260   }
261
262   {
263     /* Like the above, but trigger the flaw in two_way_long_needle
264        by using a needle of length LONG_NEEDLE_THRESHOLD (32) or greater.
265        Rather than trying to find the right alignment manually, I've
266        arbitrarily chosen the following needle and template for the
267        haystack, and ensure that for each placement of the needle in
268        that haystack, memmem finds it.  */
269     const char *needle = "\nwith_gnu_ld-extend-to-len-32-b\n";
270     const char *h =
271       "\n"
272       "with_build_libsubdir\n"
273       "with_local_prefix\n"
274       "with_gxx_include_dir\n"
275       "with_cpp_install_dir\n"
276       "with_e_\n"
277       "..............................\n"
278       "with_FGHIJKLMNOPQRSTUVWXYZ\n"
279       "with_567890123456789\n"
280       "with_multilib_list\n";
281     size_t h_len = strlen (h);
282     char *haystack = malloc (h_len + 1);
283     size_t i;
284     ASSERT (haystack);
285     for (i = 0; i < h_len - strlen (needle); i++)
286       {
287         const char *p;
288         memcpy (haystack, h, h_len + 1);
289         memcpy (haystack + i, needle, strlen (needle) + 1);
290         p = memmem (haystack, strlen (haystack), needle, strlen (needle));
291         ASSERT (p);
292         ASSERT (p - haystack == i);
293       }
294   }
295
296   return 0;
297 }