This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [tsan] ThreadSanitizer instrumentation part
- From: Xinliang David Li <davidxl at google dot com>
- To: Wei Mi <wmi at google dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>, Dmitry Vyukov <dvyukov at google dot com>, Diego Novillo <dnovillo at google dot com>, Jakub Jelinek <jakub at redhat dot com>, Dodji Seketeli <dodji at redhat dot com>
- Date: Wed, 31 Oct 2012 23:00:17 -0700
- Subject: Re: [tsan] ThreadSanitizer instrumentation part
> --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.