about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--string/test-memchr.c38
-rw-r--r--sysdeps/powerpc/powerpc64/power7/memchr.S12
3 files changed, 49 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 374a69f8db..628540538b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
 
 	* math/Makefile (gen-libm-calls): Remove w_scalblnF.
diff --git a/string/test-memchr.c b/string/test-memchr.c
index 449a19ae59..e7ba02b617 100644
--- a/string/test-memchr.c
+++ b/string/test-memchr.c
@@ -71,7 +71,7 @@ do_one_test (impl_t *impl, const CHAR *s, int c, size_t n, CHAR *exp_res)
 }
 
 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;
   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)
-    do_one_test (impl, (CHAR *) (buf + align), seek_char, len, result);
+    do_one_test (impl, (CHAR *) (buf + align), seek_char, n, result);
 }
 
 static void
@@ -167,7 +167,7 @@ do_random_tests (void)
 int
 test_main (void)
 {
-  size_t i;
+  size_t i, j;
 
   test_init ();
 
@@ -178,15 +178,35 @@ test_main (void)
 
   for (i = 1; i < 8; ++i)
     {
-      do_test (0, 16 << i, 2048, 23);
-      do_test (i, 64, 256, 23);
-      do_test (0, 16 << i, 2048, 0);
-      do_test (i, 64, 256, 0);
+      do_test (0, 16 << i, 2048, 2048, 23);
+      do_test (i, 64, 256, 256, 23);
+      do_test (0, 16 << i, 2048, 2048, 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)
     {
-      do_test (0, i, i + 1, 23);
-      do_test (0, i, i + 1, 0);
+      do_test (0, i, i + 1, i + 1, 23);
+      do_test (0, i, i + 1, i + 1, 0);
     }
 
   do_random_tests ();
diff --git a/sysdeps/powerpc/powerpc64/power7/memchr.S b/sysdeps/powerpc/powerpc64/power7/memchr.S
index 03f0d7c2dd..0737100fd5 100644
--- a/sysdeps/powerpc/powerpc64/power7/memchr.S
+++ b/sysdeps/powerpc/powerpc64/power7/memchr.S
@@ -26,7 +26,17 @@ ENTRY (__memchr)
 	dcbt	0,r3
 	clrrdi  r8,r3,3
 	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
 	cmpldi	r5,32
 	li	r9, -1