In this testcase we were generating an uninitialized variable when doing -fsanitize=shift,bounds sanitization. The shift instrumentation is done first; after that, the IR looks like
res[i] = (m > 31) ? __ubsan (... tab[i] ...) ? 0, ... tab[i] ...; where tab[i] are identical. That means that when we instrument the first tab[i] (we shouldn't do this I suppose), the second tab[i] is changed as well as they're shared. But that doesn't play well with SAVE_EXPRs, because SAVE_EXPR <i> would only be initialized on one path. Fixed by unsharing the operands when constructing the ubsan check. The .gimple diff is in essence just + i.2 = i; + UBSAN_BOUNDS (0B, i.2, 21); - UBSAN_BOUNDS (0B, i.1, 21); (Merely not instrumenting __ubsan_* wouldn't help exactly because of the sharing.) Bootstrapped/regtested on x86_64-linux, ok for trunk? 2015-07-22 Marek Polacek <pola...@redhat.com> PR sanitizer/66908 * c-ubsan.c: Include gimplify.h. (ubsan_instrument_division): Unshare OP0 and OP1. (ubsan_instrument_shift): Likewise. * c-c++-common/ubsan/pr66908.c: New test. diff --git gcc/c-family/c-ubsan.c gcc/c-family/c-ubsan.c index 0baf118..3869511 100644 --- gcc/c-family/c-ubsan.c +++ gcc/c-family/c-ubsan.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "internal-fn.h" #include "stor-layout.h" #include "builtins.h" +#include "gimplify.h" /* Instrument division by zero and INT_MIN / -1. If not instrumenting, return NULL_TREE. */ @@ -54,6 +55,9 @@ ubsan_instrument_division (location_t loc, tree op0, tree op1) gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (op0)) == TYPE_MAIN_VARIANT (TREE_TYPE (op1))); + op0 = unshare_expr (op0); + op1 = unshare_expr (op1); + if (TREE_CODE (type) == INTEGER_TYPE && (flag_sanitize & SANITIZE_DIVIDE)) t = fold_build2 (EQ_EXPR, boolean_type_node, @@ -134,6 +138,9 @@ ubsan_instrument_shift (location_t loc, enum tree_code code, HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0); tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1); + op0 = unshare_expr (op0); + op1 = unshare_expr (op1); + t = fold_convert_loc (loc, op1_utype, op1); t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1); diff --git gcc/testsuite/c-c++-common/ubsan/pr66908.c gcc/testsuite/c-c++-common/ubsan/pr66908.c index e69de29..5f731f0 100644 --- gcc/testsuite/c-c++-common/ubsan/pr66908.c +++ gcc/testsuite/c-c++-common/ubsan/pr66908.c @@ -0,0 +1,15 @@ +/* PR sanitizer/66908 */ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=shift,bounds -O2 -Werror=maybe-uninitialized" } */ +/* { dg-additional-options "-std=gnu90" { target c } } */ + +struct S { int a[22]; }; +static int const e[22] = { }; + +void +foo (struct S const *s, unsigned int m, unsigned int *res) +{ + unsigned int i; + for (i = 0; i < 22; ++i) + res[i] = ((s->a[i] + e[i]) << m); +} Marek