d8307d
commit 0ef2f4400c06927af34c515555f68840a70ba409
d8307d
Author: Wilco Dijkstra <wdijkstr@arm.com>
d8307d
Date:   Wed Sep 19 16:50:18 2018 +0100
d8307d
d8307d
    Fix strstr bug with huge needles (bug 23637)
d8307d
    
d8307d
    The generic strstr in GLIBC 2.28 fails to match huge needles.  The optimized
d8307d
    AVAILABLE macro reads ahead a large fixed amount to reduce the overhead of
d8307d
    repeatedly checking for the end of the string.  However if the needle length
d8307d
    is larger than this, two_way_long_needle may confuse this as meaning the end
d8307d
    of the string and return NULL.  This is fixed by adding the needle length to
d8307d
    the amount to read ahead.
d8307d
    
d8307d
            [BZ #23637]
d8307d
            * string/test-strstr.c (pr23637): New function.
d8307d
            (test_main): Add tests with longer needles.
d8307d
            * string/strcasestr.c (AVAILABLE): Fix readahead distance.
d8307d
            * string/strstr.c (AVAILABLE): Likewise.
d8307d
    
d8307d
        (cherry picked from commit 83a552b0bb9fc2a5e80a0ab3723c0a80ce1db9f2)
d8307d
d8307d
diff --git a/string/strcasestr.c b/string/strcasestr.c
d8307d
index 5909fe3cdba88e47..421764bd1b0ff22e 100644
d8307d
--- a/string/strcasestr.c
d8307d
+++ b/string/strcasestr.c
d8307d
@@ -37,8 +37,9 @@
d8307d
 /* Two-Way algorithm.  */
d8307d
 #define RETURN_TYPE char *
d8307d
 #define AVAILABLE(h, h_l, j, n_l)			\
d8307d
-  (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \
d8307d
-			      (j) + (n_l) <= (h_l)))
d8307d
+  (((j) + (n_l) <= (h_l)) \
d8307d
+   || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \
d8307d
+       (j) + (n_l) <= (h_l)))
d8307d
 #define CHECK_EOL (1)
d8307d
 #define RET0_IF_0(a) if (!a) goto ret0
d8307d
 #define CANON_ELEMENT(c) TOLOWER (c)
d8307d
diff --git a/string/strstr.c b/string/strstr.c
d8307d
index 265e9f310ce507ce..79ebcc75329d0b17 100644
d8307d
--- a/string/strstr.c
d8307d
+++ b/string/strstr.c
d8307d
@@ -33,8 +33,9 @@
d8307d
 
d8307d
 #define RETURN_TYPE char *
d8307d
 #define AVAILABLE(h, h_l, j, n_l)			\
d8307d
-  (((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \
d8307d
-			      (j) + (n_l) <= (h_l)))
d8307d
+  (((j) + (n_l) <= (h_l)) \
d8307d
+   || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \
d8307d
+       (j) + (n_l) <= (h_l)))
d8307d
 #define CHECK_EOL (1)
d8307d
 #define RET0_IF_0(a) if (!a) goto ret0
d8307d
 #define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C))
d8307d
diff --git a/string/test-strstr.c b/string/test-strstr.c
d8307d
index 8d99716ff39cc2c2..5861b01b73e4c315 100644
d8307d
--- a/string/test-strstr.c
d8307d
+++ b/string/test-strstr.c
d8307d
@@ -151,6 +151,32 @@ check2 (void)
d8307d
     }
d8307d
 }
d8307d
 
d8307d
+#define N 1024
d8307d
+
d8307d
+static void
d8307d
+pr23637 (void)
d8307d
+{
d8307d
+  char *h = (char*) buf1;
d8307d
+  char *n = (char*) buf2;
d8307d
+
d8307d
+  for (int i = 0; i < N; i++)
d8307d
+    {
d8307d
+      n[i] = 'x';
d8307d
+      h[i] = ' ';
d8307d
+      h[i + N] = 'x';
d8307d
+    }
d8307d
+
d8307d
+  n[N] = '\0';
d8307d
+  h[N * 2] = '\0';
d8307d
+
d8307d
+  /* Ensure we don't match at the first 'x'.  */
d8307d
+  h[0] = 'x';
d8307d
+
d8307d
+  char *exp_result = stupid_strstr (h, n);
d8307d
+  FOR_EACH_IMPL (impl, 0)
d8307d
+    check_result (impl, h, n, exp_result);
d8307d
+}
d8307d
+
d8307d
 static int
d8307d
 test_main (void)
d8307d
 {
d8307d
@@ -158,6 +184,7 @@ test_main (void)
d8307d
 
d8307d
   check1 ();
d8307d
   check2 ();
d8307d
+  pr23637 ();
d8307d
 
d8307d
   printf ("%23s", "");
d8307d
   FOR_EACH_IMPL (impl, 0)
d8307d
@@ -202,6 +229,9 @@ test_main (void)
d8307d
 	do_test (15, 9, hlen, klen, 1);
d8307d
 	do_test (15, 15, hlen, klen, 0);
d8307d
 	do_test (15, 15, hlen, klen, 1);
d8307d
+
d8307d
+	do_test (15, 15, hlen + klen * 4, klen * 4, 0);
d8307d
+	do_test (15, 15, hlen + klen * 4, klen * 4, 1);
d8307d
       }
d8307d
 
d8307d
   do_test (0, 0, page_size - 1, 16, 0);