2 * Copyright (C) 2004, 2007-2024 Free Software Foundation, Inc.
3 * Written by Bruno Haible and Eric Blake
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.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>. */
22 #include "signature.h"
23 SIGNATURE_CHECK (memmem
, void *, (void const *, size_t, void const *, size_t));
29 #include "zerosize-ptr.h"
33 main (int argc
, char *argv
[])
36 /* Declare failure if test takes too long, by using default abort
37 caused by SIGALRM. All known platforms that lack alarm also lack
38 memmem, and the replacement memmem is known to not take too
40 int alarm_value
= 100;
41 signal (SIGALRM
, SIG_DFL
);
46 const char input
[] = "foo";
47 const char *result
= memmem (input
, strlen (input
), "", 0);
48 ASSERT (result
== input
);
52 const char input
[] = "foo";
53 const char *result
= memmem (input
, strlen (input
), "o", 1);
54 ASSERT (result
== input
+ 1);
58 const char input
[] = "ABC ABCDAB ABCDABCDABDE";
59 const char *result
= memmem (input
, strlen (input
), "ABCDABD", 7);
60 ASSERT (result
== input
+ 15);
64 const char input
[] = "ABC ABCDAB ABCDABCDABDE";
65 const char *result
= memmem (input
, strlen (input
), "ABCDABE", 7);
66 ASSERT (result
== NULL
);
70 const char input
[] = "ABC ABCDAB ABCDABCDABDE";
71 const char *result
= memmem (input
, strlen (input
), "ABCDABCD", 8);
72 ASSERT (result
== input
+ 11);
75 /* Check that length 0 does not dereference the pointer. */
76 void *page_boundary
= zerosize_ptr ();
80 const char *result
= memmem (page_boundary
, 0, "foo", 3);
81 ASSERT (result
== NULL
);
85 const char input
[] = "foo";
86 const char *result
= memmem (input
, strlen (input
), page_boundary
, 0);
87 ASSERT (result
== input
);
91 /* Check that a long periodic needle does not cause false positives. */
93 const char input
[] = "F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD"
94 "_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD"
96 const char need
[] = "_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD";
97 const char *result
= memmem (input
, strlen (input
), need
, strlen (need
));
98 ASSERT (result
== NULL
);
101 const char input
[] = "F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD"
102 "_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD"
103 "_C3_A7_20_EF_BF_BD_DA_B5_C2_A6_20"
104 "_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD";
105 const char need
[] = "_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD";
106 const char *result
= memmem (input
, strlen (input
), need
, strlen (need
));
107 ASSERT (result
== input
+ 115);
110 /* Check that a very long haystack is handled quickly if the needle is
111 short and occurs near the beginning. */
113 size_t repeat
= 10000;
116 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
117 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
118 size_t n
= strlen (needle
);
119 char *haystack
= (char *) malloc (m
+ 1);
120 if (haystack
!= NULL
)
122 memset (haystack
, 'A', m
);
125 for (; repeat
> 0; repeat
--)
127 ASSERT (memmem (haystack
, m
, needle
, n
) == haystack
+ 1);
134 /* Check that a very long needle is discarded quickly if the haystack is
137 size_t repeat
= 10000;
139 const char *haystack
=
140 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
141 "ABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB";
142 size_t n
= strlen (haystack
);
143 char *needle
= (char *) malloc (m
+ 1);
146 memset (needle
, 'A', m
);
148 for (; repeat
> 0; repeat
--)
150 ASSERT (memmem (haystack
, n
, needle
, m
) == NULL
);
157 /* Check that the asymptotic worst-case complexity is not quadratic. */
160 char *haystack
= (char *) malloc (2 * m
+ 1);
161 char *needle
= (char *) malloc (m
+ 1);
162 if (haystack
!= NULL
&& needle
!= NULL
)
166 memset (haystack
, 'A', 2 * m
);
167 haystack
[2 * m
] = 'B';
169 memset (needle
, 'A', m
);
172 result
= memmem (haystack
, 2 * m
+ 1, needle
, m
+ 1);
173 ASSERT (result
== haystack
+ m
);
179 /* Check that long needles not present in a haystack can be handled
180 with sublinear speed. */
182 size_t repeat
= 10000;
185 char *haystack
= (char *) malloc (m
);
186 char *needle
= (char *) malloc (n
);
187 if (haystack
!= NULL
&& needle
!= NULL
)
191 memset (haystack
, 'A', m
);
192 memset (needle
, 'B', n
);
194 for (; repeat
> 0; repeat
--)
196 result
= memmem (haystack
, m
, needle
, n
);
197 ASSERT (result
== NULL
);
205 /* Ensure that with a barely periodic "short" needle, memmem's
206 search does not mistakenly skip just past the match point.
207 This use of memmem would mistakenly return NULL before
209 const char *haystack
=
211 "with_build_libsubdir\n"
212 "with_local_prefix\n"
213 "with_gxx_include_dir\n"
214 "with_cpp_install_dir\n"
215 "enable_generated_files_in_srcdir\n"
218 "with_demangler_in_ld\n"
222 "enable_werror_always\n"
225 "enable_gather_detailed_mem_stats\n"
226 "enable_build_with_cxx\n"
229 "enable___cxa_atexit\n"
230 "enable_decimal_float\n"
231 "enable_fixed_point\n"
237 "with_build_sysroot\n"
243 "with_multilib_list\n";
244 const char *needle
= "\n"
246 const char* p
= memmem (haystack
, strlen (haystack
),
247 needle
, strlen (needle
));
248 ASSERT (p
- haystack
== 114);
252 /* Same bug, shorter trigger. */
253 const char *haystack
= "..wi.d.";
254 const char *needle
= ".d.";
255 const char* p
= memmem (haystack
, strlen (haystack
),
256 needle
, strlen (needle
));
257 ASSERT (p
- haystack
== 4);
261 /* Like the above, but trigger the flaw in two_way_long_needle
262 by using a needle of length LONG_NEEDLE_THRESHOLD (32) or greater.
263 Rather than trying to find the right alignment manually, I've
264 arbitrarily chosen the following needle and template for the
265 haystack, and ensure that for each placement of the needle in
266 that haystack, memmem finds it. */
267 const char *needle
= "\nwith_gnu_ld-extend-to-len-32-b\n";
270 "with_build_libsubdir\n"
271 "with_local_prefix\n"
272 "with_gxx_include_dir\n"
273 "with_cpp_install_dir\n"
275 "..............................\n"
276 "with_FGHIJKLMNOPQRSTUVWXYZ\n"
277 "with_567890123456789\n"
278 "with_multilib_list\n";
279 size_t h_len
= strlen (h
);
280 char *haystack
= malloc (h_len
+ 1);
283 for (i
= 0; i
< h_len
- strlen (needle
); i
++)
286 memcpy (haystack
, h
, h_len
+ 1);
287 memcpy (haystack
+ i
, needle
, strlen (needle
) + 1);
288 p
= memmem (haystack
, strlen (haystack
), needle
, strlen (needle
));
290 ASSERT (p
- haystack
== i
);
295 /* Test case from Yves Bastide.
296 <https://www.openwall.com/lists/musl/2014/04/18/2> */
298 const char input
[] = "playing play play play always";
299 const char *result
= memmem (input
, strlen (input
), "play play play", 14);
300 ASSERT (result
== input
+ 8);
303 /* Test long needles. */
306 char *haystack
= (char *) malloc (2 * m
+ 1);
307 char *needle
= (char *) malloc (m
+ 1);
308 if (haystack
!= NULL
&& needle
!= NULL
)
312 memset (haystack
+ 1, ' ', m
- 1);
313 memset (haystack
+ m
, 'x', m
);
314 haystack
[2 * m
] = '\0';
315 memset (needle
, 'x', m
);
317 p
= memmem (haystack
, strlen (haystack
), needle
, strlen (needle
));
319 ASSERT (p
- haystack
== m
);
325 return test_exit_status
;