public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: [tsan] ThreadSanitizer instrumentation part
@ 2012-11-01  6:00 Xinliang David Li
  2012-11-01  6:27 ` Jakub Jelinek
       [not found] ` <CA+4CFy4uuCtFuiqai0b_VXib1te=DeBv1_EWDFjf8UP6MYMJPg@mail.gmail.com>
  0 siblings, 2 replies; 56+ messages in thread
From: Xinliang David Li @ 2012-11-01  6:00 UTC (permalink / raw)
  To: Wei Mi
  Cc: GCC Patches, Dmitry Vyukov, Diego Novillo, Jakub Jelinek, Dodji Seketeli

> --fno-default-inline @gol
> +-fmove-loop-invariants -fmudflap -fmudflapir -fmudflapth -fno-branch-count-reg @gol
> +-ftsan -ftsan-ignore -fno-default-inline @gol

Change -ftsan to -fthread-sanitizer

>  -fno-defer-pop -fno-function-cse -fno-guess-branch-probability @gol
>  -fno-inline -fno-math-errno -fno-peephole -fno-peephole2 @gol
>  -fno-sched-interblock -fno-sched-spec -fno-signed-zeros @gol
> @@ -5956,6 +5957,11 @@ appending @file{.dce} to the source file
>  Dump each function after adding mudflap instrumentation.  The file name is
>  made by appending @file{.mudflap} to the source file name.
>
> +
>  @item sra
>  @opindex fdump-tree-sra
>  Dump each function after performing scalar replacement of aggregates.  The
> @@ -6798,6 +6804,12 @@ instrumentation (and therefore faster ex
>  some protection against outright memory corrupting writes, but allows
>  erroneously read data to propagate within a program.
>
> +@item -ftsan -ftsan-ignore
> +@opindex ftsan
> +@opindex ftsan-ignore
> +Add ThreadSanitizer instrumentation. Use @option{-ftsan-ignore} to specify
> +an ignore file. Refer to http://go/tsan for details.
> +

-ftsan --> -fthread-sanitizer

> + *
> + * IT is free software; you can redistribute it and/or modify it under
> + * the terms of the GNU General Public License as published by the Free
> + * Software Foundation; either version 3, or (at your option) any later
> + * version. See http://www.gnu.org/licenses/
> + /

You can copy this part of header from asan.c


> +static int func_calls;
> +
> +/* Returns a definition of a runtime functione with type TYP and name NAME.  */


s/functione/function/

> +
> +static tree
> +build_func_decl (tree typ, const char *name)
> +/* Builds the following decl
> +   void __tsan_read/writeX (void *addr);  */
> +
> +static tree
> +get_memory_access_decl (int is_write, unsigned size)

Change is_write to type bool.


> +{
> +  tree typ, *decl;
> +  char fname [64];
> +  static tree cache [2][17];

There is no need to make this function local. define a macro for value 17.
> +
> +  is_write = !!is_write;


No need for this after making is_write bool.


> +  if (size <= 1)
> +    size = 1;
> +  else if (size <= 3)
> +    size = 2;
> +  else if (size <= 7)
> +    size = 4;


Missing function comment:

/* This function returns the function decl for __tsan_init.  */

> +static tree
> +get_init_decl (void)
> +{
> +  tree typ;
> +  return decl;
> +}
> +

> +/* Builds the following gimple sequence:
> +   __tsan_read/writeX (&EXPR);  */
> +
> +static gimple_seq
> +instr_memory_access (tree expr, int is_write)
> +{
> +  tree addr_expr, expr_type, call_expr, fdecl;
> +  gimple_seq gs;
> +  unsigned size;
> +
> +  gcc_assert (is_gimple_addressable (expr));
> +  addr_expr = build_addr (unshare_expr (expr), current_function_decl);
> +  expr_type = TREE_TYPE (expr);
> +  while (TREE_CODE (expr_type) == ARRAY_TYPE)
> +    expr_type = TREE_TYPE (expr_type);
> +  size = (TREE_INT_CST_LOW (TYPE_SIZE (expr_type))) / BITS_PER_UNIT;
> +  fdecl = get_memory_access_decl (is_write, size);
> +  call_expr = build_call_expr (fdecl, 1, addr_expr);
> +  gs = NULL;
> +  force_gimple_operand (call_expr, &gs, true, 0);
> +  return gs;


Use gimple creator API: gimple_build_call --> see examples in tree-profile.c.

Return the gimple_stmt_iterator for the newly created call stmt.


> +}
> +
> +/* Builds the following gimple sequence:
> +   __tsan_vptr_update (&EXPR, RHS);  */
> +
> +static gimple_seq
> +instr_vptr_update (tree expr, tree rhs)
> +{
> +  tree expr_ptr, call_expr, fdecl;
> +  gimple_seq gs;
> +
> +  expr_ptr = build_addr (unshare_expr (expr), current_function_decl);
> +  fdecl = get_vptr_update_decl ();
> +  call_expr = build_call_expr (fdecl, 2, expr_ptr, rhs);
> +  gs = NULL;
> +  force_gimple_operand (call_expr, &gs, true, 0);
> +  return gs;
> +}


Same as above -- directly use gimple_build_call interface.


> +
> +/* Returns gimple seq that needs to be inserted at function entry.  */
> +
> +static gimple_seq
> +instr_func_entry (void)
> +{
> +  tree retaddr_decl, pc_addr, fdecl, call_expr;
> +  gimple_seq gs;
> +
> +  retaddr_decl = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
> +  pc_addr = build_call_expr (retaddr_decl, 1, integer_zero_node);
> +  fdecl = get_func_entry_decl ();
> +  call_expr = build_call_expr (fdecl, 1, pc_addr);
> +  gs = NULL;
> +  force_gimple_operand (call_expr, &gs, true, 0);
> +  return gs;
> +}


Same as above.


> +
> +/* Returns gimple seq that needs to be inserted before function exit.  */
> +
> +static gimple_seq
> +instr_func_exit (void)
> +{
> +  tree fdecl, call_expr;
> +  gimple_seq gs;
> +
> +  fdecl = get_func_exit_decl ();
> +  call_expr = build_call_expr (fdecl, 0);
> +  gs = NULL;
> +  force_gimple_operand (call_expr, &gs, true, 0);
> +  return gs;
> +}
> +


Same as above.


> +/* Sets location LOC for all gimples in the SEQ.  */
> +
> +static void
> +set_location (gimple_seq seq, location_t loc)
> +{
> +  gimple_seq_node n;
> +
> +  for (n = gimple_seq_first (seq); n != NULL; n = n->gsbase.next)
> +    gimple_set_location (n, loc);
> +}

Is there a need for this function? The location can be passed into the
creator functions.


> +
> +/* Check as to whether EXPR refers to a store to vptr.  */
> +
> +static tree
> +is_vptr_store (gimple stmt, tree expr, int is_write)
> +{
> +  if (is_write == 1
> +      && gimple_assign_single_p (stmt)
> +      && TREE_CODE (expr) == COMPONENT_REF)
> +    {
> +      tree field = TREE_OPERAND (expr, 1);
> +      if (TREE_CODE (field) == FIELD_DECL
> +          && DECL_VIRTUAL_P (field))
> +        return gimple_assign_rhs1 (stmt);
> +    }
> +  return NULL;
> +}
> +
> +/* Checks as to whether EXPR refers to constant var/field/param.
> +   Don't bother to instrument them.  */
> +
> +static int

change int --> bool

> +is_load_of_const (tree expr, int is_write)

Better name: is_load_of_const_p (...)

> +{
> +  if (is_write)
> +    return 0;

returns false;


> +  if (TREE_CODE (expr) == COMPONENT_REF)
> +    expr = TREE_OPERAND (expr, 1);
> +  if (TREE_CODE (expr) == VAR_DECL
> +      || TREE_CODE (expr) == PARM_DECL
> +      || TREE_CODE (expr) == FIELD_DECL)
> +    {
> +      if (TREE_READONLY (expr))
> +        return 1;

returns true;

> +    }
> +  return 0;

returns false;


> +      || TREE_CODE (base) == STRING_CST)
> +    return;
> +
> +  tcode = TREE_CODE (expr);
> +
> +  /* Below are things we do not instrument
> +     (no possibility of races or not implemented yet).  */
> +  if (/* Compiler-emitted artificial variables.  */
> +      (DECL_P (expr) && DECL_ARTIFICIAL (expr))
> +      /* The var does not live in memory -> no possibility of races.  */
> +      || (tcode == VAR_DECL
> +          && TREE_ADDRESSABLE (expr) == 0

 ==> !TREE_ADDRESSABLE (expr)

> +         && TREE_STATIC (expr) == 0)


To detect stack varaible, TREE_STATIC can not be used.  Use
!DECL_EXTERNAL instead.


> +      /* Not implemented.  */
> +      || TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE

> +    return;
> +
> +  func_mops++;
> +  stmt = gsi_stmt (gsi);
> +  loc = gimple_location (stmt);
> +  rhs = is_vptr_store (stmt, expr, is_write);
> +  if (rhs == NULL)
> +    gs = instr_memory_access (expr, is_write);
> +  else
> +    gs = instr_vptr_update (expr, rhs);

Pass the location to the instrumetors.

> +  set_location (gs, loc);

Remove this.

> +  /* Instrumentation for assignment of a function result
> +     must be inserted after the call.  Instrumentation for
> +     reads of function arguments must be inserted before the call.
> +     That's because the call can contain synchronization.  */
> +  if (is_gimple_call (stmt) && is_write)
> +    gsi_insert_seq_after (&gsi, gs, GSI_NEW_STMT);
> +  else
> +    gsi_insert_seq_before (&gsi, gs, GSI_SAME_STMT);
> +}
> +

> +}
> +
> +
> +void tsan_finish_file (void)

function name starts a new line.

void
tsan_finish_file

> +{
> +  tree ctor_statements;
> +
> +  ctor_statements = NULL_TREE;
> +  append_to_statement_list (build_call_expr (get_init_decl (), 0),
> +                            &ctor_statements);
> +  cgraph_build_static_cdtor ('I', ctor_statements,
> +                             MAX_RESERVED_INIT_PRIORITY - 1);
> +}
> +
> +/* The pass descriptor.  */


David


On Wed, Oct 31, 2012 at 11:34 AM, Wei Mi <wmi@google.com> wrote:
> Hi,
>
> The patch is about ThreadSanitizer. ThreadSanitizer is a data race
> detector for C/C++ programs. It contains two parts: instrumentation
> and runtime library. This patch is the first part, and runtime will be
> included in the second part. Dmitry(dvyukov@google.com) is the author
> of this part, and I try to migrate it to trunk. Ok for trunk?
>
> gcc/ChangeLog:
> 2012-10-31  Wei Mi  <wmi@gmail.com>
>
>         * Makefile.in (tsan.o): New
>         * passes.c (init_optimization_passes): Add tsan passes
>         * tree-pass.h (register_pass_info): Ditto
>         * cfghooks.h (GCC_CFGHOOKS_H): Avoid including duplicate headers
>         * doc/invoke.texi: Document tsan related options
>         * toplev.c (compile_file): Add tsan pass in driver
>         * gcc.c (LINK_COMMAND_SPEC): Add -lasan in link command if there
>         -ftsan is on.
>         * tsan.c: New file about tsan
>         * tsan.h: Ditto
>
> Please check the following links for background:
> http://code.google.com/p/data-race-test
> http://gcc.gnu.org/wiki/cauldron2012?action=AttachFile&do=get&target=kcc.pdf
> (the second half is about ThreadSanitizer).
>
> A small testcase race_on_heap.cc is attached to show its
> functionality. Run the small testcase with -ftsan produce the
> following warning:
>
> WARNING: ThreadSanitizer: data race (pid=5978)
>   Write of size 4 at 0x7d0600039040 by thread 3:
>     #0 Thread2(void*) ??:0 (exe+0x0000000052c0)
>
>   Previous write of size 4 at 0x7d0600039040 by thread 2:
>     #0 Thread1(void*) ??:0 (exe+0x00000000527d)
>
>   Location is heap block of size 99 at 0x7d0600039030 allocated by thread 1:
>     #0 malloc /usr/local/google/home/wmi/Work/llvm-main/trunk/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:293
> (exe+0x00000000e9ce)
>     #1 alloc() ??:0 (exe+0x0000000052fc)
>     #2 AllocThread(void*) ??:0 (exe+0x00000000532c)
>
>   Thread 3 (tid=5981, running) created at:
>     #0 pthread_create
> /usr/local/google/home/wmi/Work/llvm-main/trunk/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:645
> (exe+0x00000000bf1d)
>     #1 main ??:0 (exe+0x000000005433)
>
>   Thread 2 (tid=5980, finished) created at:
>     #0 pthread_create
> /usr/local/google/home/wmi/Work/llvm-main/trunk/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:645
> (exe+0x00000000bf1d)
>     #1 main ??:0 (exe+0x000000005400)
>
>   Thread 1 (tid=5979, finished) created at:
>     #0 pthread_create
> /usr/local/google/home/wmi/Work/llvm-main/trunk/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:645
> (exe+0x00000000bf1d)
>     #1 main ??:0 (exe+0x000000005384)
>
> Thanks,
> Wei.

^ permalink raw reply	[flat|nested] 56+ messages in thread
* Re: [tsan] ThreadSanitizer instrumentation part
@ 2012-11-01 19:35 Xinliang David Li
  2012-11-01 20:54 ` Jakub Jelinek
  0 siblings, 1 reply; 56+ messages in thread
From: Xinliang David Li @ 2012-11-01 19:35 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Dmitry Vyukov, Wei Mi, GCC Patches, Diego Novillo, Dodji Seketeli

On Thu, Nov 1, 2012 at 12:16 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Thu, Nov 01, 2012 at 11:57:21AM -0700, Xinliang David Li wrote:
>> That is exactly related to tsan -- it should skip local variable that
>> is not address taken (though still addressable, which by addressable,
>> it means the variable has a memory home).
>>
>> The problem is that if 'addressable' bit is not equivalent to 'address
>> taken', it will be too conservative to use it --- as addressable
>> variables may not be address taken.
>
> But TREE_ADDRESSABLE is equivalent to address taken.

It seems not -- unless our definition of them is different. I debugged
the following program:


int foo()
{
  int a[1000];
  int i, s;

  for (i = 0; i < 1000; i++)
    a[i] = i;

  for (i = 0; i < 1000; i++)
    s += a[i];

   return s;
}

a's address is not taken (at source level), but it is marked as addressable.

>
>> Note that even 'address taken' is too conservative to use here. Only
>> when it is escaped the thread (via non TLS global pointers or other
>> escaped local, heap memories), should it be considered to be
>> instrumented.
>
> If you need it even less conservative, I guess you could do say:
>   struct ptr_info_def pi;
>   memset (&pi, 0, sizeof (pi));
>   pi.escaped = 1;
>   pi.nonlocal = 1;
>   return pt_solution_includes (&pi, decl);
>

That will be nice.  Are points-to info exposed to client code like
this? Are there standard aliaser interfaces for them?

thanks,

David

> (the nonlocal in pt_solution_includes_1 performs the is_global_var check
> that needs to be done, and escaped checks whether decl is in the escaped
> set).
>
> Then say for
> int foo(int i)
> {
>   int a[100], b[100], c[100], d[100], *p;
>   if (i < 10)
>     p = a;
>   else if (i < 60)
>     p = b;
>   else if (i <= 65)
>     p = c;
>   else
>     p = d;
>   p[i] = 1;
>   p[2 * i] = 2;
>   return p[i + 1];
> }
> still none of a, b, c, and d vars will be included, even when they are
> TREE_ADDRESSABLE, but if you say pass p to another function, or set a global
> var to it, it will already return true for them.
>
>         Jakub

^ permalink raw reply	[flat|nested] 56+ messages in thread
* Re: [tsan] ThreadSanitizer instrumentation part
@ 2012-11-01 18:11 Xinliang David Li
       [not found] ` <CACT4Y+azNYV+8ieRthd-SkQqGO82dj2+JOdL5c15DyBc9LwyfA@mail.gmail.com>
                   ` (3 more replies)
  0 siblings, 4 replies; 56+ messages in thread
From: Xinliang David Li @ 2012-11-01 18:11 UTC (permalink / raw)
  To: Dmitry Vyukov
  Cc: Jakub Jelinek, Wei Mi, GCC Patches, Diego Novillo, Dodji Seketeli

On Thu, Nov 1, 2012 at 10:06 AM, Dmitry Vyukov <dvyukov@google.com> wrote:
> On Thu, Nov 1, 2012 at 7:47 PM, Xinliang David Li <davidxl@google.com>
> wrote:
>>
>> On Wed, Oct 31, 2012 at 11:27 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> > On Wed, Oct 31, 2012 at 11:00:17PM -0700, Xinliang David Li wrote:
>> >> > +  /* Below are things we do not instrument
>> >> > +     (no possibility of races or not implemented yet).  */
>> >> > +  if (/* Compiler-emitted artificial variables.  */
>> >> > +      (DECL_P (expr) && DECL_ARTIFICIAL (expr))
>> >> > +      /* The var does not live in memory -> no possibility of races.
>> >> > */
>> >> > +      || (tcode == VAR_DECL
>> >> > +          && TREE_ADDRESSABLE (expr) == 0
>> >>
>> >>  ==> !TREE_ADDRESSABLE (expr)
>> >>
>> >> > +         && TREE_STATIC (expr) == 0)
>> >>
>> >>
>> >> To detect stack varaible, TREE_STATIC can not be used.  Use
>> >> !DECL_EXTERNAL instead.
>> >
>> > TREE_STATIC is right for that.
>>
>> Hmm, what does this condition try to capture then?
>
>
>
> As far as I remember, I've seen global variables marked as !ADDRESSABLE. And
> this condition is to instrument global vars in any case.
> But it was a long time ago.

But it skips those globals without static storage and marked as not addressable.

It seems to me you want to skip all stack local variables that are not
address escaped.  Without address escape analysis, the address taken
bit (not the same as addressable attribute) should be used. As far as
I can tell, such bit is not available in var_decl. The varpool_node
has one, but it is only for var_decls with static storage.  It is also
unfortunate that there is no single bit to test if a variable is
function auto, though there is an interface to call which is
'auto_var_in_fn_p (...)'.  The condition to skip such variable
references are:

  if (tcode == VAR_DECL && auto_var_in_fn_p (expr, ..) &&
!address_taken (expr))

The TREE_ADDRESSABLE check seems redundant -- if the var_decl (instead
of ssa name) appears in the assignment, why would it not be
'addressable'? And being addressable does not mean it is address taken
either.

Diego, is there a way to check address taken attribute for auto vars?

thanks,

David

^ permalink raw reply	[flat|nested] 56+ messages in thread
* [tsan] ThreadSanitizer instrumentation part
@ 2012-10-31 18:56 Wei Mi
  2012-10-31 23:17 ` Jakub Jelinek
  2012-11-01  6:58 ` Jakub Jelinek
  0 siblings, 2 replies; 56+ messages in thread
From: Wei Mi @ 2012-10-31 18:56 UTC (permalink / raw)
  To: gcc-patches
  Cc: Dmitry Vyukov, David Li, Diego Novillo, Jakub Jelinek, Dodji Seketeli

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

Hi,

The patch is about ThreadSanitizer. ThreadSanitizer is a data race
detector for C/C++ programs. It contains two parts: instrumentation
and runtime library. This patch is the first part, and runtime will be
included in the second part. Dmitry(dvyukov@google.com) is the author
of this part, and I try to migrate it to trunk. Ok for trunk?

gcc/ChangeLog:
2012-10-31  Wei Mi  <wmi@gmail.com>

        * Makefile.in (tsan.o): New
        * passes.c (init_optimization_passes): Add tsan passes
        * tree-pass.h (register_pass_info): Ditto
        * cfghooks.h (GCC_CFGHOOKS_H): Avoid including duplicate headers
        * doc/invoke.texi: Document tsan related options
        * toplev.c (compile_file): Add tsan pass in driver
        * gcc.c (LINK_COMMAND_SPEC): Add -lasan in link command if there
        -ftsan is on.
        * tsan.c: New file about tsan
        * tsan.h: Ditto

Please check the following links for background:
http://code.google.com/p/data-race-test
http://gcc.gnu.org/wiki/cauldron2012?action=AttachFile&do=get&target=kcc.pdf
(the second half is about ThreadSanitizer).

A small testcase race_on_heap.cc is attached to show its
functionality. Run the small testcase with -ftsan produce the
following warning:

WARNING: ThreadSanitizer: data race (pid=5978)
  Write of size 4 at 0x7d0600039040 by thread 3:
    #0 Thread2(void*) ??:0 (exe+0x0000000052c0)

  Previous write of size 4 at 0x7d0600039040 by thread 2:
    #0 Thread1(void*) ??:0 (exe+0x00000000527d)

  Location is heap block of size 99 at 0x7d0600039030 allocated by thread 1:
    #0 malloc /usr/local/google/home/wmi/Work/llvm-main/trunk/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:293
(exe+0x00000000e9ce)
    #1 alloc() ??:0 (exe+0x0000000052fc)
    #2 AllocThread(void*) ??:0 (exe+0x00000000532c)

  Thread 3 (tid=5981, running) created at:
    #0 pthread_create
/usr/local/google/home/wmi/Work/llvm-main/trunk/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:645
(exe+0x00000000bf1d)
    #1 main ??:0 (exe+0x000000005433)

  Thread 2 (tid=5980, finished) created at:
    #0 pthread_create
/usr/local/google/home/wmi/Work/llvm-main/trunk/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:645
(exe+0x00000000bf1d)
    #1 main ??:0 (exe+0x000000005400)

  Thread 1 (tid=5979, finished) created at:
    #0 pthread_create
/usr/local/google/home/wmi/Work/llvm-main/trunk/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:645
(exe+0x00000000bf1d)
    #1 main ??:0 (exe+0x000000005384)

Thanks,
Wei.

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 23152 bytes --]

Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 193016)
+++ gcc/Makefile.in	(working copy)
@@ -1351,6 +1351,7 @@ OBJS = \
 	trans-mem.o \
 	tree-affine.o \
 	tree-call-cdce.o \
+	tsan.o \
 	tree-cfg.o \
 	tree-cfgcleanup.o \
 	tree-chrec.o \
@@ -2618,6 +2619,12 @@ tree-nomudflap.o : $(CONFIG_H) $(SYSTEM_
    $(C_TREE_H) $(C_COMMON_H) $(GIMPLE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) \
    output.h langhooks.h tree-mudflap.h $(TM_H) coretypes.h \
    $(GGC_H) gt-tree-mudflap.h $(TREE_PASS_H) $(DIAGNOSTIC_CORE_H)
+tsan.o : $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(TREE_INLINE_H) \
+   $(GIMPLE_H) $(DIAGNOSTIC_H) langhooks.h \
+   $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_PASS_H) $(CGRAPH_H) $(GGC_H) \
+   $(BASIC_BLOCK_H) $(FLAGS_H) $(FUNCTION_H) \
+   $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_CORE_H) $(GIMPLE_H) tree-iterator.h \
+   intl.h cfghooks.h output.h options.h c-family/c-common.h tsan.h
 tree-pretty-print.o : tree-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \
    $(TREE_H) $(DIAGNOSTIC_H) $(HASHTAB_H) $(TREE_FLOW_H) \
    $(TM_H) coretypes.h dumpfile.h tree-iterator.h $(SCEV_H) langhooks.h \
@@ -2671,7 +2678,8 @@ toplev.o : toplev.c $(CONFIG_H) $(SYSTEM
    $(CGRAPH_H) $(COVERAGE_H) alloc-pool.h $(GGC_H) \
    $(OPTS_H) params.def tree-mudflap.h $(TREE_PASS_H) $(GIMPLE_H) \
    tree-ssa-alias.h $(PLUGIN_H) realmpfr.h tree-diagnostic.h \
-   $(TREE_PRETTY_PRINT_H) opts-diagnostic.h $(COMMON_TARGET_H)
+   $(TREE_PRETTY_PRINT_H) opts-diagnostic.h $(COMMON_TARGET_H) \
+   tsan.h
 
 hwint.o : hwint.c $(CONFIG_H) $(SYSTEM_H) $(DIAGNOSTIC_CORE_H)
 
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 193016)
+++ gcc/passes.c	(working copy)
@@ -1439,6 +1439,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_split_crit_edges);
       NEXT_PASS (pass_pre);
       NEXT_PASS (pass_sink_code);
+      NEXT_PASS (pass_tsan);
       NEXT_PASS (pass_tree_loop);
 	{
 	  struct opt_pass **p = &pass_tree_loop.pass.sub;
@@ -1544,6 +1545,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_tm_edges);
     }
   NEXT_PASS (pass_lower_complex_O0);
+  NEXT_PASS (pass_tsan_O0);
   NEXT_PASS (pass_cleanup_eh);
   NEXT_PASS (pass_lower_resx);
   NEXT_PASS (pass_nrv);
Index: gcc/tree-pass.h
===================================================================
--- gcc/tree-pass.h	(revision 193016)
+++ gcc/tree-pass.h	(working copy)
@@ -256,6 +256,8 @@ struct register_pass_info
 
 extern struct gimple_opt_pass pass_mudflap_1;
 extern struct gimple_opt_pass pass_mudflap_2;
+extern struct gimple_opt_pass pass_tsan;
+extern struct gimple_opt_pass pass_tsan_O0;
 extern struct gimple_opt_pass pass_lower_cf;
 extern struct gimple_opt_pass pass_refactor_eh;
 extern struct gimple_opt_pass pass_lower_eh;
Index: gcc/cfghooks.h
===================================================================
--- gcc/cfghooks.h	(revision 193016)
+++ gcc/cfghooks.h	(working copy)
@@ -19,6 +19,9 @@ You should have received a copy of the G
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#ifndef GCC_CFGHOOKS_H
+#define GCC_CFGHOOKS_H
+
 /* Only basic-block.h includes this.  */
 
 struct cfg_hooks
@@ -219,3 +222,4 @@ extern void gimple_register_cfg_hooks (v
 extern struct cfg_hooks get_cfg_hooks (void);
 extern void set_cfg_hooks (struct cfg_hooks);
 
+#endif  /* GCC_CFGHOOKS_H */
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 193016)
+++ gcc/doc/invoke.texi	(working copy)
@@ -308,6 +308,7 @@ Objective-C and Objective-C++ Dialects}.
 -fdump-tree-ssa@r{[}-@var{n}@r{]} -fdump-tree-pre@r{[}-@var{n}@r{]} @gol
 -fdump-tree-ccp@r{[}-@var{n}@r{]} -fdump-tree-dce@r{[}-@var{n}@r{]} @gol
 -fdump-tree-gimple@r{[}-raw@r{]} -fdump-tree-mudflap@r{[}-@var{n}@r{]} @gol
+-fdump-tree-tsan@r{[}-@var{n}@r{]} @gol
 -fdump-tree-dom@r{[}-@var{n}@r{]} @gol
 -fdump-tree-dse@r{[}-@var{n}@r{]} @gol
 -fdump-tree-phiprop@r{[}-@var{n}@r{]} @gol
@@ -380,8 +381,8 @@ Objective-C and Objective-C++ Dialects}.
 -floop-parallelize-all -flto -flto-compression-level @gol
 -flto-partition=@var{alg} -flto-report -fmerge-all-constants @gol
 -fmerge-constants -fmodulo-sched -fmodulo-sched-allow-regmoves @gol
--fmove-loop-invariants fmudflap -fmudflapir -fmudflapth -fno-branch-count-reg @gol
--fno-default-inline @gol
+-fmove-loop-invariants -fmudflap -fmudflapir -fmudflapth -fno-branch-count-reg @gol
+-ftsan -ftsan-ignore -fno-default-inline @gol
 -fno-defer-pop -fno-function-cse -fno-guess-branch-probability @gol
 -fno-inline -fno-math-errno -fno-peephole -fno-peephole2 @gol
 -fno-sched-interblock -fno-sched-spec -fno-signed-zeros @gol
@@ -5956,6 +5957,11 @@ appending @file{.dce} to the source file
 Dump each function after adding mudflap instrumentation.  The file name is
 made by appending @file{.mudflap} to the source file name.
 
+@item tsan
+@opindex fdump-tree-tsan
+Dump each function after adding ThreadSanitizer instrumentation.  The file name is
+made by appending @file{.tsan} to the source file name.
+
 @item sra
 @opindex fdump-tree-sra
 Dump each function after performing scalar replacement of aggregates.  The
@@ -6798,6 +6804,12 @@ instrumentation (and therefore faster ex
 some protection against outright memory corrupting writes, but allows
 erroneously read data to propagate within a program.
 
+@item -ftsan -ftsan-ignore
+@opindex ftsan
+@opindex ftsan-ignore
+Add ThreadSanitizer instrumentation. Use @option{-ftsan-ignore} to specify
+an ignore file. Refer to http://go/tsan for details.
+
 @item -fthread-jumps
 @opindex fthread-jumps
 Perform optimizations that check to see if a jump branches to a
Index: gcc/toplev.c
===================================================================
--- gcc/toplev.c	(revision 193016)
+++ gcc/toplev.c	(working copy)
@@ -73,6 +73,7 @@ along with GCC; see the file COPYING3.
 #include "alloc-pool.h"
 #include "tree-mudflap.h"
 #include "gimple.h"
+#include "tsan.h"
 #include "tree-ssa-alias.h"
 #include "plugin.h"
 
@@ -570,6 +571,10 @@ compile_file (void)
       if (flag_mudflap)
 	mudflap_finish_file ();
 
+      /* File-scope initialization for ThreadSanitizer.  */
+      if (flag_tsan)
+        tsan_finish_file ();
+
       output_shared_constant_pool ();
       output_object_blocks ();
       finish_tm_clone_pairs ();
Index: gcc/gcc.c
===================================================================
--- gcc/gcc.c	(revision 193016)
+++ gcc/gcc.c	(working copy)
@@ -679,6 +679,7 @@ proper position among the other output f
     %{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
     %(mflib) " STACK_SPLIT_SPEC "\
     %{fprofile-arcs|fprofile-generate*|coverage:-lgcov}\
+    %{ftsan:-ltsan}\
     %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
     %{!nostdlib:%{!nostartfiles:%E}} %{T*} }}}}}}"
 #endif
Index: gcc/tsan.c
===================================================================
--- gcc/tsan.c	(revision 0)
+++ gcc/tsan.c	(revision 0)
@@ -0,0 +1,534 @@
+/* GCC instrumentation plugin for ThreadSanitizer.
+ * Copyright (c) 2012, Google Inc. All rights reserved.
+ * Author: Dmitry Vyukov (dvyukov)
+ *
+ * IT is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any later
+ * version. See http://www.gnu.org/licenses/
+ */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "intl.h"
+#include "tm.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "function.h"
+#include "tree-flow.h"
+#include "tree-pass.h"
+#include "tree-iterator.h"
+#include "cfghooks.h"
+#include "langhooks.h"
+#include "output.h"
+#include "options.h"
+#include "target.h"
+#include "cgraph.h"
+#include "diagnostic.h"
+
+/* Number of instrumented memory accesses in the current function.  */
+
+static int func_mops;
+
+/* Number of function calls in the current function.  */
+
+static int func_calls;
+
+/* Returns a definition of a runtime functione with type TYP and name NAME.  */
+
+static tree
+build_func_decl (tree typ, const char *name)
+{
+  tree decl;
+
+  decl = build_fn_decl (name, typ);
+  TREE_NOTHROW (decl) = 1;
+  DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("leaf"),
+                                     NULL, DECL_ATTRIBUTES (decl));
+  DECL_ASSEMBLER_NAME (decl);
+  return decl;
+}
+
+/* Builds the following decl
+   void __tsan_read/writeX (void *addr);  */
+
+static tree
+get_memory_access_decl (int is_write, unsigned size)
+{
+  tree typ, *decl;
+  char fname [64];
+  static tree cache [2][17];
+
+  is_write = !!is_write;
+  if (size <= 1)
+    size = 1;
+  else if (size <= 3)
+    size = 2;
+  else if (size <= 7)
+    size = 4;
+  else if (size <= 15)
+    size = 8;
+  else
+    size = 16;
+  decl = &cache[is_write][size];
+  if (*decl == NULL)
+    {
+      snprintf(fname, sizeof fname, "__tsan_%s%d",
+               is_write ? "write" : "read", size);
+      typ = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
+      *decl = build_func_decl (typ, fname);
+    }
+  return *decl;
+}
+
+/* Builds the following decl
+   void __tsan_vptr_update (void *vptr, void *val);  */
+
+static tree
+get_vptr_update_decl (void)
+{
+  tree typ;
+  static tree decl;
+
+  if (decl != NULL)
+    return decl;
+  typ = build_function_type_list (void_type_node,
+                                  ptr_type_node, ptr_type_node, NULL_TREE);
+  decl = build_func_decl (typ, "__tsan_vptr_update");
+  return decl;
+}
+
+
+/* Builds the following decl
+   void __tsan_init (void);  */
+
+static tree
+get_init_decl (void)
+{
+  tree typ;
+  static tree decl;
+
+  if (decl != NULL)
+    return decl;
+  typ = build_function_type_list (void_type_node, NULL_TREE);
+  decl = build_func_decl (typ, "__tsan_init");
+  return decl;
+}
+
+/* Builds the following decl
+   void __tsan_func_entry (void *addr);  */
+
+static tree
+get_func_entry_decl (void)
+{
+  tree typ;
+  static tree decl;
+
+  if (decl != NULL)
+    return decl;
+  typ = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
+  decl = build_func_decl (typ, "__tsan_func_entry");
+  return decl;
+}
+
+/* Builds the following decl
+   void __tsan_func_exit (void);  */
+
+static tree
+get_func_exit_decl (void)
+{
+  tree typ;
+  static tree decl;
+
+  if (decl != NULL)
+    return decl;
+  typ = build_function_type_list (void_type_node, NULL_TREE);
+  decl = build_func_decl (typ, "__tsan_func_exit");
+  return decl;
+}
+
+/* Builds the following gimple sequence:
+   __tsan_read/writeX (&EXPR);  */
+
+static gimple_seq
+instr_memory_access (tree expr, int is_write)
+{
+  tree addr_expr, expr_type, call_expr, fdecl;
+  gimple_seq gs;
+  unsigned size;
+
+  gcc_assert (is_gimple_addressable (expr));
+  addr_expr = build_addr (unshare_expr (expr), current_function_decl);
+  expr_type = TREE_TYPE (expr);
+  while (TREE_CODE (expr_type) == ARRAY_TYPE)
+    expr_type = TREE_TYPE (expr_type);
+  size = (TREE_INT_CST_LOW (TYPE_SIZE (expr_type))) / BITS_PER_UNIT;
+  fdecl = get_memory_access_decl (is_write, size);
+  call_expr = build_call_expr (fdecl, 1, addr_expr);
+  gs = NULL;
+  force_gimple_operand (call_expr, &gs, true, 0);
+  return gs;
+}
+
+/* Builds the following gimple sequence:
+   __tsan_vptr_update (&EXPR, RHS);  */
+
+static gimple_seq
+instr_vptr_update (tree expr, tree rhs)
+{
+  tree expr_ptr, call_expr, fdecl;
+  gimple_seq gs;
+
+  expr_ptr = build_addr (unshare_expr (expr), current_function_decl);
+  fdecl = get_vptr_update_decl ();
+  call_expr = build_call_expr (fdecl, 2, expr_ptr, rhs);
+  gs = NULL;
+  force_gimple_operand (call_expr, &gs, true, 0);
+  return gs;
+}
+
+/* Returns gimple seq that needs to be inserted at function entry.  */
+
+static gimple_seq
+instr_func_entry (void)
+{
+  tree retaddr_decl, pc_addr, fdecl, call_expr;
+  gimple_seq gs;
+
+  retaddr_decl = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
+  pc_addr = build_call_expr (retaddr_decl, 1, integer_zero_node);
+  fdecl = get_func_entry_decl ();
+  call_expr = build_call_expr (fdecl, 1, pc_addr);
+  gs = NULL;
+  force_gimple_operand (call_expr, &gs, true, 0);
+  return gs;
+}
+
+/* Returns gimple seq that needs to be inserted before function exit.  */
+
+static gimple_seq
+instr_func_exit (void)
+{
+  tree fdecl, call_expr;
+  gimple_seq gs;
+
+  fdecl = get_func_exit_decl ();
+  call_expr = build_call_expr (fdecl, 0);
+  gs = NULL;
+  force_gimple_operand (call_expr, &gs, true, 0);
+  return gs;
+}
+
+/* Sets location LOC for all gimples in the SEQ.  */
+
+static void
+set_location (gimple_seq seq, location_t loc)
+{
+  gimple_seq_node n;
+
+  for (n = gimple_seq_first (seq); n != NULL; n = n->gsbase.next)
+    gimple_set_location (n, loc);
+}
+
+/* Check as to whether EXPR refers to a store to vptr.  */
+
+static tree
+is_vptr_store (gimple stmt, tree expr, int is_write)
+{
+  if (is_write == 1
+      && gimple_assign_single_p (stmt)
+      && TREE_CODE (expr) == COMPONENT_REF)
+    {
+      tree field = TREE_OPERAND (expr, 1);
+      if (TREE_CODE (field) == FIELD_DECL
+          && DECL_VIRTUAL_P (field))
+        return gimple_assign_rhs1 (stmt);
+    }
+  return NULL;
+}
+
+/* Checks as to whether EXPR refers to constant var/field/param.
+   Don't bother to instrument them.  */
+
+static int
+is_load_of_const (tree expr, int is_write)
+{
+  if (is_write)
+    return 0;
+  if (TREE_CODE (expr) == COMPONENT_REF)
+    expr = TREE_OPERAND (expr, 1);
+  if (TREE_CODE (expr) == VAR_DECL
+      || TREE_CODE (expr) == PARM_DECL
+      || TREE_CODE (expr) == FIELD_DECL)
+    {
+      if (TREE_READONLY (expr))
+        return 1;
+    }
+  return 0;
+}
+
+/* Instruments EXPR if needed.  */
+
+static void
+instrument_expr (gimple_stmt_iterator gsi, tree expr, int is_write)
+{
+  enum tree_code tcode;
+  unsigned fld_off, fld_size;
+  tree base, rhs;
+  gimple stmt;
+  gimple_seq gs;
+  location_t loc;
+
+  base = get_base_address (expr);
+  if (base == NULL_TREE
+      || TREE_CODE (base) == SSA_NAME
+      || TREE_CODE (base) == STRING_CST)
+    return;
+
+  tcode = TREE_CODE (expr);
+
+  /* Below are things we do not instrument
+     (no possibility of races or not implemented yet).  */
+  if (/* Compiler-emitted artificial variables.  */
+      (DECL_P (expr) && DECL_ARTIFICIAL (expr))
+      /* The var does not live in memory -> no possibility of races.  */
+      || (tcode == VAR_DECL
+          && TREE_ADDRESSABLE (expr) == 0
+          && TREE_STATIC (expr) == 0)
+      /* Not implemented.  */
+      || TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE
+      /* Not implemented.  */
+      || tcode == CONSTRUCTOR
+      /* Not implemented.  */
+      || tcode == PARM_DECL
+      /* Load of a const variable/parameter/field.  */
+      || is_load_of_const (expr, is_write))
+    return;
+
+  if (tcode == COMPONENT_REF)
+    {
+      tree field = TREE_OPERAND (expr, 1);
+      if (TREE_CODE (field) == FIELD_DECL)
+        {
+          fld_off = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field));
+          fld_size = TREE_INT_CST_LOW (DECL_SIZE (field));
+          if (((fld_off % BITS_PER_UNIT) != 0)
+              || ((fld_size % BITS_PER_UNIT) != 0))
+            {
+              /* As of now it crashes compilation.
+                 TODO: handle bit-fields as if touching the whole field.  */
+              return;
+            }
+        }
+    }
+
+  /* TODO: handle other cases
+     (FIELD_DECL, MEM_REF, ARRAY_RANGE_REF, TARGET_MEM_REF, ADDR_EXPR).  */
+  if (tcode != ARRAY_REF
+      && tcode != VAR_DECL
+      && tcode != COMPONENT_REF
+      && tcode != INDIRECT_REF
+      && tcode != MEM_REF)
+    return;
+
+  func_mops++;
+  stmt = gsi_stmt (gsi);
+  loc = gimple_location (stmt);
+  rhs = is_vptr_store (stmt, expr, is_write);
+  if (rhs == NULL)
+    gs = instr_memory_access (expr, is_write);
+  else
+    gs = instr_vptr_update (expr, rhs);
+  set_location (gs, loc);
+  /* Instrumentation for assignment of a function result
+     must be inserted after the call.  Instrumentation for
+     reads of function arguments must be inserted before the call.
+     That's because the call can contain synchronization.  */
+  if (is_gimple_call (stmt) && is_write)
+    gsi_insert_seq_after (&gsi, gs, GSI_NEW_STMT);
+  else
+    gsi_insert_seq_before (&gsi, gs, GSI_SAME_STMT);
+}
+
+/* Instruments the gimple pointed to by GSI.  */
+
+static void
+instrument_gimple (gimple_stmt_iterator gsi)
+{
+  unsigned i;
+  gimple stmt;
+  enum gimple_code gcode;
+  tree rhs, lhs;
+
+  stmt = gsi_stmt (gsi);
+  gcode = gimple_code (stmt);
+  if (gcode == GIMPLE_CALL)
+    {
+      if (gimple_call_fndecl (stmt) != get_init_decl ())
+        func_calls++;
+    }
+  else if (gcode == GIMPLE_ASSIGN)
+    {
+      /* Handle assignment lhs as store.  */
+      lhs = gimple_assign_lhs (stmt);
+      instrument_expr (gsi, lhs, 1);
+      /* Handle operands as loads.  */
+      for (i = 1; i < gimple_num_ops (stmt); i++)
+        {
+          rhs = gimple_op (stmt, i);
+          instrument_expr (gsi, rhs, 0);
+        }
+    }
+}
+
+/* Instruments all interesting memory accesses in the current function.  */
+
+static void
+instrument_memory_accesses (void)
+{
+  basic_block bb;
+  gimple_stmt_iterator gsi;
+
+  FOR_EACH_BB (bb)
+    {
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+        {
+          instrument_gimple (gsi);
+        }
+    }
+}
+
+/* Instruments function entry.  */
+
+static void
+instrument_func_entry (void)
+{
+  gimple_seq seq;
+  basic_block entry_bb;
+  edge entry_edge;
+  gimple_stmt_iterator gsi;
+
+  /* Insert new BB before the first BB.  */
+  seq = instr_func_entry ();
+  gcc_assert (seq != NULL);
+  entry_bb = ENTRY_BLOCK_PTR;
+  entry_edge = single_succ_edge (entry_bb);
+  set_location (seq, cfun->function_start_locus);
+  entry_bb = split_edge (entry_edge);
+  gsi = gsi_start_bb (entry_bb);
+  gsi_insert_seq_after (&gsi, seq, GSI_NEW_STMT);
+}
+
+/* Instruments function exits.  */
+
+static void
+instrument_func_exit (void)
+{
+  location_t loc;
+  gimple_seq seq;
+  basic_block exit_bb;
+  gimple_stmt_iterator gsi;
+  gimple stmt;
+  edge e;
+  edge_iterator ei;
+
+  /* Find all function exits.  */
+  exit_bb = EXIT_BLOCK_PTR;
+  FOR_EACH_EDGE (e, ei, exit_bb->preds)
+    {
+      gsi = gsi_last_bb (e->src);
+      stmt = gsi_stmt (gsi);
+      gcc_assert (gimple_code (stmt) == GIMPLE_RETURN);
+      loc = gimple_location (stmt);
+      seq = instr_func_exit ();
+      gcc_assert (seq != NULL);
+      set_location (seq, loc);
+      gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
+    }
+}
+
+/* ThreadSanitizer instrumentation pass.  */
+
+static unsigned
+tsan_pass (void)
+{
+  struct gimplify_ctx gctx;
+
+  func_calls = 0;
+  func_mops = 0;
+  push_gimplify_context (&gctx);
+  instrument_memory_accesses ();
+  if (func_calls || func_mops)
+    {
+      instrument_func_entry ();
+      instrument_func_exit ();
+    }
+  pop_gimplify_context (NULL);
+  return 0;
+}
+
+/* The pass's gate.  */
+
+static bool
+tsan_gate (void)
+{
+  return flag_tsan != 0;
+}
+
+/* Inserts __tsan_init () into the list of CTORs.  */
+
+void tsan_finish_file (void)
+{
+  tree ctor_statements;
+
+  ctor_statements = NULL_TREE;
+  append_to_statement_list (build_call_expr (get_init_decl (), 0),
+                            &ctor_statements);
+  cgraph_build_static_cdtor ('I', ctor_statements,
+                             MAX_RESERVED_INIT_PRIORITY - 1);
+}
+
+/* The pass descriptor.  */
+
+struct gimple_opt_pass pass_tsan = {{
+  GIMPLE_PASS,
+  "tsan",                               /* name  */
+  tsan_gate,                            /* gate  */
+  tsan_pass,                            /* execute  */
+  NULL,                                 /* sub  */
+  NULL,                                 /* next  */
+  0,                                    /* static_pass_number  */
+  TV_NONE,                              /* tv_id  */
+  PROP_ssa | PROP_cfg,                  /* properties_required  */
+  0,                                    /* properties_provided  */
+  0,                                    /* properties_destroyed  */
+  0,                                    /* todo_flags_start  */
+  TODO_verify_all | TODO_update_ssa
+    | TODO_update_address_taken /* todo_flags_finish  */
+}};
+
+static bool                             
+tsan_gate_O0 (void)
+{ 
+  return flag_tsan != 0 && !optimize;   
+} 
+
+struct gimple_opt_pass pass_tsan_O0 = {{
+  GIMPLE_PASS,
+  "tsan0",                              /* name  */
+  tsan_gate_O0,                         /* gate  */
+  tsan_pass,                         /* execute  */
+  NULL,                                 /* sub  */
+  NULL,                                 /* next  */
+  0,                                    /* static_pass_number  */
+  TV_NONE,                              /* tv_id  */
+  PROP_ssa | PROP_cfg,                  /* properties_required  */
+  0,                                    /* properties_provided  */
+  0,                                    /* properties_destroyed  */
+  0,                                    /* todo_flags_start  */
+  TODO_verify_all | TODO_update_ssa
+    | TODO_update_address_taken /* todo_flags_finish  */
+}};
+
Index: gcc/tsan.h
===================================================================
--- gcc/tsan.h	(revision 0)
+++ gcc/tsan.h	(revision 0)
@@ -0,0 +1,26 @@
+/* ThreadSanitizer, a data race detector.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   Contributed by Dmitry Vyukov <dvyukov@google.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef TREE_TSAN
+#define TREE_TSAN
+
+extern void tsan_finish_file (void);
+
+#endif /* TREE_TSAN */
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 193016)
+++ gcc/common.opt	(working copy)
@@ -1518,6 +1518,14 @@ fmove-loop-invariants
 Common Report Var(flag_move_loop_invariants) Init(1) Optimization
 Move loop invariant computations out of loops
 
+ftsan
+Common RejectNegative Report Var(flag_tsan)
+Add ThreadSanitizer instrumentation
+
+ftsan-ignore=
+Common RejectNegative Joined Var(flag_tsan_ignore)
+-ftsan-ignore=filename	ThreadSanitizer ignore file
+
 fdce
 Common Var(flag_dce) Init(1) Optimization
 Use the RTL dead code elimination pass

[-- Attachment #3: race_on_heap.cc --]
[-- Type: application/octet-stream, Size: 1012 bytes --]

// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

void *Thread1(void *p) {
  *(int*)p = 42;
  return 0;
}

void *Thread2(void *p) {
  *(int*)p = 44;
  return 0;
}

void *alloc() {
  return malloc(99);
}

void *AllocThread(void* arg) {
  return alloc();
}

int main() {
  void *p = 0;
  pthread_t t[2];
  pthread_create(&t[0], 0, AllocThread, 0);
  pthread_join(t[0], &p);
  fprintf(stderr, "addr=%p\n", p);
  pthread_create(&t[0], 0, Thread1, (char*)p + 16);
  pthread_create(&t[1], 0, Thread2, (char*)p + 16);
  pthread_join(t[0], 0);
  pthread_join(t[1], 0);
  return 0;
}

// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
// CHECK: WARNING: ThreadSanitizer: data race
// ...
// CHECK:   Location is heap block of size 99 at [[ADDR]] allocated by thread 1:
// CHCEKL     #0 malloc
// CHECK:     #1 alloc
// CHECK:     #2 AllocThread
// ...
// CHECK:   Thread 1 (tid={{.*}}, finished) created at:
// CHECK:     #0 pthread_create
// CHECK:     #1 main

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

end of thread, other threads:[~2012-12-03 16:58 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-01  6:00 [tsan] ThreadSanitizer instrumentation part Xinliang David Li
2012-11-01  6:27 ` Jakub Jelinek
2012-11-01 15:47   ` Xinliang David Li
     [not found] ` <CA+4CFy4uuCtFuiqai0b_VXib1te=DeBv1_EWDFjf8UP6MYMJPg@mail.gmail.com>
     [not found]   ` <CAAkRFZKWhxJP=0p-6JCgMrMGPTj4Vv3m9yNhRgioOKxzTsss1Q@mail.gmail.com>
     [not found]     ` <CA+4CFy7ecGOkmXsdkC=LbSK5KMdBSR6eT0oLmfn2nbyr0S2bMA@mail.gmail.com>
2012-11-03  1:31       ` Wei Mi
2012-11-03 17:05         ` Wei Mi
2012-11-03 18:39           ` Jakub Jelinek
2012-11-06  0:37             ` Wei Mi
2012-11-12 18:58               ` Wei Mi
2012-11-13 16:41               ` Jakub Jelinek
2012-11-13 17:25                 ` Xinliang David Li
2012-11-13 17:36                   ` Jakub Jelinek
2012-11-13 17:55                     ` Xinliang David Li
2012-11-14  0:08                 ` Wei Mi
2012-11-14  0:54                   ` Richard Henderson
2012-11-14  1:06                     ` Wei Mi
2012-11-16 23:13                       ` Wei Mi
2012-11-18 18:52                         ` Konstantin Serebryany
2012-11-22  7:23                           ` Wei Mi
     [not found]                             ` <CACT4Y+aR5vizMRb7VCXK7w=bnEz29g9WjQkjvu=8=kds610D1Q@mail.gmail.com>
     [not found]                               ` <CACT4Y+YrUg13dqtUTD23qEWnySNgQ1T_H06R2=ytpXKZeG8UUQ@mail.gmail.com>
2012-11-22  7:45                                 ` Xinliang David Li
     [not found]                                   ` <CACT4Y+a07z9-VtGKQ7gGCyHWb_XH4sVWFtPG=qpkk_gJXfc40A@mail.gmail.com>
2012-11-22 22:06                                     ` Wei Mi
2012-11-22  8:08                               ` Jakub Jelinek
2012-11-22 15:13                                 ` [PATCH] Convert asan to use sanitizer.def builtins, initialize them if the FE didn't Jakub Jelinek
2012-12-03 16:58                                   ` Dodji Seketeli
2012-11-22  9:54                             ` [tsan] ThreadSanitizer instrumentation part Jakub Jelinek
2012-11-22 13:21                               ` [tsan] libsanitizer tweaks Jakub Jelinek
2012-11-22 23:22                                 ` Diego Novillo
2012-11-22 22:08                               ` [tsan] ThreadSanitizer instrumentation part Wei Mi
2012-11-22 23:04                                 ` H.J. Lu
2012-11-22 23:06                                   ` Jakub Jelinek
2012-11-22 23:18                                 ` Jack Howarth
2012-11-23  0:53                                   ` Wei Mi
  -- strict thread matches above, loose matches on Subject: below --
2012-11-01 19:35 Xinliang David Li
2012-11-01 20:54 ` Jakub Jelinek
2012-11-01 20:57   ` Xinliang David Li
2012-11-01 21:07     ` Jakub Jelinek
2012-11-01 21:19       ` Xinliang David Li
2012-11-01 21:24         ` Jakub Jelinek
2012-11-01 21:43           ` Xinliang David Li
2012-11-01 18:11 Xinliang David Li
     [not found] ` <CACT4Y+azNYV+8ieRthd-SkQqGO82dj2+JOdL5c15DyBc9LwyfA@mail.gmail.com>
     [not found]   ` <CACT4Y+YQDBVxL2GdK9o-8kn===1XzX9JaBJUpM5N4MYCJAeo=Q@mail.gmail.com>
2012-11-01 18:20     ` Xinliang David Li
2012-11-01 18:22 ` Diego Novillo
2012-11-01 18:24 ` Jakub Jelinek
2012-11-01 18:32   ` Xinliang David Li
2012-11-01 18:49     ` Jakub Jelinek
2012-11-01 18:57       ` Xinliang David Li
2012-11-01 19:16         ` Jakub Jelinek
     [not found]           ` <CACT4Y+bbG3MOBX0vmP-Dvf=oPDp6GBDodJ+FbHrXEmjHjWn-qw@mail.gmail.com>
2012-11-01 20:53             ` Jakub Jelinek
2012-11-02 13:31 ` Martin Jambor
2012-11-02 15:54   ` Xinliang David Li
2012-11-02 15:58     ` Jakub Jelinek
2012-11-02 16:14       ` Xinliang David Li
2012-10-31 18:56 Wei Mi
2012-10-31 23:17 ` Jakub Jelinek
2012-11-01  6:02   ` Xinliang David Li
     [not found]   ` <CACT4Y+Z77tgge+k4+DOMkCLOWL4-xhate5Ccmav3Vox3_8Pqcw@mail.gmail.com>
2012-11-01  7:22     ` Jakub Jelinek
2012-11-01  6:58 ` Jakub Jelinek

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).