Protect against integer overflow in malloca() calls.
[gnulib.git] / lib / strcasestr.c
1 /* Case-insensitive searching in a string.
2    Copyright (C) 2005-2007 Free Software Foundation, Inc.
3    Written by Bruno Haible <bruno@clisp.org>, 2005.
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 2, or (at your option)
8    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, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18
19 #include <config.h>
20
21 /* Specification.  */
22 #include <string.h>
23
24 #include <ctype.h>
25 #include <stdbool.h>
26 #include <stddef.h>  /* for NULL, in case a nonstandard string.h lacks it */
27
28 #include "malloca.h"
29
30 #define TOLOWER(Ch) (isupper (Ch) ? tolower (Ch) : (Ch))
31
32 /* Knuth-Morris-Pratt algorithm.
33    See http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm
34    Return a boolean indicating success.  */
35 static bool
36 knuth_morris_pratt (const char *haystack, const char *needle,
37                     const char **resultp)
38 {
39   size_t m = strlen (needle);
40
41   /* Allocate the table.  */
42   size_t *table = (size_t *) nmalloca (m, sizeof (size_t));
43   if (table == NULL)
44     return false;
45   /* Fill the table.
46      For 0 < i < m:
47        0 < table[i] <= i is defined such that
48        forall 0 < x < table[i]: needle[x..i-1] != needle[0..i-1-x],
49        and table[i] is as large as possible with this property.
50      This implies:
51      1) For 0 < i < m:
52           If table[i] < i,
53           needle[table[i]..i-1] = needle[0..i-1-table[i]].
54      2) For 0 < i < m:
55           rhaystack[0..i-1] == needle[0..i-1]
56           and exists h, i <= h < m: rhaystack[h] != needle[h]
57           implies
58           forall 0 <= x < table[i]: rhaystack[x..x+m-1] != needle[0..m-1].
59      table[0] remains uninitialized.  */
60   {
61     size_t i, j;
62
63     /* i = 1: Nothing to verify for x = 0.  */
64     table[1] = 1;
65     j = 0;
66
67     for (i = 2; i < m; i++)
68       {
69         /* Here: j = i-1 - table[i-1].
70            The inequality needle[x..i-1] != needle[0..i-1-x] is known to hold
71            for x < table[i-1], by induction.
72            Furthermore, if j>0: needle[i-1-j..i-2] = needle[0..j-1].  */
73         unsigned char b = TOLOWER ((unsigned char) needle[i - 1]);
74
75         for (;;)
76           {
77             /* Invariants: The inequality needle[x..i-1] != needle[0..i-1-x]
78                is known to hold for x < i-1-j.
79                Furthermore, if j>0: needle[i-1-j..i-2] = needle[0..j-1].  */
80             if (b == TOLOWER ((unsigned char) needle[j]))
81               {
82                 /* Set table[i] := i-1-j.  */
83                 table[i] = i - ++j;
84                 break;
85               }
86             /* The inequality needle[x..i-1] != needle[0..i-1-x] also holds
87                for x = i-1-j, because
88                  needle[i-1] != needle[j] = needle[i-1-x].  */
89             if (j == 0)
90               {
91                 /* The inequality holds for all possible x.  */
92                 table[i] = i;
93                 break;
94               }
95             /* The inequality needle[x..i-1] != needle[0..i-1-x] also holds
96                for i-1-j < x < i-1-j+table[j], because for these x:
97                  needle[x..i-2]
98                  = needle[x-(i-1-j)..j-1]
99                  != needle[0..j-1-(x-(i-1-j))]  (by definition of table[j])
100                     = needle[0..i-2-x],
101                hence needle[x..i-1] != needle[0..i-1-x].
102                Furthermore
103                  needle[i-1-j+table[j]..i-2]
104                  = needle[table[j]..j-1]
105                  = needle[0..j-1-table[j]]  (by definition of table[j]).  */
106             j = j - table[j];
107           }
108         /* Here: j = i - table[i].  */
109       }
110   }
111
112   /* Search, using the table to accelerate the processing.  */
113   {
114     size_t j;
115     const char *rhaystack;
116     const char *phaystack;
117
118     *resultp = NULL;
119     j = 0;
120     rhaystack = haystack;
121     phaystack = haystack;
122     /* Invariant: phaystack = rhaystack + j.  */
123     while (*phaystack != '\0')
124       if (TOLOWER ((unsigned char) needle[j])
125           == TOLOWER ((unsigned char) *phaystack))
126         {
127           j++;
128           phaystack++;
129           if (j == m)
130             {
131               /* The entire needle has been found.  */
132               *resultp = rhaystack;
133               break;
134             }
135         }
136       else if (j > 0)
137         {
138           /* Found a match of needle[0..j-1], mismatch at needle[j].  */
139           rhaystack += table[j];
140           j -= table[j];
141         }
142       else
143         {
144           /* Found a mismatch at needle[0] already.  */
145           rhaystack++;
146           phaystack++;
147         }
148   }
149
150   freea (table);
151   return true;
152 }
153
154 /* Find the first occurrence of NEEDLE in HAYSTACK, using case-insensitive
155    comparison.
156    Note: This function may, in multibyte locales, return success even if
157    strlen (haystack) < strlen (needle) !  */
158 char *
159 strcasestr (const char *haystack, const char *needle)
160 {
161   if (*needle != '\0')
162     {
163       /* Minimizing the worst-case complexity:
164          Let n = strlen(haystack), m = strlen(needle).
165          The naïve algorithm is O(n*m) worst-case.
166          The Knuth-Morris-Pratt algorithm is O(n) worst-case but it needs a
167          memory allocation.
168          To achieve linear complexity and yet amortize the cost of the memory
169          allocation, we activate the Knuth-Morris-Pratt algorithm only once
170          the naïve algorithm has already run for some time; more precisely,
171          when
172            - the outer loop count is >= 10,
173            - the average number of comparisons per outer loop is >= 5,
174            - the total number of comparisons is >= m.
175          But we try it only once.  If the memory allocation attempt failed,
176          we don't retry it.  */
177       bool try_kmp = true;
178       size_t outer_loop_count = 0;
179       size_t comparison_count = 0;
180       size_t last_ccount = 0;                   /* last comparison count */
181       const char *needle_last_ccount = needle;  /* = needle + last_ccount */
182
183       /* Speed up the following searches of needle by caching its first
184          character.  */
185       unsigned char b = TOLOWER ((unsigned char) *needle);
186
187       needle++;
188       for (;; haystack++)
189         {
190           if (*haystack == '\0')
191             /* No match.  */
192             return NULL;
193
194           /* See whether it's advisable to use an asymptotically faster
195              algorithm.  */
196           if (try_kmp
197               && outer_loop_count >= 10
198               && comparison_count >= 5 * outer_loop_count)
199             {
200               /* See if needle + comparison_count now reaches the end of
201                  needle.  */
202               if (needle_last_ccount != NULL)
203                 {
204                   needle_last_ccount +=
205                     strnlen (needle_last_ccount, comparison_count - last_ccount);
206                   if (*needle_last_ccount == '\0')
207                     needle_last_ccount = NULL;
208                   last_ccount = comparison_count;
209                 }
210               if (needle_last_ccount == NULL)
211                 {
212                   /* Try the Knuth-Morris-Pratt algorithm.  */
213                   const char *result;
214                   bool success =
215                     knuth_morris_pratt (haystack, needle - 1, &result);
216                   if (success)
217                     return (char *) result;
218                   try_kmp = false;
219                 }
220             }
221
222           outer_loop_count++;
223           comparison_count++;
224           if (TOLOWER ((unsigned char) *haystack) == b)
225             /* The first character matches.  */
226             {
227               const char *rhaystack = haystack + 1;
228               const char *rneedle = needle;
229
230               for (;; rhaystack++, rneedle++)
231                 {
232                   if (*rneedle == '\0')
233                     /* Found a match.  */
234                     return (char *) haystack;
235                   if (*rhaystack == '\0')
236                     /* No match.  */
237                     return NULL;
238                   comparison_count++;
239                   if (TOLOWER ((unsigned char) *rhaystack)
240                       != TOLOWER ((unsigned char) *rneedle))
241                     /* Nothing in this round.  */
242                     break;
243                 }
244             }
245         }
246     }
247   else
248     return (char *) haystack;
249 }