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 <pola...@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