Message ID | 20141119110746.GA29446@redhat.com |
---|---|
State | New |
Headers | show |
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 --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--; +}