1 /* Test and measure strstr functions.
2 Copyright (C) 2010-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
21 # define TEST_NAME "strstr"
22 # define TEST_FUNC strstr
24 # define TEST_NAME "wcsstr"
25 # define TEST_FUNC wcsstr
30 # define STRLEN strlen
31 # define STRCPY strcpy
32 # define MEMCPY memcpy
33 # define MEMSET memset
34 # define MEMPCPY mempcpy
39 # define STRLEN wcslen
40 # define STRCPY wcscpy
41 # define MEMCPY wmemcpy
42 # define MEMSET wmemset
43 # define MEMPCPY wmempcpy
45 /* The test requires up to 8191 characters, so allocate at least 32Kb
46 (considering 4kb page size). */
50 #include "test-string.h"
53 # define STRSTR c_strstr
54 # define libc_hidden_builtin_def(arg) /* nothing */
55 # define __strnlen strnlen
57 # define C_IMPL STRSTR
60 # define weak_alias(a, b)
61 # define WCSSTR c_wcsstr
62 # define __wmemcmp wmemcmp
63 # define __wcsnlen wcsnlen
64 # define __wcslen wcslen
66 # define C_IMPL WCSSTR
69 /* Naive implementation to verify results. */
71 simple_strstr (const CHAR
*s1
, const CHAR
*s2
)
73 ssize_t s1len
= STRLEN (s1
);
74 ssize_t s2len
= STRLEN (s2
);
79 for (ssize_t i
= 0; i
<= s1len
- s2len
; ++i
)
82 for (j
= 0; j
< s2len
; ++j
)
83 if (s1
[i
+ j
] != s2
[j
])
86 return (CHAR
*) s1
+ i
;
93 typedef CHAR
*(*proto_t
) (const CHAR
*, const CHAR
*);
99 check_result (impl_t
*impl
, const CHAR
*s1
, const CHAR
*s2
,
102 CHAR
*result
= CALL (impl
, s1
, s2
);
103 if (result
!= exp_result
)
105 error (0, 0, "Wrong result in function %s %p %p", impl
->name
,
115 do_one_test (impl_t
*impl
, const CHAR
*s1
, const CHAR
*s2
, CHAR
*exp_result
)
117 if (check_result (impl
, s1
, s2
, exp_result
) < 0)
123 do_test (size_t align1
, size_t align2
, size_t len1
, size_t len2
,
126 align1
= align1
* sizeof (CHAR
);
127 align2
= align2
* sizeof (CHAR
);
129 CHAR
*s1
= (CHAR
*) (buf1
+ align1
);
130 CHAR
*s2
= (CHAR
*) (buf2
+ align2
);
132 static const CHAR d
[] = L("1234567890abcdef");
133 const size_t dl
= STRLEN (d
);
135 for (size_t l
= len2
; l
> 0; l
= l
> dl
? l
- dl
: 0)
137 size_t t
= l
> dl
? dl
: l
;
138 ss2
= MEMPCPY (ss2
, d
, t
);
145 for (size_t l
= len1
; l
> 0; l
= l
> dl
? l
- dl
: 0)
147 size_t t
= l
> dl
? dl
: l
;
149 ++ss1
[len2
> 7 ? 7 : len2
- 1];
155 MEMSET (s1
, '0', len1
);
156 MEMCPY (s1
+ len1
- len2
, s2
, len2
);
160 FOR_EACH_IMPL (impl
, 0)
161 do_one_test (impl
, s1
, s2
, fail
? NULL
: s1
+ len1
- len2
);
168 L("F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD_C3_A7_20_EF_BF_BD");
169 const CHAR s2
[] = L("_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD");
172 exp_result
= simple_strstr (s1
, s2
);
173 FOR_EACH_IMPL (impl
, 0)
174 check_result (impl
, s1
, s2
, exp_result
);
180 const CHAR s1_stack
[] = L(", enable_static, \0, enable_shared, ");
181 const size_t s1_char_count
= 18;
182 const size_t s1_byte_len
= 18 * sizeof (CHAR
);
183 const CHAR
*s2_stack
= &(s1_stack
[s1_char_count
]);
184 const size_t s2_byte_len
= 18 * sizeof (CHAR
);
186 const size_t page_size_real
= getpagesize ();
188 /* Haystack at end of page. The following page is protected. */
189 CHAR
*s1_page_end
= (void *) buf1
+ page_size
- s1_byte_len
;
190 STRCPY (s1_page_end
, s1_stack
);
192 /* Haystack which crosses a page boundary.
193 Note: page_size is at least 2 * getpagesize. See test_init. */
194 CHAR
*s1_page_cross
= (void *) buf1
+ page_size_real
- 8;
195 STRCPY (s1_page_cross
, s1_stack
);
197 /* Needle at end of page. The following page is protected. */
198 CHAR
*s2_page_end
= (void *) buf2
+ page_size
- s2_byte_len
;
199 STRCPY (s2_page_end
, s2_stack
);
201 /* Needle which crosses a page boundary.
202 Note: page_size is at least 2 * getpagesize. See test_init. */
203 CHAR
*s2_page_cross
= (void *) buf2
+ page_size_real
- 8;
204 STRCPY (s2_page_cross
, s2_stack
);
206 exp_result
= simple_strstr (s1_stack
, s2_stack
);
207 FOR_EACH_IMPL (impl
, 0)
209 check_result (impl
, s1_stack
, s2_stack
, exp_result
);
210 check_result (impl
, s1_stack
, s2_page_end
, exp_result
);
211 check_result (impl
, s1_stack
, s2_page_cross
, exp_result
);
213 check_result (impl
, s1_page_end
, s2_stack
, exp_result
);
214 check_result (impl
, s1_page_end
, s2_page_end
, exp_result
);
215 check_result (impl
, s1_page_end
, s2_page_cross
, exp_result
);
217 check_result (impl
, s1_page_cross
, s2_stack
, exp_result
);
218 check_result (impl
, s1_page_cross
, s2_page_end
, exp_result
);
219 check_result (impl
, s1_page_cross
, s2_page_cross
, exp_result
);
226 /* Check that a long periodic needle does not cause false positives. */
228 const CHAR input
[] = L("F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD"
229 "_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD"
230 "_C3_A7_20_EF_BF_BD");
231 const CHAR need
[] = L("_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD");
232 FOR_EACH_IMPL (impl
, 0)
233 check_result (impl
, input
, need
, NULL
);
237 const CHAR input
[] = L("F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD"
238 "_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD"
239 "_C3_A7_20_EF_BF_BD_DA_B5_C2_A6_20"
240 "_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD");
241 const CHAR need
[] = L("_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD");
242 FOR_EACH_IMPL (impl
, 0)
243 check_result (impl
, input
, need
, (CHAR
*) input
+ 115);
253 CHAR
*h
= (CHAR
*) buf1
;
254 CHAR
*n
= (CHAR
*) buf2
;
256 for (int i
= 0; i
< N
; i
++)
266 /* Ensure we don't match at the first 'x'. */
269 CHAR
*exp_result
= simple_strstr (h
, n
);
270 FOR_EACH_IMPL (impl
, 0)
271 check_result (impl
, h
, n
, exp_result
);
277 /* Check that a very long haystack is handled quickly if the needle is
278 short and occurs near the beginning. */
282 L("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
283 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
284 CHAR
*haystack
= xmalloc ((m
+ 1) * sizeof (CHAR
));
285 MEMSET (haystack
, L('A'), m
);
286 haystack
[0] = L('B');
287 haystack
[m
] = L('\0');
289 FOR_EACH_IMPL (impl
, 0)
290 check_result (impl
, haystack
, needle
, haystack
+ 1);
295 /* Check that a very long needle is discarded quickly if the haystack is
299 const CHAR
*haystack
=
300 L("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
301 "ABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB");
302 CHAR
*needle
= xmalloc ((m
+ 1) * sizeof (CHAR
));
303 MEMSET (needle
, L
'A', m
);
306 FOR_EACH_IMPL (impl
, 0)
307 check_result (impl
, haystack
, needle
, NULL
);
312 /* Check that the asymptotic worst-case complexity is not quadratic. */
315 CHAR
*haystack
= xmalloc ((2 * m
+ 2) * sizeof (CHAR
));
316 CHAR
*needle
= xmalloc ((m
+ 2) * sizeof (CHAR
));
318 MEMSET (haystack
, L('A'), 2 * m
);
319 haystack
[2 * m
] = L('B');
320 haystack
[2 * m
+ 1] = L('\0');
322 MEMSET (needle
, L('A'), m
);
324 needle
[m
+ 1] = L('\0');
326 FOR_EACH_IMPL (impl
, 0)
327 check_result (impl
, haystack
, needle
, haystack
+ m
);
334 /* Ensure that with a barely periodic "short" needle, STRSTR's
335 search does not mistakenly skip just past the match point. */
336 const CHAR
*haystack
=
338 "with_build_libsubdir\n"
339 "with_local_prefix\n"
340 "with_gxx_include_dir\n"
341 "with_cpp_install_dir\n"
342 "enable_generated_files_in_srcdir\n"
345 "with_demangler_in_ld\n"
349 "enable_werror_always\n"
352 "enable_gather_detailed_mem_stats\n"
353 "enable_build_with_cxx\n"
356 "enable___cxa_atexit\n"
357 "enable_decimal_float\n"
358 "enable_fixed_point\n"
364 "with_build_sysroot\n"
370 "with_multilib_list\n");
375 FOR_EACH_IMPL (impl
, 0)
376 check_result (impl
, haystack
, needle
, (CHAR
*) haystack
+ 114);
380 /* Same bug, shorter trigger. */
381 const CHAR
*haystack
= L("..wi.d.");
382 const CHAR
*needle
= L(".d.");
383 FOR_EACH_IMPL (impl
, 0)
384 check_result (impl
, haystack
, needle
, (CHAR
*) haystack
+ 4);
387 /* Test case from Yves Bastide.
388 <https://www.openwall.com/lists/musl/2014/04/18/2> */
390 const CHAR
*input
= L("playing play play play always");
391 const CHAR
*needle
= L("play play play");
392 FOR_EACH_IMPL (impl
, 0)
393 check_result (impl
, input
, needle
, (CHAR
*) input
+ 8);
396 /* Test long needles. */
399 CHAR
*haystack
= xmalloc ((2 * m
+ 1) * sizeof (CHAR
));
400 CHAR
*needle
= xmalloc ((m
+ 1) * sizeof (CHAR
));
401 haystack
[0] = L('x');
402 MEMSET (haystack
+ 1, L(' '), m
- 1);
403 MEMSET (haystack
+ m
, L('x'), m
);
404 haystack
[2 * m
] = L('\0');
405 MEMSET (needle
, L('x'), m
);
408 FOR_EACH_IMPL (impl
, 0)
409 check_result (impl
, haystack
, needle
, haystack
+ m
);
428 FOR_EACH_IMPL (impl
, 0)
429 printf ("\t%s", impl
->name
);
432 for (size_t klen
= 2; klen
< 32; ++klen
)
433 for (size_t hlen
= 2 * klen
; hlen
< 16 * klen
; hlen
+= klen
)
435 do_test (0, 0, hlen
, klen
, 0);
436 do_test (0, 0, hlen
, klen
, 1);
437 do_test (0, 3, hlen
, klen
, 0);
438 do_test (0, 3, hlen
, klen
, 1);
439 do_test (0, 9, hlen
, klen
, 0);
440 do_test (0, 9, hlen
, klen
, 1);
441 do_test (0, 15, hlen
, klen
, 0);
442 do_test (0, 15, hlen
, klen
, 1);
444 do_test (3, 0, hlen
, klen
, 0);
445 do_test (3, 0, hlen
, klen
, 1);
446 do_test (3, 3, hlen
, klen
, 0);
447 do_test (3, 3, hlen
, klen
, 1);
448 do_test (3, 9, hlen
, klen
, 0);
449 do_test (3, 9, hlen
, klen
, 1);
450 do_test (3, 15, hlen
, klen
, 0);
451 do_test (3, 15, hlen
, klen
, 1);
453 do_test (9, 0, hlen
, klen
, 0);
454 do_test (9, 0, hlen
, klen
, 1);
455 do_test (9, 3, hlen
, klen
, 0);
456 do_test (9, 3, hlen
, klen
, 1);
457 do_test (9, 9, hlen
, klen
, 0);
458 do_test (9, 9, hlen
, klen
, 1);
459 do_test (9, 15, hlen
, klen
, 0);
460 do_test (9, 15, hlen
, klen
, 1);
462 do_test (15, 0, hlen
, klen
, 0);
463 do_test (15, 0, hlen
, klen
, 1);
464 do_test (15, 3, hlen
, klen
, 0);
465 do_test (15, 3, hlen
, klen
, 1);
466 do_test (15, 9, hlen
, klen
, 0);
467 do_test (15, 9, hlen
, klen
, 1);
468 do_test (15, 15, hlen
, klen
, 0);
469 do_test (15, 15, hlen
, klen
, 1);
471 do_test (15, 15, hlen
+ klen
* 4, klen
* 4, 0);
472 do_test (15, 15, hlen
+ klen
* 4, klen
* 4, 1);
475 do_test (0, 0, page_size
- 1, 16, 0);
476 do_test (0, 0, page_size
- 1, 16, 1);
481 #include <support/test-driver.c>