public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Instrument bit field and unaligned accesses for TSAN
@ 2014-12-29 23:13 Bernd Edlinger
  2015-01-02 19:01 ` Jakub Jelinek
  0 siblings, 1 reply; 32+ messages in thread
From: Bernd Edlinger @ 2014-12-29 23:13 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 939 bytes --]

Hi,

I noticed that currently the tsan pass does not instrument bit fileld accesses or unaligned data.
Thus some race conditions are not found by the sanitizer.

Furthermore the function __tsan_vptr_update is not called with the correct parameters.

This patch uses two already existing interfaces for unaligned or bit field accessses,
__tsan_read_range and __tsan_write_range, and fixes the parameters of the __tsan_vptr_update
function.

As a little surprise, the test case g++.dg/tsan/aligned_vs_unaligned_race.C started to fail at -O2
with this patch, but actually that was due to a combination of invalid C code and inverted logic
in the test case.  So actually that test was failing all the time, because TSAN cannot find
the race condition because __tsan_write8 should only be called with aligned addresses.


Boot-strapped and reggession tested on x86_64-linux-gnu.
OK for trunk?


Thanks
Bernd.
 		 	   		  

[-- Attachment #2: changelog-tsan-bitfields.txt --]
[-- Type: text/plain, Size: 633 bytes --]

gcc/ChangeLog:
2014-12-29  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	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.  Pass "rhs" to BUILT_IN_TSAN_VPTR_UPDATE.

testsuite/ChangeLog:
2014-12-29  Bernd Edlinger  <bernd.edlinger@hotmail.de>

	* c-c++-common/tsan/bitfield_race.c: New testcase.
	* g++.dg/tsan/aligned_vs_unaligned_race.C: Fixed.


[-- Attachment #3: patch-tsan-bitfields.diff --]
[-- Type: application/octet-stream, Size: 7027 bytes --]

Index: gcc/sanitizer.def
===================================================================
--- gcc/sanitizer.def	(revision 218963)
+++ gcc/sanitizer.def	(working copy)
@@ -188,6 +188,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE8, "__tsa
 		      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, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_WRITE_RANGE, "__tsan_write_range",
+		      BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
 
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_ATOMIC8_LOAD,
 		      "__tsan_atomic8_load",
Index: gcc/tsan.c
===================================================================
--- gcc/tsan.c	(revision 218963)
+++ gcc/tsan.c	(working copy)
@@ -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 ex
   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 ex
 	  && 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,13 +227,21 @@ instrument_expr (gimple_stmt_iterator gsi, tree ex
       gimple_set_location (g, loc);
       gimple_seq_add_stmt_without_update (&seq, g);
     }
-  if (rhs == NULL)
+  if ((size & -size) != size || 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
     {
       builtin_decl = builtin_decl_implicit (BUILT_IN_TSAN_VPTR_UPDATE);
-      g = gimple_build_call (builtin_decl, 1, expr_ptr);
+      g = gimple_build_call (builtin_decl, 2, expr_ptr, unshare_expr (rhs));
     }
   gimple_set_location (g, loc);
   gimple_seq_add_stmt_without_update (&seq, g);
Index: gcc/testsuite/c-c++-common/tsan/bitfield_race.c
===================================================================
--- gcc/testsuite/c-c++-common/tsan/bitfield_race.c	(revision 0)
+++ gcc/testsuite/c-c++-common/tsan/bitfield_race.c	(working copy)
@@ -0,0 +1,26 @@
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <unistd.h>
+
+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)" } */
Index: gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C
===================================================================
--- gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C	(revision 218963)
+++ gcc/testsuite/g++.dg/tsan/aligned_vs_unaligned_race.C	(working copy)
@@ -1,3 +1,4 @@
+/* { dg-shouldfail "tsan" } */
 #include <pthread.h>
 #include <stdio.h>
 #include <stdint.h>
@@ -11,8 +12,9 @@ void *Thread1(void *x) {
 
 void *Thread2(void *x) {
   char *p1 = reinterpret_cast<char *>(&Global[0]);
-  uint64_t *p4 = reinterpret_cast<uint64_t *>(p1 + 1);
-  (*p4)++;
+  struct __attribute__((packed, aligned(1))) u_uint64_t { uint64_t val; };
+  u_uint64_t *p4 = reinterpret_cast<u_uint64_t *>(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;
 }

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2015-01-21 18:05 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-29 23:13 [PATCH] Instrument bit field and unaligned accesses for TSAN Bernd Edlinger
2015-01-02 19:01 ` Jakub Jelinek
2015-01-02 21:06   ` Bernd Edlinger
2015-01-02 21:29     ` Jakub Jelinek
2015-01-02 22:02       ` Bernd Edlinger
2015-01-02 22:11         ` Jakub Jelinek
2015-01-14 16:58           ` Dmitry Vyukov
2015-01-04 13:55         ` [PATCH] Fix parameters of __tsan_vptr_update Bernd Edlinger
2015-01-11 13:38           ` Bernd Edlinger
2015-01-14 15:09             ` Dmitry Vyukov
2015-01-16  8:34             ` [PING] " Bernd Edlinger
2015-01-16 17:20               ` Jeff Law
2015-01-16 17:32               ` Dmitry Vyukov
2015-01-16 17:52                 ` Bernd Edlinger
2015-01-19  8:50                   ` Dmitry Vyukov
2015-01-19  9:51                     ` Jakub Jelinek
2015-01-19 15:46                     ` Mike Stump
2015-01-20  4:03                       ` Konstantin Serebryany
2015-01-20  7:18                         ` Bernd Edlinger
2015-01-21  6:15                           ` Konstantin Serebryany
2015-01-21  8:34                             ` Bernd Edlinger
2015-01-21  9:09                           ` Dmitry Vyukov
2015-01-21 10:50                             ` Bernd Edlinger
2015-01-21 11:33                               ` Bernd Edlinger
2015-01-21 11:51                                 ` Jakub Jelinek
2015-01-21 12:55                                   ` Bernd Edlinger
2015-01-21 18:47                                 ` Mike Stump
2015-01-21 10:50                             ` Dmitry Vyukov
2015-01-21 14:42                             ` Dmitry Vyukov
2015-01-21 16:15                               ` Bernd Edlinger
2015-01-21 16:17                                 ` Dmitry Vyukov
2015-01-21 19:01                                   ` Mike Stump

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).