Fix powerpc64/power7 memchr for large input sizes

Current optimized powercp64/power7 memchr uses a strategy to check for
p versus align(p+n) (where 'p' is the input char pointer and n the
maximum size to check for the byte) without taking care for possible
overflow on the pointer addition in case of large 'n'.

It was triggered by 3038145ca2 where default rawmemchr (used to
created ppc64 rawmemchr in ifunc selection) now uses memchr (p, c, (size_t)-1)
on its implementation.

This patch fixes it by implement a satured addition where overflows
sets the maximum pointer size to UINTPTR_MAX.

Checked on powerpc64le-linux-gnu.

	[BZ# 20971]
	* sysdeps/powerpc/powerpc64/power7/memchr.S (__memchr): Avoid
	overflow in pointer addition.
	* string/test-memchr.c (do_test): Add an argument to pass as
	the size on memchr.
	(test_main): Add check for SIZE_MAX.
This commit is contained in:
Adhemerval Zanella 2016-12-15 18:27:10 +00:00
parent e4d6a83565
commit b224637928
3 changed files with 49 additions and 10 deletions

View File

@ -1,3 +1,12 @@
2016-12-16 Adhemerval Zanella <adhemerval.zanella@linaro.org>
[BZ# 20971]
* sysdeps/powerpc/powerpc64/power7/memchr.S (__memchr): Avoid
overflow in pointer addition.
* string/test-memchr.c (do_test): Add an argument to pass as
the size on memchr.
(test_main): Add check for SIZE_MAX.
2016-12-16 Gabriel F. T. Gomes <gftg@linux.vnet.ibm.com> 2016-12-16 Gabriel F. T. Gomes <gftg@linux.vnet.ibm.com>
* math/Makefile (gen-libm-calls): Remove w_scalblnF. * math/Makefile (gen-libm-calls): Remove w_scalblnF.

View File

@ -71,7 +71,7 @@ do_one_test (impl_t *impl, const CHAR *s, int c, size_t n, CHAR *exp_res)
} }
static void static void
do_test (size_t align, size_t pos, size_t len, int seek_char) do_test (size_t align, size_t pos, size_t len, size_t n, int seek_char)
{ {
size_t i; size_t i;
CHAR *result; CHAR *result;
@ -103,7 +103,7 @@ do_test (size_t align, size_t pos, size_t len, int seek_char)
} }
FOR_EACH_IMPL (impl, 0) FOR_EACH_IMPL (impl, 0)
do_one_test (impl, (CHAR *) (buf + align), seek_char, len, result); do_one_test (impl, (CHAR *) (buf + align), seek_char, n, result);
} }
static void static void
@ -167,7 +167,7 @@ do_random_tests (void)
int int
test_main (void) test_main (void)
{ {
size_t i; size_t i, j;
test_init (); test_init ();
@ -178,15 +178,35 @@ test_main (void)
for (i = 1; i < 8; ++i) for (i = 1; i < 8; ++i)
{ {
do_test (0, 16 << i, 2048, 23); do_test (0, 16 << i, 2048, 2048, 23);
do_test (i, 64, 256, 23); do_test (i, 64, 256, 256, 23);
do_test (0, 16 << i, 2048, 0); do_test (0, 16 << i, 2048, 2048, 0);
do_test (i, 64, 256, 0); do_test (i, 64, 256, 256, 0);
/* Check for large input sizes and for these cases we need to
make sure the bye is within the size range (that's why
7 << i must be smaller than 2048. */
do_test (0, 7 << i, 2048, SIZE_MAX, 23);
do_test (0, 2048 - i, 2048, SIZE_MAX, 23);
do_test (i, 64, 256, SIZE_MAX, 23);
do_test (0, 7 << i, 2048, SIZE_MAX, 0);
do_test (0, 2048 - i, 2048, SIZE_MAX, 0);
do_test (i, 64, 256, SIZE_MAX, 0);
} }
for (i = 1; i < 16; ++i)
{
for (j = 1; j < 16; j++)
{
do_test (0, 16 - j, 16, SIZE_MAX, 23);
do_test (i, 16 - j, 16, SIZE_MAX, 23);
}
}
for (i = 1; i < 32; ++i) for (i = 1; i < 32; ++i)
{ {
do_test (0, i, i + 1, 23); do_test (0, i, i + 1, i + 1, 23);
do_test (0, i, i + 1, 0); do_test (0, i, i + 1, i + 1, 0);
} }
do_random_tests (); do_random_tests ();

View File

@ -26,7 +26,17 @@ ENTRY (__memchr)
dcbt 0,r3 dcbt 0,r3
clrrdi r8,r3,3 clrrdi r8,r3,3
insrdi r4,r4,8,48 insrdi r4,r4,8,48
add r7,r3,r5 /* Calculate the last acceptable address. */
/* Calculate the last acceptable address and check for possible
addition overflow by using satured math:
r7 = r3 + r5
r7 |= -(r7 < x) */
add r7,r3,r5
subfc r6,r3,r7
subfe r9,r9,r9
extsw r6,r9
or r7,r7,r6
insrdi r4,r4,16,32 insrdi r4,r4,16,32
cmpldi r5,32 cmpldi r5,32
li r9, -1 li r9, -1