Fix strstr bug with huge needles (bug 23637)

The generic strstr in GLIBC 2.28 fails to match huge needles.  The optimized
AVAILABLE macro reads ahead a large fixed amount to reduce the overhead of
repeatedly checking for the end of the string.  However if the needle length
is larger than this, two_way_long_needle may confuse this as meaning the end
of the string and return NULL.  This is fixed by adding the needle length to
the amount to read ahead.

	[BZ #23637]
	* string/test-strstr.c (pr23637): New function.
	(test_main): Add tests with longer needles.
	* string/strcasestr.c (AVAILABLE): Fix readahead distance.
	* string/strstr.c (AVAILABLE): Likewise.
This commit is contained in:
Wilco Dijkstra 2018-09-19 16:50:18 +01:00
parent d734727837
commit 83a552b0bb
4 changed files with 44 additions and 4 deletions

View File

@ -1,3 +1,11 @@
2018-09-19 Wilco Dijkstra <wdijkstr@arm.com>
[BZ #23637]
* string/test-strstr.c (pr23637): New function.
(test_main): Add tests with longer needles.
* string/strcasestr.c (AVAILABLE): Fix readahead distance.
* string/strstr.c (AVAILABLE): Likewise.
2018-09-19 Szabolcs Nagy <szabolcs.nagy@arm.com>
* sysdeps/ieee754/flt-32/e_powf.c (checkint): Fix documentation.

View File

@ -37,7 +37,8 @@
/* Two-Way algorithm. */
#define RETURN_TYPE char *
#define AVAILABLE(h, h_l, j, n_l) \
(((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \
(((j) + (n_l) <= (h_l)) \
|| ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \
(j) + (n_l) <= (h_l)))
#define CHECK_EOL (1)
#define RET0_IF_0(a) if (!a) goto ret0

View File

@ -33,7 +33,8 @@
#define RETURN_TYPE char *
#define AVAILABLE(h, h_l, j, n_l) \
(((j) + (n_l) <= (h_l)) || ((h_l) += __strnlen ((void*)((h) + (h_l)), 512), \
(((j) + (n_l) <= (h_l)) \
|| ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \
(j) + (n_l) <= (h_l)))
#define CHECK_EOL (1)
#define RET0_IF_0(a) if (!a) goto ret0

View File

@ -151,6 +151,32 @@ check2 (void)
}
}
#define N 1024
static void
pr23637 (void)
{
char *h = (char*) buf1;
char *n = (char*) buf2;
for (int i = 0; i < N; i++)
{
n[i] = 'x';
h[i] = ' ';
h[i + N] = 'x';
}
n[N] = '\0';
h[N * 2] = '\0';
/* Ensure we don't match at the first 'x'. */
h[0] = 'x';
char *exp_result = stupid_strstr (h, n);
FOR_EACH_IMPL (impl, 0)
check_result (impl, h, n, exp_result);
}
static int
test_main (void)
{
@ -158,6 +184,7 @@ test_main (void)
check1 ();
check2 ();
pr23637 ();
printf ("%23s", "");
FOR_EACH_IMPL (impl, 0)
@ -202,6 +229,9 @@ test_main (void)
do_test (15, 9, hlen, klen, 1);
do_test (15, 15, hlen, klen, 0);
do_test (15, 15, hlen, klen, 1);
do_test (15, 15, hlen + klen * 4, klen * 4, 0);
do_test (15, 15, hlen + klen * 4, klen * 4, 1);
}
do_test (0, 0, page_size - 1, 16, 0);