re PR sanitizer/81281 (UBSAN: false positive, dropped promotion to long type.)
authorJakub Jelinek <jakub@redhat.com>
Wed, 6 Dec 2017 19:22:06 +0000 (20:22 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 6 Dec 2017 19:22:06 +0000 (20:22 +0100)
PR sanitizer/81281
* match.pd ((T)(P + A) - (T)P -> (T) A): Split into separate
simplify for plus with :c added, and pointer_plus without that.
((T)P - (T)(P + A) -> -(T) A): Likewise.  If type is integral
with undefined overflow and the conversion is not widening,
perform negation in utype and only convert to type afterwards.
((T)(P + A) - (T)(P + B) -> (T)A - (T)B): Split into separate
simplify for plus with :c added, and pointer_plus without that.
If type is integral with undefined overflow and the conversion is
not widening, perform minus in utype and only convert to type
afterwards.  Move the last pointer_diff_expr simplify into the
two outermost ifs.

* gcc.c-torture/execute/pr81281.c: New test.
* gcc.dg/pr81281-1.c: New test.
* gcc.dg/pr81281-2.c: New test.
* g++.dg/ubsan/pr81281.C: New test.
* g++.dg/ubsan/pr81281-aux.cc: New test.

From-SVN: r255449

gcc/ChangeLog
gcc/match.pd
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ubsan/pr81281-aux.cc [new file with mode: 0644]
gcc/testsuite/g++.dg/ubsan/pr81281.C [new file with mode: 0644]
gcc/testsuite/gcc.c-torture/execute/pr81281.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr81281-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr81281-2.c [new file with mode: 0644]

index de037da6b02776fadda7f56701de0589e48089f7..9cfc382239bb1077c000e83cefe05caee1429f83 100644 (file)
@@ -1,3 +1,18 @@
+2017-12-06  Jakub Jelinek  <jakub@redhat.com>
+
+       PR sanitizer/81281
+       * match.pd ((T)(P + A) - (T)P -> (T) A): Split into separate
+       simplify for plus with :c added, and pointer_plus without that.
+       ((T)P - (T)(P + A) -> -(T) A): Likewise.  If type is integral
+       with undefined overflow and the conversion is not widening,
+       perform negation in utype and only convert to type afterwards.
+       ((T)(P + A) - (T)(P + B) -> (T)A - (T)B): Split into separate
+       simplify for plus with :c added, and pointer_plus without that.
+       If type is integral with undefined overflow and the conversion is
+       not widening, perform minus in utype and only convert to type
+       afterwards.  Move the last pointer_diff_expr simplify into the
+       two outermost ifs.
+
 2017-12-06  Martin Sebor  <msebor@redhat.com>
 
        PR tree-optimization/82646
index 53f8b86b7d5613cf880090e6f2f51d6605d7b082..0a4ff6bb8df1a5f477e8df2101fadec420792c7f 100644 (file)
@@ -1783,28 +1783,32 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (bit_not @0))
 
   /* (T)(P + A) - (T)P -> (T) A */
