The issue here was that we were diagnosing an artificial check that we created within the scope of shift instrumentation. In other words, for shifts we create something like (unsigned) A >> (B - C) and signed-integer-overflow triggered on that subtraction. Fixed by making the subtraction work on unsigned types. This only happened in C99/C++11 mode. Middle end seems to cope well with RSHIFT_EXPR whose second op has an unsigned type.
Bootstrapped/regtested on x86_64-linux, ok for trunk? 2014-10-23 Marek Polacek <pola...@redhat.com> * c-ubsan.c (ubsan_instrument_shift): Perform the MINUS_EXPR in unsigned type. * c-c++-common/ubsan/undefined-2.c: New test. diff --git gcc/c-family/c-ubsan.c gcc/c-family/c-ubsan.c index 5a42303..7f4dc25 100644 --- gcc/c-family/c-ubsan.c +++ gcc/c-family/c-ubsan.c @@ -128,19 +128,19 @@ ubsan_instrument_shift (location_t loc, enum tree_code code, tree op1_utype = unsigned_type_for (type1); HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0); tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1); - tree precm1 = build_int_cst (type1, op0_prec - 1); t = fold_convert_loc (loc, op1_utype, op1); t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1); /* For signed x << y, in C99/C11, the following: - (unsigned) x >> (precm1 - y) + (unsigned) x >> (uprecm1 - y) if non-zero, is undefined. */ if (code == LSHIFT_EXPR && !TYPE_UNSIGNED (type0) && flag_isoc99) { - tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1); + tree x = fold_build2 (MINUS_EXPR, unsigned_type_node, uprecm1, + fold_convert (op1_utype, op1)); tt = fold_convert_loc (loc, unsigned_type_for (type0), op0); tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x); tt = fold_build2 (NE_EXPR, boolean_type_node, tt, @@ -148,13 +148,14 @@ ubsan_instrument_shift (location_t loc, enum tree_code code, } /* For signed x << y, in C++11 and later, the following: - x < 0 || ((unsigned) x >> (precm1 - y)) + x < 0 || ((unsigned) x >> (uprecm1 - y)) if > 1, is undefined. */ if (code == LSHIFT_EXPR && !TYPE_UNSIGNED (TREE_TYPE (op0)) && (cxx_dialect >= cxx11)) { - tree x = fold_build2 (MINUS_EXPR, integer_type_node, precm1, op1); + tree x = fold_build2 (MINUS_EXPR, unsigned_type_node, uprecm1, + fold_convert (op1_utype, op1)); tt = fold_convert_loc (loc, unsigned_type_for (type0), op0); tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x); tt = fold_build2 (GT_EXPR, boolean_type_node, tt, diff --git gcc/testsuite/c-c++-common/ubsan/undefined-2.c gcc/testsuite/c-c++-common/ubsan/undefined-2.c index e69de29..7b06709 100644 --- gcc/testsuite/c-c++-common/ubsan/undefined-2.c +++ gcc/testsuite/c-c++-common/ubsan/undefined-2.c @@ -0,0 +1,22 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=undefined -fno-sanitize-recover=signed-integer-overflow" } */ +/* { dg-additional-options "-std=gnu11" { target c } } */ +/* { dg-additional-options "-std=c++11" { target c++ } } */ + +volatile int w, z; + +__attribute__ ((noinline, noclone)) int +foo (int x, int y) +{ + z++; + return x << y; +} + +int +main () +{ + w = foo (0, -__INT_MAX__); + return 0; +} + +/* { dg-output "shift exponent -\[^\n\r]* is negative\[^\n\r]*(\n|\r\n|\r)" } */ Marek