diff mbox

Fix for fold_negate_expr (PR sanitizer/63879)

Message ID 20141119110746.GA29446@redhat.com
State New
Headers show

Commit Message

Marek Polacek Nov. 19, 2014, 11:07 a.m. UTC
The problem here is that negate_expr_p returns true (as it should)
for UINT_MAX(OVF), but fold_negate_expr didn't actually fold it,
and that is a no-no; if negate_expr_p is true, fold_negate_expr must
not return NULL_TREE.  I added the following hunk for bootstrap and
regtest for better coverage:

@@ -752,6 +755,12 @@ fold_negate_expr (location_t loc, tree t)
       break;
     }
 
+#ifdef ENABLE_CHECKING
+  if (negate_expr_p (t))
+    internal_error ("fold_negate_expr should never return NULL_TREE "
+		    "if negate_expr_p is true");
+#endif
+
   return NULL_TREE;
 }

Fixed by adjusting fold_negate_expr so that it folds non-trapping
wrapping constants.  The SANITIZE_SI_OVERFLOW check is important
to not regress -Woverflow warnings (ug).

negate_expr_p hunk is to match the NEGATE_EXPR case in fold_negate_expr.
 
Bootstrapped/regtested on power8-linux, ok for trunk?

2014-11-19  Marek Polacek  <polacek@redhat.com>

	PR sanitizer/63879
	* fold-const.c (negate_expr_p) <case NEGATE_EXPR>: Return
	!TYPE_OVERFLOW_SANITIZED.
	(fold_negate_expr) <case INTEGER_CST>: Fold when overflow
	does not trap and when overflow wraps, or when SANITIZE_SI_OVERFLOW
	is 0.

	* c-c++-common/ubsan/pr63879-1.c: New test.
	* c-c++-common/ubsan/pr63879-2.c: New test.


	Marek

Comments

Richard Biener Nov. 19, 2014, 11:46 a.m. UTC | #1
On Wed, 19 Nov 2014, Marek Polacek wrote:

> The problem here is that negate_expr_p returns true (as it should)
> for UINT_MAX(OVF), but fold_negate_expr didn't actually fold it,
> and that is a no-no; if negate_expr_p is true, fold_negate_expr must
> not return NULL_TREE.  I added the following hunk for bootstrap and
> regtest for better coverage:
> 
> @@ -752,6 +755,12 @@ fold_negate_expr (location_t loc, tree t)
>        break;
>      }
>  
> +#ifdef ENABLE_CHECKING
> +  if (negate_expr_p (t))
> +    internal_error ("fold_negate_expr should never return NULL_TREE "
> +		    "if negate_expr_p is true");
> +#endif
> +
>    return NULL_TREE;
>  }
> 
> Fixed by adjusting fold_negate_expr so that it folds non-trapping
> wrapping constants.  The SANITIZE_SI_OVERFLOW check is important
> to not regress -Woverflow warnings (ug).
> 
> negate_expr_p hunk is to match the NEGATE_EXPR case in fold_negate_expr.
>  
> Bootstrapped/regtested on power8-linux, ok for trunk?

Ok.

Thanks,
Richard.