-  (for add (plus pointer_plus)
-   (simplify
-    (minus (convert (add @@0 @1))
-     (convert @0))
-    (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
-        /* For integer types, if A has a smaller type
-           than T the result depends on the possible
-           overflow in P + A.
-           E.g. T=size_t, A=(unsigned)429497295, P>0.
-           However, if an overflow in P + A would cause
-           undefined behavior, we can assume that there
-           is no overflow.  */
-        || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
-            && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
-        /* For pointer types, if the conversion of A to the
-           final type requires a sign- or zero-extension,
-           then we have to punt - it is not defined which
-           one is correct.  */
-        || (POINTER_TYPE_P (TREE_TYPE (@0))
-            && TREE_CODE (@1) == INTEGER_CST
-            && tree_int_cst_sign_bit (@1) == 0))
-     (convert @1))))
+  (simplify
+   (minus (convert (plus:c @0 @1))
+    (convert @0))
+   (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
+       /* For integer types, if A has a smaller type
+          than T the result depends on the possible
+          overflow in P + A.
+          E.g. T=size_t, A=(unsigned)429497295, P>0.
+          However, if an overflow in P + A would cause
+          undefined behavior, we can assume that there
+          is no overflow.  */
+       || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+           && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))))
+    (convert @1)))
+  (simplify
+   (minus (convert (pointer_plus @@0 @1))
+    (convert @0))
+   (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
+       /* For pointer types, if the conversion of A to the
+          final type requires a sign- or zero-extension,
+          then we have to punt - it is not defined which
+          one is correct.  */
+       || (POINTER_TYPE_P (TREE_TYPE (@0))
+           && TREE_CODE (@1) == INTEGER_CST
+           && tree_int_cst_sign_bit (@1) == 0))
+    (convert @1)))
    (simplify
     (pointer_diff (pointer_plus @@0 @1) @0)
     /* The second argument of pointer_plus must be interpreted as signed, and
@@ -1813,10 +1817,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      (convert (convert:stype @1))))
 
   /* (T)P - (T)(P + A) -> -(T) A */
-  (for add (plus pointer_plus)
-   (simplify
-    (minus (convert @0)
-     (convert (add @@0 @1)))
+  (simplify
+   (minus (convert @0)
+    (convert (plus:c @0 @1)))
+   (if (INTEGRAL_TYPE_P (type)
+       && TYPE_OVERFLOW_UNDEFINED (type)
+       && element_precision (type) <= element_precision (TREE_TYPE (@1)))
+    (with { tree utype = unsigned_type_for (type); }
+     (convert (negate (convert:utype @1))))
     (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
         /* For integer types, if A has a smaller type
            than T the result depends on the possible
@@ -1826,7 +1834,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
            undefined behavior, we can assume that there
            is no overflow.  */
         || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
-            && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
+            && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))))
+     (negate (convert @1)))))
+  (simplify
+   (minus (convert @0)
+    (convert (pointer_plus @@0 @1)))
+   (if (INTEGRAL_TYPE_P (type)
+       && TYPE_OVERFLOW_UNDEFINED (type)
+       && element_precision (type) <= element_precision (TREE_TYPE (@1)))
+    (with { tree utype = unsigned_type_for (type); }
+     (convert (negate (convert:utype @1))))
+    (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
         /* For pointer types, if the conversion of A to the
            final type requires a sign- or zero-extension,
            then we have to punt - it is not defined which
@@ -1843,10 +1861,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      (negate (convert (convert:stype @1)))))
 
   /* (T)(P + A) - (T)(P + B) -> (T)A - (T)B */
-  (for add (plus pointer_plus)
-   (simplify
-    (minus (convert (add @@0 @1))
-     (convert (add @0 @2)))
+  (simplify
+   (minus (convert (plus:c @0 @1))
+    (convert (plus:c @0 @2)))
+   (if (INTEGRAL_TYPE_P (type)
+       && TYPE_OVERFLOW_UNDEFINED (type)
+       && element_precision (type) <= element_precision (TREE_TYPE (@1)))
+    (with { tree utype = unsigned_type_for (type); }
+     (convert (minus (convert:utype @1) (convert:utype @2))))
     (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
         /* For integer types, if A has a smaller type
            than T the result depends on the possible
@@ -1856,7 +1878,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
            undefined behavior, we can assume that there
            is no overflow.  */
         || (INTEGRAL_TYPE_P (TREE_TYPE (@0))
-            && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))
+            && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))))
+     (minus (convert @1) (convert @2)))))
+  (simplify
+   (minus (convert (pointer_plus @@0 @1))
+    (convert (pointer_plus @0 @2)))
+   (if (INTEGRAL_TYPE_P (type)
+       && TYPE_OVERFLOW_UNDEFINED (type)
+       && element_precision (type) <= element_precision (TREE_TYPE (@1)))
+    (with { tree utype = unsigned_type_for (type); }
+     (convert (minus (convert:utype @1) (convert:utype @2))))
+    (if (element_precision (type) <= element_precision (TREE_TYPE (@1))
         /* For pointer types, if the conversion of A to the
            final type requires a sign- or zero-extension,
            then we have to punt - it is not defined which
@@ -1866,13 +1898,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
             && tree_int_cst_sign_bit (@1) == 0
             && TREE_CODE (@2) == INTEGER_CST
             && tree_int_cst_sign_bit (@2) == 0))
-     (minus (convert @1) (convert @2)))))))
+     (minus (convert @1) (convert @2)))))
    (simplify
     (pointer_diff (pointer_plus @@0 @1) (pointer_plus @0 @2))
     /* The second argument of pointer_plus must be interpreted as signed, and
        thus sign-extended if necessary.  */
     (with { tree stype = signed_type_for (TREE_TYPE (@1)); }
-     (minus (convert (convert:stype @1)) (convert (convert:stype @2)))))
+     (minus (convert (convert:stype @1)) (convert (convert:stype @2)))))))
 
 
 /* Simplifications of MIN_EXPR, MAX_EXPR, fmin() and fmax().  */
