re PR sanitizer/68260 (false positive with tsan)
authorJakub Jelinek <jakub@redhat.com>
Wed, 14 Sep 2016 09:01:49 +0000 (11:01 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 14 Sep 2016 09:01:49 +0000 (11:01 +0200)
PR sanitizer/68260
* tsan.c: Include target.h.
(enum tsan_atomic_action): Add bool_clear and bool_test_and_set.
(BOOL_CLEAR, BOOL_TEST_AND_SET): Define.
(tsan_atomic_table): Add BUILT_IN_ATOMIC_CLEAR and
BUILT_IN_ATOMIC_TEST_AND_SET entries.
(instrument_builtin_call): Handle bool_clear and bool_test_and_set.

* c-c++-common/tsan/pr68260.c: New test.

From-SVN: r240129

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/tsan/pr68260.c [new file with mode: 0644]
gcc/tsan.c

index a0b660b79626dd89384097a8c57cf533e43500b9..5759b8d1f67e0707317f8d2cf4207d92a3ae6f68 100644 (file)
@@ -1,3 +1,13 @@
+2016-09-14  Jakub Jelinek  <jakub@redhat.com>
+
+       PR sanitizer/68260
+       * tsan.c: Include target.h.
+       (enum tsan_atomic_action): Add bool_clear and bool_test_and_set.
+       (BOOL_CLEAR, BOOL_TEST_AND_SET): Define.
+       (tsan_atomic_table): Add BUILT_IN_ATOMIC_CLEAR and
+       BUILT_IN_ATOMIC_TEST_AND_SET entries.
+       (instrument_builtin_call): Handle bool_clear and bool_test_and_set.
+
 2016-09-14  Bernd Edlinger  <bernd.edlinger@hotmail.de>
            Martin Liska  <mliska@suse.cz>
 
index 39de996eb71ba37967f2ce73b71298cf0a7fa54f..36e57c6edc157d17f1c2dc0216b19c8f167ad64a 100644 (file)
@@ -1,3 +1,8 @@
+2016-09-14  Jakub Jelinek  <jakub@redhat.com>
+
+       PR sanitizer/68260
+       * c-c++-common/tsan/pr68260.c: New test.
+
 2016-09-13  Joe Seymour  <joe.s@somniumtech.com>
 
        PR target/70713
diff --git a/gcc/testsuite/c-c++-common/tsan/pr68260.c b/gcc/testsuite/c-c++-common/tsan/pr68260.c
new file mode 100644 (file)
index 0000000..86ffd2b
--- /dev/null
@@ -0,0 +1,28 @@
+/* PR sanitizer/68260 */
+
+#include <pthread.h>
+#include <stdbool.h>
+
+bool lock;
+int counter;
+
+void *
+tf (void *arg)
+{
+  (void) arg;
+  while (__atomic_test_and_set (&lock, __ATOMIC_ACQUIRE))
+    ;
+  ++counter;
+  __atomic_clear (&lock, __ATOMIC_RELEASE);
+  return (void *) 0;
+}
+
+int
+main ()
+{
+  pthread_t thr;
+  pthread_create (&thr, 0, tf, 0);
+  tf ((void *) 0);
+  pthread_join (thr, 0);
+  return 0;
+}
index aa95f4ee69e0eaf0e5a8e9651733c663b0d7ae76..d69432e52948260868e6d2cec3b948578c0b89cd 100644 (file)
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tsan.h"
 #include "asan.h"
 #include "builtins.h"
+#include "target.h"
 
 /* Number of instrumented memory accesses in the current function.  */
 
@@ -240,7 +241,8 @@ instrument_expr (gimple_stmt_iterator gsi, tree expr, bool is_write)
 enum tsan_atomic_action
 {
   check_last, add_seq_cst, add_acquire, weak_cas, strong_cas,
-  bool_cas, val_cas, lock_release, fetch_op, fetch_op_seq_cst
+  bool_cas, val_cas, lock_release, fetch_op, fetch_op_seq_cst,
+  bool_clear, bool_test_and_set
 };
 
 /* Table how to map sync/atomic builtins to their corresponding
@@ -274,6 +276,10 @@ static const struct tsan_map_atomic
   TRANSFORM (fcode, tsan_fcode, fetch_op, code)
 #define FETCH_OPS(fcode, tsan_fcode, code) \
   TRANSFORM (fcode, tsan_fcode, fetch_op_seq_cst, code)
+#define BOOL_CLEAR(fcode, tsan_fcode) \
+  TRANSFORM (fcode, tsan_fcode, bool_clear, ERROR_MARK)
+#define BOOL_TEST_AND_SET(fcode, tsan_fcode) \
+  TRANSFORM (fcode, tsan_fcode, bool_test_and_set, ERROR_MARK)
 
   CHECK_LAST (ATOMIC_LOAD_1, TSAN_ATOMIC8_LOAD),
   CHECK_LAST (ATOMIC_LOAD_2, TSAN_ATOMIC16_LOAD),
@@ -463,7 +469,11 @@ static const struct tsan_map_atomic
   LOCK_RELEASE (SYNC_LOCK_RELEASE_2, TSAN_ATOMIC16_STORE),
   LOCK_RELEASE (SYNC_LOCK_RELEASE_4, TSAN_ATOMIC32_STORE),
   LOCK_RELEASE (SYNC_LOCK_RELEASE_8, TSAN_ATOMIC64_STORE),
-  LOCK_RELEASE (SYNC_LOCK_RELEASE_16, TSAN_ATOMIC128_STORE)
+  LOCK_RELEASE (SYNC_LOCK_RELEASE_16, TSAN_ATOMIC128_STORE),
+
+  BOOL_CLEAR (ATOMIC_CLEAR, TSAN_ATOMIC8_STORE),
+
+  BOOL_TEST_AND_SET (ATOMIC_TEST_AND_SET, TSAN_ATOMIC8_EXCHANGE)
 };
 
 /* Instrument an atomic builtin.  */
@@ -615,6 +625,57 @@ instrument_builtin_call (gimple_stmt_iterator *gsi)
                                build_int_cst (NULL_TREE,
                                               MEMMODEL_RELEASE));
            return;
