This avoids simplifying 2 * (a * (__INT_MAX__/2 + 1)) to a * INT_MIN which introduces undefined overflow for a == -1.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied. Richard. 2015-10-29 Richard Biener <rguent...@suse.de> PR middle-end/68142 * fold-const.c (extract_muldiv_1): Avoid introducing undefined overflow. * c-c++-common/ubsan/pr68142.c: New testcase. Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c (revision 229517) --- gcc/fold-const.c (working copy) *************** extract_muldiv_1 (tree t, tree c, enum t *** 6008,6015 **** or (for divide and modulus) if it is a multiple of our constant. */ if (code == MULT_EXPR || wi::multiple_of_p (t, c, TYPE_SIGN (type))) ! return const_binop (code, fold_convert (ctype, t), ! fold_convert (ctype, c)); break; CASE_CONVERT: case NON_LVALUE_EXPR: --- 6015,6031 ---- or (for divide and modulus) if it is a multiple of our constant. */ if (code == MULT_EXPR || wi::multiple_of_p (t, c, TYPE_SIGN (type))) ! { ! tree tem = const_binop (code, fold_convert (ctype, t), ! fold_convert (ctype, c)); ! /* If the multiplication overflowed to INT_MIN then we lost sign ! information on it and a subsequent multiplication might ! spuriously overflow. See PR68142. */ ! if (TREE_OVERFLOW (tem) ! && wi::eq_p (tem, wi::min_value (TYPE_PRECISION (ctype), SIGNED))) ! return NULL_TREE; ! return tem; ! } break; CASE_CONVERT: case NON_LVALUE_EXPR: Index: gcc/testsuite/c-c++-common/ubsan/pr68142.c =================================================================== *** gcc/testsuite/c-c++-common/ubsan/pr68142.c (revision 0) --- gcc/testsuite/c-c++-common/ubsan/pr68142.c (working copy) *************** *** 0 **** --- 1,31 ---- + /* { dg-do run } */ + /* { dg-options "-fsanitize=undefined -fsanitize-undefined-trap-on-error" } */ + + int __attribute__((noinline,noclone)) + h(int a) + { + return 2 * (a * (__INT_MAX__/2 + 1)); + } + int __attribute__((noinline,noclone)) + i(int a) + { + return (2 * a) * (__INT_MAX__/2 + 1); + } + int __attribute__((noinline,noclone)) + j(int a, int b) + { + return (b * a) * (__INT_MAX__/2 + 1); + } + int __attribute__((noinline,noclone)) + k(int a, int b) + { + return (2 * a) * b; + } + int main() + { + volatile int tem = h(-1); + tem = i(-1); + tem = j(-1, 2); + tem = k(-1, __INT_MAX__/2 + 1); + return 0; + }