[PATCH] Fix ubsan tree sharing (PR sanitizer/66908)
Marek Polacek
polacek@redhat.com
Wed Jul 22 17:35:00 GMT 2015
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 <polacek@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
More information about the Gcc-patches
mailing list