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