index a42348fbb77217f26868d8fdc3c48f942f107370..782e04d3639771d2dc75f22cf90b47ab3bb425b0 100644 (file)
@@ -1,3 +1,12 @@
+2017-12-06  Jakub Jelinek  <jakub@redhat.com>
+
+       PR sanitizer/81281
+       * gcc.c-torture/execute/pr81281.c: New test.
+       * gcc.dg/pr81281-1.c: New test.
+       * gcc.dg/pr81281-2.c: New test.
+       * g++.dg/ubsan/pr81281.C: New test.
+       * g++.dg/ubsan/pr81281-aux.cc: New test.
+
 2017-12-06  Martin Sebor  <msebor@redhat.com>
 
        PR tree-optimization/82646
diff --git a/gcc/testsuite/g++.dg/ubsan/pr81281-aux.cc b/gcc/testsuite/g++.dg/ubsan/pr81281-aux.cc
new file mode 100644 (file)
index 0000000..4a34a61
--- /dev/null
@@ -0,0 +1,3 @@
+extern const int ci = 1716607962;
+int i = -943738830;
+long long ll = -43165919987465092LL;
diff --git a/gcc/testsuite/g++.dg/ubsan/pr81281.C b/gcc/testsuite/g++.dg/ubsan/pr81281.C
new file mode 100644 (file)
index 0000000..a812924
--- /dev/null
@@ -0,0 +1,26 @@
+// PR sanitizer/81281
+// { dg-do run }
+// { dg-options "-fsanitize=undefined -fno-sanitize-recover=undefined" }
+// { dg-additional-sources "pr81281-aux.cc" }
+
+extern const int ci;
+extern int i;
+extern long long ll;
+
+int
+foo ()
+{
+  int a = (int) (-2024172551 - i - (ci - ll))
+         - ((int) (-2024172551 - i - (ci - ll))
+            - (int) (-2024172551 - (long long)ci));
+  return a;
+}
+
+int
+main ()
+{
+  if (__SIZEOF_INT__ * __CHAR_BIT__ == 32
+      && __SIZEOF_LONG_LONG__ * __CHAR_BIT__ == 64)
+    foo ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr81281.c b/gcc/testsuite/gcc.c-torture/execute/pr81281.c
new file mode 100644 (file)
index 0000000..5d8908f
--- /dev/null
@@ -0,0 +1,33 @@
+/* PR sanitizer/81281 */
+
+void
+foo (unsigned p, unsigned a, unsigned b)
+{
+  unsigned q = p + 7;
+  if (a - (1U + __INT_MAX__) >= 2)
+    __builtin_unreachable ();
+  int d = p + b;
+  int c = p + a;
+  if (c - d != __INT_MAX__)
+    __builtin_abort ();
+}
+
+void
+bar (unsigned p, unsigned a)
+{
+  unsigned q = p + 7;
+  if (a - (1U + __INT_MAX__) >= 2)
+    __builtin_unreachable ();
+  int c = p;
+  int d = p + a;
+  if (c - d != -__INT_MAX__ - 1)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  foo (-1U, 1U + __INT_MAX__, 1U);
+  bar (-1U, 1U + __INT_MAX__);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr81281-1.c b/gcc/testsuite/gcc.dg/pr81281-1.c
new file mode 100644 (file)
index 0000000..5fec25d
--- /dev/null
@@ -0,0 +1,150 @@
+/* PR sanitizer/81281 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-not "p_\[0-9]*\\(D\\)" "optimized" } } */
+
+long long
+f1 (int p, int a, int b)
+{
+  int c = p + 1;
+  int d = a + 2;
+  int e = b + 3;
+  long long f = p + a;
+  long long g = p + b;
+  return f - g;
+}
+
+long long
+f2 (int p, int a, int b)
+{
+  int c = a + 1;
+  int d = p + 2;
+  int e = b + 3;
+  long long f = p + a;
+  long long g = p + b;
+  return f - g;
+}
+
+long long
+f3 (int p, int a, int b)
+{
+  int c = b + 1;
+  int d = p + 2;
+  int e = a + 3;
+  long long f = p + a;
+  long long g = p + b;
+  return f - g;
+}
+
+signed char
+f4 (int p, int a, int b)
+{
+  int c = p + 1;
+  int d = a + 2;
+  int e = b + 3;
+  signed char f = p + a;
+  signed char g = p + b;
+  return f - g;
+}
+
+signed char
+f5 (int p, int a, int b)
+{
+  int c = a + 1;
+  int d = p + 2;
+  int e = b + 3;
+  signed char f = p + a;
+  signed char g = p + b;
+  return f - g;
+}
+
+signed char
+f6 (int p, int a, int b)
+{
+  int c = b + 1;
+  int d = p + 2;
+  int e = a + 3;
+  signed char f = p + a;
+  signed char g = p + b;
+  return f - g;
+}
+
+long long
+f7 (int p, int a)
+{
+  int c = p + 1;
+  int d = a + 2;
+  long long f = p + a;
+  long long g = p;
+  return f - g;
+}
+
+long long
+f8 (int p, int a)
+{
+  int c = a + 1;
+  int d = p + 2;
+  long long f = p + a;
+  long long g = p;
+  return f - g;
+}
+
+signed char
+f9 (int p, int a)
+{
+  int c = p + 1;
+  int d = a + 2;
+  signed char f = p + a;
+  signed char g = p;
+  return f - g;
+}
+
+signed char
+f10 (int p, int a)
+{
+  int c = a + 1;
+  int d = p + 2;
+  signed char f = p + a;
+  signed char g = p;
+  return f - g;
+}
+
+long long
+f11 (int p, int a)
+{
+  int c = p + 1;
+  int d = a + 2;
+  long long f = p;
+  long long g = p + a;
+  return f - g;
+}
+
+long long
+f12 (int p, int a)
+{
+  int c = a + 1;
+  int d = p + 2;
+  long long f = p;
+  long long g = p + a;
+  return f - g;
+}
+
+signed char
+f13 (int p, int a)
+{
+  int c = p + 1;
+  int d = a + 2;
+  signed char f = p;
+  signed char g = p + a;
+  return f - g;
+}
+
+signed char
+f14 (int p, int a)
+{
+  int c = a + 1;
+  int d = p + 2;
+  signed char f = p;
+  signed char g = p + a;
+  return f - g;
+}
diff --git a/gcc/testsuite/gcc.dg/pr81281-2.c b/gcc/testsuite/gcc.dg/pr81281-2.c
new file mode 100644 (file)
index 0000000..ba2c648
--- /dev/null
@@ -0,0 +1,80 @@
+/* PR sanitizer/81281 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-not "p_\[0-9]*\\(D\\)" "optimized" } } */
+
+typedef __SIZE_TYPE__ size_t;
+typedef __INTPTR_TYPE__ T;
+
+T
+f1 (char *p, size_t a, size_t b)
+{
+  char *c = p + 1;
+  size_t d = a + 2;
+  size_t e = b + 3;
+  T f = (T) (p + a);
+  T g = (T) (p + b);
+  return f - g;
+}
+
+T
+f2 (char *p, size_t a, size_t b)
+{
+  size_t c = a + 1;
+  char *d = p + 2;
+  size_t e = b + 3;
+  T f = (T) (p + a);
+  T g = (T) (p + b);
+  return f - g;
+}
+
+T
+f3 (char *p, size_t a, size_t b)
+{
+  size_t c = b + 1;
+  char *d = p + 2;
+  size_t e = a + 3;
+  T f = (T) (p + a);
+  T g = (T) (p + b);
+  return f - g;
+}
+
+T
+f4 (char *p, size_t a)
+{
+  char *c = p + 1;
+  size_t d = a + 2;
+  T f = (T) (p + a);
+  T g = (T) p;
+  return f - g;
+}
+
+T
+f5 (char *p, size_t a)
+{
+  size_t c = a + 1;
+  char *d = p + 2;
+  T f = (T) (p + a);
+  T g = (T) p;
+  return f - g;
+}
+
+T
+f6 (char *p, size_t a)
+{
+  char *c = p + 1;
+  size_t d = a + 2;
+  T f = (T) p;
+  T g = (T) (p + a);
+  return f - g;
+}
+
+T
+f7 (char *p, size_t a)
+{
+  size_t c = a + 1;
+  char *d = p + 2;
+  T f = (T) p;
+  T g = (T) (p + a);
+  return f - g;
+}