test-strstr.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /* Test and measure strstr functions.
  2. Copyright (C) 2010-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #define TEST_MAIN
  16. #ifndef WIDE
  17. # define TEST_NAME "strstr"
  18. # define TEST_FUNC strstr
  19. #else
  20. # define TEST_NAME "wcsstr"
  21. # define TEST_FUNC wcsstr
  22. #endif
  23. #ifndef WIDE
  24. # define CHAR char
  25. # define STRLEN strlen
  26. # define STRCPY strcpy
  27. # define MEMCPY memcpy
  28. # define MEMSET memset
  29. # define MEMPCPY mempcpy
  30. # define L(s) s
  31. #else
  32. # include <wchar.h>
  33. # define CHAR wchar_t
  34. # define STRLEN wcslen
  35. # define STRCPY wcscpy
  36. # define MEMCPY wmemcpy
  37. # define MEMSET wmemset
  38. # define MEMPCPY wmempcpy
  39. # define L(s) L ## s
  40. /* The test requires up to 8191 characters, so allocate at least 32Kb
  41. (considering 4kb page size). */
  42. # define BUF1PAGES 4
  43. #endif
  44. #include "test-string.h"
  45. #ifndef WIDE
  46. # define STRSTR c_strstr
  47. # define libc_hidden_builtin_def(arg) /* nothing */
  48. # define __strnlen strnlen
  49. # include "strstr.c"
  50. # define C_IMPL STRSTR
  51. #else
  52. # undef weak_alias
  53. # define weak_alias(a, b)
  54. # define WCSSTR c_wcsstr
  55. # define __wmemcmp wmemcmp
  56. # define __wcsnlen wcsnlen
  57. # define __wcslen wcslen
  58. # include "wcsstr.c"
  59. # define C_IMPL WCSSTR
  60. #endif
  61. /* Naive implementation to verify results. */
  62. static CHAR *
  63. simple_strstr (const CHAR *s1, const CHAR *s2)
  64. {
  65. ssize_t s1len = STRLEN (s1);
  66. ssize_t s2len = STRLEN (s2);
  67. if (s2len > s1len)
  68. return NULL;
  69. for (ssize_t i = 0; i <= s1len - s2len; ++i)
  70. {
  71. size_t j;
  72. for (j = 0; j < s2len; ++j)
  73. if (s1[i + j] != s2[j])
  74. break;
  75. if (j == s2len)
  76. return (CHAR *) s1 + i;
  77. }
  78. return NULL;
  79. }
  80. typedef CHAR *(*proto_t) (const CHAR *, const CHAR *);
  81. IMPL (C_IMPL, 1)
  82. IMPL (TEST_FUNC, 1)
  83. static int
  84. check_result (impl_t *impl, const CHAR *s1, const CHAR *s2,
  85. CHAR *exp_result)
  86. {
  87. CHAR *result = CALL (impl, s1, s2);
  88. if (result != exp_result)
  89. {
  90. error (0, 0, "Wrong result in function %s %p %p", impl->name,
  91. result, exp_result);
  92. ret = 1;
  93. return -1;
  94. }
  95. return 0;
  96. }
  97. static void
  98. do_one_test (impl_t *impl, const CHAR *s1, const CHAR *s2, CHAR *exp_result)
  99. {
  100. if (check_result (impl, s1, s2, exp_result) < 0)
  101. return;
  102. }
  103. static void
  104. do_test (size_t align1, size_t align2, size_t len1, size_t len2,
  105. int fail)
  106. {
  107. align1 = align1 * sizeof (CHAR);
  108. align2 = align2 * sizeof (CHAR);
  109. CHAR *s1 = (CHAR *) (buf1 + align1);
  110. CHAR *s2 = (CHAR *) (buf2 + align2);
  111. static const CHAR d[] = L("1234567890abcdef");
  112. const size_t dl = STRLEN (d);
  113. CHAR *ss2 = s2;
  114. for (size_t l = len2; l > 0; l = l > dl ? l - dl : 0)
  115. {
  116. size_t t = l > dl ? dl : l;
  117. ss2 = MEMPCPY (ss2, d, t);
  118. }
  119. s2[len2] = '\0';
  120. if (fail)
  121. {
  122. CHAR *ss1 = s1;
  123. for (size_t l = len1; l > 0; l = l > dl ? l - dl : 0)
  124. {
  125. size_t t = l > dl ? dl : l;
  126. MEMCPY (ss1, d, t);
  127. ++ss1[len2 > 7 ? 7 : len2 - 1];
  128. ss1 += t;
  129. }
  130. }
  131. else
  132. {
  133. MEMSET (s1, '0', len1);
  134. MEMCPY (s1 + len1 - len2, s2, len2);
  135. }
  136. s1[len1] = '\0';
  137. FOR_EACH_IMPL (impl, 0)
  138. do_one_test (impl, s1, s2, fail ? NULL : s1 + len1 - len2);
  139. }
  140. static void
  141. check1 (void)
  142. {
  143. const CHAR s1[] =
  144. 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");
  145. const CHAR s2[] = L("_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD");
  146. CHAR *exp_result;
  147. exp_result = simple_strstr (s1, s2);
  148. FOR_EACH_IMPL (impl, 0)
  149. check_result (impl, s1, s2, exp_result);
  150. }
  151. static void
  152. check2 (void)
  153. {
  154. const CHAR s1_stack[] = L(", enable_static, \0, enable_shared, ");
  155. const size_t s1_char_count = 18;
  156. const size_t s1_byte_len = 18 * sizeof (CHAR);
  157. const CHAR *s2_stack = &(s1_stack[s1_char_count]);
  158. const size_t s2_byte_len = 18 * sizeof (CHAR);
  159. CHAR *exp_result;
  160. const size_t page_size_real = getpagesize ();
  161. /* Haystack at end of page. The following page is protected. */
  162. CHAR *s1_page_end = (void *) buf1 + page_size - s1_byte_len;
  163. STRCPY (s1_page_end, s1_stack);
  164. /* Haystack which crosses a page boundary.
  165. Note: page_size is at least 2 * getpagesize. See test_init. */
  166. CHAR *s1_page_cross = (void *) buf1 + page_size_real - 8;
  167. STRCPY (s1_page_cross, s1_stack);
  168. /* Needle at end of page. The following page is protected. */
  169. CHAR *s2_page_end = (void *) buf2 + page_size - s2_byte_len;
  170. STRCPY (s2_page_end, s2_stack);
  171. /* Needle which crosses a page boundary.
  172. Note: page_size is at least 2 * getpagesize. See test_init. */
  173. CHAR *s2_page_cross = (void *) buf2 + page_size_real - 8;
  174. STRCPY (s2_page_cross, s2_stack);
  175. exp_result = simple_strstr (s1_stack, s2_stack);
  176. FOR_EACH_IMPL (impl, 0)
  177. {
  178. check_result (impl, s1_stack, s2_stack, exp_result);
  179. check_result (impl, s1_stack, s2_page_end, exp_result);
  180. check_result (impl, s1_stack, s2_page_cross, exp_result);
  181. check_result (impl, s1_page_end, s2_stack, exp_result);
  182. check_result (impl, s1_page_end, s2_page_end, exp_result);
  183. check_result (impl, s1_page_end, s2_page_cross, exp_result);
  184. check_result (impl, s1_page_cross, s2_stack, exp_result);
  185. check_result (impl, s1_page_cross, s2_page_end, exp_result);
  186. check_result (impl, s1_page_cross, s2_page_cross, exp_result);
  187. }
  188. }
  189. static void
  190. check3 (void)
  191. {
  192. /* Check that a long periodic needle does not cause false positives. */
  193. {
  194. const CHAR input[] = L("F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD"
  195. "_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD"
  196. "_C3_A7_20_EF_BF_BD");
  197. const CHAR need[] = L("_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD");
  198. FOR_EACH_IMPL (impl, 0)
  199. check_result (impl, input, need, NULL);
  200. }
  201. {
  202. const CHAR input[] = L("F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD"
  203. "_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD"
  204. "_C3_A7_20_EF_BF_BD_DA_B5_C2_A6_20"
  205. "_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD");
  206. const CHAR need[] = L("_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD");
  207. FOR_EACH_IMPL (impl, 0)
  208. check_result (impl, input, need, (CHAR *) input + 115);
  209. }
  210. }
  211. #define N 1024
  212. static void
  213. pr23637 (void)
  214. {
  215. CHAR *h = (CHAR*) buf1;
  216. CHAR *n = (CHAR*) buf2;
  217. for (int i = 0; i < N; i++)
  218. {
  219. n[i] = 'x';
  220. h[i] = ' ';
  221. h[i + N] = 'x';
  222. }
  223. n[N] = '\0';
  224. h[N * 2] = '\0';
  225. /* Ensure we don't match at the first 'x'. */
  226. h[0] = 'x';
  227. CHAR *exp_result = simple_strstr (h, n);
  228. FOR_EACH_IMPL (impl, 0)
  229. check_result (impl, h, n, exp_result);
  230. }
  231. static void
  232. pr23865 (void)
  233. {
  234. /* Check that a very long haystack is handled quickly if the needle is
  235. short and occurs near the beginning. */
  236. {
  237. size_t m = 1000000;
  238. const CHAR *needle =
  239. L("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
  240. "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
  241. CHAR *haystack = xmalloc ((m + 1) * sizeof (CHAR));
  242. MEMSET (haystack, L('A'), m);
  243. haystack[0] = L('B');
  244. haystack[m] = L('\0');
  245. FOR_EACH_IMPL (impl, 0)
  246. check_result (impl, haystack, needle, haystack + 1);
  247. free (haystack);
  248. }
  249. /* Check that a very long needle is discarded quickly if the haystack is
  250. short. */
  251. {
  252. size_t m = 1000000;
  253. const CHAR *haystack =
  254. L("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
  255. "ABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABAB");
  256. CHAR *needle = xmalloc ((m + 1) * sizeof (CHAR));
  257. MEMSET (needle, L'A', m);
  258. needle[m] = L('\0');
  259. FOR_EACH_IMPL (impl, 0)
  260. check_result (impl, haystack, needle, NULL);
  261. free (needle);
  262. }
  263. /* Check that the asymptotic worst-case complexity is not quadratic. */
  264. {
  265. size_t m = 1000000;
  266. CHAR *haystack = xmalloc ((2 * m + 2) * sizeof (CHAR));
  267. CHAR *needle = xmalloc ((m + 2) * sizeof (CHAR));
  268. MEMSET (haystack, L('A'), 2 * m);
  269. haystack[2 * m] = L('B');
  270. haystack[2 * m + 1] = L('\0');
  271. MEMSET (needle, L('A'), m);
  272. needle[m] = L('B');
  273. needle[m + 1] = L('\0');
  274. FOR_EACH_IMPL (impl, 0)
  275. check_result (impl, haystack, needle, haystack + m);
  276. free (needle);
  277. free (haystack);
  278. }
  279. {
  280. /* Ensure that with a barely periodic "short" needle, STRSTR's
  281. search does not mistakenly skip just past the match point. */
  282. const CHAR *haystack =
  283. L("\n"
  284. "with_build_libsubdir\n"
  285. "with_local_prefix\n"
  286. "with_gxx_include_dir\n"
  287. "with_cpp_install_dir\n"
  288. "enable_generated_files_in_srcdir\n"
  289. "with_gnu_ld\n"
  290. "with_ld\n"
  291. "with_demangler_in_ld\n"
  292. "with_gnu_as\n"
  293. "with_as\n"
  294. "enable_largefile\n"
  295. "enable_werror_always\n"
  296. "enable_checking\n"
  297. "enable_coverage\n"
  298. "enable_gather_detailed_mem_stats\n"
  299. "enable_build_with_cxx\n"
  300. "with_stabs\n"
  301. "enable_multilib\n"
  302. "enable___cxa_atexit\n"
  303. "enable_decimal_float\n"
  304. "enable_fixed_point\n"
  305. "enable_threads\n"
  306. "enable_tls\n"
  307. "enable_objc_gc\n"
  308. "with_dwarf2\n"
  309. "enable_shared\n"
  310. "with_build_sysroot\n"
  311. "with_sysroot\n"
  312. "with_specs\n"
  313. "with_pkgversion\n"
  314. "with_bugurl\n"
  315. "enable_languages\n"
  316. "with_multilib_list\n");
  317. const CHAR *needle =
  318. L("\n"
  319. "with_gnu_ld\n");
  320. FOR_EACH_IMPL (impl, 0)
  321. check_result (impl, haystack, needle, (CHAR*) haystack + 114);
  322. }
  323. {
  324. /* Same bug, shorter trigger. */
  325. const CHAR *haystack = L("..wi.d.");
  326. const CHAR *needle = L(".d.");
  327. FOR_EACH_IMPL (impl, 0)
  328. check_result (impl, haystack, needle, (CHAR*) haystack + 4);
  329. }
  330. /* Test case from Yves Bastide.
  331. <https://www.openwall.com/lists/musl/2014/04/18/2> */
  332. {
  333. const CHAR *input = L("playing play play play always");
  334. const CHAR *needle = L("play play play");
  335. FOR_EACH_IMPL (impl, 0)
  336. check_result (impl, input, needle, (CHAR*) input + 8);
  337. }
  338. /* Test long needles. */
  339. {
  340. size_t m = 1024;
  341. CHAR *haystack = xmalloc ((2 * m + 1) * sizeof (CHAR));
  342. CHAR *needle = xmalloc ((m + 1) * sizeof (CHAR));
  343. haystack[0] = L('x');
  344. MEMSET (haystack + 1, L(' '), m - 1);
  345. MEMSET (haystack + m, L('x'), m);
  346. haystack[2 * m] = L('\0');
  347. MEMSET (needle, L('x'), m);
  348. needle[m] = L('\0');
  349. FOR_EACH_IMPL (impl, 0)
  350. check_result (impl, haystack, needle, haystack + m);
  351. free (needle);
  352. free (haystack);
  353. }
  354. }
  355. static int
  356. test_main (void)
  357. {
  358. test_init ();
  359. check1 ();
  360. check2 ();
  361. check3 ();
  362. pr23637 ();
  363. pr23865 ();
  364. printf ("%23s", "");
  365. FOR_EACH_IMPL (impl, 0)
  366. printf ("\t%s", impl->name);
  367. putchar ('\n');
  368. for (size_t klen = 2; klen < 32; ++klen)
  369. for (size_t hlen = 2 * klen; hlen < 16 * klen; hlen += klen)
  370. {
  371. do_test (0, 0, hlen, klen, 0);
  372. do_test (0, 0, hlen, klen, 1);
  373. do_test (0, 3, hlen, klen, 0);
  374. do_test (0, 3, hlen, klen, 1);
  375. do_test (0, 9, hlen, klen, 0);
  376. do_test (0, 9, hlen, klen, 1);
  377. do_test (0, 15, hlen, klen, 0);
  378. do_test (0, 15, hlen, klen, 1);
  379. do_test (3, 0, hlen, klen, 0);
  380. do_test (3, 0, hlen, klen, 1);
  381. do_test (3, 3, hlen, klen, 0);
  382. do_test (3, 3, hlen, klen, 1);
  383. do_test (3, 9, hlen, klen, 0);
  384. do_test (3, 9, hlen, klen, 1);
  385. do_test (3, 15, hlen, klen, 0);
  386. do_test (3, 15, hlen, klen, 1);
  387. do_test (9, 0, hlen, klen, 0);
  388. do_test (9, 0, hlen, klen, 1);
  389. do_test (9, 3, hlen, klen, 0);
  390. do_test (9, 3, hlen, klen, 1);
  391. do_test (9, 9, hlen, klen, 0);
  392. do_test (9, 9, hlen, klen, 1);
  393. do_test (9, 15, hlen, klen, 0);
  394. do_test (9, 15, hlen, klen, 1);
  395. do_test (15, 0, hlen, klen, 0);
  396. do_test (15, 0, hlen, klen, 1);
  397. do_test (15, 3, hlen, klen, 0);
  398. do_test (15, 3, hlen, klen, 1);
  399. do_test (15, 9, hlen, klen, 0);
  400. do_test (15, 9, hlen, klen, 1);
  401. do_test (15, 15, hlen, klen, 0);
  402. do_test (15, 15, hlen, klen, 1);
  403. do_test (15, 15, hlen + klen * 4, klen * 4, 0);
  404. do_test (15, 15, hlen + klen * 4, klen * 4, 1);
  405. }
  406. do_test (0, 0, page_size - 1, 16, 0);
  407. do_test (0, 0, page_size - 1, 16, 1);
  408. return ret;
  409. }
  410. #include <support/test-driver.c>