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