From fe86867f07504f643ab9bf1147bac785222cadb0 Mon Sep 17 00:00:00 2001 From: Bernd Edlinger Date: Fri, 2 Jan 2015 22:16:59 +0000 Subject: [PATCH] Instrument bit field and unaligned accesses for TSAN. gcc/ChangeLog: 2015-01-02 Bernd Edlinger Instrument bit field and unaligned accesses for TSAN. * sanitizer.def (BUILT_IN_TSAN_READ_RANGE): New built-in function. (BUILT_IN_TSAN_WRITE_RANGE): New built-in function. * tsan.c (instrument_expr): Handle COMPONENT_REF and BIT_FIELD_REF. Use BUILT_IN_TSAN_READ_RANGE and BUILT_IN_TSAN_WRITE_RANGE for unaligned memory regions. testsuite/ChangeLog: 2015-01-02 Bernd Edlinger * c-c++-common/tsan/bitfield_race.c: New testcase. * g++.dg/tsan/aligned_vs_unaligned_race.C: Fixed. From-SVN: r219150 --- gcc/ChangeLog | 9 ++ gcc/sanitizer.def | 4 + gcc/testsuite/ChangeLog | 5 ++ .../c-c++-common/tsan/bitfield_race.c | 26 ++++++ .../g++.dg/tsan/aligned_vs_unaligned_race.C | 8 +- gcc/tsan.c | 84 ++++++++++++++++--- 6 files changed, 122 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/tsan/bitfield_race.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9e621089d72..3957600745c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2015-01-02 Bernd Edlinger + + Instrument bit field and unaligned accesses for TSAN. + * sanitizer.def (BUILT_IN_TSAN_READ_RANGE): New built-in function. + (BUILT_IN_TSAN_WRITE_RANGE): New built-in function. + * tsan.c (instrument_expr): Handle COMPONENT_REF and BIT_FIELD_REF. + Use BUILT_IN_TSAN_READ_RANGE and BUILT_IN_TSAN_WRITE_RANGE for + unaligned memory regions. + 2015-01-01 Anthony Green * config/moxie/predicates.md (moxie_general_movsrc_operand): diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def index 3fc8c8396be..723348e9e1a 100644 --- a/gcc/sanitizer.def +++ b/gcc/sanitizer.def @@ -188,6 +188,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE8, "__tsan_write8", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE16, "__tsan_write16", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_READ_RANGE, "__tsan_read_range", + BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_RANGE, "__tsan_write_range", + BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOMIC8_LOAD, "__tsan_atomic8_load", diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a47a1a18ede..cb1ba6834d0 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2015-01-02 Bernd Edlinger + + * c-c++-common/tsan/bitfield_race.c: New testcase. + * g++.dg/tsan/aligned_vs_unaligned_race.C: Fixed. + 2015-01-02 Tobias Burnus * gfortran.dg/coarray/collectives_4.f90: New. diff --git a/gcc/testsuite/c-c++-common/tsan/bitfield_race.c b/gcc/testsuite/c-c++-common/tsan/bitfield_race.c new file mode 100644 index 00000000000..e8de09727a9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/tsan/bitfield_race.c @@ -0,0 +1,26 @@ +/* { dg-shouldfail "tsan" } */ + +#include +#include + +struct bitfield +{ + int a:10; + int b:10; +} Global; + +void *Thread1(void *x) { + sleep(1); + Global.a = 42; + return x; +} + +int main() { + pthread_t t; + pthread_create(&t, 0, Thread1, 0); + Global.b = 43; + pthread_join(t, 0); + return Global.a; +} + +/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */ diff --git a/gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C b/gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C index 390be86d716..e547e0ce2d2 100644 --- a/gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C +++ b/gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C @@ -1,3 +1,4 @@ +/* { dg-shouldfail "tsan" } */ #include #include #include @@ -11,8 +12,9 @@ void *Thread1(void *x) { void *Thread2(void *x) { char *p1 = reinterpret_cast(&Global[0]); - uint64_t *p4 = reinterpret_cast(p1 + 1); - (*p4)++; + struct __attribute__((packed, aligned(1))) u_uint64_t { uint64_t val; }; + u_uint64_t *p4 = reinterpret_cast(p1 + 1); + (*p4).val++; return NULL; } @@ -23,7 +25,7 @@ int main() { pthread_join(t[0], NULL); pthread_join(t[1], NULL); printf("Pass\n"); - /* { dg-prune-output "ThreadSanitizer: data race.*(\n|\r\n|\r)" } */ + /* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */ /* { dg-output "Pass.*" } */ return 0; } diff --git a/gcc/tsan.c b/gcc/tsan.c index 678fcdc1f04..7992a449508 100644 --- a/gcc/tsan.c +++ b/gcc/tsan.c @@ -62,6 +62,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-propagate.h" #include "tsan.h" #include "asan.h" +#include "builtins.h" /* Number of instrumented memory accesses in the current function. */ @@ -121,13 +122,12 @@ instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_write) gimple stmt, g; gimple_seq seq; location_t loc; + unsigned int align; size = int_size_in_bytes (TREE_TYPE (expr)); - if (size == -1) + if (size <= 0) return false; - /* For now just avoid instrumenting bit field acceses. - TODO: handle bit-fields as if touching the whole field. */ HOST_WIDE_INT bitsize, bitpos; tree offset; machine_mode mode; @@ -155,17 +155,71 @@ instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_write) && DECL_HARD_REGISTER (base))) return false; - if (size == 0 - || bitpos % (size * BITS_PER_UNIT) - || bitsize != size * BITS_PER_UNIT) - return false; - stmt = gsi_stmt (gsi); loc = gimple_location (stmt); rhs = is_vptr_store (stmt, expr, is_write); - gcc_checking_assert (rhs != NULL || is_gimple_addressable (expr)); - expr_ptr = build_fold_addr_expr (unshare_expr (expr)); seq = NULL; + + if ((TREE_CODE (expr) == COMPONENT_REF + && DECL_BIT_FIELD_TYPE (TREE_OPERAND (expr, 1))) + || TREE_CODE (expr) == BIT_FIELD_REF) + { + base = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) == COMPONENT_REF) + { + expr = TREE_OPERAND (expr, 1); + if (is_write && DECL_BIT_FIELD_REPRESENTATIVE (expr)) + expr = DECL_BIT_FIELD_REPRESENTATIVE (expr); + if (!tree_fits_uhwi_p (DECL_FIELD_OFFSET (expr)) + || !tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (expr)) + || !tree_fits_uhwi_p (DECL_SIZE (expr))) + return false; + bitpos = tree_to_uhwi (DECL_FIELD_OFFSET (expr)) * BITS_PER_UNIT + + tree_to_uhwi (DECL_FIELD_BIT_OFFSET (expr)); + bitsize = tree_to_uhwi (DECL_SIZE (expr)); + } + else + { + if (!tree_fits_uhwi_p (TREE_OPERAND (expr, 2)) + || !tree_fits_uhwi_p (TREE_OPERAND (expr, 1))) + return false; + bitpos = tree_to_uhwi (TREE_OPERAND (expr, 2)); + bitsize = tree_to_uhwi (TREE_OPERAND (expr, 1)); + } + if (bitpos < 0 || bitsize <= 0) + return false; + size = (bitpos % BITS_PER_UNIT + bitsize + BITS_PER_UNIT - 1) + / BITS_PER_UNIT; + align = get_object_alignment (base); + if (align < BITS_PER_UNIT) + return false; + bitpos = bitpos & ~(BITS_PER_UNIT - 1); + if ((align - 1) & bitpos) + { + align = (align - 1) & bitpos; + align = align & -align; + } + gcc_checking_assert (is_gimple_addressable (base)); + expr = build_fold_addr_expr (unshare_expr (base)); + if (!is_gimple_mem_ref_addr (expr)) + { + g = gimple_build_assign (make_ssa_name (TREE_TYPE (expr)), expr); + expr = gimple_assign_lhs (g); + gimple_set_location (g, loc); + gimple_seq_add_stmt_without_update (&seq, g); + } + expr = build2 (MEM_REF, char_type_node, expr, + build_int_cst (TREE_TYPE (expr), bitpos / BITS_PER_UNIT)); + expr_ptr = build_fold_addr_expr (expr); + } + else + { + align = get_object_alignment (expr); + if (align < BITS_PER_UNIT) + return false; + gcc_checking_assert (is_gimple_addressable (expr)); + expr_ptr = build_fold_addr_expr (unshare_expr (expr)); + } if (!is_gimple_val (expr_ptr)) { g = gimple_build_assign (make_ssa_name (TREE_TYPE (expr_ptr)), expr_ptr); @@ -173,7 +227,15 @@ instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_write) gimple_set_location (g, loc); gimple_seq_add_stmt_without_update (&seq, g); } - if (rhs == NULL) + if ((size & (size - 1)) == 0 || size > 16 + || align < MIN (size, 8) * BITS_PER_UNIT) + { + builtin_decl = builtin_decl_implicit (is_write + ? BUILT_IN_TSAN_WRITE_RANGE + : BUILT_IN_TSAN_READ_RANGE); + g = gimple_build_call (builtin_decl, 2, expr_ptr, size_int (size)); + } + else if (rhs == NULL) g = gimple_build_call (get_memory_access_decl (is_write, size), 1, expr_ptr); else -- 2.30.2