> 2014-11-19  Marek Polacek  <polacek@redhat.com>
> 
> 	PR sanitizer/63879
> 	* fold-const.c (negate_expr_p) <case NEGATE_EXPR>: Return
> 	!TYPE_OVERFLOW_SANITIZED.
> 	(fold_negate_expr) <case INTEGER_CST>: Fold when overflow
> 	does not trap and when overflow wraps, or when SANITIZE_SI_OVERFLOW
> 	is 0.
> 
> 	* c-c++-common/ubsan/pr63879-1.c: New test.
> 	* c-c++-common/ubsan/pr63879-2.c: New test.
> 
> diff --git gcc/fold-const.c gcc/fold-const.c
> index f6fb8af..719e06e 100644
> --- gcc/fold-const.c
> +++ gcc/fold-const.c
> @@ -408,9 +408,11 @@ negate_expr_p (tree t)
>  	      && TYPE_OVERFLOW_WRAPS (type));
>  
>      case FIXED_CST:
> -    case NEGATE_EXPR:
>        return true;
>  
> +    case NEGATE_EXPR:
> +      return !TYPE_OVERFLOW_SANITIZED (type);
> +
>      case REAL_CST:
>        /* We want to canonicalize to positive real constants.  Pretend
>           that only negative ones can be easily negated.  */
> @@ -555,7 +557,8 @@ fold_negate_expr (location_t loc, tree t)
>        tem = fold_negate_const (t, type);
>        if (TREE_OVERFLOW (tem) == TREE_OVERFLOW (t)
>  	  || (!TYPE_OVERFLOW_TRAPS (type)
> -	      && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0))
> +	      && TYPE_OVERFLOW_WRAPS (type))
> +	  || (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
>  	return tem;
>        break;
>  
> diff --git gcc/testsuite/c-c++-common/ubsan/pr63879-1.c gcc/testsuite/c-c++-common/ubsan/pr63879-1.c
> index e69de29..2035849 100644
> --- gcc/testsuite/c-c++-common/ubsan/pr63879-1.c
> +++ gcc/testsuite/c-c++-common/ubsan/pr63879-1.c
> @@ -0,0 +1,23 @@
> +/* PR sanitizer/63879 */
> +/* { dg-do compile } */
> +/* { dg-options "-fsanitize=undefined" } */
> +
> +struct A
> +{
> +  int inode;
> +} * a;
> +int b, c;
> +void
> +fn1 ()
> +{
> +  int d = 0;
> +  while (b)
> +    {
> +      if (a->inode)
> +        d++;
> +      a = 0;
> +    }
> +  c = d - 1;
> +  for (; c >= 0; c--)
> +    ;
> +}
> diff --git gcc/testsuite/c-c++-common/ubsan/pr63879-2.c gcc/testsuite/c-c++-common/ubsan/pr63879-2.c
> index e69de29..34eb8e7 100644
> --- gcc/testsuite/c-c++-common/ubsan/pr63879-2.c
> +++ gcc/testsuite/c-c++-common/ubsan/pr63879-2.c
> @@ -0,0 +1,13 @@
> +/* PR sanitizer/63879 */
> +/* { dg-do compile } */
> +/* { dg-options "-fsanitize=undefined" } */
> +
> +int a;
> +void
> +fn1 ()
> +{
> +  int b = 2;
> +  for (; a;)
> +    while (b >= 0)
> +      b--;
> +}
> 
> 	Marek
> 
>
diff mbox

Patch

diff --git gcc/fold-const.c gcc/fold-const.c
index f6fb8af..719e06e 100644
--- gcc/fold-const.c
+++ gcc/fold-const.c
@@ -408,9 +408,11 @@  negate_expr_p (tree t)
 	      && TYPE_OVERFLOW_WRAPS (type));
 
     case FIXED_CST:
-    case NEGATE_EXPR:
       return true;
 
+    case NEGATE_EXPR:
+      return !TYPE_OVERFLOW_SANITIZED (type);
+
     case REAL_CST:
       /* We want to canonicalize to positive real constants.  Pretend
          that only negative ones can be easily negated.  */
@@ -555,7 +557,8 @@  fold_negate_expr (location_t loc, tree t)
       tem = fold_negate_const (t, type);
       if (TREE_OVERFLOW (tem) == TREE_OVERFLOW (t)
 	  || (!TYPE_OVERFLOW_TRAPS (type)
-	      && (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0))
+	      && TYPE_OVERFLOW_WRAPS (type))
+	  || (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0)
 	return tem;
       break;
 
diff --git gcc/testsuite/c-c++-common/ubsan/pr63879-1.c gcc/testsuite/c-c++-common/ubsan/pr63879-1.c
index e69de29..2035849 100644
--- gcc/testsuite/c-c++-common/ubsan/pr63879-1.c
+++ gcc/testsuite/c-c++-common/ubsan/pr63879-1.c
@@ -0,0 +1,23 @@ 
+/* PR sanitizer/63879 */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=undefined" } */
+
+struct A
+{
+  int inode;
+} * a;
+int b, c;
+void
+fn1 ()
+{
+  int d = 0;
+  while (b)
+    {
+      if (a->inode)
+        d++;
+      a = 0;
+    }
+  c = d - 1;
+  for (; c >= 0; c--)
+    ;
+}
diff --git gcc/testsuite/c-c++-common/ubsan/pr63879-2.c gcc/testsuite/c-c++-common/ubsan/pr63879-2.c
index e69de29..34eb8e7 100644
--- gcc/testsuite/c-c++-common/ubsan/pr63879-2.c
+++ gcc/testsuite/c-c++-common/ubsan/pr63879-2.c
@@ -0,0 +1,13 @@ 
+/* PR sanitizer/63879 */
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=undefined" } */
+
+int a;
+void
+fn1 ()
+{
+  int b = 2;
+  for (; a;)
+    while (b >= 0)
+      b--;
+}