+         case bool_clear:
+         case bool_test_and_set:
+           if (BOOL_TYPE_SIZE != 8)
+             {
+               decl = NULL_TREE;
+               for (j = 1; j < 5; j++)
+                 if (BOOL_TYPE_SIZE == (8 << j))
+                   {
+                     enum built_in_function tsan_fcode
+                       = (enum built_in_function)
+                         (tsan_atomic_table[i].tsan_fcode + j);
+                     decl = builtin_decl_implicit (tsan_fcode);
+                     break;
+                   }
+               if (decl == NULL_TREE)
+                 return;
+             }
+           last_arg = gimple_call_arg (stmt, num - 1);
+           if (!tree_fits_uhwi_p (last_arg)
+               || memmodel_base (tree_to_uhwi (last_arg)) >= MEMMODEL_LAST)
+             return;
+           t = TYPE_ARG_TYPES (TREE_TYPE (decl));
+           t = TREE_VALUE (TREE_CHAIN (t));
+           if (tsan_atomic_table[i].action == bool_clear)
+             {
+               update_gimple_call (gsi, decl, 3, gimple_call_arg (stmt, 0),
+                                   build_int_cst (t, 0), last_arg);
+               return;
+             }
+           t = build_int_cst (t, targetm.atomic_test_and_set_trueval);
+           update_gimple_call (gsi, decl, 3, gimple_call_arg (stmt, 0),
+                               t, last_arg);
+           stmt = gsi_stmt (*gsi);
+           lhs = gimple_call_lhs (stmt);
+           if (lhs == NULL_TREE)
+             return;
+           if (targetm.atomic_test_and_set_trueval != 1
+               || !useless_type_conversion_p (TREE_TYPE (lhs),
+                                              TREE_TYPE (t)))
+             {
+               tree new_lhs = make_ssa_name (TREE_TYPE (t));
+               gimple_call_set_lhs (stmt, new_lhs);
+               if (targetm.atomic_test_and_set_trueval != 1)
+                 g = gimple_build_assign (lhs, NE_EXPR, new_lhs,
+                                          build_int_cst (TREE_TYPE (t), 0));
+               else
+                 g = gimple_build_assign (lhs, NOP_EXPR, new_lhs);
+               gsi_insert_after (gsi, g, GSI_NEW_STMT);
+               update_stmt (stmt);
+             }
+           return;
          default:
            continue;
          }